13 KiB
13 KiB
Coding Conventions
Analysis Date: 2026-04-18
Naming Patterns
Files:
- Use Next.js route filenames in
src/app:page.tsx,layout.tsx,route.ts,not-found.tsx,robots.ts, andsitemap.tsas seen insrc/app/[locale]/page.tsx,src/app/[locale]/layout.tsx,src/app/api/projects/route.ts, andsrc/app/[locale]/not-found.tsx. - Use
PascalCase.tsxfor reusable components insrc/components, for examplesrc/components/project/ProjectCard.tsx,src/components/project/TagFilterPanel.tsx, andsrc/components/signals/SignalFeedClient.tsx. - Use lower-case utility filenames in
src/lib, for examplesrc/lib/auth.ts,src/lib/cache.ts,src/lib/signal-hotness.ts, andsrc/lib/validations.ts. src/hooksis not limited to React hooks.src/hooks/useProjects.tsandsrc/hooks/useHome.tsexport server-side data access and aggregation functions, not hook APIs. Extend those files only when adding the same kind of server query layer.
Functions:
- Use
camelCasefor functions and helpers:isValidApiKeyinsrc/lib/auth.ts,normalizeProjectSortinsrc/hooks/useProjects.ts,runWithCacheFallbackinsrc/lib/cache.ts, andcollectSelectedTagSlugsinsrc/app/api/tags/reset-projects/route.ts. - Use
PascalCaseonly for React components and error classes:ProjectCardinsrc/components/project/ProjectCard.tsx,ProjectsResultsClientinsrc/app/[locale]/projects/ProjectsResultsClient.tsx, andTagMaintenanceApiErrorinsrc/app/api/tags/maintenance/service.ts. - Use
GETandPOSTnamed exports for route handlers insrc/app/api/**/route.ts.
Variables:
- Use
UPPER_SNAKE_CASEfor constants and configuration knobs, for exampleDB_RETRY_DELAYS_MSinsrc/hooks/useProjects.ts,DEFAULT_RESET_CATEGORIESinsrc/app/api/tags/reset-projects/route.ts,TAGS_CACHE_REVALIDATE_SECONDSinsrc/app/api/tags/route.ts, andN8N_WEBHOOK_URLinsrc/app/api/search/ai/route.ts. - Use descriptive typed local variables for parsed or normalized input, such as
validatedQueryinsrc/app/api/projects/route.ts,normalizedTagSlugsinsrc/hooks/useProjects.ts, andvalidationResultinsrc/app/api/webhook/signals/route.ts.
Types:
- Prefer
typealiases for data shapes and Prisma payloads, for exampleProjectWithFlatTagsinsrc/hooks/useProjects.ts,HomePageDatainsrc/hooks/useHome.ts, andResetResultIteminsrc/app/api/tags/reset-projects/route.ts. - Use
interfacefor component props, for exampleProjectCardPropsinsrc/components/project/ProjectCard.tsx,ProjectsPageClientPropsinsrc/app/[locale]/projects/ProjectsPageClient.tsx, andSignalFeedClientPropsinsrc/components/signals/SignalFeedClient.tsx.
Code Style
Formatting:
- Prettier is configured in
.prettierrc.jsonfor 2-space indentation, semicolons, double quotes, trailing commas set toes5, andprintWidth100. - The repository is not uniformly formatted to that config. Files such as
src/lib/validations.ts,src/hooks/useProjects.ts, andsrc/app/api/tags/maintenance/route.tsmatch the configured double-quote and semicolon style, whilesrc/app/api/projects/route.ts,src/app/api/search/ai/route.ts,src/lib/auth.ts, andsrc/components/project/ProjectCard.tsxuse single quotes and omit semicolons. - For new files, follow
.prettierrc.json. When editing existing files, preserve the file-local style unless the whole file is reformatted.
Linting:
- ESLint extends
next/core-web-vitalsandprettierin.eslintrc.json. console.warnandconsole.errorare allowed; otherconsolecalls are warned byno-console.- Quality checks on 2026-04-18:
pnpm lintpassed with✔ No ESLint warnings or errors.
Import Organization
Order:
- Framework and platform imports first, for example
next/server,next/cache,zod,@prisma/client, orreact. - Internal alias imports from
@/, for example@/lib/prisma,@/hooks/useProjects, and@/lib/validations. - Relative imports last, for example
./serviceinsrc/app/api/tags/maintenance/route.ts.
Path Aliases:
- Use the
@/*alias fromtsconfig.jsonandvitest.config.tsfor internal imports. - Prefer
@/over deep relative paths acrosssrc, for example@/lib/prismainsrc/app/api/tags/route.tsand@/lib/tag-taxonomyinsrc/hooks/useProjects.ts.
Component and Module Design
React Components:
- Default-export only route-level pages and layouts, for example
src/app/[locale]/page.tsx,src/app/[locale]/projects/page.tsx, andsrc/app/layout.tsx. - Use named exports for reusable components, for example
ProjectCardinsrc/components/project/ProjectCard.tsx,HomeRankingsinsrc/components/home/HomeRankings.tsx, andAnnouncementBarinsrc/components/layout/AnnouncementBar.tsx. - Mark interactive components with
'use client', as seen insrc/app/[locale]/projects/ProjectsResultsClient.tsx,src/app/[locale]/projects/ProjectsPageClient.tsx,src/components/project/TagFilterPanel.tsx, andsrc/components/signals/SignalFeedClient.tsx. - Keep server components async and free of client hooks, as seen in
src/app/[locale]/projects/[id]/page.tsx,src/app/[locale]/signals/page.tsx, andsrc/components/project/ProjectSidebar.tsx. - Type component props explicitly with a local
interface ...Props.
Service and Query Modules:
- Centralize Prisma-backed read logic in
src/hooks/useProjects.tsandsrc/hooks/useHome.ts. Despite the directory name, these modules act as query services for routes and server components. - Keep route handlers thin where possible and delegate business rules to local services for mutations. The clearest example is
src/app/api/tags/maintenance/route.tsdelegating tosrc/app/api/tags/maintenance/service.ts. - Reuse shared utility modules in
src/libfor cross-cutting concerns:src/lib/auth.ts,src/lib/cache.ts,src/lib/prisma.ts,src/lib/signal-hotness.ts,src/lib/slug.ts, andsrc/lib/tag-taxonomy.ts.
Exports:
- Prefer named exports across shared modules. No barrel files were detected under
srcon 2026-04-18.
Validation
Schema Placement:
- Put broadly shared Zod schemas in
src/lib/validations.ts. Examples includeProjectInputSchema,SignalWebhookPayloadSchema,SignalQuerySchema, andTagMaintenanceRequestSchema. - Define route-local Zod schemas only when the contract is tightly coupled to a single endpoint, as in
ProjectsQuerySchemainsrc/app/api/projects/route.tsandN8NSearchResponseSchemainsrc/app/api/search/ai/route.ts.
Validation Flow:
- Use
.safeParse()when the route needs to return a custom400payload 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 has aZodErrorcatch branch, as insrc/app/api/projects/route.ts,src/app/api/search/ai/route.ts, andsrc/app/api/signals/route.ts. - Use
z.coercefor query-string number parsing in shared schemas, as inSignalQuerySchemaandProjectQuerySchemainsrc/lib/validations.ts. - Add cross-field validation with
.superRefine()for multi-item or relation rules, as inTagMergeSchemaandTagMaintenanceRequestSchemainsrc/lib/validations.ts.
Data Access
Prisma:
- Use the singleton Prisma client from
src/lib/prisma.ts. - Define Prisma payload types close to the query layer with
Prisma.*GetPayload, as inProjectWithTagsAndLinksandTagWithProjectCountinsrc/hooks/useProjects.ts. - Prefer explicit
includeandselectclauses to control payload shape, as seen throughoutsrc/hooks/useProjects.ts,src/hooks/useHome.ts,src/app/api/signals/route.ts, andsrc/app/api/tags/reset-projects/route.ts. - Use
prisma.$transaction(...)for write paths that change multiple tables, as insrc/app/api/tags/maintenance/route.tsandsrc/app/api/tags/reset-projects/route.ts.
Caching and Fallbacks:
- Wrap cacheable server reads with
unstable_cache, using stable key arrays andrevalidatewindows, as insrc/app/api/tags/route.ts,src/hooks/useProjects.ts, andsrc/hooks/useHome.ts. - Route cached reads through
runWithCacheFallbackfromsrc/lib/cache.tsso execution can fall back whenunstable_cacheis unavailable. - Cache fetcher functions keyed by input when the function signature varies, as in
topTagsCacheandfixedProjectTypeFilterCacheinsrc/hooks/useProjects.ts.
Retry and Degrade Patterns:
- Use retry wrappers for transient DB issues on read paths.
withDbRetryandisTransientDbErrorinsrc/hooks/useProjects.tsare the current pattern. - Degrade to safe defaults on non-critical homepage and filter data instead of failing the whole page, as in
safeQueryinsrc/hooks/useHome.tsandconsole.errorfallback branches insrc/hooks/useProjects.ts.
Error Handling
Patterns:
- Wrap route handlers in
try/catchand return JSON error payloads throughNextResponse.json, as insrc/app/api/projects/route.ts,src/app/api/tags/route.ts,src/app/api/search/ai/route.ts, andsrc/app/api/webhook/signals/route.ts. - Return
400for schema and cursor validation failures,401for invalid API keys,409for tag conflicts inside service code, and500for unexpected errors. - Use domain-specific error classes when mutation services need to communicate status and details back to routes.
TagMaintenanceApiErrorinsrc/app/api/tags/maintenance/service.tsis the established pattern. - Include machine-readable
success,error,details, and sometimesmessagefields in JSON responses. The exact shape varies by route and is not fully normalized.
Logging:
- Use
console.errorfor failures andconsole.warnfor degraded or summary logging, for examplesrc/hooks/useHome.ts,src/hooks/useProjects.ts,src/app/api/signals/route.ts, andsrc/app/api/webhook/signals/route.ts. - Error-path tests currently allow log output to stderr, as verified by
pnpm teston 2026-04-18 fromsrc/app/api/tags/route.test.ts.
Comments
When to Comment:
- Comments are sparse and usually explain non-obvious intent, numbered route steps, or bilingual product context.
- English and Chinese comments coexist. Examples include the numbered route comments in
src/app/api/tags/maintenance/route.ts, Chinese comments insrc/hooks/useProjects.ts, and mixed bilingual commentary insrc/components/project/ProjectCard.tsx. - Prefer comments only where intent is not obvious from code.
JSDoc/TSDoc:
- JSDoc is uncommon. The clearest example is the security-sensitive note on
isValidApiKeyinsrc/lib/auth.ts.
Function Design
Size:
- Read/query modules tolerate large files with many helpers.
src/hooks/useProjects.tsis 602 lines,src/hooks/useHome.tsis 250 lines, andsrc/app/api/signals/route.tsis 355 lines. - Keep complex logic split into local helpers inside the same file before extracting a new module. Current examples include
parseSlugListinsrc/app/api/projects/route.ts,parseSectionsinsrc/app/api/signals/route.ts, andcollectValidationErrorsForProjectIteminsrc/app/api/tags/reset-projects/route.ts.
Parameters:
- Prefer a single typed options object for query functions, as in
getProjectsinsrc/hooks/useProjects.ts. - Use small helper functions for normalization of query and payload input, such as
normalizePositiveIntegerinsrc/hooks/useProjects.tsandnormalizeSluginsrc/app/api/tags/reset-projects/route.ts.
Return Values:
- Return plain serializable objects from server query helpers when the result is meant for pages or APIs, as in
getProjects,getHomePageData, andgetProjectsByIds. - Flatten Prisma relation shapes before returning to callers when the UI expects direct lists, as in
getProjects,getProjectBySlug, andgetProjectsByIdsinsrc/hooks/useProjects.ts.
Environment and Configuration
Environment Files:
.env,.env.local, and.env.exampleare present at repository root. Use.env.exampleas the naming reference; do not commit real secrets.
Observed Variables:
.env.exampledefinesDATABASE_URL,WEBHOOK_API_KEY,N8N_AI_SEARCH_WEBHOOK,NEXT_INTL_DEFAULT_LOCALE, andNEXT_INTL_SUPPORTED_LOCALES.- Source code reads
WEBHOOK_API_KEYinsrc/lib/auth.ts,N8N_AI_SEARCH_WEBHOOKinsrc/app/api/search/ai/route.ts,NEXT_PUBLIC_SITE_URLinsrc/app/robots.tsandsrc/app/sitemap.ts,VERCEL_ENVinsrc/app/layout.tsx, andNODE_ENVinsrc/lib/prisma.ts. NEXT_INTL_DEFAULT_LOCALEandNEXT_INTL_SUPPORTED_LOCALESappear in.env.examplebut were not detected in runtime code on 2026-04-18. Locale behavior is hard-coded insrc/middleware.tsandsrc/i18n/request.ts.
Conventions:
- Fail fast at module load only for truly required integration config.
src/app/api/search/ai/route.tsthrows immediately ifN8N_AI_SEARCH_WEBHOOKis unset. - Use safe fallbacks for public metadata values, as in
src/app/robots.tsandsrc/app/sitemap.tsdefaultingNEXT_PUBLIC_SITE_URLtohttps://agentpark.ai. - Keep deployment and framework config in root files:
next.config.js,tailwind.config.ts,postcss.config.mjs,tsconfig.json,.eslintrc.json,.prettierrc.json, andvitest.config.ts.
Convention analysis: 2026-04-18