Skip to content

Prisma Integration + Scaffolding Fixes#22

Open
eugenegraves wants to merge 44 commits intomainfrom
prisma
Open

Prisma Integration + Scaffolding Fixes#22
eugenegraves wants to merge 44 commits intomainfrom
prisma

Conversation

@eugenegraves
Copy link
Copy Markdown
Collaborator

@eugenegraves eugenegraves commented Feb 9, 2026

Prisma & Database Scaffold Fixes

Shadow database (MySQL/MariaDB)

Prisma Migrate requires a temporary shadow database; the restricted user account couldn't create it. Added:

  • shadowDatabaseUrl = env("SHADOW_DATABASE_URL") in the Prisma schema for MySQL/MariaDB with local Docker
  • SHADOW_DATABASE_URL in .env pointing to root (mysql://root:rootpassword@localhost:${port}/)

Migrations succeed while the app still uses the limited user account.

MariaDB connection string

Prisma's provider = "mysql" expects mysql:// URLs. Switched MariaDB URLs from mariadb:// to mysql:// in generateEnv.ts.

MongoDB support

  • Migrations: Prisma doesn't support migrate dev for MongoDB. Use db push instead (same as SQLite).
  • Auth: Mongo root user lives in admin. Added authSource=admin to the MongoDB URL so SCRAM auth works.

Stale database volumes

PostgreSQL (and others) failed when reusing volumes with leftover data. Run bun db:reset before bun db:up during scaffold to clear volumes and avoid initdb "directory exists but is not empty" errors.

Project-specific Docker names

Switched Docker Compose project name from -p ${databaseEngine} to -p ${toDockerProjectName(projectName)}. Each project gets its own containers and volumes, avoiding drift and conflicting migration history.

Import merge for Prisma + Elysia

Fixed the import merge logic so import type { Elysia } and import { Elysia, t } from elysia are merged correctly. Previously this produced invalid syntax in generated server.ts with Prisma + auth/count, which broke Prettier and format.

Summary by CodeRabbit

  • New Features
    • Full Prisma support: schema & client generation, Prisma-aware scaffolding, migrations and Docker workflows; configurable database directory and sanitized Docker project naming; graceful ORM disconnect on shutdown.
  • Bug Fixes / Reliability
    • More robust command execution with clearer failure reporting for format/install routines; Git availability check before repo init.
  • Chores
    • Broadened lint/typecheck includes to cover tests and scaffolds; added/updated ORM tool versions and deps.
  • Security/Defaults
    • Docker/database examples updated to use root credentials for initialization.

jrs239 and others added 30 commits October 26, 2025 22:31
- Removed static compat.json validator
- Added compat.test.ts powered by Bun’s built-in test runner
- Tests import real data from src/data.ts for frameworks, DBs, ORMs, hosts, and auth providers
- Added host↔engine and ORM↔engine subset checks
- Skipped scaffold smoke tests pending e2e setup
…ed up eslint errors and added small fixes so all tests run smooth with bun test
- replace useless test with actual db host/engine checks
- rename ok -> isAllowed to make eslint happy
- add missing types and remove unused import
- Move host-engine validation to tests/utils/hostRules.ts
- Update both test files to use shared logic
- Remove duplicate export statement from compat.test.ts
…eScript's inference instead absolute/no-explicit-return-type
Updated logging functions to simplify output formatting.
tests: replace compat validator with bun:test suite using src/data.ts
This file generates a Prisma client based on the specified database engine and host, and writes it to a specified directory.
santimuri08 and others added 9 commits November 11, 2025 22:19
Added graceful shutdown for Prisma (disconnect on SIGINT/SIGTERM) and
aliased prisma client as 'db' so handlers work consistently across ORMs.

Changes:
- generateServer.ts: lifecycle cleanup block for prisma.()
- generateDBBlock.ts: const db = prisma alias for handler compatibility
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Threads a new databaseDirectory option across scaffolding, adds Prisma schema/client generation and Prisma-aware handlers, integrates Docker orchestration for DBs, updates package/env scripts and dependency mappings, replaces shell $ execution with Bun.spawnSync, adds a Git preflight check, and broadens TypeScript/ESLint include/ignore patterns.

Changes

Cohort / File(s) Summary
Prisma generators
src/generators/db/generatePrismaSchema.ts, src/generators/configurations/generatePrismaClient.ts
Add programmatic Prisma schema builder and Prisma client generator; host-aware generator behavior (edge vs standard) and exported generatePrismaSchema/generatePrismaClient functions.
DB scaffolding & Docker
src/generators/db/scaffoldDatabase.ts, src/generators/db/scaffoldDocker.ts, src/generators/db/generateDockerContainer.ts, src/generators/db/dockerInitTemplates.ts
Integrate Prisma workflows into scaffolding, add docker-compose per databaseDirectory, use sanitized Docker project names, and change container init credentials to root-based defaults.
Handlers & templates
src/generators/db/handlerTemplates.ts, src/generators/db/generateHandlers.ts
Add Prisma-backed query operations and Prisma driver configurations; thread databaseDirectory into template import paths via a replace helper and extend driver key typing.
Project generation
src/generators/project/generateDBBlock.ts, src/generators/project/generateImportsBlock.ts, src/generators/project/generateServer.ts, src/generators/project/scaffoldBackend.ts
Thread databaseDirectory through imports/DB block/server generation, add Prisma DB block and lifecycle cleanup, refactor import emission to separate type/value imports, and ensure backend directory creation.
Package / env / config
src/generators/configurations/generatePackageJson.ts, src/generators/configurations/generateEnv.ts, src/generators/configurations/scaffoldConfigurationFiles.ts
Thread databaseDirectory into package/env scaffolding, add Prisma scripts and dependency selection (usesAccelerate), update default DB URLs and docker script paths to use ${databaseDirectory}.
Data & versions
src/data.ts, src/versions.ts
Add prismaRuntimeDependencies and prismaDevDependencies exports; add drizzle-kit version entry.
CLI commands
src/commands/installDependencies.ts, src/commands/formatProject.ts, src/commands/initializeGit.ts
Replace bun $ usage with Bun.spawnSync, parse/validate command strings, add explicit spawn error handling, switch to node:process, and add Git availability preflight with abort path.
Utilities
src/utils/checkGitInstalled.ts, src/utils/toDockerProjectName.ts
Add checkGitInstalled async helper and toDockerProjectName sanitizer for Docker project flags.
Scaffold wiring & types
src/scaffold.ts, src/typeGuards.ts, tsconfig.json, eslint.config.mjs
Thread databaseDirectory through scaffold flow, tighten isPrismaDialect predicate, include tests/**/* and test-scaffold/**/* in tsconfig, and expand ESLint ignore patterns.
Minor templates & misc
src/templates/svelte/composables/counter.svelte.ts
Add top-level // @ts-nocheck`` directive for Svelte 5 runes handling.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as "Developer (CLI)"
  participant CLI as "scaffold CLI"
  participant Gen as "Generators (schema, client, handlers)"
  participant Docker as "Docker / Compose"
  participant FS as "Filesystem"
  participant Git as "Git"
  participant Prisma as "Prisma CLI"

  rect rgba(200,230,255,0.5)
  Dev->>CLI: run scaffold (includes databaseDirectory)
  CLI->>Gen: generatePackageJson, generateEnv, generatePrismaSchema, generatePrismaClient
  Gen->>FS: write schema.prisma, client.ts, package.json, env files
  end

  rect rgba(200,255,220,0.5)
  CLI->>Docker: bring up per-databaseDirectory docker-compose (project name via toDockerProjectName)
  Docker->>FS: write/read docker-compose.db.yml under databaseDirectory
  end

  rect rgba(255,230,200,0.5)
  CLI->>Prisma: run prisma generate / migrate / db push via Bun.spawnSync
  Prisma->>FS: write generated client artifacts
  end

  rect rgba(230,230,255,0.5)
  CLI->>Git: checkGitInstalled -> initialize repo if available
  Git->>FS: git init, add, commit
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I nibble lines and stitch a key,

schema sprouts where roots will be,
docker hums beneath my paws,
prisma wakes and answers laws,
hop!—a scaffold grows for me.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Prisma Integration + Scaffolding Fixes' clearly summarizes the main changes: adding Prisma support and fixing scaffolding-related issues. It is concise, specific, and directly reflects the primary objectives outlined in the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch prisma

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@src/generators/configurations/generatePackageJson.ts`:
- Around line 208-228: The `@prisma/extension-accelerate` package is currently
being added from prismaDevDependencies but is required at runtime by the
generated Prisma client; move the entry for "@prisma/extension-accelerate" from
prismaDevDependencies into prismaRuntimeDependencies in the data source so that
when the code checks usesAccelerate and populates dependencies (the block using
prismaRuntimeDependencies, prismaDevDependencies, resolveVersion and the
usesAccelerate flag) the package is added to dependencies rather than
devDependencies; update the arrays accordingly and ensure the existing
conditional that skips adding the dev dependency for accelerate (the check for
dep.value === '@prisma/extension-accelerate' && !usesAccelerate) is removed or
adjusted since accelerate should now be handled as a runtime dependency.

In `@src/generators/db/generatePrismaSchema.ts`:
- Around line 61-64: The datasource builder buildDatasourceBlock currently
always emits provider and url but must conditionally add shadowDatabaseUrl for
MySQL/MariaDB; update buildDatasourceBlock(cfg: DialectConfig) to append
`shadowDatabaseUrl = env("SHADOW_DATABASE_URL")` when cfg.provider is "mysql" or
"mariadb", and update generatePrismaSchema to rely on that updated block; also
modify the .env generator to emit a SHADOW_DATABASE_URL entry for those engines
so prisma migrate dev can use the shadow DB when the main DB user lacks CREATE
DATABASE privileges.

In `@src/generators/db/scaffoldDatabase.ts`:
- Around line 157-161: Replace the npx call with Bun-compatible invocation and
stop execution on failure: change the command in the try block that currently
runs await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd) to use
bunx (e.g., bunx prisma) so it resolves correctly in Bun projects, and when
catching errors in that block do not merely console.error — rethrow the error or
call process.exit(1) so execution does not continue to the subsequent migration
step (the code after the prisma generate try/catch). Ensure the change is
applied around the existing invocation and catch for prisma generate so the
migration step won't run when generation fails.
- Around line 190-205: The migration commands in the scaffold flow use "npx
prisma" but should use "bunx prisma" to match the runtime environment; update
the two invocations that build the shell commands (the branch where
databaseEngine === 'sqlite' and the else branch) to replace `npx prisma db push
--schema ${schemaArg}` and `npx prisma migrate dev --name init --skip-generate
--schema ${schemaArg}` with `bunx prisma ...`, preserving the use of schemaArg,
projectCwd, and the nothrow()/result.exitCode checks (look for the variables
`databaseEngine`, `schemaArg`, `projectCwd` in this file and the command
construction).

In `@src/generators/project/generateDBBlock.ts`:
- Around line 95-108: The generated code unconditionally injects a MySQL-only
"mode" into the drizzle constructor; update the return logic in
generateDBBlock.ts (the branch that builds the pool using expr and returns the
const pool / const db block) so that the mode option is only included when
databaseEngine indicates a MySQL-family engine (e.g., 'mysql' or 'mariadb') or
when databaseHost === 'planetscale' (mysqlMode variable), otherwise call
drizzle(pool, { schema }) with no mode; implement this by building the options
object conditionally (use mysqlMode only when appropriate) before returning the
template that creates db.

In `@src/generators/project/generateImportsBlock.ts`:
- Around line 215-221: The generated import statements in generateImportsBlock
(using rawImports) are producing invalid merged imports because lines push
`import type { Elysia }` and `import type { User }` which the merge logic treats
as default imports; update the pushes so Elysia is a value import (e.g., `import
{ Elysia }` not `import type`) since `new Elysia()` is used at runtime, and
ensure `@prisma/client` combines both PrismaClient and User as named imports
(push a single named-import string or push `import { PrismaClient, User }`
rather than a second `import type`), or alternatively adjust the import-merge
logic in the merge routine to treat `import type { ... }` as named imports
(preserving the type-only modifier) so named imports aren’t misclassified as
default imports.
🧹 Nitpick comments (9)
src/templates/svelte/composables/counter.svelte.ts (1)

1-1: Consider a narrower suppression instead of @ts-nocheck.

@ts-nocheck disables TypeScript checking for the entire file. Since only $state() on line 3 is unrecognized by plain tsc, a targeted // @ts-expect-error`` comment above that line would preserve type-checking for the rest of the file (parameter types, return shape, etc.).

That said, for a small scaffolded template where svelte-check handles runes natively, this is a minor concern.

♻️ Suggested narrower suppression
-// `@ts-nocheck` - Svelte 5 runes ($state) are processed at build time
 export const counter = (initialCount: number) => {
+	// `@ts-expect-error` - Svelte 5 rune processed at build time
 	let count = $state(initialCount);
src/versions.ts (1)

58-58: Prisma dependency versions should be centralized here too.

The drizzle-kit addition follows the correct pattern of using versions.ts as the single source of truth. However, the new Prisma dependencies in src/data.ts (lines 172–188) hardcode their versions ('6.2.0', '1.2.1') instead of referencing this registry. This is inconsistent with how every other dependency version is managed (e.g., versions['drizzle-orm'], versions['elysia']).

Consider adding prisma, @prisma/client, and @prisma/extension-accelerate entries here and referencing them from data.ts.

Proposed addition to versions.ts
 	/* ── ORM ──────────────────────────────────────────────── */
 	'drizzle-kit': '0.31.8',
 	'drizzle-orm': '0.45.1',
+	'@prisma/client': '6.2.0',
+	'@prisma/extension-accelerate': '1.2.1',
+	prisma: '6.2.0',
src/data.ts (1)

172-188: Hardcoded versions — use versions.ts for consistency.

As noted in the versions.ts review, these versions should reference the central versions map rather than being hardcoded, matching the pattern used by all other dependencies in this file (e.g., versions['elysia'], versions['drizzle-orm']).

Proposed fix (after adding entries to versions.ts)
 export const prismaRuntimeDependencies: AvailableDependency[] = [
 	{
-		latestVersion: '6.2.0',
+		latestVersion: versions['@prisma/client'],
 		value: '@prisma/client'
 	}
 ];

 export const prismaDevDependencies: AvailableDependency[] = [
 	{
-		latestVersion: '6.2.0',
+		latestVersion: versions['prisma'],
 		value: 'prisma'
 	},
 	{
-		latestVersion: '1.2.1',
+		latestVersion: versions['@prisma/extension-accelerate'],
 		value: '@prisma/extension-accelerate'
 	}
 ];
src/commands/initializeGit.ts (1)

27-32: abort() exits with code 0 despite an error condition.

When Git is not installed, abort() is called, which internally calls exit(0). This signals success to the shell/CI, even though the operation failed due to a missing prerequisite. If this tool is used in automated pipelines, a zero exit code would mask the failure.

That said, this is the existing convention in abort.ts and not introduced by this PR, so this is a minor observation for potential future improvement.

src/generators/db/handlerTemplates.ts (1)

280-299: Inconsistent indentation in generated Prisma template code.

The return statements are indented with extra leading spaces relative to the preceding Prisma calls, which will produce oddly-formatted generated code. For example, insertHistory has the return at a different indent level than the await db.countHistory.create(...) call.

✏️ Suggested formatting fix
 const prismaQueryOperations: QueryOperations = {
-	insertHistory: `const newHistory = await db.countHistory.create({
-  data: { count }
-})
-  return newHistory`,
-	insertUser: `const newUser = await db.user.upsert({
-  where: { auth_sub: authSub },
-  update: { metadata: userIdentity },
-  create: { auth_sub: authSub, metadata: userIdentity }
-})
-  return newUser`,
-	selectHistory: `const history = await db.countHistory.findUnique({
-  where: { uid }
-})
-  return history`,
-	selectUser: `const user = await db.user.findUnique({
-  where: { auth_sub: authSub }
-})
-  return user`
+	insertHistory: `const newHistory = await db.countHistory.create({
+    data: { count }
+  })
+  return newHistory`,
+	insertUser: `const newUser = await db.user.upsert({
+    where: { auth_sub: authSub },
+    update: { metadata: userIdentity },
+    create: { auth_sub: authSub, metadata: userIdentity }
+  })
+  return newUser`,
+	selectHistory: `const history = await db.countHistory.findUnique({
+    where: { uid }
+  })
+  return history`,
+	selectUser: `const user = await db.user.findUnique({
+    where: { auth_sub: authSub }
+  })
+  return user`
 };
src/scaffold.ts (1)

113-128: The void (... && await ...) pattern works but is non-obvious.

This correctly awaits scaffoldDatabase when conditions are met, but the void + short-circuit && chaining for conditional async execution is unusual. A plain if block would be more readable.

♻️ Suggested simplification
-	void (
-		databaseDirectory !== undefined &&
-		databaseEngine !== 'none' &&
-		databaseEngine !== undefined &&
-		(await scaffoldDatabase({
-			authOption,
-			backendDirectory,
-			databaseDirectory,
-			databaseEngine,
-			databaseHost,
-			databasePort,
-			orm,
-			projectName,
-			typesDirectory
-		}))
-	);
+	if (
+		databaseDirectory !== undefined &&
+		databaseEngine !== 'none' &&
+		databaseEngine !== undefined
+	) {
+		await scaffoldDatabase({
+			authOption,
+			backendDirectory,
+			databaseDirectory,
+			databaseEngine,
+			databaseHost,
+			databasePort,
+			orm,
+			projectName,
+			typesDirectory
+		});
+	}
src/generators/project/generateImportsBlock.ts (1)

223-232: Loose equality == instead of ===.

Line 224 uses orm == 'drizzle' while every other comparison in this file uses strict equality (===). Not a bug here, but inconsistent.

✏️ Fix
-	if (
-		orm == 'drizzle' &&
+	if (
+		orm === 'drizzle' &&
src/generators/configurations/generateEnv.ts (1)

38-42: Hardcoded db/ path in SQLite URL may drift from databaseDirectory.

The SQLite DATABASE_URL hardcodes file:./db/database.sqlite, but other generators (e.g., generateDrizzleConfig.ts) derive this path from the databaseDirectory parameter. If databaseDirectory ever differs from 'db', the .env value will be inconsistent with the schema/config paths. Consider threading databaseDirectory into GenerateEnvProps and using it here.

Proposed fix
 type GenerateEnvProps = Pick<
 	CreateConfiguration,
 	'databaseEngine' | 'databaseHost' | 'projectName'
 > & {
+	databaseDirectory?: string;
 	databasePort?: number;
 	envVariables?: string[];
 };
 	if (
 		databaseEngine === 'sqlite' &&
 		(databaseHost === 'none' || databaseHost === undefined)
 	) {
-		vars.push('DATABASE_URL=file:./db/database.sqlite');
+		const dir = databaseDirectory ?? 'db';
+		vars.push(`DATABASE_URL=file:./${dir}/database.sqlite`);
 	}
src/generators/db/scaffoldDatabase.ts (1)

18-31: databaseDirectory is declared both in the Pick and in the intersection.

databaseDirectory appears in both the Pick<CreateConfiguration, ...> (line 23) and the explicit & { ... } block (line 28). The explicit databaseDirectory: string in the intersection shadows the picked type. If the intent is to make it required (string instead of string | undefined), this works but is confusing — consider removing it from the Pick to make the intent clear.

Comment on lines +208 to +228
const usesAccelerate =
orm === 'prisma' &&
(databaseHost === 'neon' || databaseHost === 'planetscale');

switch (databaseHost) {
case 'neon':
dependencies['@neondatabase/serverless'] = resolveVersion(
'@neondatabase/serverless',
versions['@neondatabase/serverless']
);
break;
case 'planetscale':
dependencies['@planetscale/database'] = resolveVersion(
'@planetscale/database',
versions['@planetscale/database']
if (orm === 'prisma') {
prismaRuntimeDependencies.forEach((dep) => {
dependencies[dep.value] = resolveVersion(
dep.value,
dep.latestVersion
);
break;
case 'turso':
dependencies['@libsql/client'] = resolveVersion(
'@libsql/client',
versions['@libsql/client']
});

prismaDevDependencies.forEach((dep) => {
if (dep.value === '@prisma/extension-accelerate' && !usesAccelerate)
return;
devDependencies[dep.value] = resolveVersion(
dep.value,
dep.latestVersion
);
break;
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

@prisma/extension-accelerate runtime dependency vs dev dependency documentation

💡 Result:

@prisma/extension-accelerate should be a runtime dependency (put it in dependencies), because it’s imported and used by your application code at runtime (e.g., import { withAccelerate } from "@prisma/extension-accelerate";). Prisma’s guides install it without --save-dev, while installing the Prisma CLI (prisma) with --save-dev. (prismagraphql.com)

Citations:


🏁 Script executed:

# Find and inspect src/data.ts to check where `@prisma/extension-accelerate` is defined
find . -name "data.ts" -type f | head -20

Repository: absolutejs/create-absolutejs

Length of output: 85


🏁 Script executed:

# Search for `@prisma/extension-accelerate` in the codebase
rg "@prisma/extension-accelerate" -n

Repository: absolutejs/create-absolutejs

Length of output: 383


🏁 Script executed:

# Check src/data.ts around line 186 to see which dependency array it's in
sed -n '170,200p' src/data.ts

Repository: absolutejs/create-absolutejs

Length of output: 645


🏁 Script executed:

# Check the import in generatePrismaClient.ts to see how it's used
sed -n '15,25p' src/generators/configurations/generatePrismaClient.ts

Repository: absolutejs/create-absolutejs

Length of output: 425


@prisma/extension-accelerate must be a runtime dependency, not a dev dependency.

According to Prisma's official documentation, @prisma/extension-accelerate is imported and used at runtime in the generated Prisma client code (see src/generators/configurations/generatePrismaClient.ts line 18). Placing it in devDependencies (currently in src/data.ts line 186) means it will not be installed in production environments when using npm install --production or equivalent flags, causing runtime failures when Accelerate is enabled.

Move @prisma/extension-accelerate from prismaDevDependencies to prismaRuntimeDependencies in src/data.ts.

🤖 Prompt for AI Agents
In `@src/generators/configurations/generatePackageJson.ts` around lines 208 - 228,
The `@prisma/extension-accelerate` package is currently being added from
prismaDevDependencies but is required at runtime by the generated Prisma client;
move the entry for "@prisma/extension-accelerate" from prismaDevDependencies
into prismaRuntimeDependencies in the data source so that when the code checks
usesAccelerate and populates dependencies (the block using
prismaRuntimeDependencies, prismaDevDependencies, resolveVersion and the
usesAccelerate flag) the package is added to dependencies rather than
devDependencies; update the arrays accordingly and ensure the existing
conditional that skips adding the dev dependency for accelerate (the check for
dep.value === '@prisma/extension-accelerate' && !usesAccelerate) is removed or
adjusted since accelerate should now be handled as a runtime dependency.

Comment thread src/generators/db/generatePrismaSchema.ts
Comment on lines +157 to +161
try {
await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd);
} catch (error) {
console.error('Error generating Prisma client:', error);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

npx in a Bun-based project; swallowed error allows broken continuation.

Two concerns:

  1. The project uses Bun (imported from 'bun' on line 3, bun db:up on line 169). Using npx prisma here may fail or use a different package resolution path. Consider bunx prisma for consistency.

  2. If prisma generate fails, the catch only logs and continues to the migration step (lines 163+), which will also fail. Consider bailing out early on failure.

Proposed fix
 	try {
-		await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd);
+		await $`bunx prisma generate --schema ${schemaArg}`.cwd(projectCwd);
 	} catch (error) {
 		console.error('Error generating Prisma client:', error);
+		return;
 	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
try {
await $`npx prisma generate --schema ${schemaArg}`.cwd(projectCwd);
} catch (error) {
console.error('Error generating Prisma client:', error);
}
try {
await $`bunx prisma generate --schema ${schemaArg}`.cwd(projectCwd);
} catch (error) {
console.error('Error generating Prisma client:', error);
return;
}
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 157 - 161, Replace the
npx call with Bun-compatible invocation and stop execution on failure: change
the command in the try block that currently runs await $`npx prisma generate
--schema ${schemaArg}`.cwd(projectCwd) to use bunx (e.g., bunx prisma) so it
resolves correctly in Bun projects, and when catching errors in that block do
not merely console.error — rethrow the error or call process.exit(1) so
execution does not continue to the subsequent migration step (the code after the
prisma generate try/catch). Ensure the change is applied around the existing
invocation and catch for prisma generate so the migration step won't run when
generation fails.

Comment thread src/generators/db/scaffoldDatabase.ts Outdated
Comment on lines +190 to +205
if (databaseEngine === 'sqlite') {
const result = await $`npx prisma db push --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();
if (result.exitCode !== 0)
console.error('Error running Prisma migrations:', result.stderr);

return;
}

