support custom recurrence intervals (every N days/weeks, monthly) #2

Open
opened 2026-05-17 19:44:45 +00:00 by padreug · 0 comments
Owner

Problem

models.Recurrence and the publisher only support daily or weekly (with a fixed weekday). Real chore cadences need more — "every 3 days", "every 2 weeks", "monthly", etc. See the chore brief that prompted this: aiolabs/webapp#57.

Server-side scope

This issue tracks the lnbits-side mirror. The client-side (and tag-convention design) lives in aiolabs/webapp#57.

Models

models.Recurrence (currently {frequency: 'daily'|'weekly', day_of_week?, end_date?}) extends to:

class Recurrence(BaseModel):
    frequency: Literal["daily", "weekly", "every-n-days", "every-n-weeks", "monthly"]
    interval: int | None = None        # required for every-n-* (e.g. 3 for "every 3 days")
    day_of_week: str | None = None     # weekly / every-n-weeks
    day_of_month: str | None = None    # monthly: "1".."31" or "last"
    end_date: str | None = None        # cutoff (unchanged)

Keep daily / weekly as shorthand aliases — accept both shapes on read so we don't break already-published events.

Publisher (nostr_publisher.build_task_event)

Emit the new tags (proposal mirrors webapp#57):

  • ["recurrence", "every-n-days"] + ["recurrence-interval", "<n>"]
  • ["recurrence", "every-n-weeks"] + ["recurrence-interval", "<n>"] + ["recurrence-day", "<weekday>"]
  • ["recurrence", "monthly"] + ["recurrence-day-of-month", "<1..31|last>"]

Sync (nostr_sync._handle_task_event)

Parse the new tags into Recurrence. Today the parser hard-codes ("daily", "weekly") and discards anything else.

Storage

recurrence column already stores arbitrary JSON, so no migration needed — just the in-memory model widens.

Open questions

  1. Adopt RRULE (["rrule", "FREQ=WEEKLY;INTERVAL=2;BYDAY=MO"]) instead of growing our own tag set? Standard, more parsing, deferred to webapp#57's decision.
  2. How does "every N days" enumerate occurrences during sync — we don't (we don't materialize occurrences server-side), the client expands. Keep that property; the server is a cache of base events + per-occurrence completions only.
  • aiolabs/webapp#57 — client-side mirror and tag-convention design.
  • aiolabs/webapp#56 — webapp doesn't publish 31922 yet; this change has to be coordinated with whatever publish flow lands there.
## Problem `models.Recurrence` and the publisher only support `daily` or `weekly` (with a fixed weekday). Real chore cadences need more — "every 3 days", "every 2 weeks", "monthly", etc. See the chore brief that prompted this: [aiolabs/webapp#57](https://git.atitlan.io/aiolabs/webapp/issues/57). ## Server-side scope This issue tracks the lnbits-side mirror. The client-side (and tag-convention design) lives in aiolabs/webapp#57. ### Models `models.Recurrence` (currently `{frequency: 'daily'|'weekly', day_of_week?, end_date?}`) extends to: ```python class Recurrence(BaseModel): frequency: Literal["daily", "weekly", "every-n-days", "every-n-weeks", "monthly"] interval: int | None = None # required for every-n-* (e.g. 3 for "every 3 days") day_of_week: str | None = None # weekly / every-n-weeks day_of_month: str | None = None # monthly: "1".."31" or "last" end_date: str | None = None # cutoff (unchanged) ``` Keep `daily` / `weekly` as shorthand aliases — accept both shapes on read so we don't break already-published events. ### Publisher (`nostr_publisher.build_task_event`) Emit the new tags (proposal mirrors webapp#57): - `["recurrence", "every-n-days"]` + `["recurrence-interval", "<n>"]` - `["recurrence", "every-n-weeks"]` + `["recurrence-interval", "<n>"]` + `["recurrence-day", "<weekday>"]` - `["recurrence", "monthly"]` + `["recurrence-day-of-month", "<1..31|last>"]` ### Sync (`nostr_sync._handle_task_event`) Parse the new tags into `Recurrence`. Today the parser hard-codes `("daily", "weekly")` and discards anything else. ### Storage `recurrence` column already stores arbitrary JSON, so no migration needed — just the in-memory model widens. ### Open questions 1. Adopt RRULE (`["rrule", "FREQ=WEEKLY;INTERVAL=2;BYDAY=MO"]`) instead of growing our own tag set? Standard, more parsing, deferred to webapp#57's decision. 2. How does "every N days" enumerate occurrences during sync — we don't (we don't materialize occurrences server-side), the client expands. Keep that property; the server is a cache of base events + per-occurrence completions only. ## Related - aiolabs/webapp#57 — client-side mirror and tag-convention design. - aiolabs/webapp#56 — webapp doesn't publish 31922 yet; this change has to be coordinated with whatever publish flow lands there.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/tasks#2
No description provided.