Skip to content

v0.102.0 — Campaign configuration: the settings and the Treasury model

Shipped 2026-09-21 — built on version/0.102.0, twenty-one commits, merged to main as 0fe2aef5, tagged v0.102.0. The twelfth of the releases the near-term roadmap sequences from the August 2026 heuristic evaluation, and part one of Campaign configuration; the roadmap page is the settings and the Treasury model. Part two, the Treasure Manager, is v0.103.0. The help is Campaigns → Configuration and The Treasury. Module releases: dnd5e 0.16.0 and system8 0.17.0 (Module API 1.38.0); Action API 0.4.0.

The tabletop properties a group decides at session zero — starting level, which options are open, how characters advance, how treasure moves, what players may do without the GM — had nowhere to live: a campaign carried grid and reference data and nothing a rulebook calls a variant. Now each system module declares its settings and the platform declares three groups of its own, the values are stored once on the campaign, a Configuration set of sections on Edit Campaign renders them, a creation walkthrough asks the session-zero ones first, and — because half of session zero is about treasure — the Treasury's data model ships with them, so the treasure settings govern something. Decisions CC-D1 (defaults at read; a schema change is never a migration) through CC-D8 (what the walkthrough asks) at their recommendations.

The schema and the settings

  • Module API 1.38.0 (CC.1) — SystemModule.campaignConfigurationSchema: a typed, ordered list of settings in groups, each with one of seven kinds (number, boolean, choice, multi-choice, text, filter over a module catalogue faceted by source, table by level or tier), a default and help text, askedAt: creation, requires, editableBy; getCampaignCatalogue for what a filter ranges over; startingKitFor for what a new character begins with. Pure functions in packages/shared: validation, resolution (a missing key reads its default — CC-D1), reconciliation on a system change, describeCampaignSetting for the walkthrough's side card, and a schema-shape check the server runs at load so a broken module schema is logged and left out rather than taking the campaign down.
  • One column and two routes (CC.2) — campaigns.configuration holds only the edited keys; GET /api/campaigns/:id/configuration answers the combined schema, the edited keys, every key resolved, features, canEdit and isOwner; PATCH merges a partial record (null clears a key), validates strictly, refuses an owner-only key for a non-owner, and commits.
  • The platform's groups (CC.3) — Players (eight keys, every default today's behaviour; two of them are grants: a role-default row on the campaign with principal collaborator/map or collaborator/character, which the permission resolver reads at each child, so the tab and the Share dialog read one thing; three gate routes: making maps, inviting, custom channels), Rolls (three, declared; the client routes a roll's frame in v0.103.0), Treasure (six).
  • The Configuration sections (CC.4) — every group of the combined schema is a section of Edit Campaign under a Configuration heading, one autosaving field per setting by kind (a filter is a catalogue picker with source facets; a table a grid), the help under the label, default until edited and Reset to default after, inert with a reason where a feature is missing or the key is the owner's.
  • dnd5e 0.16.0 (CC.5) — six groups, ~40 settings per edition: character creation (starting level, ability score methods, rerolls, point-buy budget, filters over sources / classes / species / backgrounds / feats / spells, multiclassing, HP at level up, starting magic items, starting gold by level), advancement, combat, rest and recovery, gear and magic, inspiration; the catalogues from the bundled SRD with source on every entry; the starting kit from the class record (2024's option A; 2014's Equipment section read (a) throughout), items matched to the equipment catalogue for weight and value. system8 0.17.0 (CC.6) — five groups, 23 settings with the docs' values as defaults, the nine classes and Classless, feats and powers by the docs' slug, and starting-wealth.md's kit and table. Both built against a platform that may not have the types (CI resolves @purple-cat/shared against main): the setting types are mirrored and the members spread from an object, typechecked against both hosts.
  • The creation walkthrough (CC.7) — Create makes the record and stays on the page; then one step per group asked at creation (the system's before the platform's — CC-D8), each field the same autosaving one with the composed explanation beside it, then distance and area, currencies and reference data as the Edit form's own sections, then a summary and Done. Walkthrough.tsx is the generic stepper the character walkthrough will reuse.
  • A system change re-validates (CC.8) — kept, dropped with reasons, said in the answer and a toast. Action API 0.4.0 (CC.9) — api.campaign.configuration(key?), read-only, once per run; useCampaignConfiguration() on the client. The .cat archive (CC.10) carries configuration in campaign.yml and the Treasury as treasury/buckets.yml and items.yml.

The Treasury's model

  • The holder model (CC.11 — CC-D3) — equipment gains campaign_id, holder_type, holder_id, bucket_id, earmarked_character_id and price; character_id is nullable and kept in step; existing rows backfill to holder_type: character; the inventory reads by holder; an item a bucket holds is refused on the sheet's edit and delete.
  • Buckets (CC.12) — treasuries (one per campaign, keyed by its id) and treasury_buckets (party / hoard / merchant / starting / loot, revealed, carriedBy validated against treasure.partyTreasure); the party bucket comes with the campaign; a member sees the revealed buckets and the party's; a deleted bucket's items become nobody's rather than vanishing. /api/treasury/:campaignId and /buckets.
  • The transfer (CC.13 — CC-D5, D6, D7) — POST …/transfer { itemId, quantity?, to }: a conditional write that refuses when someone was first (already-moved), a stack split as a row of its own, a coin item claimed by a character credited to the wallet, the campaign's id on an item entering the Treasury. An Editor moves anything; a member moves their own character's items and claims from a bucket they can see.
  • The treasury as an entity (CC.14 — CC-D4) — versioned as itself (treasury:<campaignId>: the buckets and every item with the campaign's id), its permissions its campaign's; every bucket write and transfer a commit, and a transfer also a commit of a character at either end, whose before-state is read ahead of the write. Listed, diffed, blamed and restored through /api/history like the rest.
  • Treasure mode (CC.15) — treasury-only refuses a player's hand-added item; distribution-only also refuses claims until v0.103.0 gives it a session; earmarks honoured. Starting equipment (CC.16) — on a character's link: the system's kit transferred in and its coins credited (system norms), the coins and a merchant bucket (starting currency), a starting bucket for the GM's earmarks (GM-curated), nothing (free); once per character. The Players gates (CC.17) — characters per player, new characters pending until an Editor accepts (their kit granted then), and sheetEditing: gm-only locking the owner's sheet to control in the one access resolver.

Guards and verification

Every platform key names the file that reads it or says why it is declared ahead of its enforcement (CC.18); every module schema is checked at load; the help wiki's Campaigns page describes the walkthrough, the Configuration sections and the Treasury. Verified live: the three platform groups and the 5e and System 8 groups in the nav, a grant-backed toggle writing its row, the 5e Classes picker listing the SRD under its source, a filter saving, the walkthrough's eight steps end to end. Harness tests hold the double-claim, the wallet credit, the stack split, the modes, the gates and the treasury's commits.