Shops: central catalog plus GM-curated shops for parties and campaigns #138

Open
nasandre wants to merge 1 commit from feature/shops into main
Owner

Implements the shop plan (docs/crafting-harvesting-shop-plan.md §4): one central shop over the whole item catalog, plus GM-curated shops connected to parties and campaigns.

Central shop (virtual)

Synthesized on request over all three item sources - official magic/sourcebook items (enabled-sourcebook gated), mundane SRD gear and homebrew (the 222 Morena items included). Catalog-priced, with a rarity fallback for unpriced items (Common 50 gp .. Mythic 25,000, 10 gp default). Never stored, so it can never go stale.

Custom shops (GM-owned)

  • Storage-backed CRUD (shop entity, encounters pattern). Owners, campaigns-permission users, full_control and connected-campaign DMs manage; players see shops connected to their parties/campaigns.
  • Curated listings reference catalog items by a stable { kind: 'official'|'homebrew', id } ref, with optional price override and optional stock (default unlimited; finite stock decrements and refuses when sold out).
  • Connected to campaigns and parties from the existing lists.

Purchase transaction

POST /shops/:id/buy - resolve ref -> price (override -> catalog -> rarity fallback) -> funds check -> gp deduction -> item mapped into the buyer's equipment (magic/rarity/attunement/description carried across) -> stock decrement -> ledger entry (capped at 100). gp only per the agreed v1; buyers need edit access to the character.

UI

  • /shops management page (nav, campaigns permission): create/edit shops, connect campaigns/parties, curate via dual-catalog search, quick homebrew form that authors an item and lists it in one step.
  • ShopModal from the character sheet Inventory header (gold badge, shop picker, search, Buy with live funds checks).

Validation

  • Backend 35 suites / 755 tests (15 new: pricing fallback + SRD cost conversion, ref resolution across all three sources, central synthesis, transaction incl. funds refusal / price override / stock to sold-out / ledger, mapping fidelity, visibility rules), frontend 33 files / 374 tests, tsc clean x3.
  • Live-verified: central shop serves all three sources; purchases flow end-to-end against a probe account (cleaned up afterwards).

Routing fix en route

The shops router mounts with a /shops path prefix - a bare internal router.use(requireAuth) intercepted every later-mounted route (including /auth/register). Mount is now path-scoped.

Known limitations

  • Mundane SRD equipment rows are name-only stubs upstream, so they price at the 10 gp default; magic items and homebrew carry real prices (rarity fallback covers the unpriced Morea materials).
  • Sell-back ratio, crafting commissions and mixed-denomination payments are future phases per the plan doc.
Implements the shop plan (docs/crafting-harvesting-shop-plan.md §4): one central shop over the whole item catalog, plus GM-curated shops connected to parties and campaigns. ## Central shop (virtual) Synthesized on request over all three item sources - official magic/sourcebook items (enabled-sourcebook gated), mundane SRD gear and homebrew (the 222 Morena items included). Catalog-priced, with a rarity fallback for unpriced items (Common 50 gp .. Mythic 25,000, 10 gp default). Never stored, so it can never go stale. ## Custom shops (GM-owned) - Storage-backed CRUD (`shop` entity, encounters pattern). Owners, `campaigns`-permission users, `full_control` and connected-campaign DMs manage; players see shops connected to their parties/campaigns. - Curated listings reference catalog items by a stable `{ kind: 'official'|'homebrew', id }` ref, with optional price override and optional stock (default unlimited; finite stock decrements and refuses when sold out). - Connected to campaigns and parties from the existing lists. ## Purchase transaction `POST /shops/:id/buy` - resolve ref -> price (override -> catalog -> rarity fallback) -> funds check -> gp deduction -> item mapped into the buyer's equipment (magic/rarity/attunement/description carried across) -> stock decrement -> ledger entry (capped at 100). gp only per the agreed v1; buyers need edit access to the character. ## UI - **/shops management page** (nav, campaigns permission): create/edit shops, connect campaigns/parties, curate via dual-catalog search, **quick homebrew** form that authors an item and lists it in one step. - **ShopModal** from the character sheet Inventory header (gold badge, shop picker, search, Buy with live funds checks). ## Validation - Backend 35 suites / **755 tests** (15 new: pricing fallback + SRD cost conversion, ref resolution across all three sources, central synthesis, transaction incl. funds refusal / price override / stock to sold-out / ledger, mapping fidelity, visibility rules), frontend 33 files / **374 tests**, `tsc` clean x3. - Live-verified: central shop serves all three sources; purchases flow end-to-end against a probe account (cleaned up afterwards). ## Routing fix en route The shops router mounts with a `/shops` path prefix - a bare internal `router.use(requireAuth)` intercepted every later-mounted route (including /auth/register). Mount is now path-scoped. ## Known limitations - Mundane SRD equipment rows are name-only stubs upstream, so they price at the 10 gp default; magic items and homebrew carry real prices (rarity fallback covers the unpriced Morea materials). - Sell-back ratio, crafting commissions and mixed-denomination payments are future phases per the plan doc.
One central shop over the whole item catalog, plus GM-owned custom shops
connected to campaigns and parties with a curated selection.

- Central shop (virtual, never stored): synthesizes a shop view over the
  official magic/sourcebook items (enabled-sourcebook gated), mundane SRD
  gear and homebrew items. Catalog-priced; unpriced items fall back by
  rarity (Common 50 gp .. Mythic 25,000, default 10).
- Custom shops: storage-backed CRUD under the 'shop' entity, owned by
  their creator, manageable by 'campaigns'-permission users and
  connected-campaign DMs. Listings reference catalog items by a stable
  { kind, id } ref with optional price override and optional stock
  (default unlimited; finite stock decrements and refuses when empty).
- Purchase transaction: resolve ref -> price -> funds check -> gp
  deduction -> catalog item mapped into the buyer's equipment (magic,
  rarity, attunement and description carried across) -> stock decrement
  -> ledger entry (capped at 100) on custom shops. gp only; buyers need
  edit access to the character they buy for.
- Visibility: players see the central shop plus shops connected to their
  parties/campaigns; GMs see all.
- GM page (/shops, campaigns permission): create/edit shops, connect
  campaigns/parties, curate listings via dual-catalog search, quick
  homebrew form that authors an item and lists it in one step.
- Player-facing ShopModal from the character sheet Inventory header:
  shop picker, search, Buy with live gold checks.

One routing pitfall fixed en route: the shops router is mounted with a
/shops path prefix - a bare internal `router.use(requireAuth)` would
otherwise have intercepted every later-mounted route including
/auth/register.

15 backend tests: pricing fallback + SRD cost conversion, ref resolution
across all three sources, central-shop synthesis, purchase transaction
(funds refusal, price overrides, stock decrement to sold-out, ledger),
mapping fidelity and visibility rules.

Known limitation: mundane SRD equipment rows are name-only stubs upstream,
so they price at the 10 gp default until detail enrichment; magic items
and homebrew carry real prices.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feature/shops:feature/shops
git switch feature/shops

Merge

Merge the changes and update on Forgejo.
git switch main
git merge --no-ff feature/shops
git switch feature/shops
git rebase main
git switch main
git merge --ff-only feature/shops
git switch feature/shops
git rebase main
git switch main
git merge --no-ff feature/shops
git switch main
git merge --squash feature/shops
git switch main
git merge --ff-only feature/shops
git switch main
git merge feature/shops
git push origin main
Sign in to join this conversation.
No reviewers
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
nasandre/dnd-character-generator!138
No description provided.