Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/PRODUCT-ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ instead (see subsystem F).
| M | Windows around the tools: Overview, Guests, Money, Checklist, Sync & history, palette | E, L | ⬜ planned — master plan, phase 2 |
| N | Day-of binder and vendor links | E, J | ⬜ planned — master plan, phase 3 |
| O | One live document: tools stop keeping copies; real-time sync | — | ⬜ planned — master plan, phase 4 |
| P | The toolbox, and travel, ceremony, boxes and bar | L, O | ✅ **built** — [spec](superpowers/specs/2026-09-29-toolbox-and-new-tools-design.md), plans for [the toolbox](superpowers/plans/2026-09-29-toolbox.md), [travel and calendars](superpowers/plans/2026-09-29-timeline-travel-and-calendars.md), [the cast and Ceremony](superpowers/plans/2026-09-29-cast-and-ceremony.md), [Boxes](superpowers/plans/2026-09-29-boxes.md) and [the Bar](superpowers/plans/2026-09-29-bar.md), 2026-09-29; the proposals joining tools to each other wait on the maintainer |

## Decisions log

Expand Down
146 changes: 146 additions & 0 deletions docs/superpowers/plans/2026-09-29-bar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Bar Implementation Plan

**Goal:** A couple buying their own drinks — a marquee, a barn, a venue that
charges corkage — learn how much of each to buy, in the units a UK shop sells
it in, and what it will roughly cost. Every figure is on screen, can be
changed, and can be put back.

**Architecture:** A slice of its own, `bar`, holding only what the couple
chose: the kind of bar, the crowd, and each figure they changed from its
default. Nothing the calculator works out is stored: who is coming is read
live from the guest list, and the amounts are worked out from that and the
figures every time, so a guest saying no changes the wine. Merged as one part,
as Ceremony is. Built as Boxes was: pure sums, a page that reads and writes the
wedding on its one history, a tool off until added.

**Tech Stack:** TypeScript, the suite's kit, pdf-lib for the shopping list.
**No new dependencies.**

