Skip to content

feat: add prisma-mysql-starter foundation#56

Merged
AkkalDhami merged 5 commits intoAkkalDhami:mainfrom
faizkhairi:feat/prisma-mysql-starter
Mar 23, 2026
Merged

feat: add prisma-mysql-starter foundation#56
AkkalDhami merged 5 commits intoAkkalDhami:mainfrom
faizkhairi:feat/prisma-mysql-starter

Conversation

@faizkhairi
Copy link
Copy Markdown
Contributor

@faizkhairi faizkhairi commented Mar 21, 2026

Summary

Adds a new prisma-mysql-starter foundation template that provides a production-ready starting point for Node.js + TypeScript backend applications using Prisma ORM with MySQL.

Closes #38

What's included

  • Prisma schema configured for MySQL with a sample User model (autoincrement ID, createdAt/updatedAt timestamps)
  • Two architecture variants: MVC and Feature-based, matching the existing prisma-mongodb-starter structure
  • Registry entry (packages/registry/foundation/prisma-mysql-starter.json) with all dependencies and env vars
  • All required ServerCN components integrated:
    • http-status-codes (status-codes.ts)
    • health-controller (health.controller.ts with basic + detailed endpoints)
    • async-handler (AsyncHandler wrapper)
    • api-response-formatter (ApiResponse class)
    • global-error-handler (errorHandler middleware)
    • logger (pino with pino-pretty)
    • shutdown-handler (configureGracefulShutdown)
    • Custom ApiError class