const result =
await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();
if (result.exitCode !== 0)
console.error('Error running Prisma migrations:', result.stderr);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

SQLite and non-SQLite migration commands also use npx — same concern applies.

Consistent with the earlier comment on line 158, lines 191 and 201 also use npx prisma instead of bunx prisma.

Proposed fix
-	const result = await $`npx prisma db push --schema ${schemaArg}`
+	const result = await $`bunx prisma db push --schema ${schemaArg}`
 		.cwd(projectCwd)
 		.nothrow();
-	const result = await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}`
+	const result = await $`bunx prisma migrate dev --name init --skip-generate --schema ${schemaArg}`
 		.cwd(projectCwd)
 		.nothrow();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (databaseEngine === 'sqlite') {
const result = await $`npx prisma db push --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();
if (result.exitCode !== 0)
console.error('Error running Prisma migrations:', result.stderr);
return;
}
const result =
await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();
if (result.exitCode !== 0)
console.error('Error running Prisma migrations:', result.stderr);
if (databaseEngine === 'sqlite') {
const result = await $`bunx prisma db push --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();
if (result.exitCode !== 0)
console.error('Error running Prisma migrations:', result.stderr);
return;
}
const result =
await $`npx prisma migrate dev --name init --skip-generate --schema ${schemaArg}`
.cwd(projectCwd)
.nothrow();
if (result.exitCode !== 0)
console.error('Error running Prisma migrations:', result.stderr);
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 190 - 205, The migration
commands in the scaffold flow use "npx prisma" but should use "bunx prisma" to
match the runtime environment; update the two invocations that build the shell
commands (the branch where databaseEngine === 'sqlite' and the else branch) to
replace `npx prisma db push --schema ${schemaArg}` and `npx prisma migrate dev
--name init --skip-generate --schema ${schemaArg}` with `bunx prisma ...`,
preserving the use of schemaArg, projectCwd, and the nothrow()/result.exitCode
checks (look for the variables `databaseEngine`, `schemaArg`, `projectCwd` in
this file and the command construction).

Comment thread src/generators/project/generateDBBlock.ts
Comment thread src/generators/project/generateImportsBlock.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/generators/db/scaffoldDocker.ts (1)

56-57: ⚠️ Potential issue | 🔴 Critical

Align composeFile path construction in scaffoldDocker.ts with generatePackageJson.ts.

Line 76 constructs composeFile without a fallback for falsy databaseDirectory, while generatePackageJson.ts (line 274) uses databaseDirectory ?? 'db' to ensure consistency. If databaseDirectory is empty or undefined, the docker compose commands on lines 77-78 will reference a different file than the bun db:up and bun db:down scripts (which default to db/ via generatePackageJson.ts), causing container lookup failures during teardown.

Change line 76 to:

const composeFile = `${databaseDirectory ?? 'db'}/docker-compose.db.yml`;
🤖 Fix all issues with AI agents
In `@src/utils/toDockerProjectName.ts`:
- Around line 1-5: toDockerProjectName currently allows uppercase letters which
violate Docker Compose project name rules; update the function to call
.toLowerCase() on the input (e.g., use name.toLowerCase() before applying the
.replace chains in toDockerProjectName) so the subsequent regex replacements
produce a lowercase, valid project name while preserving the existing
collapsing/trimming behavior and the 'db' fallback.
🧹 Nitpick comments (9)
src/commands/formatProject.ts (2)

1-1: Inconsistent module specifier for process.

This file imports from 'node:process' while src/commands/installDependencies.ts (line 1) imports from 'process'. Both resolve to the same module, but the inconsistency is a minor style nit. Consider aligning on one form across the codebase (preferably 'node:process' as it's the explicit Node-prefixed convention).


19-38: Duplicated command-parsing and spawn logic — consider extracting a shared helper.

The pattern of splitting a command string, validating the binary, calling Bun.spawnSync, and checking proc.success / reading proc.stderr is identical between this file and installDependencies.ts. Extracting a small utility (e.g., runCommand(cmd: string, cwd: string)) would reduce duplication and centralize error handling.

♻️ Example helper sketch
// src/utils/runCommand.ts
export function runCommandSync(cmd: string, cwd: string): void {
  const parts = cmd.split(/\s+/);
  const bin = parts[0];
  if (!bin) throw new Error(`Empty command: "${cmd}"`);
  const args = parts.slice(1);

  const proc = Bun.spawnSync([bin, ...args], {
    cwd,
    stderr: 'pipe',
    stdout: 'ignore',
  });

  if (!proc.success) {
    const errMsg =
      proc.stderr?.toString().trim() || `Exit code ${proc.exitCode}`;
    throw new Error(errMsg);
  }
}
src/commands/installDependencies.ts (1)

20-29: stdout: 'ignore' may suppress package-manager warnings.

Some package managers (notably npm) emit deprecation and peer-dependency warnings to stdout. With stdout: 'ignore', users won't see these during install. This is likely an acceptable tradeoff for a clean spinner UX, but worth noting in case debugging install issues becomes painful later. Consider stdout: 'pipe' and logging on failure if that becomes an issue.

src/generators/db/handlerTemplates.ts (2)

280-299: Inconsistent indentation in generated template strings.

The return statements are indented with extra leading spaces relative to the Prisma API calls, which will produce oddly-indented generated code. For example, return newHistory on line 284 is indented under data: { count } rather than aligned with the const declaration on line 281.

♻️ Suggested indentation fix
 const prismaQueryOperations: QueryOperations = {
 	insertHistory: `const newHistory = await db.countHistory.create({
   data: { count }
 })
-  return newHistory`,
+return newHistory`,
 	insertUser: `const newUser = await db.user.upsert({
   where: { auth_sub: authSub },
   update: { metadata: userIdentity },
   create: { auth_sub: authSub, metadata: userIdentity }
 })
-  return newUser`,
+return newUser`,
 	selectHistory: `const history = await db.countHistory.findUnique({
   where: { uid }
 })
-  return history`,
+return history`,
 	selectUser: `const user = await db.user.findUnique({
   where: { auth_sub: authSub }
 })
-  return user`
+return user`
 };

Note: verify the expected indentation level in the generated output by checking how other QueryOperations (e.g., drizzleQueryOperations) format their return statements within the template.


391-395: All Prisma driver configs are identical — consider deduplication.

Every *:prisma:* entry in driverConfigurations uses the exact same { dbType, importLines, queries } object. This is a lot of copy-paste that could drift if the Prisma config ever changes.

♻️ Extract a shared prisma config object
+const prismaDriverConfig = {
+	dbType: 'PrismaClient',
+	importLines: `import type { PrismaClient } from '@prisma/client'`,
+	queries: prismaQueryOperations
+} as const;
+
 const driverConfigurations = {
-	'cockroachdb:prisma:local': {
-		dbType: 'PrismaClient',
-		importLines: `import type { PrismaClient } from '@prisma/client'`,
-		queries: prismaQueryOperations
-	},
+	'cockroachdb:prisma:local': prismaDriverConfig,
 	// ... same for all other prisma entries

Also applies to: 419-423, 429-433, 439-443, 461-470, 499-513, 535-539, 558-567

src/generators/db/scaffoldDatabase.ts (1)

19-32: databaseDirectory is declared twice in the type — once via Pick and once in the intersection.

CreateConfiguration['databaseDirectory'] is string | undefined, but the & { databaseDirectory: string } intersection narrows it to string. This works in TypeScript but is confusing and error-prone. Consider removing it from the Pick to make the intent clear.

Proposed fix
 type ScaffoldDatabaseProps = Pick<
 	CreateConfiguration,
 	| 'projectName'
 	| 'databaseHost'
 	| 'orm'
-	| 'databaseDirectory'
 	| 'authOption'
 	| 'databaseEngine'
 > & {
 	backendDirectory: string;
 	databaseDirectory: string;
 	databasePort?: number;
 	typesDirectory: string;
 };
src/generators/project/generateImportsBlock.ts (1)

270-320: Import merge refactor correctly handles import type vs value imports — nice improvement.

The new ImportEntry structure with typeOnlyNames and valueNames sets correctly addresses the original import-merge bug described in the PR objectives. When a module has both type-only and value imports, the emission logic (Lines 324-346) correctly produces import { type Foo, bar } from '...' syntax, which is valid TypeScript.

Two minor static analysis findings on Lines 296 and 316: the forEach callbacks implicitly return the result of Set.add(). This is functionally harmless (the return value is ignored by forEach) but triggers the Biome lint rule useIterableCallbackReturn. A trivial fix:

Proposed fix for linter warnings
-			.forEach((name) => entry.typeOnlyNames.add(name));
+			.forEach((name) => { entry.typeOnlyNames.add(name); });
-			.forEach((name) => entry.valueNames.add(name));
+			.forEach((name) => { entry.valueNames.add(name); });
src/generators/project/generateDBBlock.ts (1)

76-83: Path replacement assumes all expressions contain db/ — fragile for non-sqlite engines.

Line 80 does hostCfg.expr.replace('db/', ${databaseDirectory}/). Looking at connectionMap, only sqlite.none contains db/ in its expression (new Database("db/database.sqlite")). For all other engines (e.g., new SQL(getEnv("DATABASE_URL"))), the replace is a no-op. This works today, but the approach is fragile — if a future engine expression coincidentally contains db/, it would be incorrectly replaced.

src/generators/configurations/generatePackageJson.ts (1)

339-352: Inconsistent databaseDirectory fallback pattern across the file.

Line 274 uses databaseDirectory ?? 'db' (nullish coalescing — only catches null/undefined), while Line 340 uses databaseDirectory ? ... : 'db/...' (truthy check — also catches empty string). Similarly, Line 328 uses databaseDirectory ?? 'db'. Pick one pattern for consistency.

Proposed fix — use nullish coalescing consistently
 	if (orm === 'prisma') {
-		const schemaPath = databaseDirectory
-			? `${databaseDirectory}/schema.prisma`
-			: 'db/schema.prisma';
+		const schemaPath = `${databaseDirectory ?? 'db'}/schema.prisma`;
 		scripts['postinstall'] = `prisma generate --schema ${schemaPath}`;

Comment on lines +1 to +5
export const toDockerProjectName = (name: string): string =>
name
.replace(/[^a-zA-Z0-9_-]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '') || 'db';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Docker Compose project name case sensitivity specification requirements

💡 Result:

Docker Compose project names are effectively lowercase-only, so case sensitivity is enforced by validation: any uppercase letters make the project name invalid.

Specification / requirements

  • The Compose Specification defines the project name constraint as: only lowercase letters (a-z), decimal digits (0-9), dashes (-), and underscores (_); and it must start with a lowercase letter or digit. This means MyProj is invalid, myproj is valid. [1]
  • Docker’s Compose docs repeat the same rule and note that if the directory name (default source of the project name) violates the constraint, you must override the project name using another mechanism. [2]

How you set/override the project name (and where it matters)

  • Precedence (highest → lowest): -p/--project-name, COMPOSE_PROJECT_NAME, top-level name: in the Compose file, then directory-based defaults. [2], [3]
  • The top-level name: key is part of the Compose Specification (supported by docker compose / Compose v2), not the legacy docker-compose v1 file formats—using it with v1 commonly triggers schema/validation errors. [2], [1]

Sources

  • [1] Compose Specification (Project name section)
  • [2] Docker Docs: “Specify a project name”
  • [3] Docker Docs: Environment variables (COMPOSE_PROJECT_NAME)

Add .toLowerCase() to ensure valid Docker Compose project names.

Docker Compose project names must match the pattern [a-z0-9][a-z0-9_-]* per the Compose Specification—uppercase letters are not permitted. The current implementation allows uppercase characters, producing invalid project names. Adding .toLowerCase() ensures the output complies with the specification.

♻️ Proposed fix
 export const toDockerProjectName = (name: string): string =>
 	name
+		.toLowerCase()
 		.replace(/[^a-zA-Z0-9_-]/g, '-')
 		.replace(/-+/g, '-')
 		.replace(/^-|-$/g, '') || 'db';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const toDockerProjectName = (name: string): string =>
name
.replace(/[^a-zA-Z0-9_-]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '') || 'db';
export const toDockerProjectName = (name: string): string =>
name
.toLowerCase()
.replace(/[^a-zA-Z0-9_-]/g, '-')
.replace(/-+/g, '-')
.replace(/^-|-$/g, '') || 'db';
🤖 Prompt for AI Agents
In `@src/utils/toDockerProjectName.ts` around lines 1 - 5, toDockerProjectName
currently allows uppercase letters which violate Docker Compose project name
rules; update the function to call .toLowerCase() on the input (e.g., use
name.toLowerCase() before applying the .replace chains in toDockerProjectName)
so the subsequent regex replacements produce a lowercase, valid project name
while preserving the existing collapsing/trimming behavior and the 'db'
fallback.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/generators/configurations/generateEnv.ts (1)

41-55: ⚠️ Potential issue | 🔴 Critical

SHADOW_DATABASE_URL is not automatically generated; users must provide it via CLI flag if needed.

The function does not emit SHADOW_DATABASE_URL for MySQL/MariaDB. If this is required by the PR objective, it's currently missing. However, users can provide it manually via the --env SHADOW_DATABASE_URL=... CLI flag, which will be merged into .env through the envVariables parameter. If automatic generation for MySQL/MariaDB is intended, the code needs to be updated in generateEnv.ts to construct and add the shadow database URL alongside the primary DATABASE_URL.

🧹 Nitpick comments (1)
src/generators/configurations/generatePackageJson.ts (1)

339-352: Inconsistent fallback pattern for databaseDirectory.

Lines 274 and 328 use databaseDirectory ?? 'db', but line 340 uses a ternary databaseDirectory ? ... : 'db/schema.prisma'. This means an empty string '' would produce different results: ?? would keep '', while the ternary would fall back to 'db/schema.prisma'. Consider using a consistent pattern, e.g.:

♻️ Suggested normalization
-	const schemaPath = databaseDirectory
-		? `${databaseDirectory}/schema.prisma`
-		: 'db/schema.prisma';
+	const schemaPath = `${databaseDirectory ?? 'db'}/schema.prisma`;

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/generators/db/scaffoldDatabase.ts (1)

61-75: ⚠️ Potential issue | 🔴 Critical

SQLite block runs unconditionally — will break for Prisma + SQLite.

When orm === 'prisma' and databaseEngine === 'sqlite':

  1. Line 62-65 skips the checkSqliteInstalled() call (because orm is not undefined/'none').
  2. Lines 66-74 still execute, calling sqlite3 which may not be installed — this will throw.
  3. Even if sqlite3 is installed, this pre-creates the DB with a hand-written SQL schema, then Prisma later runs prisma db push (line 178) with its own schema, causing a conflict or redundancy.

Guard lines 66-74 so they only run when the ORM is not Prisma (or has no ORM):

Proposed fix
 	if (databaseEngine === 'sqlite') {
 		void (
 			(orm === undefined || orm === 'none') &&
 			(await checkSqliteInstalled())
 		);
-		const sqliteSchema = generateSqliteSchema(authOption);
-		writeFileSync(
-			join(projectDatabaseDirectory, 'schema.sql'),
-			sqliteSchema
-		);
-		const schemaPath = `${databaseDirectory}/schema.sql`;
-		await $`sqlite3 ${databaseDirectory}/database.sqlite ".read ${schemaPath}"`.cwd(
-			projectName
-		);
+		if (orm === undefined || orm === 'none') {
+			const sqliteSchema = generateSqliteSchema(authOption);
+			writeFileSync(
+				join(projectDatabaseDirectory, 'schema.sql'),
+				sqliteSchema
+			);
+			const schemaPath = `${databaseDirectory}/schema.sql`;
+			await $`sqlite3 ${databaseDirectory}/database.sqlite ".read ${schemaPath}"`.cwd(
+				projectName
+			);
+		}
 	}
🤖 Fix all issues with AI agents
In `@src/generators/configurations/generatePackageJson.ts`:
- Around line 296-301: The generated package.json script scripts['db:init']
references init.sql which doesn't exist; update the scripts['db:init']
assignment in generatePackageJson (the block using isLocal, databaseEngine,
databaseDirectory and dbDir) to reference schema.sql instead of init.sql so it
matches the file written by your DB scaffold (schema.sql).

In `@src/generators/db/scaffoldDatabase.ts`:
- Around line 155-174: Import resolveDockerExe from the module that exports
checkDockerInstalled (same place checkDockerInstalled is imported) and use it in
the database start sequence in scaffoldDatabase (e.g., call await
resolveDockerExe() to get dockerExe and replace the hardcoded "docker compose"
invocation with `${dockerExe} compose`) so the command uses the resolved Docker
executable; update the import list to include resolveDockerExe and change the
exec invocation that currently runs "docker compose -p ..." to use the resolved
dockerExe variable instead.
🧹 Nitpick comments (1)
src/generators/configurations/generatePackageJson.ts (1)

244-245: Inconsistent databaseDirectory fallback patterns across the file.

Three different approaches are used for the same fallback:

  • Line 244: databaseDirectory ?? 'db' (nullish coalescing)
  • Line 297: databaseDirectory ?? 'db' (nullish coalescing)
  • Line 309: databaseDirectory ? \...` : 'db/schema.prisma'` (ternary)

Consider normalizing to a single default at the top of the function (e.g., const dbDir = databaseDirectory ?? 'db') and reusing it everywhere, which would also eliminate the ad-hoc const dbDir at line 297.

Proposed refactor
 }: CreatePackageJsonProps) => {
+	const dbDir = databaseDirectory ?? 'db';
 	const s = spinner();
 	// ...
 
-	const composeFile = `${databaseDirectory ?? 'db'}/docker-compose.db.yml`;
+	const composeFile = `${dbDir}/docker-compose.db.yml`;
 
 	// ...
 
-	const dbDir = databaseDirectory ?? 'db';
 	scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`;
 
 	// ...
 
-	const schemaPath = databaseDirectory
-		? `${databaseDirectory}/schema.prisma`
-		: 'db/schema.prisma';
+	const schemaPath = `${dbDir}/schema.prisma`;

Also applies to: 297-297, 309-311

Comment on lines 296 to 301
if (isLocal && databaseEngine === 'sqlite') {
scripts['db:sqlite'] = 'sqlite3 db/database.sqlite';
scripts['db:init'] = 'sqlite3 db/database.sqlite < db/init.sql';
const dbDir = databaseDirectory ?? 'db';
scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`;
scripts['db:init'] =
`sqlite3 ${dbDir}/database.sqlite < ${dbDir}/init.sql`;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for both init.sql and schema.sql references in TypeScript files
rg -n "init\.sql|schema\.sql" --type=ts -C2

Repository: absolutejs/create-absolutejs

Length of output: 1132


🏁 Script executed:

#!/bin/bash
# Search for all references to init.sql in the entire codebase
rg "init\.sql" -n

Repository: absolutejs/create-absolutejs

Length of output: 187


Change db:init script to reference schema.sql instead of init.sql.

The generated db:init script references init.sql, but src/generators/db/scaffoldDatabase.ts line 68 writes the schema file as schema.sql. This causes the db:init script to fail at runtime because the referenced file doesn't exist.

Proposed fix
 	scripts['db:init'] =
-		`sqlite3 ${dbDir}/database.sqlite < ${dbDir}/init.sql`;
+		`sqlite3 ${dbDir}/database.sqlite < ${dbDir}/schema.sql`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isLocal && databaseEngine === 'sqlite') {
scripts['db:sqlite'] = 'sqlite3 db/database.sqlite';
scripts['db:init'] = 'sqlite3 db/database.sqlite < db/init.sql';
const dbDir = databaseDirectory ?? 'db';
scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`;
scripts['db:init'] =
`sqlite3 ${dbDir}/database.sqlite < ${dbDir}/init.sql`;
}
if (isLocal && databaseEngine === 'sqlite') {
const dbDir = databaseDirectory ?? 'db';
scripts['db:sqlite'] = `sqlite3 ${dbDir}/database.sqlite`;
scripts['db:init'] =
`sqlite3 ${dbDir}/database.sqlite < ${dbDir}/schema.sql`;
}
🤖 Prompt for AI Agents
In `@src/generators/configurations/generatePackageJson.ts` around lines 296 - 301,
The generated package.json script scripts['db:init'] references init.sql which
doesn't exist; update the scripts['db:init'] assignment in generatePackageJson
(the block using isLocal, databaseEngine, databaseDirectory and dbDir) to
reference schema.sql instead of init.sql so it matches the file written by your
DB scaffold (schema.sql).

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@src/generators/db/scaffoldDatabase.ts`:
- Around line 192-206: Replace the ephemeral "node:20-slim npx prisma" approach
in scaffoldDatabase.ts: stop running npx inside throwaway containers (the block
using resolveDockerExe(), toDockerProjectName(), mongoUrl and the
result/.nothrow() flow) and instead either (A) run prisma from the host (reuse
the host-installed Prisma invoked earlier) against the docker network DB
address, or (B) build/use a cached Prisma-ready image (pin the Prisma CLI
version) and run that image so dependencies aren't downloaded on each scaffold;
also remove .nothrow() and explicitly check result.exitCode to log and surface
errors (currently only result.stderr is printed) and preserve returning
dockerFreshInstall. Ensure references to resolveDockerExe, projectPath, network,
mongoUrl, result, and dockerFreshInstall are updated accordingly.
- Around line 171-175: The Promise executor parameter name `resolve` shadows the
imported `resolve` from the `path` module; update the anonymous functions that
create the delays (the two new Promise((resolve) => setTimeout(resolve, ...))
calls in scaffoldDatabase.ts inside the scaffoldDatabase flow and the
databaseEngine === 'mongodb' branch) to use a different parameter name (e.g.,
`done`, `res`, or `resolveTimer`) so they no longer shadow `path.resolve`; keep
behavior unchanged and only rename the parameter in those Promise executors.
- Around line 156-179: The Docker startup block in scaffoldDatabase.ts currently
catches errors from commands like bun db:up and the waitCommand but only logs
them and allows execution to continue; modify the catch in the async block that
wraps the docker startup (the try/catch around bun db:reset, bun db:up, and
initTemplates waitCommand) to re-throw the caught error or return a rejected
promise so execution stops (e.g., throw error) instead of proceeding to the
migration steps; reference databaseEngine, projectCwd, toDockerProjectName,
projectName, databaseDirectory, initTemplates and waitCommand to locate the
block to change.
🧹 Nitpick comments (4)
src/generators/db/generateDockerContainer.ts (1)

139-141: Consider quoting environment values in the generated YAML.

The env values are emitted bare (e.g., ACCEPT_EULA: Y). In YAML 1.1 — which some Docker Compose parser versions use — bare Y is interpreted as boolean true, and other values could be similarly misinterpreted. Wrapping values in quotes would make the output safe regardless of the YAML parser version.

This is a pre-existing pattern so not blocking, but since this file is being touched, it's a good opportunity to harden it.

♻️ Suggested fix
 	const envLines = Object.entries(env)
-		.map(([key, value]) => `            ${key}: ${value}`)
+		.map(([key, value]) => `            ${key}: "${value}"`)
 		.join('\n');
src/generators/db/scaffoldDatabase.ts (3)

20-32: databaseDirectory is declared twice in the type.

It appears in the Pick<…> on line 25 and in the & { … } block on line 29. If the intent is to make an optional field required, only the intersection override is needed (remove it from Pick). Otherwise the duplication is confusing.

Proposed fix
 type ScaffoldDatabaseProps = Pick<
 	CreateConfiguration,
 	| 'projectName'
 	| 'databaseHost'
 	| 'orm'
-	| 'databaseDirectory'
 	| 'authOption'
 	| 'databaseEngine'
 > & {
 	databaseDirectory: string;
 	backendDirectory: string;
 	typesDirectory: string;
 };

6-8: Consolidate imports from the same module.

checkDockerInstalled and resolveDockerExe are imported from the same module in two separate statements.

Proposed fix
-import { checkDockerInstalled } from '../../utils/checkDockerInstalled';
-import { resolveDockerExe } from '../../utils/checkDockerInstalled';
+import { checkDockerInstalled, resolveDockerExe } from '../../utils/checkDockerInstalled';

209-216: Hardcoded Docker-network DB URLs duplicate the credential constants in generateEnv.ts.

dockerNetworkUrls redefines the same credentials (passwords, ports, DB names) that exist in generateEnv.ts's databaseURLS. If credentials change in one place, they'll silently diverge. Consider extracting shared credential constants or deriving these URLs from a single source.

Comment on lines +156 to +179
if (databaseEngine !== 'sqlite') {
try {
await $`bun db:reset`.cwd(projectCwd).nothrow();
await $`bun db:up`.cwd(projectCwd);
const { initTemplates } = await import('./dockerInitTemplates');
if (databaseEngine in initTemplates) {
const waitCommand =
initTemplates[databaseEngine as keyof typeof initTemplates]
?.wait;
if (waitCommand) {
await $`docker compose -p ${toDockerProjectName(projectName)} -f ${databaseDirectory}/docker-compose.db.yml exec -T db bash -lc '${waitCommand}'`
.cwd(projectCwd)
.nothrow();
}
} else {
await new Promise((resolve) => setTimeout(resolve, 5000));
}
// Brief delay for MongoDB to fully stabilize before Prisma connections
if (databaseEngine === 'mongodb') {
await new Promise((resolve) => setTimeout(resolve, 3000));
}
} catch (error) {
console.error('Error starting database container:', error);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Error in Docker startup block is swallowed — scaffold silently continues with broken DB.

If bun db:up fails (line 159) or the wait command fails, the outer catch on line 177 logs the error but execution continues to the migration steps (lines 182+), which will also fail. Consider returning early or re-throwing so the user gets a clear signal that the database didn't start.

Proposed fix
 	} catch (error) {
 		console.error('Error starting database container:', error);
+		return { dockerFreshInstall };
 	}
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 156 - 179, The Docker
startup block in scaffoldDatabase.ts currently catches errors from commands like
bun db:up and the waitCommand but only logs them and allows execution to
continue; modify the catch in the async block that wraps the docker startup (the
try/catch around bun db:reset, bun db:up, and initTemplates waitCommand) to
re-throw the caught error or return a rejected promise so execution stops (e.g.,
throw error) instead of proceeding to the migration steps; reference
databaseEngine, projectCwd, toDockerProjectName, projectName, databaseDirectory,
initTemplates and waitCommand to locate the block to change.

Comment on lines +171 to +175
await new Promise((resolve) => setTimeout(resolve, 5000));
}
// Brief delay for MongoDB to fully stabilize before Prisma connections
if (databaseEngine === 'mongodb') {
await new Promise((resolve) => setTimeout(resolve, 3000));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

resolve parameter shadows the path.resolve import.

The resolve callback parameter in the new Promise((resolve) => …) on lines 171 and 175 shadows the resolve import from 'path' on line 2. This is a latent bug risk — if someone adds path logic inside these callbacks, they'll accidentally call the Promise resolver instead.

Proposed fix
-			await new Promise((resolve) => setTimeout(resolve, 5000));
+			await new Promise((r) => setTimeout(r, 5000));
 		}
 		// Brief delay for MongoDB to fully stabilize before Prisma connections
 		if (databaseEngine === 'mongodb') {
-			await new Promise((resolve) => setTimeout(resolve, 3000));
+			await new Promise((r) => setTimeout(r, 3000));
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await new Promise((resolve) => setTimeout(resolve, 5000));
}
// Brief delay for MongoDB to fully stabilize before Prisma connections
if (databaseEngine === 'mongodb') {
await new Promise((resolve) => setTimeout(resolve, 3000));
await new Promise((r) => setTimeout(r, 5000));
}
// Brief delay for MongoDB to fully stabilize before Prisma connections
if (databaseEngine === 'mongodb') {
await new Promise((r) => setTimeout(r, 3000));
🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 171 - 175, The Promise
executor parameter name `resolve` shadows the imported `resolve` from the `path`
module; update the anonymous functions that create the delays (the two new
Promise((resolve) => setTimeout(resolve, ...)) calls in scaffoldDatabase.ts
inside the scaffoldDatabase flow and the databaseEngine === 'mongodb' branch) to
use a different parameter name (e.g., `done`, `res`, or `resolveTimer`) so they
no longer shadow `path.resolve`; keep behavior unchanged and only rename the
parameter in those Promise executors.

Comment on lines +192 to +206
if (databaseEngine === 'mongodb') {
const docker = resolveDockerExe();
const projectPath = resolve(projectCwd);
const network = `${toDockerProjectName(projectName)}_default`;
const mongoUrl =
'mongodb://root:rootpassword@db:27017/database?authSource=admin';

const result = await $`${docker} run --rm --network ${network} -v ${projectPath}:/app -w /app -e "DATABASE_URL=${mongoUrl}" node:20-slim npx prisma db push --schema ${schemaArg}`
.nothrow();

if (result.exitCode !== 0)
console.error('Error running Prisma migrations:', result.stderr);

return { dockerFreshInstall };
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Prisma migrations run via npx inside ephemeral node:20-slim containers — slow and fragile.

Lines 199 and 224 spin up a fresh node:20-slim container and run npx prisma …, which means Prisma is downloaded from npm on every scaffold invocation. This is:

  1. Slow — downloading Prisma + its binary engine each time adds significant latency.
  2. Fragile — network issues during scaffold will cause silent migration failures (.nothrow() suppresses the exit code messaging to stderr only).
  3. Inconsistent — the host already has Prisma installed (line 147 uses it), so running a different version inside the container could produce schema drift.

Consider building or caching a Prisma-ready image, or running migrations from the host with the Docker network's DB address exposed via port mapping (which is already configured in docker-compose).

Also, npx inside the containers should ideally be bunx or at minimum the Prisma version should be pinned to avoid version skew between host and container.

Also applies to: 219-235

🤖 Prompt for AI Agents
In `@src/generators/db/scaffoldDatabase.ts` around lines 192 - 206, Replace the
ephemeral "node:20-slim npx prisma" approach in scaffoldDatabase.ts: stop
running npx inside throwaway containers (the block using resolveDockerExe(),
toDockerProjectName(), mongoUrl and the result/.nothrow() flow) and instead
either (A) run prisma from the host (reuse the host-installed Prisma invoked
earlier) against the docker network DB address, or (B) build/use a cached
Prisma-ready image (pin the Prisma CLI version) and run that image so
dependencies aren't downloaded on each scaffold; also remove .nothrow() and
explicitly check result.exitCode to log and surface errors (currently only
result.stderr is printed) and preserve returning dockerFreshInstall. Ensure
references to resolveDockerExe, projectPath, network, mongoUrl, result, and
dockerFreshInstall are updated accordingly.

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.

3 participants