**Spec:** [Phase 4 of the toolbox spec](../specs/2026-09-29-toolbox-and-new-tools-design.md#phase-4--bar)

## The sum

1. **Who.** The people coming are the guests who have not said no, or a
number the couple types instead (and the page says so while it is typed).
Evening-only guests are added for the evening. A share of everyone is not
drinking alcohol — children, drivers, anyone who does not — and drinks soft
drinks instead, at the same rate.
2. **Four parts of the day**, each drinks per head of those drinking:
the drinks reception (hours × drinks an hour), the toast (glasses),
the meal (glasses of wine), the evening bar (hours × drinks an hour).
A part the couple is not buying for — a venue's paying evening bar — is
set to nothing.
3. **What is poured in each part.** The toast is fizz and the meal is wine,
split red and white. The reception and the evening pour a mix — fizz,
wine, beer, spirits — as shares, set by the kind of bar and each one
changeable.
4. **A lighter or heavier crowd** takes a fifth off or puts a fifth on, except
the toast, which is one glass whoever is raising it.
5. **Into what a shop sells**: glasses to 75cl bottles by the glass size, beer
and cider one bottle or can a drink in cases of 24, spirits to 70cl
bottles by the measure, mixers and soft drinks to litres, ice to kilos.
6. **Less what they already have**, then rounded up to whole cases when they
are buying on sale or return (fizz and wine in sixes, beer in 24s).
7. **The spend**: each line priced by the couple, per bottle, case, litre or
kilo; the lines with no price are left out of the estimate and it says so.

## The kinds of bar

| Kind | Reception | Evening |
|---|---|---|
| Full bar | fizz 70%, beer 30% | beer 40%, wine 40%, spirits 20% |
| Beer and wine | fizz 70%, beer 30% | beer 50%, wine 50% |
| Signature cocktails, beer and wine | cocktails 70%, beer 30% | beer 40%, wine 40%, cocktails 20% |
| No and low | as beer and wine, every line alcohol-free, no spirits | |

A cocktail is bought as a spirit measure and a mixer. Choosing a kind puts the
mix back to that kind's; it is one step on the history.

## The defaults

**Agreed by the maintainer, 2026-09-29, before building**, as they stand:

| Figure | Default | Why |
|---|---|---|
| Not drinking alcohol | 20% of guests | Roughly one UK adult in five does not drink, and children and drivers are in the count. |
| Evening-only guests | 0 | Typed by the couple. |
| Drinks reception | 2 hours × 1.5 an hour = 3 each | UK guidance: two in the first hour, one an hour after. |
| Toast | 1 glass | Universal. |
| The meal | 2 glasses of wine (175ml) — just under half a bottle | "Half a bottle a head" is the UK rule of thumb. |
| Evening bar | 4 hours × 1 an hour | "One drink an hour" after the first. |
| Red of the wine | 50% | |
| Fizz glass | 125ml — 6 to a bottle | |
| Wine glass | 175ml | The UK's standard medium glass. |
| Spirit measure | 25ml — 28 to a 70cl bottle | The UK's single measure. |
| Mixer | 150ml a spirit or cocktail | |
| Soft drink | 250ml | |
| Ice | 1kg a person | UK ice suppliers: 1kg a head for drinks, 1.5kg to chill bottles too. |
| Crowd | Usual; lighter −20%, heavier +20% | |
| Whole cases | On | Sale or return costs nothing to round up. |
| Where bought | Fizz and wine: wine merchant. Beer and spirits: cash and carry. Mixers, soft drinks, ice: supermarket. | |
| Prices | None until typed | Prices date quickly and differ by shop. |

For 100 coming with the defaults: 42 bottles of fizz, 36 white and 36 red,
9 cases of beer, 3 bottles of spirits, 10 litres of mixers, 50 of soft drinks,
100kg of ice.

## 4a — The sum and the page

- [x] `bar` joins the contract's slices: `{ kind, crowd, people, figures,
mix, lines, wholeCases }`, only what the couple chose. Merged as one part.
- [x] Pure sums (`lib/bar/sum.ts`): who, the parts, the lines, the spend;
every default in one table (`lib/bar/defaults.ts`).
- [x] Pure actions: change a figure, put it back, choose a kind (resets the
mix), a line's price, what they have, where it is bought.
- [x] The page, `/bar`: the figures on the left, what to buy on the right.
Each changed figure shows its default and puts it back. Registered as a
tool, off until added. The example wedding has a bar.
- [x] The front page's area: what is bought for how many, and the estimate.

## 4b — On paper

- [x] The shopping list, grouped by where each thing is bought, as a PDF and
as CSV. It joins the wedding pack.

## 4c — Planners

- [x] The library keeps bar settings: the kind, the crowd, the figures, the
mix, the prices and where each is bought — no guest count and nothing a
couple already has. Using it replaces the wedding's settings. A migration
widens the database's kinds, proved against PGlite.

## Not in this phase

The proposals in the spec that join Bar to other tools — hours from the
Timeline's blocks, the spend in Money, "buy the drinks" on the Checklist,
crates as Boxes — each wait for the maintainer to accept them.

## Status

**Complete — 4a, 4b and 4c, 2026-09-29.** 1,865 suite tests and 116 in the
contract package, typecheck and build clean, all 109 Playwright tests green.
No new dependencies. **One migration**, `20260929000006_library_bar`, widening
the library's kinds again: apply it, with Phases 2 and 3's, before deploying.

**What executing it found.**

- The guest list does not say who is invited for the evening only, which a UK
wedding's evening bar depends on, so evening-only guests are a figure of the
Bar's, typed, drinking in the evening and not before.
- The amounts exist for every wedding with guests, whether or not it uses the
Bar, so the wedding pack prints the drinks only while the Bar is shown —
otherwise every pack would have gained a page nobody asked for.
- A figure's field and a price's needed decimals the whole-number field did
not allow; it became one `NumberInput` with a step, used by Money, Boxes,
the Timeline's journeys and the Bar, rather than a second field.
- Putting a figure back and changing it shared a label, and the history
folds same-labelled edits made within 700ms into one step, so undoing the
one undid both; putting back is its own step now.
- The panel headings came before any heading of their level; the figures
have a heading of their own, as What to buy does.
- The page, the shopping list and the CSV say "42 bottles, 7 cases of 6" from
one function, so they cannot disagree.
- As built, where it differs from the spec: the toast is fizz and the meal
wine, with only the reception and the evening pouring a mix; a cocktail is
bought as a spirit measure and a mixer; prices start empty; and "no and
low" is a kind of bar, naming every drink alcohol-free.
75 changes: 75 additions & 0 deletions docs/superpowers/plans/2026-09-29-boxes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Boxes Implementation Plan

**Goal:** The couple pack for the day in boxes: what is in each, found in a
moment ("where are my shoes?"), and each box tied to the part of the day it is
needed for — "this box has my shoes in it and needs to be at the house for 9".

**Architecture:** A slice of its own, `boxes`, merged box by box as guests and
jobs are, since two people pack at once. A box's where and when are its
block's — the location and the resolved start — read from the Timeline, never
typed onto the box, so moving the block moves the box. Who takes it is people
from the crew, named as Delegation names them. Built as Ceremony was: pure
actions, a page that reads and writes the wedding on its one history, a tool
off until added.

**Tech Stack:** TypeScript, the suite's kit, pdf-lib for the labels and the
list. **No new dependencies.**

**Spec:** [Phase 3 of the toolbox spec](../specs/2026-09-29-toolbox-and-new-tools-design.md#phase-3--boxes)

## 3a — The boxes

- [x] `boxes` joins the contract's slices: `{ boxes: Box[] }`, a box being a
number, a name, items (a label, how many, packed or not), the block it is
needed for or none, who takes it, and notes. Merged per box.
- [x] Pure actions: add, change, remove a box; add, change, tick, remove and
move an item to another box. Numbers go on from the highest.
- [x] *Add the usual boxes*, UK first, matched by name so it never doubles up:
the rings and paperwork, getting ready, the day's odds and ends, overnight.
- [x] Finding: one search over every box's items and names.
- [x] Checks. What is left: a box needed for a block the day no longer has;
things still to pack in the last week. The page: a box nobody is taking, and
somebody taking it who has left the crew.
- [x] The page, `/boxes`, and the front page's area. Registered as a tool, off
until added. The example wedding packs for its day.

## 3b — On paper

- [x] A label for each box, four to a sheet: the number large, the name, where
and by when, who is taking it, and what is in it.
- [x] The packing list, every box and every item with a box to tick, as a PDF
and as CSV. The list joins the wedding pack.

## 3c — Planners

- [x] The library keeps a set of boxes: their names and what goes in each,
without who takes them or when they are needed. The database's kinds are
widened by a migration, proved against PGlite.

## Status

**Complete — 3a, 3b and 3c, 2026-09-29.** 1,840 suite tests and 113 in the
contract package, typecheck and build clean, all 103 Playwright tests green.
No new dependencies. **One migration**, `20260929000005_library_boxes`,
widening the library's kinds again: apply it, with Phase 2's, before
deploying.

**What executing it found.**

- A box's where and when are its block's, read through `dayPlaces` — the
timeline's blocks with their resolved starts — so nothing about a place or
a time is stored on a box, and a block moved moves every box needed at it.
- What is left had a local `places` of its own (the room's space names), which
the new helper's first name shadowed; the compiler said so, and the helper
is `dayPlaces`.
- "Nobody is taking it" is a problem only for a box with somewhere to be; the
honeymoon bag, not for the day, is the couple's own.
- Delegation named a crew member who is a guest by the guest list, inline;
Boxes needed the same rule, so it is one `personName` both use.
- The slice merges box by box, as guests and jobs do, proved by two people
ticking in two boxes and both ticks surviving the merge.
- As built, where it differs from the spec: a thing moves to another box from
a menu on its row rather than by dragging — reachable from a keyboard, and
one way to do it; items have no notes of their own, the box has them; and a
library set of boxes adds what a wedding has none of by name, as the usual
boxes and the checklist do, rather than replacing its boxes.
90 changes: 90 additions & 0 deletions docs/superpowers/plans/2026-09-29-cast-and-ceremony.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# One Cast, and Ceremony Implementation Plan

**Goal:** The people a wedding is built around — the couple, their parents
and grandparents, their wedding parties, and roles of the couple's own
devising — are recorded once and shared by Group shots and a new Ceremony tool,
which plans the processional: who walks, in what order, how, and to what music.

**Architecture:** The cast leaves the `shots` slice for a slice of its own,
`cast`, since two tools now edit it and a tool writes only its own slice. It is
moved by the load-time pass that already converts older shapes, and read from
either place until then, so a document the server reads before any browser
has loaded it still has its cast. Ceremony is built as Group shots was: a
slice, `ceremony`; pure actions over it; a page that reads and writes the
wedding directly, on its one history. A processional group's members are the
same kinds a shot's are, resolved by the same code.

**Tech Stack:** TypeScript, the suite's kit, pdf-lib for the page. **No new
dependencies.**

**Spec:** [Phase 2 of the toolbox spec](../specs/2026-09-29-toolbox-and-new-tools-design.md#phase-2--one-cast-and-ceremony)

## 2a — One cast

- [x] `cast` joins the contract's slices. `CastSlice { roles: Cast; customRoles }`.
- [x] `readCast(doc)`: the `cast` slice, or — for a document not yet converted —
the cast and custom roles still inside `shots`, old role names included.
`Shots` keeps only its sections.
- [x] The load-time pass writes the cast to its own slice and takes it out of
`shots`, silently, as it converts "bride" and "groom".
- [x] Each partner's grandparents join the fixed roles, as a party role.
- [x] Group shots reads and writes the cast there; "Who's who" edits `cast`.
Readiness, the front page, the prints and the validator follow.

## 2b — Ceremony

- [x] `ceremony` joins the contract's slices: `{ processional: WalkGroup[] }`,
a group being a label, members (the shot's member kinds), how they walk
(alone, in pairs, in threes), which side they go to, and a cue — the music,
and when it changes.
- [x] Pure actions: add, change, move, remove a group; add and remove members.
- [x] *Suggest an order* from the cast: the officiant, grandparents, parents,
the wedding parties, then the couple — a starting point, every part of it
editable, and nothing in it assuming who walks with whom.
- [x] Checks: somebody walking who has declined; a role nobody has been cast
in. What is left and the front page say so, when Ceremony is shown.
- [x] The page, `/ceremony`: the order on the left, the picked group on the
right, with the member picker Group shots uses (moved to be shared).
Registered as a tool, off until added.
- [x] The example wedding gets a processional, since it shows every tool.
- Not done, on purpose: a tour chapter. The tour is held to under thirty steps
and has twenty-nine; Ceremony's list carries the anchor one would point at
(`ceremony.order`) for when a chapter elsewhere is trimmed.
- The resolver both tools use moved to `lib/cast/resolve` as `resolveMembers`,
taking any group with a label and members; its words no longer say "shot".

## 2c — Paper, and planners

- [x] One page for the officiant and whoever runs the day, and the order as
plain text to paste into an email. The page joins the wedding pack.
- [x] The library keeps a processional: its groups, roles and cues, with no
guest named.

## Status

**Complete — 2a, 2b and 2c, 2026-09-29.** 1,816 suite tests and 110 in the
contract package, typecheck and build clean, all 96 Playwright tests green.
No new dependencies. **One migration**, `20260929000004_library_processional`,
widening the library's kinds: apply it before deploying, as every migration.

**What executing it found.**

- The cast is read from either place, not only after the load pass has
moved it, because the planner's Weddings page runs What is left on the
server over stored documents nobody has opened since.
- After parsing, the contract fills an absent slice with `{}`, so "this
wedding has its own cast" is decided by what the slice holds, not by its
being there.
- Group shots' resolver was already the right shape for a processional — a
label and members — so it moved to `lib/cast/resolve` rather than being
copied; "Who's in it" became one `MemberPicker`; Money's nullable number
had already gone to the kit in Phase 1, and the guest picker went to
`components/cast`.
- The processional's page and its email text are made from one list of rows,
so they cannot disagree.
- The library's kinds are fixed in the database as well as in the code; the
migration test proves a processional is kept and an unknown kind still is
not.
- The officiant is words ("The officiant", "The registrar") rather than a
crew member: nothing yet needs the link, and words were already a member
kind.
Loading
Loading