MySQL-specific changes from MongoDB starter

  • schema.prisma: provider = "mysql" with Int @id @default(autoincrement()) instead of MongoDB ObjectId
  • package.json: Added db:migrate and db:deploy scripts for Prisma migrations (MySQL supports migrations unlike MongoDB's push-only workflow)
  • Swagger titles updated to "Prisma MySQL Starter"
  • DATABASE_URL included in both MVC and Feature env validation (consistent with drizzle-mysql-starter pattern)

File structure

prisma-mysql-starter/
  feature/                         # Feature-based architecture
    package.json
    prisma/schema.prisma
    swagger.config.ts
    src/
      app.ts
      server.ts
      docs/swagger.json
      routes/index.ts
      modules/health/
        health.controller.ts
        health.routes.ts
      shared/
        configs/ (env, prisma, swagger)
        constants/ (status-codes)
        errors/ (api-error)
        middlewares/ (error-handler, not-found-handler)
        utils/ (api-response, async-handler, logger, shutdown)
  mvc/                             # MVC architecture
    package.json
    prisma/schema.prisma
    swagger.config.ts
    src/
      app.ts
      server.ts
      docs/swagger.json
      configs/ (env, prisma, swagger)
      constants/ (status-codes)
      controllers/ (health.controller)
      middlewares/ (error-handler, not-found-handler)
      routes/ (health.routes)
      utils/ (api-error, api-response, async-handler, logger, shutdown)

Summary by CodeRabbit

  • New Features

    • New Express + Prisma + MySQL starter templates (MVC and feature) with ready-to-run npm scripts.
    • Pre-configured health endpoints (basic and detailed), Swagger UI at /api/docs, and Swagger generation workflow.
    • Built-in Prisma setup with User model and migration/DB workflows, environment validation, structured API responses, centralized error handling, request logging, graceful shutdown, and logger configuration.
  • Documentation

    • Added a guide describing the Prisma MySQL Starter, setup commands, env examples, and migration usage.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 21, 2026

@faizkhairi is attempting to deploy a commit to the akkaldhami's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: be562585-1d65-461f-a4ce-bdf44e1bde68

📥 Commits

Reviewing files that changed from the base of the PR and between 52c94c7 and 9d93779.

📒 Files selected for processing (1)
  • apps/web/src/content/docs/express/foundations/prisma-mysql-starter.mdx
✅ Files skipped from review due to trivial changes (1)
  • apps/web/src/content/docs/express/foundations/prisma-mysql-starter.mdx

📝 Walkthrough

Walkthrough

Adds a new prisma-mysql-starter foundation and registry manifest plus two Express TypeScript starter templates (MVC and feature) with Prisma MySQL schema, env validation, health endpoints, API utilities, error handling, logger, graceful shutdown, and Swagger support.

Changes

Cohort / File(s) Summary
Registry Entry
packages/registry/foundation/prisma-mysql-starter.json
New foundation manifest registering prisma-mysql-starter: schema ref, template mappings (mvc, feature), listed runtime/dev dependencies, and required env variables.
Templates: package manifests
packages/templates/node/express/foundation/prisma-mysql-starter/.../package.json (both mvc and feature)
Added package.json for both template variants with scripts for dev/build/start/typecheck/prisma/lint/format/docs and lint-staged config.
Prisma schema (MySQL)
.../feature/prisma/schema.prisma, .../mvc/prisma/schema.prisma
New Prisma schemas configured for MySQL with generator client and a User model.
App & Server bootstrap
.../feature/src/app.ts, .../feature/src/server.ts, .../mvc/src/app.ts, .../mvc/src/server.ts
New app/server files: source-map support, middleware stack, conditional Swagger, route mounting, not-found/error handlers, server.listen and graceful shutdown registration.
Health feature & routes
.../feature/src/modules/health/*, .../feature/src/routes/index.ts, .../mvc/src/controllers/health.controller.ts, .../mvc/src/routes/health.routes.ts, .../*/docs/swagger.json
Health controllers for /api/health and /api/health/detailed, routers wiring, and placeholder swagger.json files.
Env, Prisma & Swagger configs
.../feature/src/shared/configs/*, .../mvc/src/configs/*, .../feature/swagger.config.ts, .../mvc/swagger.config.ts
Zod-based env validation (process exit on failure), Prisma client instantiation with conditional logging, and swagger-autogen config to generate ./src/docs/swagger.json.
Error/response/status utilities
.../feature/src/shared/errors/api-error.ts, .../mvc/src/utils/api-error.ts, .../feature/src/shared/utils/api-response.ts, .../mvc/src/utils/api-response.ts, .../*/status-codes.ts
Added ApiError class with static factories, ApiResponse<T> helpers, STATUS_CODES constant and StatusCode type.
Middlewares & utils
.../shared/middlewares/*, .../shared/utils/*, .../mvc/src/middlewares/*, .../mvc/src/utils/*
Added notFoundHandler, errorHandler, AsyncHandler, logger (pino with pino-pretty in dev), and graceful shutdown helper that disconnects Prisma.
Docs
apps/web/src/content/docs/express/foundations/prisma-mysql-starter.mdx
New documentation page describing the Prisma MySQL Starter, usage, env examples, Prisma snippets, and migration instructions.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Server as HTTP Server
  participant App as Express App
  participant Router as Router (/api/health)
  participant Controller as Health Controller
  participant Prisma as Prisma DB
  participant Logger as Logger
  participant Shutdown as Shutdown

  Client->>Server: HTTP GET /api/health
  Server->>App: forward request
  App->>Router: dispatch to /api/health
  Router->>Controller: invoke handler (AsyncHandler)
  Controller->>Logger: log request/health info
  alt reads DB (non-critical)
    Controller->>Prisma: optional query
  end
  Controller-->>Client: ApiResponse JSON (status, timestamp, uptime)
  Note over Server,Shutdown: server started with configureGracefulShutdown(server)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Hopping through MySQL rows tonight,

Prisma seeds beneath the moonlight,
Two templates stitched, ready to start,
Health checks hum and logs play their part,
A rabbit cheers — clean code, tiny heart!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: add prisma-mysql-starter foundation' accurately describes the main change—adding a new foundation template for Prisma with MySQL, and is concise and clear.
Linked Issues check ✅ Passed All coding requirements from issue #38 are met: Prisma configured for MySQL with sample User model, environment configuration with DATABASE_URL validation, both MVC and Feature architecture variants, and all required ServerCN components integrated.
Out of Scope Changes check ✅ Passed All changes are directly related to the prisma-mysql-starter foundation objective. No unrelated modifications to existing functionality or out-of-scope refactoring detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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: 12

🧹 Nitpick comments (3)
packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/configs/prisma.ts (1)

4-8: Consider singleton pattern for development hot-reload scenarios.

In development with hot-module reloading (e.g., ts-node-dev, nodemon), this module may be re-imported multiple times, creating multiple PrismaClient instances and exhausting database connections. A common pattern caches the client on globalThis.

♻️ Optional: Add singleton pattern for development
 import { PrismaClient } from "@prisma/client";
 import env from "./env";

+const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
+
-const prisma = new PrismaClient({
+const prisma = globalForPrisma.prisma ?? new PrismaClient({
   log: env.NODE_ENV === "development" ? ["query", "warn", "error"] : ["error"]
 });

+if (env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
+
 export default prisma;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/configs/prisma.ts`
around lines 4 - 8, The PrismaClient instantiation can create multiple instances
during hot-reload; modify the module to export a singleton by storing the
PrismaClient on globalThis (e.g., globalThis.__prisma or
globalThis.__prismaClient) so repeated imports return the cached instance;
update the existing prisma variable creation (where PrismaClient is constructed)
to first check and reuse globalThis.__prisma, assign the new client to that
global when created, and export that singleton `prisma` (also consider only
attaching the cache in non-production environments).
packages/templates/node/express/foundation/prisma-mysql-starter/mvc/package.json (1)

21-27: tsc --noEmit in lint-staged may not work correctly on individual files.

Running tsc --noEmit on staged files via lint-staged passes individual file paths to tsc, which can cause issues with project-wide type checking (imports, module resolution, tsconfig paths). Consider removing it from lint-staged and relying on the separate typecheck script or CI.

♻️ Suggested change
   "lint-staged": {
     "src/**/*.ts": [
       "eslint --fix",
-      "prettier --write",
-      "tsc --noEmit"
+      "prettier --write"
     ]
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/package.json`
around lines 21 - 27, The lint-staged config currently runs "tsc --noEmit" which
invokes TypeScript per-file and can break project-level type checks; remove "tsc
--noEmit" from the "lint-staged" entry (the object keyed by "lint-staged" and
its array for "src/**/*.ts") and rely on the existing "typecheck" npm script or
CI to run full project type checking instead; ensure only "eslint --fix" and
"prettier --write" remain in that array so lint-staged runs fast and local
typechecks still occur via the "typecheck" script.
packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/modules/health/health.controller.ts (1)

31-38: Cache process.memoryUsage() call to avoid redundant invocations.

process.memoryUsage() is called twice (once for heapUsed, once for heapTotal). While minor for a health endpoint, caching the result is cleaner and ensures consistent values.

♻️ Suggested improvement
+    const memUsage = process.memoryUsage();
     memory: {
       used:
-        Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) /
+        Math.round((memUsage.heapUsed / 1024 / 1024) * 100) /
         100,
       total:
-        Math.round((process.memoryUsage().heapTotal / 1024 / 1024) * 100) /
+        Math.round((memUsage.heapTotal / 1024 / 1024) * 100) /
         100,
       unit: "MB"
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/modules/health/health.controller.ts`
around lines 31 - 38, The memory block repeatedly calls process.memoryUsage();
cache its result once (e.g., const mem = process.memoryUsage()) inside the
health endpoint handler (the method in HealthController that builds the memory
object) and replace the duplicate calls with mem.heapUsed and mem.heapTotal so
you return consistent values and avoid redundant invocations in the memory {
used, total, unit } construction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/registry/foundation/prisma-mysql-starter.json`:
- Around line 28-37: The package template currently lists "morgan" inside the
"dev" dependencies array, but morgan is a runtime middleware and must be
installed as a production dependency; move "morgan" out of the "dev" array and
add it to the runtime dependencies list (the top-level "dependencies" or
equivalent field in this JSON template) so that the "morgan" package is
available in production builds and imports (reference the "dev" array containing
"morgan" and the dependency list where runtime packages are declared).

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/package.json`:
- Line 19: The "docs" npm script currently runs "node swagger.config.ts" which
fails because Node can't execute TypeScript or ESM TypeScript files directly;
update the package.json "docs" script to invoke a TypeScript-aware runner (e.g.,
replace the command to use "tsx" so it runs swagger.config.ts correctly) and
ensure the target file swagger.config.ts is referenced unchanged; no other code
changes required.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/configs/swagger.ts`:
- Around line 6-8: The setupSwagger function currently always mounts the docs at
"/api/docs"; change it to gate the route by environment so docs are not exposed
by default in production — modify setupSwagger to check a config/env flag (e.g.
process.env.ENABLE_SWAGGER === "true" or NODE_ENV !== "production") before
calling app.use("/api/docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
keep the same function name setupSwagger and the same route but only register it
when the opt-in condition is met.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/middlewares/error-handler.ts`:
- Around line 7-33: The errorHandler middleware can attempt to write a response
after headers have already been sent, causing ERR_HTTP_HEADERS_SENT; update the
errorHandler function to check res.headersSent at the start and if true call
next(err) to delegate handling; keep existing logging behavior (logger.error)
but only perform res.status(...).json(...) when res.headersSent is false;
reference the errorHandler function, the res.headersSent property and the
next(err) call when making the change.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/utils/api-response.ts`:
- Around line 19-41: The constructor of ApiResponse (constructor in
api-response.ts) sets data = null which conflicts with send()'s conditional
inclusion (send uses this.data !== undefined), causing data to always appear;
remove the default assignment (data = null) in the constructor parameter list or
change the param type so that absent data remains undefined, and ensure
ApiResponseParams<T> and the constructor initialize this.data only from the
provided value so that send()'s this.data !== undefined check correctly omits
data when not supplied.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/utils/logger.ts`:
- Line 2: The import in logger.ts uses a redundant relative path
("../../shared/configs/env"); update the import to the shorter path
"../configs/env" so it references the sibling shared/configs module directly;
locate the import statement in feature/src/shared/utils/logger.ts and change the
module specifier to "../configs/env" (no behavior changes required).

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/package.json`:
- Line 19: The "docs" npm script currently uses Node to run a TypeScript file
("docs": "node swagger.config.ts") which fails; update the package.json scripts
entry for the "docs" script to run the TypeScript file with the same runtime
used by "dev" (e.g., use "tsx swagger.config.ts" or "npx tsx swagger.config.ts")
so swagger.config.ts is executed via tsx instead of node; locate the "docs" key
in package.json and replace the command accordingly.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/configs/swagger.ts`:
- Around line 6-8: The swagger docs are mounted unconditionally; update
setupSwagger to only register the route when explicitly enabled (e.g., via an
environment/config flag or when NODE_ENV !== 'production') so /api/docs is not
exposed in production by default; modify the setupSwagger function to check a
config flag (or process.env.NODE_ENV) before calling app.use("/api/docs",
swaggerUi.serve, swaggerUi.setup(swaggerDocument)) and document/validate the
flag name used for enabling docs.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/controllers/health.controller.ts`:
- Around line 23-43: The detailedHealthCheck handler currently exposes
environment, version, memory and cpu data publicly; update detailedHealthCheck
(the AsyncHandler-wrapped route) to only return the full detailed payload when
allowed: either gate it to non-production (check process.env.NODE_ENV !==
'production') or require a feature flag/auth (e.g.
process.env.ENABLE_DETAILED_HEALTH or an authentication/permission check on the
request) and otherwise return a minimal safe response (status/timestamp). Ensure
the decision logic is implemented at the start of detailedHealthCheck so the
sensitive fields (environment, version, memory, cpu) are omitted unless the
guard passes.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/middlewares/error-handler.ts`:
- Around line 16-32: The error handler currently discards structured details
from ApiError; update the middleware in error-handler.ts so when err is an
instance of ApiError (check err instanceof ApiError) you capture and include its
errors property into the JSON response (e.g., extend the response object with an
errors field) before calling res.status(...).json(...); ensure logger.error
still logs err and keep the existing stack inclusion for development.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/async-handler.ts`:
- Around line 9-12: AsyncHandler currently calls Promise.resolve(fn(req, res,
next)) which evaluates fn synchronously and lets thrown sync errors bypass
.catch(next); update AsyncHandler to catch synchronous throws and forward them
to next by wrapping the call in a try/catch (i.e., in the returned function
catch errors from fn(req, res, next) and call next(err), otherwise attach
.catch(next) to the Promise) so both sync and async errors from fn (the
AsyncRouteHandler) are sent to NextFunction.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/shutdown.ts`:
- Around line 4-27: The graceful shutdown handler in
configureGracefulShutdown(server) never disconnects Prisma; update
configureGracefulShutdown to accept either an injected Prisma client or an async
cleanup callback (e.g., configureGracefulShutdown(server, prisma) or
configureGracefulShutdown(server, asyncCleanup)), then in the signal handler
await the cleanup (await prisma.$disconnect() or await asyncCleanup()) before
calling process.exit, and ensure errors from prisma.$disconnect() are caught and
logged via logger.error inside the server.close callback and the forced shutdown
timeout remains as fallback.

