一键导入
sync-routes
Sync db-service/src/routes/api/ and routes/index.ts with the current DB schema. Use when tables are added or removed in db-service/src/db/schema.ts.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Sync db-service/src/routes/api/ and routes/index.ts with the current DB schema. Use when tables are added or removed in db-service/src/db/schema.ts.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Sync all db-service files after changing db-service/src/db/schema.ts or db-service/src/routes/api/ — runs sync-validation, sync-routes, sync-spec, and sync-api-types in sequence.
Regenerate admin TypeScript API types from the OpenAPI spec. Use after changes to db-service/src/openapi/spec.ts, db-service/src/routes/api/, or after running sync-spec.
Sync db-service/src/openapi/spec.ts with the current DB schema and routes. Use when tables are added/removed, columns change, or route files are added/removed/changed in db-service/src/routes/api/.
Sync db-service/src/validation/schema.ts with the current DB schema. Use when tables are added/removed or columns change in db-service/src/db/schema.ts.
| name | sync-routes |
| description | Sync db-service/src/routes/api/ and routes/index.ts with the current DB schema. Use when tables are added or removed in db-service/src/db/schema.ts. |
Synchronize route files and their registration with the current state of the project.
db-service/src/db/schema.ts — collect all exported table names.db-service/src/routes/api/ — list existing route files.db-service/src/validation/schema.ts — check which Create/Update schemas exist.db-service/src/routes/index.ts — check which routers are already imported and registered.1. Create db-service/src/routes/api/my-table.ts
Follow this exact structure (look at existing files for reference):
import { Router } from "express";
import { eq } from "drizzle-orm";
import { db } from "../../db/index";
import { myTable } from "../../db/schema";
import {
CreateMyTableSchema,
UpdateMyTableSchema,
UuidParamSchema,
} from "../../validation/schema";
import { validateBody, validateParams } from "../../validation/middleware";
import { assertFound, tryCatch } from "./utils";
const router = Router();
router.get("/", (_req, res) =>
tryCatch(res, async () => {
const rows = await db.select().from(myTable);
res.json(rows);
}),
);
router.get("/:id", validateParams(UuidParamSchema), (req, res) =>
tryCatch(res, async () => {
const [row] = await db
.select()
.from(myTable)
.where(eq(myTable.id, req.params.id));
if (!assertFound(row, res)) {
return;
}
res.json(row);
}),
);
router.post("/", validateBody(CreateMyTableSchema), (req, res) =>
tryCatch(res, async () => {
const [row] = await db.insert(myTable).values(req.body).returning();
res.status(201).json(row);
}),
);
router.patch(
"/:id",
validateParams(UuidParamSchema),
validateBody(UpdateMyTableSchema),
(req, res) =>
tryCatch(res, async () => {
const [row] = await db
.update(myTable)
.set(req.body)
.where(eq(myTable.id, req.params.id))
.returning();
if (!assertFound(row, res)) {
return;
}
res.json(row);
}),
);
router.delete("/:id", validateParams(UuidParamSchema), (req, res) =>
tryCatch(res, async () => {
const [row] = await db
.delete(myTable)
.where(eq(myTable.id, req.params.id))
.returning();
if (!assertFound(row, res)) {
return;
}
res.json({ ok: true });
}),
);
export default router;
Adjustments to the template:
UpdateMyTableSchema exists in validation/schema.ts → omit the PATCH /:id route and its import.PATCH and DELETE.PATCH.kebab-case matching the table name (e.g. design_system_users → design-system-users.ts).2. Register in db-service/src/routes/index.ts
Add import after the last existing api import:
import myTableRouter from "./api/my-table";
Add router.use(...) after the last existing resource route (before the misc section):
router.use("/my-table", myTableRouter);
Path: snake_case table name → kebab-case URL (e.g. design_system_users → /design-system-users).
routes/api/my-table.ts file.router.use(...) line from routes/index.ts.Many existing route files have additional endpoints beyond standard CRUD. When creating a new route file, do not add nested routes automatically — only add them if explicitly requested. Examples of existing nested routes for reference:
GET /:id/sub-resource — returns related entities (e.g. GET /components/:id/variations)GET /by-foreign-key/:foreignKeyId — filters by FK (e.g. GET /variation-property-values/by-style/:styleId)GET /by-a/:aId/by-b/:bId — compound filter (e.g. GET /styles/by-variation/:variationId/by-design-system/:designSystemId)For nested routes with non-UUID params, use inline z.object(...) validation:
const byFooSchema = z.object({ fooId: z.string().uuid() });
router.get("/by-foo/:fooId", validateParams(byFooSchema), (req, res) => ...);
const router = Router() and export default router.tryCatch(res, async () => { ... }) — never raw try/catch.validateParams(UuidParamSchema).validateBody(XxxSchema).assertFound(row, res) for single-row lookups — never inline 404 checks.if block.if blocks use full brace form — no single-line ifs.const arrow functions, not function declarations.desc() ordering for list endpoints (e.g. design-system-changes, design-system-versions, saved-queries) — apply desc(table.createdAt) when the table is an audit log or time-ordered.optionalAuthenticate middleware is used only in special routes (design-systems, legacy) — do not add it to standard CRUD routes.Report a summary:
routes/index.ts