[Backlog] In-world calendar for timeline events #126

Open
opened 2026-07-14 19:57:10 +00:00 by claude-bot · 1 comment
Contributor

Context / Motivation

Research/product brief — explicitly gated on real user pull; do not build speculatively. Wiki entries already carry structured timeline items: LoreEntry.timeline_events is a JSONB array (webapp/backend/app/models/lore_entry.py:225, mirrored in lore_entry_version.py:39), with input shape LoreTimelineEventInput (routers/campaigns.py:205) validated by _normalise_timeline_events (campaigns.py:560) — each event can link to a lore entry, session, or milestone in the campaign. What they lack is when in the world something happened (Harptos "15 Mirtul, 1492 DR" style). Prior art: World Anvil calendars, Fantasy-Calendar.com.

Spec (starting sketch)

Calendar definition — per campaign, one optional WorldCalendar: campaign_id, name (e.g. "Calendar of Harptos"), months (JSONB list of {name, days}), weekday_names (JSONB list), year_epoch_label (e.g. "DR"), current_world_date (optional "today" marker). No leap rules initially — state this limitation in the settings UI.

In-world dates on timeline events — extend the timeline_events item shape (JSONB, so no migration for the items themselves) with an optional world_date object {year, month_index, day} validated against the campaign's calendar in _normalise_timeline_events. Rendered per the calendar definition ("15 Mirtul, 1492 DR").

Campaign timeline view — a campaign page collecting all timeline events (across lore entries + milestones) that have world_date, sorted by in-world date (year → month index → day); events without world dates fall back to the existing ordering.

Out of scope

  • Leap years/intercalary days, moons, seasons, astronomical events.
  • Real-time↔world-time conversion or session-date mapping.
  • Importing Fantasy-Calendar definitions (revisit if pulled).

Open questions

  • Is there real demand? Gate: wait for explicit user requests before pulling this out of backlog.
  • Should sessions themselves (not just wiki timeline items) get an optional in-world date ("this session covered 3-5 Mirtul")?
  • Sort stability for partial dates (year-only events)?

Acceptance criteria (for when this is pulled)

  • Calendar definition CRUD (GM); month/weekday rendering matches definition.
  • Timeline events accept/validate optional world dates; invalid month/day rejected against the definition.
  • Campaign timeline view sorts by in-world date with documented partial-date behavior.

References

  • webapp/backend/app/models/lore_entry.py:225 (timeline_events JSONB), models/lore_entry_version.py:39
  • webapp/backend/app/routers/campaigns.py:205 (LoreTimelineEventInput), :560 (_normalise_timeline_events, cross-linking rules at :597-629)

Filed from the July 2026 full-project review.

## Context / Motivation Research/product brief — **explicitly gated on real user pull**; do not build speculatively. Wiki entries already carry structured timeline items: `LoreEntry.timeline_events` is a JSONB array (`webapp/backend/app/models/lore_entry.py:225`, mirrored in `lore_entry_version.py:39`), with input shape `LoreTimelineEventInput` (`routers/campaigns.py:205`) validated by `_normalise_timeline_events` (`campaigns.py:560`) — each event can link to a lore entry, session, or milestone in the campaign. What they lack is *when in the world* something happened (Harptos "15 Mirtul, 1492 DR" style). Prior art: World Anvil calendars, Fantasy-Calendar.com. ## Spec (starting sketch) **Calendar definition** — per campaign, one optional `WorldCalendar`: `campaign_id`, `name` (e.g. "Calendar of Harptos"), `months` (JSONB list of `{name, days}`), `weekday_names` (JSONB list), `year_epoch_label` (e.g. "DR"), `current_world_date` (optional "today" marker). **No leap rules initially** — state this limitation in the settings UI. **In-world dates on timeline events** — extend the `timeline_events` item shape (JSONB, so no migration for the items themselves) with an optional `world_date` object `{year, month_index, day}` validated against the campaign's calendar in `_normalise_timeline_events`. Rendered per the calendar definition ("15 Mirtul, 1492 DR"). **Campaign timeline view** — a campaign page collecting all timeline events (across lore entries + milestones) that have `world_date`, sorted by in-world date (year → month index → day); events without world dates fall back to the existing ordering. ## Out of scope - Leap years/intercalary days, moons, seasons, astronomical events. - Real-time↔world-time conversion or session-date mapping. - Importing Fantasy-Calendar definitions (revisit if pulled). ## Open questions - Is there real demand? Gate: wait for explicit user requests before pulling this out of backlog. - Should sessions themselves (not just wiki timeline items) get an optional in-world date ("this session covered 3-5 Mirtul")? - Sort stability for partial dates (year-only events)? ## Acceptance criteria (for when this is pulled) - Calendar definition CRUD (GM); month/weekday rendering matches definition. - Timeline events accept/validate optional world dates; invalid month/day rejected against the definition. - Campaign timeline view sorts by in-world date with documented partial-date behavior. ## References - `webapp/backend/app/models/lore_entry.py:225` (`timeline_events` JSONB), `models/lore_entry_version.py:39` - `webapp/backend/app/routers/campaigns.py:205` (`LoreTimelineEventInput`), `:560` (`_normalise_timeline_events`, cross-linking rules at `:597-629`) _Filed from the July 2026 full-project review._
Author
Contributor

The wiki design record #593 covers most of this issue (owner decision, 2026-09-10). The owner tracks in-world time "very loosely", so the agreed design has in-world dates without a calendar definition:

  • Timeline items get world_date {label, sort}: the date as the setting writes it ("3 Rainmonth, 812"), plus a hidden number that keeps the order correct. Year-only and approximate dates sort correctly.
  • Sessions record their in-world start and end dates, so time visibly passes, including on the map trail.
  • An event can carry both clocks: when it happened in the world, and the session in which the party learned of it.
  • A campaign timeline view merges every article's timeline items with session events.

What remains here is the optional full calendar: months, weekdays, and dates drawn from a calendar definition. The owner doesn't need it, but another group on a hosted instance might. Keep this issue for that, still waiting on real demand as it already says. If it's ever built, the label above can be generated from the calendar and sort computed from it, so nothing recorded earlier has to change.

**The wiki design record #593 covers most of this issue** (owner decision, 2026-09-10). The owner tracks in-world time "very loosely", so the agreed design has **in-world dates without a calendar definition**: - **Timeline items get `world_date {label, sort}`:** the date as the setting writes it ("3 Rainmonth, 812"), plus a hidden number that keeps the order correct. Year-only and approximate dates sort correctly. - **Sessions record their in-world start and end dates,** so time visibly passes, including on the map trail. - **An event can carry both clocks:** when it happened in the world, and the session in which the party learned of it. - **A campaign timeline view** merges every article's timeline items with session events. **What remains here is the optional full calendar**: months, weekdays, and dates drawn from a calendar definition. The owner doesn't need it, but another group on a hosted instance might. Keep this issue for that, still waiting on real demand as it already says. If it's ever built, the `label` above can be generated from the calendar and `sort` computed from it, so nothing recorded earlier has to change.
Sign in to join this conversation.
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
rbrooks/Quest-Board#126
No description provided.