Examples, the scaffolder and the deploy guide follow the dev loop - #1228
Conversation
Every database-backed example's `dev` script is now `opensaas dev`, its `db:push` is `opensaas db update`, its README drops the schema-apply pre-step, and its `.env.example` ships no default `DATABASE_URL` — a fresh clone takes the Dev database branch (ADR-0063). The two starter templates' `migrate`/`migrate:deploy` point at `prisma migration plan` and `prisma db migrate`. The scaffolder's post-step is install and generate only, and the `.env` it writes sets no `DATABASE_URL`, so scaffolding reaches no database and the first `pnpm dev` brings one up. The deploy guide migrates from the committed `migrations/` directory with `prisma db migrate`, carries the pgvector provisioning and privilege paragraph beside the Database escape (ADR-0065), and loses the file-tracing pin along with the `prisma-client` tree that no longer exists. `examples/plain-css-theming` is untouched: it has no package dependencies and no database. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
🦋 Changeset detectedLatest commit: 9fc28ca The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| This creates the SQLite database (`dev.db`) with your schema. | ||
|
|
||
| ### 5. Run the Test Script | ||
| ### 4. Run the Test Script |
There was a problem hiding this comment.
Step 4 now runs a database-dependent script before anything creates a database. Previously step 4 was pnpm db:push, which created dev.db; now the only thing that brings a database up is pnpm dev at step 5. Following the README in order, the test script calls getContext() → resolveDatabaseUrl(), which finds no DATABASE_URL (the new .env.example leaves it commented) and no .opensaas/dev-db state file, and throws DatabaseUrlUnresolvedError. Either move the test-script step after "Start the Admin UI", or say it needs pnpm dev running in another terminal — the way examples/rag-openai-chatbot was updated in this same PR.
| ``` | ||
|
|
||
| ### 5. Seed Some Data (Optional) | ||
| ### 4. Seed Some Data (Optional) |
There was a problem hiding this comment.
Same ordering problem as rag-ollama-demo: the seed/inspect step (and pnpm db:studio two lines below) is now numbered ahead of pnpm dev, but pnpm db:push was the step that used to create the database and it is gone. With no DATABASE_URL and no running dev loop there is no connection to resolve, so pnpm db:studio fails at step 4. It needs to come after "Run Development Server", or say it requires pnpm dev running in a second terminal.
| "db:push": "prisma db push", | ||
| "migrate": "prisma migrate dev", | ||
| "migrate:deploy": "prisma migrate deploy", | ||
| "db:update": "opensaas db update", |
There was a problem hiding this comment.
Removing db:push here breaks the Playwright e2e harness, which is not updated in this PR. e2e/global-setup.ts targets examples/starter-auth and calls setupDatabase(), which runs execSync('pnpm db:push --accept-data-loss', { cwd: exampleDir }) (e2e/utils/db.ts:43) — that script no longer exists, so global setup dies with "Command db:push not found" before any test runs. The same file also seeds .env with envContent.replace(/DATABASE_URL=.*/, ...); the new .env.example only carries DATABASE_URL on a commented line, so that substitution now rewrites a comment and leaves the variable unset. The e2e job is gated on github.base_ref == 'main' so it does not run on this PR, but it will fail the moment prisma-8 targets main.
| "db:push": "prisma db push", | ||
| "migrate": "prisma migrate dev", | ||
| "migrate:deploy": "prisma migrate deploy", | ||
| "db:update": "opensaas db update", |
There was a problem hiding this comment.
The nightly published-create-e2e job still drives the scaffolded project through the removed script: .github/workflows/nightly.yml runs pnpm generate; pnpm db:push; pnpm build and then asserts test -f dev.db, with DATABASE_URL: file:./dev.db. Once this scaffolder change is published, pnpm db:push will not exist in the generated project and the job fails. The examples-build job in the same file also still claims each .env.example "defaults DATABASE_URL to a value that matches its config's Prisma provider", which is no longer true for any example after this PR.
| @@ -230,17 +236,16 @@ openssl rand -base64 32 | |||
|
|
|||
| ## Step 4: Author the First Migration | |||
|
|
|||
There was a problem hiding this comment.
This step dropped the # Ensure DATABASE_URL + DIRECT_DATABASE_URL are set prerequisite, but the command still needs a live connection: the guide itself says so at "Authoring Migrations in CI" — "Planning a new one needs a database to plan against — prisma migration plan resolves its origin through the db ref ... and the connection prisma.config.ts gives it". A reader who follows Step 4 literally, with no DATABASE_URL set (which is now the documented local default) and no opensaas dev running, gets a connection failure rather than a planned migration. Restore the prerequisite line, or say to run it with pnpm dev up / DIRECT_DATABASE_URL pointed at a disposable Postgres.
| ### "Migration failed" | ||
|
|
||
| **Symptoms:** `prisma migrate deploy` errors | ||
| **Symptoms:** `prisma db migrate` errors |
There was a problem hiding this comment.
The symptom line was updated to prisma db migrate but the two solutions immediately below it were not, and they are now wrong on both counts: "Check migration files in prisma/migrations/" contradicts line 246, which says the packages live in migrations/ at the project root, and npx prisma migrate resolve is a Prisma 7 command that no longer exists in the migration plan / db migrate surface this guide now documents. Someone hitting a failed migration is sent to an empty directory and a command that errors.
| pnpm dev | ||
|
|
||
| # 4. Seed the knowledge base | ||
| # 4. Seed the knowledge base, from a second terminal |
There was a problem hiding this comment.
This is a single pasteable bash block, and pnpm dev on the line above never exits — so nothing after it runs. The prose "from a second terminal" is right, but a reader copying the block (which is the point of a QUICKSTART) hangs at step 3 and never seeds. Split the seed into its own fenced block under a "in a second terminal" heading.
|
|
||
| // The two documented setup steps, run via the borrowed toolchain. | ||
| const setupEnv = { ...process.env } | ||
| delete setupEnv.DATABASE_URL |
There was a problem hiding this comment.
Only DATABASE_URL is cleared, but findDatabaseUrl consults DIRECT_DATABASE_URL first (packages/core/src/db/url.ts, CONNECTION_VARIABLES = ["DIRECT_DATABASE_URL", "DATABASE_URL"]). On any machine or runner that exports DIRECT_DATABASE_URL, generate takes the environment branch and the guard silently stops proving what its name and the assertions below claim — that the scaffold reaches a Generated bundle with no database anywhere. Delete both variables.
Coverage Report for Core Package Coverage (./packages/core)
File CoverageNo changed files found. |
Coverage Report for UI Package Coverage (./packages/ui)
File CoverageNo changed files found. |
Coverage Report for CLI Package Coverage (./packages/cli)
File CoverageNo changed files found. |
Coverage Report for Auth Package Coverage (./packages/auth)
File CoverageNo changed files found. |
Coverage Report for Storage Package Coverage (./packages/storage)
File CoverageNo changed files found. |
Coverage Report for RAG Package Coverage (./packages/rag)
File CoverageNo changed files found. |
Coverage Report for Storage S3 Package Coverage (./packages/storage-s3)
File CoverageNo changed files found. |
Coverage Report for Storage Vercel Package Coverage (./packages/storage-vercel)
File CoverageNo changed files found. |
borisno2
left a comment
There was a problem hiding this comment.
Code review — verdict: REQUEST CHANGES
High-effort review of the full 50-file diff (claude/issue-1159-examples-scaffolder-docs → prisma-8). Eight findings are posted as inline comments; the blocking ones and the cross-cutting checks are summarised here.
Blocking
-
examples/starter/package.json/examples/starter-auth/package.json— removingdb:pushbreaks two live consumers.e2e/utils/db.ts:43runspnpm db:push --accept-data-lossinexamples/starter-auth; Playwright global setup dies before any test.e2e/global-setup.ts's/DATABASE_URL=.*/substitution now only rewrites the commented line, so the var is never set. Latent only because thee2ejob is gated onbase_ref == 'main'— it detonates at the merge tomain..github/workflows/nightly.ymlstill runspnpm db:pushand assertstest -f dev.dbagainst the scaffolded app. That fails as soon as this scaffolder change publishes. Theexamples-buildjob's comment claiming.env.exampledefaultsDATABASE_URLis now false for every example.
Workflows and e2e are correctly untouched here (a concurrent PR owns them), but this PR is what invalidates them — the two need to land together or in a stated order.
-
examples/rag-ollama-demo/README.md:82andexamples/composable-dashboard/README.md:98— steps that need a database are numbered ahead of the step that starts one.db:pushwas what created it; with noDATABASE_URLand no.opensaas/dev-dbstate file,resolveDatabaseUrl()throwsDatabaseUrlUnresolvedError. Either reorder, or add the "second terminal" noterag-openai-chatbotgot. -
docs/content/how-to/deploy.md:238— the droppedDATABASE_URL+DIRECT_DATABASE_URLprerequisite was load-bearing. Line 451 of the same guide saysprisma migration planneeds a database to plan against. Followed literally against the new local default (noDATABASE_URL, noopensaas dev), step 4 fails. -
docs/content/how-to/deploy.md:607— half-updated troubleshooting. The symptom line moved toprisma db migrate, but the solutions beneath still sayprisma/migrations/(contradicting line 246's rootmigrations/) andnpx prisma migrate resolve, a Prisma 7 command that no longer exists on this surface. A doc naming a command that isn't there is the failure mode this ticket exists to remove.
Non-blocking
examples/rag-openai-chatbot/QUICKSTART.md:25— one pasteable bash block in whichpnpm devnever exits, so the seed below it never runs, despite the prose saying "second terminal". Split the block.packages/create-opensaas-app/tests/scaffold-first-run-guard.test.ts:140— onlyDATABASE_URLis deleted, butfindDatabaseUrlprefersDIRECT_DATABASE_URL. On any environment exporting the latter, the guard quietly stops proving "no database anywhere". Delete both.examples/composable-dashboardkeeps--port 3002where every other ported example uses-p. Pre-existing spelling, faithfully preserved — a nit, not a defect. (The 3002 collision withtiptap-demois also pre-existing.)
Checked and correct
opensaas dev -- next dev -p <port>genuinely works: commander consumes the top-level--and the remainder lands in the[command...]variadic — no unknown-option error. Applied to all five custom-port examples; the seven default-port ones get a bareopensaas dev.plain-css-themingis a static CSS example with no scripts and is correctly excluded — twelve is the right count.- Command spellings:
opensaas dev,opensaas db update,prisma migration plan,prisma db migrateall match ADR-0003/ADR-0065 and the CLI surface on this branch.rm -rf .opensaas/dev-dbmatchesDEV_DATABASE_DIRinpackages/cli/src/commands/dev.ts.db:studiostill resolves while the dev loop runs, via the state file. .env.example: no activeDATABASE_URLin any of the twelve — every one is commented, andenv.test.tsnow assertsenvExample === envso the pair cannot drift.- Scaffolder: no remaining reference to
DbProvideranywhere in the repo; the post-step plan is exactlyinstall → generatewith no database step; noany, no type casts in the three changed TS files. - Tests strengthened, not loosened — the guard now asserts
.opensaas/dev-dbis absent and the env pair is identical;setup.test.tsasserts the exact two-step array. - Deploy guide: zero occurrences of
outputFileTracingIncludesorprisma-client; the pgvector provisioning-and-privilege paragraph is present at line 42 beside the Database escape, correctly noting pgvector is not a trusted extension and the58P01failure mode. - Scope: no example
opensaas.config.tsor application source, no.github/workflows/, noe2e/— only scripts, env files, docs and the scaffolder/deploy guide, as the ticket requires. - Changesets: exactly one file,
added,+18/-0. No pre-existing.changeset/file modified or deleted.
On the pre-existing SQLite state — verified independently, and it matters more than "premature"
The report is accurate. DatabaseConfig.provider on this branch is typed 'postgresql' (single literal, packages/core/src/config/types.ts:2669), yet eleven of the twelve examples still declare provider: 'sqlite' with @prisma/adapter-better-sqlite3; only rag-openai-chatbot is Postgres. So opensaas generate — and therefore opensaas dev — cannot succeed in those eleven today. That is pre-existing and belongs to another ticket.
Where I would not sign it off as merely "premature docs": the scaffolder now runs generate automatically, and scaffold-first-run-guard.test.ts asserts that opensaas generate on the scaffolded starter template reaches a Generated bundle. The starter template is one of the eleven SQLite configs. So this PR's own guard test cannot pass until the config conversion lands — this is not only documentation running ahead of the code, it is a test in this PR depending on it.
Verdict: REQUEST CHANGES. The doc/step-ordering issues (2–4) are fixable within this PR and should be. The scaffolder, env files, changeset and scope are all clean, and the -- argument form is correct. The db:push removal (1) and the SQLite precondition are sequencing constraints against sibling PRs rather than defects in this diff — but they must be sequenced explicitly, not merged on the assumption that someone else's PR lands first.
Every example README's DB-dependent step now follows the step that brings a database up. `rag-ollama-demo` and `composable-dashboard` had them numbered ahead of `pnpm dev`; `rag-openai-chatbot` numbered its seed before the server it told the reader to have running. The standalone test/seed scripts in `auth-demo`, `blog`, `json-demo` and `mcp-demo` say they need `pnpm dev` up. The QUICKSTART's single pasteable block is split, since `pnpm dev` never exits. The deploy guide restores the connection prerequisite on Step 4 — planning needs a database, as "Authoring Migrations in CI" says two hundred lines later — as the Database escape rather than the old default `DATABASE_URL`. The "Migration failed" entry is consistent again: the packages live in `migrations/` at the project root, and there is no `migrate resolve` in Prisma 8, so it says what a deployer does instead (an apply is one transaction; a failure leaves the database where it started). `scaffold-first-run-guard.test.ts` asserted `opensaas generate` on the starter template, which still declares `provider: 'sqlite'` and a Prisma 7 adapter that is not resolvable on this branch — the guard fails at config load when it actually runs. It passed only because `RUN_SCAFFOLD_GUARD=1` is set in the `e2e` job alone, which is gated on `base_ref == 'main'`. It now reads the template's declared provider and skips against #1129 until the conversion lands, and clears `DIRECT_DATABASE_URL` as well as `DATABASE_URL` so the "no database anywhere" claim is not provable by the runner's environment. `composable-dashboard` uses `-p` like every other ported example. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Review findings addressed in 9fc28ca. Per finding: 1 — 2 — README step ordering (blocking). Reordered so a reader following the numbers succeeds. I walked all twelve database-backed examples, not just the two named:
Checked mechanically as well as by eye: in every README, the first 3 — 4 — 5 — the guard test (blocking). You were right, and the reason it passes is worse than "not yet true": it never runs. I ran it for real ( Rather than loosen it, the guard now reads the declared provider in Non-blocking. QUICKSTART's single block split at
Verified: |
Implements #1159. Part of #1125.
Documents and wires the loop that #1157 and #1158 shipped:
opensaas devstarts the Dev database, generates, reconciles and spawns the app;opensaas db updatepromotes a staged change.Examples (twelve database-backed)
auth-demo,blog,composable-dashboard,custom-field,file-upload-demo,json-demo,mcp-demo,rag-ollama-demo,rag-openai-chatbot,starter,starter-auth,tiptap-demo:dev→opensaas dev(a custom port becomesopensaas dev -- next dev -p <port>)db:push→db:update→opensaas db updaterm -rf .opensaas/dev-db.env.exampleships noDATABASE_URL, only a commented escape linemigrate/migrate:deploy→prisma migration plan/prisma db migrateexamples/file-upload-demo/.gitignorestops ignoringprisma/migrations/examples/plain-css-themingis untouched — it has no dependencies and no database.Scaffolder
Post-step is
install→generate; the.envit writes sets noDATABASE_URL.DbProvideris gone fromenv.ts/setup.ts— there is one env shape now. The isolated first-run guard asserts scaffold → generate with no database and no.opensaas/dev-db.Deploy guide
migrations/directory withprisma db migrate; authoring isprisma migration planCREATE EXTENSIONfrom the committed Extension contract space on every path, a pre-installed extension is skipped, a missing one fails naming the space and SQL state58P01outputFileTracingIncludesand everyprisma-clientmentionVerification
pnpm build,pnpm lint(0 errors, 2 pre-existing warnings),pnpm format,pnpm manypkg fixDATABASE_URL/DIRECT_DATABASE_URLunset completes and writes an.envwith no activeDATABASE_URLopensaas devin that scaffolded project brought up a Dev database (postgres://postgres@127.0.0.1:64471/postgres), appliedCreate table "Note"throughdb update, and spawned the app child withPROVENANCE dev-databaseand no injectedDATABASE_URLOut of scope
Example
opensaas.config.tsfiles still declareprovider: 'sqlite'and import@prisma/adapter-better-sqlite3, so example builds fail on this branch exactly as they do onprisma-8today. That is spec 9 (#1129); the scaffolded project above had to be given a Prisma 8 config to exercise the loop. The deploy guide's Step 2 ("Switch Your Config to PostgreSQL", Prisma 7 driver adapters) is left for the same owner.🤖 Generated with Claude Code