---

Nitpick comments:
In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/modules/health/health.controller.ts`:
- Around line 31-38: The memory block repeatedly calls process.memoryUsage();
cache its result once (e.g., const mem = process.memoryUsage()) inside the
health endpoint handler (the method in HealthController that builds the memory
object) and replace the duplicate calls with mem.heapUsed and mem.heapTotal so
you return consistent values and avoid redundant invocations in the memory {
used, total, unit } construction.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/package.json`:
- Around line 21-27: The lint-staged config currently runs "tsc --noEmit" which
invokes TypeScript per-file and can break project-level type checks; remove "tsc
--noEmit" from the "lint-staged" entry (the object keyed by "lint-staged" and
its array for "src/**/*.ts") and rely on the existing "typecheck" npm script or
CI to run full project type checking instead; ensure only "eslint --fix" and
"prettier --write" remain in that array so lint-staged runs fast and local
typechecks still occur via the "typecheck" script.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/configs/prisma.ts`:
- Around line 4-8: The PrismaClient instantiation can create multiple instances
during hot-reload; modify the module to export a singleton by storing the
PrismaClient on globalThis (e.g., globalThis.__prisma or
globalThis.__prismaClient) so repeated imports return the cached instance;
update the existing prisma variable creation (where PrismaClient is constructed)
to first check and reuse globalThis.__prisma, assign the new client to that
global when created, and export that singleton `prisma` (also consider only
attaching the cache in non-production environments).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b7bfc957-6c60-499e-b5be-af5406b1efea

📥 Commits

Reviewing files that changed from the base of the PR and between 3f84f97 and d7fe423.

📒 Files selected for processing (40)
  • packages/registry/foundation/prisma-mysql-starter.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/package.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/prisma/schema.prisma
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/app.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/docs/swagger.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/modules/health/health.controller.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/modules/health/health.routes.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/routes/index.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/server.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/configs/env.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/configs/prisma.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/configs/swagger.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/constants/status-codes.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/errors/api-error.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/middlewares/error-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/middlewares/not-found-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/utils/api-response.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/utils/async-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/utils/logger.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/utils/shutdown.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/swagger.config.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/package.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/prisma/schema.prisma
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/app.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/configs/env.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/configs/prisma.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/configs/swagger.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/constants/status-codes.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/controllers/health.controller.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/docs/swagger.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/middlewares/error-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/middlewares/not-found-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/routes/health.routes.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/server.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/api-error.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/api-response.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/async-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/logger.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/shutdown.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/swagger.config.ts

Comment thread packages/registry/foundation/prisma-mysql-starter.json
import swaggerDocument from "../../docs/swagger.json";

export const setupSwagger = (app: Express) => {
app.use("/api/docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

fix the bug here, follow coderabbit review
if (process.env.ENABLE_SWAGGER !== "true") return;
add ENABLE_SWAGGER in registry json file > foundation > prisma-mysql-starter > env.

@@ -0,0 +1,33 @@
import { Request, Response, NextFunction } from "express";
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

fix this:
import { Request, Response, NextFunction } from "express";
import env from "../configs/env";

import { ApiError } from "../utils/api-error";
import { logger } from "../utils/logger";

export const errorHandler = (
err: Error,
req: Request,
res: Response,
next: NextFunction
) => {
if (res.headersSent) {
return next(err);
}

let statusCode = 500;
let message = "Internal server error";
let errors: unknown;
if (err instanceof ApiError) {
statusCode = err.statusCode;
message = err.message;
errors = err.errors;
}

logger.error(
err,
Error: ${message} | Status: ${statusCode} | Path: ${req.method} ${req.originalUrl}
);

const response = {
success: false,
message,
statusCode,
...(errors !== undefined && { errors }),
...(env.NODE_ENV === "development" && { stack: err.stack })
};

res.status(statusCode).json(response);
};

success,
message,
statusCode,
data = null,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

fix this: data = null, => data,

"lint:fix": "eslint . --fix",
"format:check": "npx prettier . --check",
"format:fix": "npx prettier . --write",
"docs": "node swagger.config.ts"
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

fix this also node swagger.config.ts => npx tsx swagger.config.ts

import swaggerDocument from "../docs/swagger.json"; // Generated by swagger-autogen by running `node swagger.config.ts`

export const setupSwagger = (app: Express) => {
app.use("/api/docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

add this: if (process.env.ENABLE_SWAGGER !== "true") return;


export function AsyncHandler(fn: AsyncRouteHandler) {
return function (req: Request, res: Response, next: NextFunction) {
Promise.resolve(fn(req, res, next)).catch(next);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

fix here also

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: 1

🧹 Nitpick comments (1)
packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/app.ts (1)

34-36: Prefer validated env access for Swagger toggle.

Use the shared env object here instead of process.env so this flag follows the same validation/parsing path as the rest of the config.

Proposed fix
-if (process.env.ENABLE_SWAGGER === "true") {
+if (env.ENABLE_SWAGGER === "true") {
   setupSwagger(app);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/app.ts`
