venue hierarchy steps 6-8 + peer commits #4
Loading…
Reference in a new issue
No description provided.
Delete branch "_disk-probe"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Ref update via API; direct push to main rejected with reference already exists.
Step 6 (docs/specs/2026-08-18): places.{rooms,calendars,availability} procedures with output schemas + strict inputs (availability is full-PUT — isOpen required); getCalendarEvents split admin/public with the mode server-pinned; bookingRequests.messages.{post,list,markRead} (post rate-limited 30/h per actor, proven to write nothing on exhaustion) + attachments.{add,list,delete} with storageKey claim-once (interim guard until the Step-8 upload mint); notify composed at the router layer mirroring the received-notification exactly. Embed subjectType "calendar": authz via the calendar's place across upsert/list/revoke, widget payloads structurally leak-free (serialized-payload pins), checkoutEligible false fail-closed. Public read collapses place-gate codes to CALENDAR_NOT_FOUND (no existence oracle). ROOM_NOT_FOUND / CALENDAR_NOT_FOUND / CANNOT_RETIRE_LAST_ACTIVE_ROOM / CALENDAR_SLUG_TAKEN promoted to USER_FACING with en+es copy (parity gates green). Hold layer untouched (deferred). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>`PlatformSettingsRepo.getAll()` is a `findMany` with no `where`, and it sits on the hottest path in the API: `getFeatureGates` calls it, and that use case runs from `features.*`, `events.*` and `ticket-types.*` — so one batched tRPC request commonly triggered it more than once. Measured in production over 7d (2026-08-19, `docs/ops/resource-burn.md`): **37,700 full-table reads of PlatformSetting against 18,950 tRPC requests** — ~2 per request — for a table that changes on the order of days. That was ~2 of the ~17.8 queries/request behind Neon's +31% growth since 2026-07-30. Adds `withCachedPlatformSettings`, a read-through cache applied at the composition root beside `withGuardedRepos` rather than inside `createPrismaRepos`. A repo that silently caches is a nasty surprise when you go hunting for stale reads, so the caching is a visible wiring decision. Also collapses a cold-cache stampede: concurrent callers share one in-flight load. Without that, a batched request on a cold cache lets every caller miss and issue its own full-table read — the exact pileup being removed. TTL is 60s, not the 10 minutes `createFooterDefaultsCache` uses, because these rows drive FEATURE GATES. A toggle that takes ten minutes to appear reads as a broken toggle; a minute reads as a save. Invalidation, which is subtler than it looks: - The five writers that call `repos.platformSettings.upsert(...)` directly (theme presets, POS terminal location) go through the cached instance and invalidate themselves. - `updatePlatformSetting` does NOT. It writes inside `repos.tx(...)`, and transaction-scoped repos are built fresh from the tx client, so the cached wrapper never sees that write. Left alone, the main settings-editing path would have kept serving pre-write values for the full TTL. The platform router now invalidates explicitly for it — unconditionally, since this cache holds the whole table so any key makes the snapshot stale. - The TTL remains the backstop for OTHER instances, which get no invalidation signal. Any future write path that goes through a transaction needs the same explicit invalidation; noted in the decorator's docs. Verified: build 8/8 · @th/adapters 1,292 (incl. 8 new) · @th/trpc 627 · @th/core 7,907. `apps/api` has 2 failures in test/seed-places.test.ts that predate this change (its prisma stub lacks `room`, which `places.ts` began requiring inf42f16b4) — fixed separately. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>Step 8 + placement persistence (docs/specs/2026-08-18). Clicking a day on an admin calendar now lands on quick-create with the date, time, venue, calendar and room already filled — and the created event KEEPS them: save-event-for-{human,org} accept optional calendarId/roomId, validated inside the write tx (cross-place calendar or room, a RETIRED room, or placement on a freeform event all reject with no mutation; a calendar without a room never guesses one). Verified against the dev DB: the row carries both columns, and a forged cross-place calendarId creates nothing. Month cells gain an always-rendered create affordance (not hover-only — hover doesn't exist on touch and month is the default view) that does not hijack the existing click-to-Day-view. The long-dead onSlotPress prop is finally wired for week/day. Prefill survives the moderator Ticketed vs Community dialog and is dropped if the venue is changed away from it. Embeds: a calendar-subject picker grouped by venue, and the widget's list view no longer renders blank for them (it was gated on "owner"; calendar subjects return "calendar"). Calendar subjects force link-out because assertEventAllowedForEmbed fails closed for them. Booking requests gain a message thread (attachments list-only — no upload mint yet). Also carries this session's earlier dashboard/calendar overflow fixes: the restored moderator dialog, the orders-table scroll, and two 320px wrap fixes. Hold layer untouched (deferred). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>Pull request closed