Esposter
Esposter

Architecture

These pages explain the durable, cross-cutting mechanisms that span multiple packages or feature areas — the repo-wide answer to "whenever we need X, we do it this way". Area-specific features live under their own sections (for example platform or esbabbler).

PageWhat it covers
PlatformThe cross-product layer model — identity, resources, datasets, publishing, events
ResourcesThe standard for product persistence and surface — resource model, capabilities, factory
DatasetsThe standard for serving tabular data — contract, DatasetProvider capability, row cap
PublishingThe Publishable capability — versioned publish copy + rate-limited public read
Authbetter-auth OAuth setup, session middleware, and the authed procedure chain
Azure servicesAzure service ownership, the storage split, event flows, and the real-time layer model
EnvironmentEnvironment detection across the three Nuxt runtime contexts
File uploadsThe two-step Azure Blob SAS upload pattern and upload procedure inventory
SerializationHow class instances survive the three transport paths (Azure Table, Nuxt payload, tRPC)
Client data accessThe useQuery + useMutation primitives — non-blocking fetch, optimistic apply, staleness
Async operationsConcurrency by declaration — reads are latest-wins, writes queue, nothing drops silently
CachingOne cached-read primitive, invalidated by tag when a write says what it changed
Persisted data — latest shape onlyNo legacy-shape schemas or migration code — parse the latest shape or reset
No compatibility debtA wrong name, shape or deployed identity is corrected in place — never aliased
Content token rewritingFinding tokens in authored content — self-delimiting matches, one pass, converge on read
Monorepo toolingpnpm workspace orchestration, virrun routing, publishing, installs, and CI job shape
Build pipelineOne bundler, shared build presets, and an external list derived from each manifest
Agent configurationThe vendor-neutral .agents tree, its .claude alias, and what stays out of the docs
Server testingtRPC router test wiring — in-memory DB, mocked Azure services, controlled auth session
Dialog shellOne dialog shell — StyledDialog owns the card, the body slot and the actions row
Destructive confirmationOne shared delete dialog — StyledDeleteFormDialog + opt-in type-the-name guard
Singleton dialogsStore-driven singleton dialogs — one mounted dialog per feature, never one per list item
NavigationNuxtLink/navigateTo for every link — never a raw anchor — and instant docs routing
Persist then notifyGuard, persist, notify — then best-effort bookkeeping that can never fail the caller
NotificationsOne typed event, one Function, fanned out to the surfaces its type declares
Conditional writesA write derived from a read is conditional on that version, and a lost race re-applies
Blob lifecycle ownershipEvery blob prefix's naming discipline and single teardown owner per lifecycle event
No pollingPolling banned repo-wide — every wait is event-driven or awaits a completion handle
No manual recoveryFailed async work retries itself on an event, with an attempt cap and a quarantine
Null vs undefinedOne absent-value sentinel in app-owned code — null survives only in boundary shapes
Module boundariesThe app's three import zones — shared/ may never reach into the client-only app tree
Browser executionWhere app/ runs — persisted state, a client-only phase, and the one use left for checkIsServer
SearchOne search stack — StyledSearchDialog palettes + useAutoSearch/useCursorSearcher
Rate limitingPostgres-backed budgets shared across instances, enforced in the authed middleware
Security postureThe app's nuxt-security configuration — CSP, permissions policy, and what is off and why
Responsive layoutOne breakpoint scale feeding both Vuetify and UnoCSS
Date and time displayEvery rendered date is a NuxtTime — the reader's locale and timezone, no mismatch
Section navigationOne scrollspy for every sidebar that tracks scrolled content, plus the rail that follows it

Cross-cutting standards we decided against are recorded in rejected — check it before proposing a new one. Ones we chose not to build yet, each with a revisit trigger, are in deferred.