一键导入
api-module-architecture
Use when changing API module structure, controllers, facade services, use-cases, support services, providers, or exports in apps/api.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Use when changing API module structure, controllers, facade services, use-cases, support services, providers, or exports in apps/api.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when adding, changing, extracting, or reusing client components, including Storybook stories and controls.
Use when adding or changing forms in apps/client.
Use when changing GitHub OAuth, session cookies, SessionGuard, logout, or authenticated API request identity.
Use when adding or changing routes in apps/client.
Use when adding or changing client state, React Query data flow, immutable context values, or Zustand stores.
Use when styling apps/client with Tailwind CSS v4.
| name | api-module-architecture |
| description | Use when changing API module structure, controllers, facade services, use-cases, support services, providers, or exports in apps/api. |
Generated from ai/registry.json. Do not edit manually.
Canonical skill: ../../../ai/skills/api-module-architecture.md.
Referenced context:
../../../ai/rules/api-module-rules.md../../../ai/rules/api-validation-rules.md../../../ai/rules/api-tenant-access-rules.md../../../ai/architecture/api-app.md../../../ai/architecture/api-module-patterns.md../../../ai/examples/good-api-module-structure.mdThis file is compiled from canonical AI knowledge files. Edit canonical files under ai, then run npm run ai:sync.
ai/skills/api-module-architecture.mdUse this skill when changing API module structure, controllers, facade services, use cases, support services, providers, or exports in apps/api.
Keep API modules small, explicit, tenant-safe, and aligned with the controller, facade, use-case, support, and Nest module boundaries used in this repository.
ai/rules/api-module-rules.mdai/rules/api-validation-rules.mdai/rules/api-tenant-access-rules.mdai/architecture/api-app.mdai/architecture/api-module-patterns.mdai/examples/good-api-module-structure.mdapi-validation when route params, DTOs, or request validation change.api-tenant-access when the refactor touches authorization, ownership, or tenant-scoped Prisma paths.config-state-audit when the refactor touches revisions, ETags, config environment state, or audit logs.api-public-management when the refactor touches API-token guards, scopes, tenant decorators, or management OpenAPI.npm --workspace @capture-flag/api run test after behavior-sensitive refactors.npm --workspace @capture-flag/api run build after module, controller, or service changes.ai/rules/api-module-rules.mdRules for Nest module structure, controllers, facade services, use cases, and support services in apps/api.
CurrentUserId, UuidParam, SessionApiController, and SessionOrApiTokenController before adding new request helpers.support with concrete responsibilities such as access, audit, input normalization, read models, credentials, config state, references, validation, writers, or initializers.PrismaService, AccessService, audit helpers, config-state helpers, token hashing, or SDK-key hashing directly into controllers.npm --workspace @capture-flag/api run test after behavior-sensitive API refactors.npm --workspace @capture-flag/api run build after module, provider, controller, or service changes.ai/rules/api-validation-rules.mdRules for Nest controllers, DTOs, and request validation in apps/api.
ValidationPipe enabled in src/main.ts.class-validator decorators for request bodies.class-transformer decorators such as @Transform and @Type for normalization.UuidParam, the shared wrapper around ParseUUIDPipe, for every UUID route param before passing it into services.@Transform before validating.@IsUUID() or @IsEmail().@IsIn(...) and shared role constants.string params for IDs backed by Prisma @db.Uuid fields.UuidParam instead of raw string params.@Body() type is a DTO with validation decorators.npm --workspace @capture-flag/api run build after API validation changes.ai/rules/api-tenant-access-rules.mdRules for private API authorization and tenant isolation.
SessionGuard and AuthenticatedRequest on session-only private API controllers.AuthenticatedApiGuard plus API token tenant/scope guards on private management routes that also accept API tokens.request.user.id, and delegate rules to services.AccessService before returning or mutating tenant-owned data.requireProjectAccess for project-scoped reads.requireProjectRole for project-scoped writes with the narrowest allowed project roles.requireOrganizationMember or requireOrganizationRole for organization-level reads and writes.owner and admin roles can satisfy project access without explicit project membership.developer scoped to feature flag writes; do not allow it to manage segments, SDK keys, environments, configs, project members, or roles.include or nested select shapes.configId and environmentId must belong to the same projectId before SDK keys, flag values, or config state changes.ai/architecture/api-app.mdapps/api is a NestJS API backed by Prisma and PostgreSQL.
request.user.id to services.SessionGuard and AuthenticatedRequest.AuthenticatedApiGuard, then API token tenant/scope guards.ApiTokenGuard directly, followed by tenant/scope guards.UuidParam, the shared wrapper around ParseUUIDPipe, in controllers.support services hold concrete reusable responsibilities such as access, audit, input normalization, read models, credentials, config state, references, validation, writers, or initializers.PrismaService./api/v1./api/v1/docs is filtered to the supported management subset.applyHttpSecurity() before request handling.ai/architecture/api-module-patterns.mdapps/api uses Nest modules with explicit providers and small service boundaries.
<domain>/
<domain>.controller.ts
<domain>.service.ts
<domain>.module.ts
dto/
use-cases/
support/
Not every module needs every folder. Add a folder only when there is a current responsibility for it.
UuidParam, receives DTO/query classes, reads CurrentUserId, and delegates.execute() calls.Controllers should remain boring. They should not know how tenant access, Prisma queries, audit logs, config revisions, SDK-key hashing, or API-token hashing work.
Acceptable controller work:
UuidParam, CurrentUserId, Body, and Query extraction;A facade service such as ProjectsService or ConfigsService is useful when the module exports a stable API or when the controller would otherwise inject many use cases directly.
Facade services should:
Direct use-case injection in a controller is also acceptable when the controller remains thin and the module does not need a facade boundary.
Use-case services in use-cases represent user-visible or API-visible operations. They are the normal home for Prisma reads/writes, authorization, ownership checks, transactions, no-op handling, audit writes, config-state bumps, and read model selection.
Prefer one execute() entry point per use case unless nearby code already uses another shape.
Support services in support should own one concrete responsibility that is reused or worth isolating from the use case.
Common responsibilities:
AccessService wrappers for domain-specific ownership resolution;Do not extract a support service only to move one obvious line out of a use case.
Modules should declare their imports, controllers, providers, and exports explicitly. Keep internal providers private unless another module currently needs them.
Use module imports for real Nest dependencies, not to reach into another module's private support services.
ai/examples/good-api-module-structure.mdSource: apps/api/src/projects/projects.controller.ts (sha256: 1a81390937f3ed3f00c344377fc8858826227237732a4c9b910ba7f94a19723e)
Source: apps/api/src/projects/projects.service.ts (sha256: baa9858a86c5899374774b72ba7cfb7afbb95e678460b5ce472105592778ccec)
Source: apps/api/src/projects/projects.module.ts (sha256: 1b5e81eefa3a22df991ce941803fd1af6e88959c5372c34a9c9418a9ff34b747)
Source: apps/api/src/projects/use-cases/create-project.service.ts (sha256: 630ab9ddd6c6a9d768e60efc436fe847a18de094a99afffeb74b82f1adc00a7a)
Source: apps/api/src/projects/support/project-audit.service.ts (sha256: 6b85227686e8f9d8fe5e3b207faedd11faceb7508a66dcc826f6542603c784a2)
Why this is canonical:
@Get("organizations/:organizationId/projects")
listForOrganization(
@CurrentUserId() userId: string,
@UuidParam("organizationId") organizationId: string,
) {
return this.projects.listForOrganization(userId, organizationId);
}
The controller parses the route and authenticated user, then delegates.
listForOrganization(userId: string, organizationId: string) {
return this.listOrganizationProjects.execute({ userId, organizationId });
}
The facade exposes controller-friendly methods while use cases own behavior.
await this.access.requireOrganizationRole(userId, organizationId, organizationManagerRoles);
return this.prisma.$transaction(async (tx) => {
const project = await tx.project.create({
data: {
organizationId,
name,
slug,
},
});
});
The use case resolves authorization before tenant-owned writes and keeps related writes in a transaction.
configAuditValue(config: {
description?: string | null;
id: string;
key: string;
name: string;
projectId: string;
}) {
return toAuditJson({
description: config.description ?? null,
id: config.id,
key: config.key,
name: config.name,
projectId: config.projectId,
});
}
The support service owns sanitized audit value shaping instead of spreading payload details across use cases.
@Module({
imports: [CommonModule, ApiTokensModule],
controllers: [ProjectsController],
providers: [
ProjectsService,
ProjectAuditService,
ProjectMemberTargetService,
ListOrganizationProjectsService,
CreateProjectService,
],
exports: [ProjectsService],
})
export class ProjectsModule {}
The module declares internal providers explicitly and exports only the facade boundary.