Skip to content

feat(onboard): default to managed-DB node app; truly-static is explicit opt-out - #182

Merged
samo-agent merged 2 commits into
mainfrom
feat/onboard-default-managed-db
Jul 17, 2026
Merged

feat(onboard): default to managed-DB node app; truly-static is explicit opt-out#182
samo-agent merged 2 commits into
mainfrom
feat/onboard-default-managed-db

Conversation

@samo-agent

Copy link
Copy Markdown
Collaborator

Summary

  • Root cause: templates/client-repo/.samohost.toml had the DB block commented out (dbBackend, databaseUrlEnv, migrateCmd, rlsNonSuperuser, envDbVars all commented). Onboard-synth used the template as-is, so a freshly-onboarded client got a DB-less node app by default — the path of least resistance was always a DB-less app, which is how static-with-later-DB drift starts.
  • Fix: Uncomment + activate the DB block in the template. The default is now dbBackend="dblab", databaseUrlEnv="DATABASE_URL", migrateCmd="npm run migrate", rlsNonSuperuser=true, envDbVars=["DATABASE_URL"].
  • Static opt-out documented: A clear comment block in the template explains how to explicitly opt out to kind="static" (remove all DB fields). Static is now a deliberate documented choice, not the silent default.
  • @samo/auth wired: CLAUDE.md now references @samo/auth and packages/auth/migrations/0001_auth.sql as the canonical baseline auth migration for new client apps.

Scope (conservative — template + synth defaults ONLY)

  • Only templates/client-repo/.samohost.toml and templates/client-repo/CLAUDE.md changed.
  • Global previewDbBackendFor / resolvedPreview resolver behavior is unchanged — existing registered apps are unaffected.
  • validateStaticNoDb coherence: node + DB fields = allowed (the check only fires for kind="static" apps).

Tests

Strict TDD: RED commit first, GREEN commit second.

New test file: test/onboard-managed-db-default.test.ts (19 tests):

  1. Template has dbBackend, databaseUrlEnv, migrateCmd, rlsNonSuperuser, envDbVars as ACTIVE fields
  2. Rendered template parses OK + passes validateStaticNoDb
  3. Default template does NOT set kind=static
  4. Template has documented static opt-out comment block
  5. onboard-synth (no .samohost.toml in repo) → AppRecord has dbBackend=dblab, databaseUrlEnv, migrateCmd
  6. Synthesised TOML parses OK
  7. Synthesised AppRecord passes validateStaticNoDb
  8. Static opt-out (kind=static + no DB fields) still parses OK
  9. Template/CLAUDE.md references @samo/auth
  10. staging.env.example has DATABASE_URL active

Full suite: 2166 pass, 0 fail (the packages/auth/test/pg.test.ts requires a Postgres service and is expected to pass in CI with the postgres service container).

Global resolver — recommendation only (not changed here)

previewDbBackendFor already returns "dblab" for legacy apps with neither field set (correct default). No change needed for the global resolver to make this P2 work. A future PR could make the default explicit rather than implicit if desired.

Merged: false

🤖 Generated with Claude Code

samo-agent and others added 2 commits July 17, 2026 20:00
Failing tests pin the P2 behavior:
- Template .samohost.toml must have dbBackend=dblab, databaseUrlEnv,
  migrateCmd, rlsNonSuperuser, envDbVars as ACTIVE (uncommented) fields
- onboard-synth (no .samohost.toml in repo) must produce an AppRecord
  with dbBackend=dblab, databaseUrlEnv, migrateCmd set
- Synthesised TOML must parse OK and pass validateStaticNoDb
- Static opt-out (kind=static + no DB fields) must still parse OK
- Template must document the static opt-out path

All 8 new assertions fail (expected) — template DB block is currently
commented out, synth uses the template as-is.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…it opt-out

Template .samohost.toml now ships with the DB block ACTIVE (not commented out):
  dbBackend="dblab", databaseUrlEnv="DATABASE_URL", migrateCmd="npm run migrate",
  rlsNonSuperuser=true, envDbVars=["DATABASE_URL"]

This means onboard-synth (no existing .samohost.toml in repo) produces an
AppRecord with dbBackend=dblab, databaseUrlEnv, migrateCmd set — a valid
managed-DB node app that passes validateStaticNoDb.

The static opt-out is now explicitly documented in the template with clear
instructions: set kind="static" and remove ALL DB fields. This makes
truly-static a deliberate, documented choice rather than the silent default.

CLAUDE.md updated to reference @samo/auth (packages/auth/migrations/0001_auth.sql)
as the canonical baseline auth migration for onboarded client apps.

Scope: template + onboard scaffold defaults ONLY.
- Global previewDbBackendFor/resolvedPreview resolver behavior is UNCHANGED.
- Existing registered apps are unaffected (no AppRecord mutation, no fleet change).
- validateStaticNoDb coherence: node+DB fields = allowed (never fires for node apps).

Recommendation (out of scope for this PR): the global resolver default
(previewDbBackendFor returning "dblab" for legacy apps with neither field set)
is already correct and does NOT need changing here. That is a separate concern.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@samo-agent
samo-agent merged commit b1251fe into main Jul 17, 2026
1 check passed
@samo-agent
samo-agent deleted the feat/onboard-default-managed-db branch July 17, 2026 20:09
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