Skip to content

feat(self-host): Tier 1 Docker / Node self-hosted deployment#990

Merged
lane711 merged 5 commits into
mainfrom
lane711/non-cloudflare-hosting-issue
Jul 2, 2026
Merged

feat(self-host): Tier 1 Docker / Node self-hosted deployment#990
lane711 merged 5 commits into
mainfrom
lane711/non-cloudflare-hosting-issue

Conversation

@lane711

@lane711 lane711 commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • SQLite driver — D1Database-compatible adapter via better-sqlite3; auto-migrates fresh databases; walk-up directory resolution for migration files (tsup flat-dist safe)
  • Filesystem + KV + Queue adapters — R2Bucket / KVNamespace / MessageQueue drop-in replacements for local deployments
  • Node server adapter — wraps the SonicJS Hono app so local bindings are injected before bootstrap middleware (Hono middleware ordering fix)
  • my-sonicjs-app/src/self-host.ts — Node/Bun entry point; reads SONICJS_DB_PATH, SONICJS_STORAGE_PATH, SONICJS_KV_PATH, PORT
  • Dockerfile + docker-compose.yml — multi-stage Alpine build; persistent /app/data volume
  • Schema fix — added password_reset_token, password_reset_expires, two_factor_enabled to auth_user in 0001_core.sql (present in Drizzle schema but missing from migration)

Smoke test results (local Docker)

GET /health  → 200 {"status":"running"}
POST /auth/sign-up/email  → 200 {token, user}
POST /auth/sign-in/email  → 200 set-cookie: better-auth.session_token=...
GET /admin (with session)  → 302 → 200

Test plan

  • packages/core unit tests for all four adapters (sqlite-driver, filesystem-driver, memory-kv-driver, sync-queue-driver)
  • Docker smoke test: health + sign-up + sign-in + admin UI (manually verified)
  • CI type-check + unit tests
  • E2E tests (CI only per CLAUDE.md)

Related

Closes #939 (non-Cloudflare hosting issue)

🤖 Generated with Claude Code

lane711 and others added 5 commits July 1, 2026 17:11
Adds a self-hosting adapter layer so SonicJS runs outside Cloudflare
Workers with no code changes to the core CMS.

- **sqlite-driver.ts** — D1Database-compatible SQLite driver via
  better-sqlite3; auto-migrates fresh databases; handles tsup's
  flat-dist layout by walking up directories to find migrations/
- **filesystem-driver.ts** — R2Bucket-compatible local storage adapter
- **memory-kv-driver.ts** — KVNamespace adapter with optional JSON
  persistence across restarts
- **sync-queue-driver.ts** — MessageQueue adapter (synchronous, in-process)
- **node-server.ts** — wraps a SonicJS Hono app in a fresh Hono wrapper
  so DB/storage/KV bindings are injected BEFORE bootstrap middleware runs
  (ordering fix: Hono appends middleware in registration order)

- **my-sonicjs-app/src/self-host.ts** — Node/Bun entry point; reads
  env vars (SONICJS_DB_PATH, SONICJS_STORAGE_PATH, etc.) and serves
  via @hono/node-server

- **Dockerfile** — multi-stage build (builder compiles native modules;
  runtime Alpine copies node_modules + built dist)
- **docker-compose.yml** — persistent volume for /app/data

- Added missing `password_reset_token`, `password_reset_expires`, and
  `two_factor_enabled` columns to auth_user (were in schema.ts / Drizzle
  model but missing from 0001_core.sql migration)

- Unit tests for all four adapters (sqlite-driver, filesystem, kv, queue)
  using the real better-sqlite3 harness per R10

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Creates initial admin user (admin@sonicjs.com / sonicjs!) on first
boot using @better-auth/utils/password for hash compatibility.
Idempotent — skips silently if any user already exists.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Admin route is gated by requireRbac('portal','access') — seeding
auth_user alone isn't enough. Call bootstrapDocumentTypes +
ensureSystemRbacSeed + addUserRoleByName via the D1-compatible
SqliteDriver after creating the auth_user/auth_account rows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rebase onto origin/main (resolved migrations-bundle conflict by
  regenerating from our updated 0001_core.sql)
- Move better-sqlite3 to root optionalDependencies so npm ci in CI
  can install the native module for sqlite-driver tests
- Inject better-sqlite3 lock file entry (npm skips it locally because
  the package is already resolved via parent node_modules in the
  conductor worktree — CI needs an explicit entry)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lane711 lane711 force-pushed the lane711/non-cloudflare-hosting-issue branch from f43cb13 to eae8588 Compare July 2, 2026 00:13
@lane711 lane711 merged commit 35e4ca3 into main Jul 2, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant