The Mongo→SQLite cutover, completed so chat-docdb can be DELETED with zero
data loss and an instant revert at every step.
- DualWriteModel: wraps a primary (served) + mirror model; reads/props fall
through to primary, the 10 write methods run on primary then replicate the
affected docs to the mirror KEYED BY THE PRIMARY'S _id (upsert if present,
delete if gone). Symmetric — same code mirrors mongoose->sqlite (pre-flip)
and sqlite->mongoose (post-flip escape hatch). Mirror failures are logged,
never thrown, so the served path can't break; gaps are caught by the
pre-flip count reconcile + the idempotent backfill.
- DocModel.upsertRaw: exact by-_id upsert (verbatim, no timestamp stamping) —
the shared primitive for the mirror AND the backfill, so live mirroring and
the one-shot copy converge on one keyspace without duplicating.
- Seam: applySqliteOverrides now honors TWO flags — CHAT_STORE_SQLITE (served)
+ CHAT_STORE_DUALWRITE (mirrored) — yielding the four cutover states. One
shared node:sqlite connection per process (was per-createModels-call).
- Route User/Session/Token through the handle (methods/index.ts) and add the
auth+billing CollectionSpecs (User/Session/Token/Balance/Transaction). These
are the collections actually populated in chat-docdb outside the 24 already
wired; User is the hot-path record every request loads and every conversation
references by _id, so it MUST move for a lossless Mongo delete.
- connectDb() is now Mongo-optional: unset MONGO_URI => SQLite-only mode, skip
the connection (final state, chat-docdb gone) with bufferCommands off so a
stray mongoose query fails fast instead of hanging.
- Dockerfile{,.multi,.static}: node:20/22-alpine -> ghcr.io/hanzoai/nodejs
:v24.18.0 (Node 24; node:sqlite built in, better-sqlite3 compiles).
- config/backfill-sqlite.js: one-shot Mongo->SQLite copy + count reconcile.
Tests: DualWriteModel.spec (10) green — mirror-by-primary-_id both directions,
read passthrough, bulkWrite, idempotent backfill, all 29 specs build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
26 lines
759 B
Docker
26 lines
759 B
Docker
# Static SPA — pre-built dist served by lightweight file server
|
|
# Gateway/ingress handles load balancing, rate limiting, SSL, SPA routing.
|
|
#
|
|
# Pre-requisite: run `make build-static-local` first to build client/dist
|
|
#
|
|
# Build: docker build -f Dockerfile.static -t ghcr.io/hanzoai/chat:latest .
|
|
# Run: docker run -p 3080:3080 ghcr.io/hanzoai/chat:latest
|
|
|
|
FROM ghcr.io/hanzoai/nodejs:v24.18.0
|
|
|
|
RUN npm install -g serve@14
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy pre-built static files
|
|
COPY client/dist/ /app/dist/
|
|
COPY client/public/ /app/public/
|
|
|
|
# Merge public assets into dist (favicon, icons, etc.)
|
|
RUN cp -rn /app/public/* /app/dist/ 2>/dev/null || true && rm -rf /app/public
|
|
|
|
EXPOSE 3080
|
|
|
|
# serve with SPA fallback on port 3080
|
|
CMD ["serve", "-s", "dist", "-l", "3080"]
|