# Palace Ring — Multiple Masters ## The Hard Step Is 1 → 2 Going from Junwon's palace to Junwon + Elizabeth is where all the real multi-master work happens. Every assumption baked into a single-master system gets surfaced and resolved. Once two palaces coexist cleanly, adding a third or fourth is mostly repetition. Going from 2 → 4 should be easy. Going from 1 → 2 is the work. ## What Has to Change to Get to 2 **Auth** - Login screen at `stable.palacering.com` - Mastername + password → session - Session routes the master to their palace, not a hardcoded one **Palace routing** - The ring currently serves one palace (Junwon's) - It needs to know which master is logged in and serve their palace data — their diary, their health logs, their butler memory - Every API endpoint that reads from a file path needs to resolve that path relative to the logged-in master's palace, not a hardcoded path **Butler identity per master** - The butler currently knows it is Ace serving Junwon in Manglasabang - For Elizabeth, the butler must know it is William serving Elizabeth in Whitehall - The butler's identity files (name, palace name, master name) must be per-palace **Palace filesystem on the server** - Junwon's palace lives on his Mac - Elizabeth's palace needs to live on palacestableserver VM - On sign-up: copy modelpalace, place at `/palaces/whitehall/` **Data isolation** - No request from Elizabeth's session can read Junwon's files - No request from Junwon's session can read Elizabeth's files - This must be enforced at the API layer, not assumed ## What Stays the Same - The apps themselves — diary, health, family, homemaking work the same for any master - The butler logic — same system, different identity and different file paths - The platform — Postgres, Caddy, Docker all unchanged ## Architecture The palacering app (`/code`) runs on the palacestableserver VM. Palace data is not centralised on the VM — each palace lives where it lives, and the app reaches it. - **Junwon's palace** (`palaces/manglasabang/`) stays on his Mac. The VM connects to the Mac over Tailscale to read his data. His data never moves. - **New masters' palaces** (e.g. Elizabeth's `palaces/whitehall/`) live on the VM filesystem. This means compute is centralised (the VM runs the app for everyone) while data is distributed (Junwon's data is on his Mac, others are on the VM). The app resolves each master's palace path from their session — Junwon's path goes over Tailscale, Elizabeth's is local on the VM. ## Current State - Junwon: palace on local Mac, app still running locally at palacering.com - Elizabeth: account in Postgres on palacestableserver VM, palace not yet provisioned - Next (MAN-84): deploy app to VM, connect to Mac over Tailscale, serve Junwon at stable.palacering.com - Then (MAN-86): add auth, dynamic paths, provision Elizabeth's palace ## What Must Change in Code (Audit: 2026-03-21) ### 1. Auth — does not exist at app level The main palacering app has no login, no session, no middleware. `family/api/auth.ts` has a token-based auth for the family feature only, with hardcoded in-memory masters. Everything else is completely open. **Must build:** - Login endpoint — mastername + password → session cookie or JWT - Middleware that extracts the logged-in master from every request - All data endpoints must refuse requests with no valid session ### 2. Hardcoded palace path — `manglasabang` everywhere Every data API endpoint resolves paths with `"palaces/manglasabang/palaceappsdata/..."` hardcoded. Must become the logged-in master's palace name. Affected: `api/diary/day.ts`, `api/diary/chat.ts`, `api/health/day.ts`, `api/health/chat.ts`, `api/notebook.ts`, `api/tasks.ts`, `push.ts`, `mail/subscribe.ts` **Fix:** Once master context exists in the request, replace `"manglasabang"` with the master's palace name from session. ### 3. Hardcoded master identity in mail `mail-accounts.ts` and `channels/email/index.ts` hardcode Junwon and Ace's email accounts. Elizabeth has no accounts. **Fix for MVP:** Elizabeth doesn't need email in the ring. Scope mail to the logged-in master's accounts only. Defer Elizabeth's email setup. ### 4. Redis thread store — no master namespacing `thread-store.ts` uses prefix `"pc-threads:"` globally. Two masters' threads will collide. **Fix:** Prefix all Redis keys with master ID: `"pc-threads:{masterId}:"`. ### 5. Session log files — shared directory, no master separation `web-bridges.ts` and `session-tails.ts` put all session logs in one directory with no master prefix. **Fix:** Subdirectory per master, or prefix filenames with master ID. ### 6. Frontend hardcodes Junwon `mail.astro` hardcodes `owner: 'junwon'` as initial state and builds account selectors statically. **Fix:** After auth, fetch accounts for the logged-in master from an API endpoint. Set initial owner from session. ### 7. Bridge/butler — no master context `ClaudeBridge` in `web-bridges.ts` loads no master-specific identity. For Elizabeth's butler (William) to know who it is, it needs to be initialised with her palace's identity files. **Fix:** Pass palace root path to bridge on init. Butler loads identity from that palace. ## Critical Order 1. **Auth first** — nothing else can be made per-master without knowing who the master is 2. **Dynamic path resolution** — replace hardcoded `manglasabang` with session master's palace 3. **Redis namespacing** — prevent cross-master data collision 4. **Butler identity per palace** — so William knows he is William ## After 2 Works When Junwon and Elizabeth both have working palaces on stable.palacering.com, the pattern is proven. Adding mom and dad becomes: provision palace, create account, done. The infrastructure handles the rest.