Move servers/dating → demos/dating/server and the dating route's
co-located _components/_lib/_design assets → demos/dating/web. Single
`npm run dating:dev` boots both server and web via concurrently.
Replace the warm-paper / raspberry-pink Claude Design adaptation with
a sober desktop-first system:
- Tokens: slate neutrals + violet accent, Inter family, dark mode via
prefers-color-scheme + explicit data-theme.
- Inline SVG icon set (Icon.svelte, Feather-style) — no Unicode glyph
placeholders.
- Layout shell: 240px rail nav on desktop, bottom tab bar on mobile;
auth + onboarding own their own shell.
- Discover: square photo carousel (dots + chevrons), name/age/location
overlay, action buttons floating off the photo edge, sticky context
panel on desktop.
- Matches: clean conversation list with unread dot + chevron-on-hover.
- Chat: 3-column on desktop (threads + thread + match context), 2-col
on tablet, single thread on mobile. Day separators, retry/dismiss
on failed messages, autogrow composer with Enter-to-send.
- Profile: sticky hero card + 3-section form, dirty/saved indicator.
- Photos: dropzone + grid with hover-only cell toolbar (set primary,
reorder, delete).
- Onboarding: sidebar stepper (320px) + content panel.
- Auth: split layout (form left, brand quote right) on ≥900px.
Server boot: env loader's repo-root resolution corrected after the
move (../../.. instead of ../..) so .env.local at the repo root is
picked up again.
Hoist BRAND.md and SECURITY.md into docs/, drop superseded audit
notes that were already closed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the chat poll-every-3-seconds compromise with a real
WebSocket pipeline. Server side:
`realtime.mjs`:
- In-memory hub mapping `userId → Set<WebSocket>`. Single-process,
zero external deps; fine for the local demo. A clustered deployment
would swap in Redis pub/sub behind the same surface.
- `attach(userId, socket)` registers a socket and self-detaches on
close/error.
- `broadcast(userIds, event)` JSON-encodes once and dispatches to
every subscriber of every listed user, swallowing per-socket errors.
`server.mjs`:
- Adds a `WebSocketServer({ noServer: true })` that listens on the
HTTP server's `'upgrade'` event for `/api/realtime` paths.
- Authentication mirrors the HTTP path: extract `dating_session` from
the upgrade request's `Cookie` header, pass through `currentSession`
and reject with 401 if it doesn't resolve.
- Rejects upgrades from origins outside the CORS allowlist (the
cookie-based auth is the second line of defence; origin gating is
the first).
- On accept, attaches the socket to the hub and sends a `hello`
envelope so the client can confirm authentication round-trip.
`routes.mjs:messagesPost`:
- After persisting a new message, calls
`broadcast(relationIds(match.users), { type: 'dating.message.created',
message: view })`. Both members (sender and counterpart) get the
push, so multi-device sessions stay in sync.
Adds `ws` (8.20) + `@types/ws` to dependencies.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the application composition root and six new runtime artifacts. lang
and logr alone could not cover an app surface — locale propagation, format
helpers, frontend preferences, validation, persistence and DOM service all
needed independent artifacts that aapp wires together under a single
locale source of truth and a shared logger.
New artifacts:
- aapp: composition root. createActiveApp + createTestApp +
App.createSiumEngine + frontend.persist + Storage wiring.
- stor: pluggable adapters (local/session/memory/cookie + SSR via
cookieAdapter.fromCookies), envelope versioning + migrate +
TTL, validate via Standard Schema, intra-tab + cross-tab sync,
Storage.clear(), per-entry adapter/namespace overrides.
- adom: reactive DOM service. shareViewport opt-in + per-window
tracker, dispose(). breakpoints, viewport, attribute writes.
- fend: frontend preferences (theme, mode, dir, density,
reducedMotion, reducedSound) with auto/clear/isAuto pattern.
- fmts: localized formatting (numbers, currency, units, dates) with
shared LocaleSource and per-domain auto/clear pattern.
- sium: validation engine. Standard Schema interop, Lang/Logger
injection, codec/refine/transform, domain types
(color/date/time), introspection.
Existing artifacts extended:
- lang: BCP 47 SupportedLocale (LangBase | base-region), mono lang
for monolingual apps, extend() leaf-overwrite warning,
EngineLang/ActiveLang naming alignment with the rest of the
project (no Instance suffix).
- logr: EngineLogger.dispose(), failureThrottleMs anti-cascade for
transports, README sync to the per-level filter API
(minLevel removed).
Cross-cutting:
- $locale: shared LocaleSource type consumed by fmts and fend.
- arts/README.md: artifact map, dependency graph, naming conventions.
- Test pages for every artifact under /test/<artifact>.
733 tests passing; svelte-check clean except 2 pre-existing errors on
sium/svelte provider (port pending).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
logr:
- entry.id auto-generated (UUID v4 / hex fallback) — survives backend dedup, batched-retry, cross-transport correlation.
- Transport.levels replaces minLevel — per-level { enabled, filter? } record. More flexible: enable/disable individual levels, attach per-level filters. Helper levelsAtLeast(level) for the common min-level case; allLevels() for the permissive case.
- Transport buffering: buffer, flushIntervalMs, writeBatch on the Transport interface. Logger tracks per-transport queues, flushes on size/time/flush()/detach/beforeunload. httpTransport and lokiTransport implement writeBatch for true batched HTTP delivery.
- logger.flush() to drain all buffered transports manually.
- Web Vitals integration (src/arts/logr/vitals.ts): registerWebVitals(logger, webVitalsSDK, options?) turns LCP/INP/CLS/FCP/TTFB samples into structured log entries tagged with route/rating. Zero-deps in logr — SDK is injected.
- ConsoleTransportOptions now exposes filter so vitals can be silenced on console while still flowing to Sentry/Datadog/Loki.
- Runtime name constant: `engine_logger` (via src/arts/logr/consts.ts) replaces hardcoded 'logr' string in failure reports, console prefix and synthetic entry tags.
lang:
- README expanded with a dedicated section on ts() and the LangString type: plain strings, LangRecord, LangRef; the `message: LangString` prop pattern for generic components; when to use the isLang* guards.
Tests: 185 passing (added vitals + buffer + entry.id coverage).
Docs: logr README now documents vitals (hot-zone patterns for LogQL / Sentry Discover / Datadog), buffering, the levels config, and the helpers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>