11 KiB
11 KiB
Coding Conventions
Analysis Date: 2026-04-20
Naming Patterns
Files:
- Use Next.js App Router filenames in
src/app, includingpage.tsx,layout.tsx, androute.ts, as seen insrc/app/[locale]/page.tsx,src/app/[locale]/layout.tsx,src/app/api/projects/route.ts, andsrc/app/api/webhook/signals/route.ts. - Use
PascalCase.tsxfor reusable components insrc/components, for examplesrc/components/search/HomeSearchBar.tsx,src/components/project/ProjectDetail.tsx, andsrc/components/signals/SignalFeedClient.tsx. - Use lower-case or kebab-case utility filenames in
src/lib, for examplesrc/lib/auth.ts,src/lib/cache.ts,src/lib/signal-hotness.ts,src/lib/prisma-url.ts, andsrc/lib/tag-taxonomy.ts. - Keep tests co-located and named
*.test.ts, for examplesrc/lib/auth.test.ts,src/app/api/tags/route.test.ts, andsrc/app/api/tags/reset-projects/route.test.ts. - Treat
src/hooksas a mixed server query layer plus client hooks.src/hooks/useProjects.tsandsrc/hooks/useHome.tsare not React hooks despite theuse*prefix.
Functions:
- Use
camelCasefor helpers and query functions, such asisValidApiKeyinsrc/lib/auth.ts,normalizeProjectSortinsrc/hooks/useProjects.ts,parseSlugListinsrc/app/api/projects/route.ts, andgetTimestampinsrc/app/api/search/ai/route.ts. - Reserve
PascalCasefor React components, prop interfaces, and domain error classes, such asProjectDetailinsrc/components/project/ProjectDetail.tsxandTagMaintenanceApiErrorinsrc/app/api/tags/maintenance/service.ts. - Export route handlers as uppercase HTTP verbs from
src/app/api/**/route.ts, for exampleGETinsrc/app/api/tags/route.tsandPOSTinsrc/app/api/webhook/signals/route.ts.
Variables:
- Use
UPPER_SNAKE_CASEfor configuration constants and env-backed settings, such asN8N_WEBHOOK_URLinsrc/app/api/search/ai/route.ts,TAGS_CACHE_REVALIDATE_SECONDSinsrc/app/api/tags/route.ts,DB_RETRY_DELAYS_MSinsrc/hooks/useProjects.ts, andENV_KEYSinsrc/lib/prisma-url.test.ts. - Use descriptive names for parsed and normalized input, such as
validatedQueryinsrc/app/api/projects/route.ts,validationResultinsrc/app/api/webhook/signals/route.ts, andnormalizedTagSlugsinsrc/hooks/useProjects.ts.
Types:
- Prefer
typealiases for Prisma payloads and request payload shapes, such asProjectWithFlatTagsinsrc/hooks/useProjects.ts,SignalWebhookPayloadinsrc/lib/validations.ts, andResetProjectsRouteTxMockinsrc/app/api/tags/reset-projects/route.test.ts. - Prefer
interfacefor React props, such asHomeSearchBarPropsinsrc/components/search/HomeSearchBar.tsxandProjectDetailPropsinsrc/components/project/ProjectDetail.tsx.
Code Style
Formatting:
- Follow
.prettierrc.json: 2-space indentation, semicolons, double quotes, trailing commases5, andprintWidth100. AGENTS.mdtreats Prettier as authoritative andpnpmas the required package manager.- The codebase currently has mixed formatting. Files such as
src/lib/validations.ts,src/lib/prisma-url.ts, andsrc/app/api/tags/route.tsmatch the configured double-quote style, whilesrc/lib/auth.ts,src/app/api/projects/route.ts, andsrc/app/api/search/ai/route.tsstill use single quotes and omit semicolons. - For new files, follow
.prettierrc.json. When editing an existing file with a different quote style, either preserve the local file style for a surgical change or reformat the full file consistently.
Linting:
.eslintrc.jsonextendsnext/core-web-vitalsandprettier.- Only
console.warnandconsole.errorare explicitly allowed byno-console. This matches the logging used insrc/app/api/tags/route.ts,src/app/api/search/ai/route.ts, andsrc/app/api/webhook/signals/route.ts. - Current verification on 2026-04-20:
pnpm lintpassed with no warnings or errors.
Import Organization
Order:
- Framework and platform imports first, such as
next/server,next/cache,zod,crypto,fs, or@prisma/client, as seen insrc/app/api/webhook/signals/route.tsandsrc/lib/prisma-url.ts. - Internal alias imports from
@/next, such as@/lib/prisma,@/lib/validations, and@/hooks/useProjects. - Relative imports last, such as
./serviceinsrc/app/api/tags/maintenance/route.tsand./MarkdownContentinsrc/components/project/ProjectDetail.tsx.
Path Aliases:
- Use the
@/*alias defined intsconfig.jsonand mirrored invitest.config.ts. - Prefer
@/imports for anything undersrc, as seen throughoutsrc/app/api/tags/route.ts,src/app/api/tags/reset-projects/route.ts, andsrc/hooks/useProjects.ts.
API Validation and Auth
Validation:
- Put shared Zod schemas in
src/lib/validations.ts. Current examples includeProjectInputSchema,SignalWebhookPayloadSchema,SignalQuerySchema,TagMaintenanceRequestSchema, andProjectTagResetRequestSchema. - Define route-local schemas only when the contract is route-specific, such as
ProjectsQuerySchemainsrc/app/api/projects/route.tsandN8NSearchResponseSchemaplusAISearchRequestSchemainsrc/app/api/search/ai/route.ts. - Use
.safeParse()when the route should return a custom400response without exceptions, as insrc/app/api/tags/maintenance/route.ts,src/app/api/tags/reset-projects/route.ts, andsrc/app/api/webhook/signals/route.ts. - Use
.parse()when the route already catchesZodError, as insrc/app/api/projects/route.ts,src/app/api/signals/route.ts, andsrc/app/api/search/ai/route.ts. - Use
z.coerce.number()for query-string pagination and limits, as insrc/lib/validations.tsandsrc/app/api/projects/route.ts. - Use
.superRefine()for cross-record constraints such as duplicate tag IDs and self-merge prevention, as inTagMergeSchema,TagMaintenanceRequestSchema, andProjectTagResetRequestSchemainsrc/lib/validations.ts.
Webhook Auth:
- Use the timing-safe
isValidApiKey(...)helper fromsrc/lib/auth.tsfor internal mutation and webhook routes. - Read the expected secret from
process.env.WEBHOOK_API_KEYunless a test passes an explicit override. - Validate the API key format at schema level first, then authenticate with
isValidApiKey(...), as done insrc/app/api/tags/maintenance/route.ts,src/app/api/tags/reset-projects/route.ts, andsrc/app/api/webhook/signals/route.ts. - Return
401with a JSON body containingsuccess: false,error: "Unauthorized", and adetailsarray on auth failure.
Data Access
Prisma:
- Use the shared Prisma client from
src/lib/prisma.ts. - Keep read-heavy query composition in
src/hooks/useProjects.tsandsrc/hooks/useHome.ts. - Keep write workflows transactional with
prisma.$transaction(...), as insrc/app/api/tags/maintenance/route.tsandsrc/app/api/tags/reset-projects/route.ts. - Use explicit
includeandselectclauses rather than broad model reads, as seen throughoutsrc/hooks/useProjects.tsandsrc/app/api/webhook/signals/route.ts.
Caching and Degrade Patterns:
- Use
unstable_cachefor repeatable server reads, as insrc/app/api/tags/route.tsandsrc/hooks/useProjects.ts. - Route cached reads through
runWithCacheFallbackfromsrc/lib/cache.ts. - Use retry helpers for transient DB reads, as in
withDbRetry(...)andisTransientDbError(...)insrc/hooks/useProjects.ts. - Degrade on schema drift where the route can still succeed, as in
src/app/api/webhook/signals/route.tsfalling back when hotness columns are unavailable.
Error Handling
Patterns:
- Wrap route handlers in
try/catchand return JSON throughNextResponse.json(...), as seen insrc/app/api/projects/route.ts,src/app/api/search/ai/route.ts, andsrc/app/api/webhook/signals/route.ts. - Return
400for schema and query validation failures,401for invalid webhook keys, and500for unexpected failures. - Use route-local or domain-specific error classes when mutation logic needs structured status and details, as in
TagMaintenanceApiErrorfromsrc/app/api/tags/maintenance/service.ts. - Keep JSON error payloads stable enough for automation. Current routes usually emit
success,error,details, and sometimesmessage, but the exact shape is not yet fully standardized acrosssrc/app/api/**/route.ts.
Logging:
- Use
console.errorfor failures andconsole.warnfor operational summaries or degraded behavior, matching.eslintrc.jsonand examples insrc/app/api/tags/route.ts,src/hooks/useProjects.ts, andsrc/app/api/webhook/signals/route.ts. - Avoid
console.login production code because lint warns on it.
Comments
When to Comment:
- Keep comments sparse and intent-focused. Existing comments mostly explain numbered handler steps, fallback rationale, or bilingual product context, as in
src/app/api/tags/maintenance/route.ts,src/hooks/useProjects.ts, andsrc/app/api/search/ai/route.ts. - Use short JSDoc only where security or contract semantics matter, such as the timing-safe explanation above
isValidApiKey(...)insrc/lib/auth.ts.
Function Design
Size:
- The repository tolerates large query and route modules. Current examples include
src/hooks/useProjects.ts,src/app/api/signals/route.ts, andsrc/app/api/tags/reset-projects/route.ts. - Keep helper functions close to the route or query layer before extracting a new module. Examples include
parseSlugList(...)insrc/app/api/projects/route.ts,normalizeSlugList(...)insrc/app/api/search/ai/route.ts, andtoSectionsJson(...)insrc/app/api/webhook/signals/route.ts.
Parameters:
- Prefer a single typed options object for non-trivial query helpers, as in
getProjects(...)fromsrc/hooks/useProjects.ts. - For route handlers, parse from
request.nextUrl.searchParamsorawait request.json()once, then normalize into a validated object before passing deeper.
Return Values:
- Return plain serializable objects from API routes and query helpers.
- Flatten Prisma relation shapes before returning UI data, as done by
getProjects(...)andgetProjectsByIds(...)insrc/hooks/useProjects.ts.
Module Design
Exports:
- Prefer named exports across shared modules and components. No barrel files were detected under
src. - Use default exports mainly for App Router pages and layouts under
src/app.
Separation of Concerns:
- Keep Prisma-backed reads in
src/hooks/useProjects.tsandsrc/hooks/useHome.ts. - Keep cross-cutting utilities in
src/lib, such assrc/lib/auth.ts,src/lib/cache.ts,src/lib/prisma.ts, andsrc/lib/validations.ts. - Keep mutation business logic in a local service file when the route would otherwise mix transport and domain rules.
src/app/api/tags/maintenance/route.tsplussrc/app/api/tags/maintenance/service.tsis the clearest existing pattern.
Convention analysis: 2026-04-20