around lines 34 - 36, Replace the direct process.env check with the validated
shared env value so the Swagger toggle uses the same parsing/validation as the
rest of config: import or reference the shared env object and change the
condition from process.env.ENABLE_SWAGGER === "true" to using env.ENABLE_SWAGGER
(e.g., if (env.ENABLE_SWAGGER) { setupSwagger(app); }), keeping the call to
setupSwagger(app) and the app reference unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/app.ts`:
- Around line 21-27: The CORS configuration using origin: env.CORS_ORIGIN treats
the env value as a single literal string and breaks when env.CORS_ORIGIN
contains multiple comma-separated origins; update the app.use(cors(...)) call to
parse env.CORS_ORIGIN into an array (split on commas, trim entries, handle "*"
or empty) and pass an origin validation function that checks reqOrigin against
that array and calls the callback accordingly; modify the cors setup around
app.use and the cors(...) invocation so origin is a function that accepts
(origin, callback) and validates against the parsed list rather than a single
string.

---

Nitpick comments:
In
`@packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/app.ts`:
- Around line 34-36: Replace the direct process.env check with the validated
shared env value so the Swagger toggle uses the same parsing/validation as the
rest of config: import or reference the shared env object and change the
condition from process.env.ENABLE_SWAGGER === "true" to using env.ENABLE_SWAGGER
(e.g., if (env.ENABLE_SWAGGER) { setupSwagger(app); }), keeping the call to
setupSwagger(app) and the app reference unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d33d40a3-0dcf-44cd-a3dd-1827e607802d

📥 Commits

Reviewing files that changed from the base of the PR and between c2da844 and 52c94c7.

📒 Files selected for processing (9)
  • packages/registry/foundation/prisma-mysql-starter.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/package.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/app.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/middlewares/error-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/src/shared/utils/api-response.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/package.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/app.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/middlewares/error-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/utils/api-response.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/registry/foundation/prisma-mysql-starter.json
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/package.json
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/app.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/mvc/src/middlewares/error-handler.ts
  • packages/templates/node/express/foundation/prisma-mysql-starter/feature/package.json

@AkkalDhami
Copy link
Copy Markdown
Owner

@faizkhairi Bro, pull the latest changes

@faizkhairi
Copy link
Copy Markdown
Contributor Author

@faizkhairi Bro, pull the latest changes

Okayy

@faizkhairi faizkhairi force-pushed the feat/prisma-mysql-starter branch from 230a773 to 5b5309e Compare March 23, 2026 04:00
@faizkhairi
Copy link
Copy Markdown
Contributor Author

faizkhairi commented Mar 23, 2026

I rebase onto main to streamline with your project's update and make this PR more clean

@AkkalDhami
Copy link
Copy Markdown
Owner

@AkkalDhami
Copy link
Copy Markdown
Owner

@faizkhairi Brother, Add minimal document also inside apps\web\src\content\docs\express\foundations\prisma-mysql-starter.mdx

Reference:
prisma mongodb starter

Add Prisma MySQL starter foundation with both MVC and feature-based
architecture variants, following the same patterns as the existing
prisma-mongodb-starter.

Closes AkkalDhami#38
…async correctness

- Move morgan from devDependencies to dependencies (runtime middleware)
- Fix docs script: use tsx instead of node for TypeScript execution
- Gate Swagger docs behind NODE_ENV !== 'production'
- Guard health endpoint: production returns only status + timestamp
- Preserve ApiError.errors in error handler response
- Fix async handler: Promise.resolve().then(() => fn()) catches sync throws
- Add prisma.$disconnect() to graceful shutdown handler

Applied to both MVC and feature-based variants.
- Swagger gate: use ENABLE_SWAGGER env var instead of NODE_ENV check
- Error handler: add headersSent guard, extract errors variable, include statusCode in response
- ApiResponse: remove data = null default (use undefined)
- Docs script: use npx tsx instead of tsx
- Registry: add ENABLE_SWAGGER to env list

Applied to both MVC and feature-based variants.
- Add ENABLE_SWAGGER env guard inside setupSwagger function (both variants)
- Fix CORS origin: split comma-separated string to array for cors v2.8.5

Addresses remaining owner review + CodeRabbit round 2 feedback.
@faizkhairi faizkhairi force-pushed the feat/prisma-mysql-starter branch from 5b5309e to 9d93779 Compare March 23, 2026 04:48
@faizkhairi
Copy link
Copy Markdown
Contributor Author

@faizkhairi Brother, Add minimal document also inside apps\web\src\content\docs\express\foundations\prisma-mysql-starter.mdx

Reference: prisma mongodb starter

I created a doc similar to prisma-mongodb-starter.mdx and drizzle-mysql-starter.mdx documentations.

@AkkalDhami AkkalDhami merged commit fb872d3 into AkkalDhami:main Mar 23, 2026
1 of 2 checks passed
@AkkalDhami
Copy link
Copy Markdown
Owner

@faizkhairi Congrats, and Thank you brother!

This was referenced Mar 23, 2026
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.

feat: prisma-mysql-starter

2 participants