@ryuenn3123/agentic-senior-core 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-context/blueprints/api-nextjs.md +184 -0
- package/.agent-context/blueprints/aspnet-api.md +247 -0
- package/.agent-context/blueprints/ci-github-actions.md +226 -0
- package/.agent-context/blueprints/ci-gitlab.md +200 -0
- package/.agent-context/blueprints/fastapi-service.md +210 -0
- package/.agent-context/blueprints/go-service.md +217 -0
- package/.agent-context/blueprints/graphql-grpc-api.md +51 -0
- package/.agent-context/blueprints/infrastructure-as-code.md +62 -0
- package/.agent-context/blueprints/kubernetes-manifests.md +76 -0
- package/.agent-context/blueprints/laravel-api.md +223 -0
- package/.agent-context/blueprints/nestjs-logic.md +247 -0
- package/.agent-context/blueprints/observability.md +227 -0
- package/.agent-context/blueprints/spring-boot-api.md +218 -0
- package/.agent-context/policies/llm-judge-threshold.json +20 -0
- package/.agent-context/profiles/platform.md +13 -0
- package/.agent-context/profiles/regulated.md +13 -0
- package/.agent-context/profiles/startup.md +13 -0
- package/.agent-context/prompts/init-project.md +86 -0
- package/.agent-context/prompts/refactor.md +45 -0
- package/.agent-context/prompts/review-code.md +47 -0
- package/.agent-context/review-checklists/architecture-review.md +70 -0
- package/.agent-context/review-checklists/frontend-usability.md +33 -0
- package/.agent-context/review-checklists/performance-audit.md +65 -0
- package/.agent-context/review-checklists/pr-checklist.md +97 -0
- package/.agent-context/review-checklists/release-operations.md +29 -0
- package/.agent-context/review-checklists/security-audit.md +113 -0
- package/.agent-context/rules/api-docs.md +186 -0
- package/.agent-context/rules/architecture.md +198 -0
- package/.agent-context/rules/database-design.md +202 -0
- package/.agent-context/rules/efficiency-vs-hype.md +143 -0
- package/.agent-context/rules/error-handling.md +234 -0
- package/.agent-context/rules/event-driven.md +226 -0
- package/.agent-context/rules/frontend-architecture.md +66 -0
- package/.agent-context/rules/git-workflow.md +200 -0
- package/.agent-context/rules/microservices.md +174 -0
- package/.agent-context/rules/naming-conv.md +141 -0
- package/.agent-context/rules/performance.md +168 -0
- package/.agent-context/rules/realtime.md +47 -0
- package/.agent-context/rules/security.md +195 -0
- package/.agent-context/rules/testing.md +178 -0
- package/.agent-context/stacks/csharp.md +149 -0
- package/.agent-context/stacks/go.md +181 -0
- package/.agent-context/stacks/java.md +135 -0
- package/.agent-context/stacks/php.md +178 -0
- package/.agent-context/stacks/python.md +153 -0
- package/.agent-context/stacks/ruby.md +80 -0
- package/.agent-context/stacks/rust.md +86 -0
- package/.agent-context/stacks/typescript.md +317 -0
- package/.agent-context/state/architecture-map.md +25 -0
- package/.agent-context/state/dependency-map.md +32 -0
- package/.agent-override.md +36 -0
- package/.agents/workflows/init-project.md +29 -0
- package/.agents/workflows/refactor.md +29 -0
- package/.agents/workflows/review-code.md +29 -0
- package/.cursorrules +140 -0
- package/.gemini/instructions.md +97 -0
- package/.github/ISSUE_TEMPLATE/v1.7-frontend-work-item.yml +54 -0
- package/.github/copilot-instructions.md +104 -0
- package/.github/workflows/benchmark-detection.yml +38 -0
- package/.github/workflows/frontend-usability-gate.yml +36 -0
- package/.github/workflows/release-gate.yml +32 -0
- package/.github/workflows/sbom-compliance.yml +32 -0
- package/.windsurfrules +106 -0
- package/AGENTS.md +131 -0
- package/CONTRIBUTING.md +136 -0
- package/LICENSE +21 -0
- package/README.md +239 -0
- package/bin/agentic-senior-core.js +1147 -0
- package/mcp.json +29 -0
- package/package.json +50 -0
- package/scripts/detection-benchmark.mjs +138 -0
- package/scripts/frontend-usability-audit.mjs +87 -0
- package/scripts/generate-sbom.mjs +61 -0
- package/scripts/init-project.ps1 +105 -0
- package/scripts/init-project.sh +131 -0
- package/scripts/llm-judge.mjs +664 -0
- package/scripts/release-gate.mjs +116 -0
- package/scripts/validate.mjs +554 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# Blueprint: Next.js API Project (App Router)
|
|
2
|
+
|
|
3
|
+
> This blueprint defines how to scaffold a Next.js API project from scratch.
|
|
4
|
+
> Follow this structure exactly. Do not deviate.
|
|
5
|
+
|
|
6
|
+
## Tech Stack
|
|
7
|
+
- **Runtime:** Node.js 20+ / Bun
|
|
8
|
+
- **Framework:** Next.js 14+ (App Router)
|
|
9
|
+
- **Validation:** Zod
|
|
10
|
+
- **ORM:** Prisma (or Drizzle)
|
|
11
|
+
- **Auth:** NextAuth.js v5 / Lucia Auth
|
|
12
|
+
- **Testing:** Vitest
|
|
13
|
+
|
|
14
|
+
## Project Structure
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
project-name/
|
|
18
|
+
├── src/
|
|
19
|
+
│ ├── app/ # Next.js App Router
|
|
20
|
+
│ │ ├── api/ # API routes
|
|
21
|
+
│ │ │ ├── auth/
|
|
22
|
+
│ │ │ │ └── [...nextauth]/
|
|
23
|
+
│ │ │ │ └── route.ts # Auth handler
|
|
24
|
+
│ │ │ ├── users/
|
|
25
|
+
│ │ │ │ ├── route.ts # GET /api/users, POST /api/users
|
|
26
|
+
│ │ │ │ └── [id]/
|
|
27
|
+
│ │ │ │ └── route.ts # GET/PUT/DELETE /api/users/:id
|
|
28
|
+
│ │ │ └── health/
|
|
29
|
+
│ │ │ └── route.ts # GET /api/health
|
|
30
|
+
│ │ ├── layout.tsx # Root layout
|
|
31
|
+
│ │ └── page.tsx # Root page
|
|
32
|
+
│ │
|
|
33
|
+
│ ├── modules/ # Feature modules (domain-driven)
|
|
34
|
+
│ │ ├── user/
|
|
35
|
+
│ │ │ ├── user.service.ts # Business logic
|
|
36
|
+
│ │ │ ├── user.repository.ts # Data access
|
|
37
|
+
│ │ │ ├── user.schema.ts # Zod schemas + DTOs
|
|
38
|
+
│ │ │ ├── user.types.ts # Type definitions
|
|
39
|
+
│ │ │ └── __tests__/
|
|
40
|
+
│ │ │ └── user.service.test.ts
|
|
41
|
+
│ │ └── order/
|
|
42
|
+
│ │ ├── order.service.ts
|
|
43
|
+
│ │ ├── order.repository.ts
|
|
44
|
+
│ │ ├── order.schema.ts
|
|
45
|
+
│ │ └── order.types.ts
|
|
46
|
+
│ │
|
|
47
|
+
│ ├── shared/ # Cross-cutting concerns
|
|
48
|
+
│ │ ├── config/
|
|
49
|
+
│ │ │ └── env.ts # Zod-validated environment variables
|
|
50
|
+
│ │ ├── errors/
|
|
51
|
+
│ │ │ ├── app-error.ts # Base error class
|
|
52
|
+
│ │ │ └── error-handler.ts # Global error handler for API routes
|
|
53
|
+
│ │ ├── middleware/
|
|
54
|
+
│ │ │ ├── auth.ts # Auth middleware
|
|
55
|
+
│ │ │ └── validate.ts # Request validation middleware
|
|
56
|
+
│ │ ├── lib/
|
|
57
|
+
│ │ │ ├── prisma.ts # Prisma client singleton
|
|
58
|
+
│ │ │ └── logger.ts # Pino logger setup
|
|
59
|
+
│ │ └── types/
|
|
60
|
+
│ │ └── api.ts # Shared API types (ApiResponse, etc.)
|
|
61
|
+
│ │
|
|
62
|
+
│ └── components/ # UI components (if full-stack)
|
|
63
|
+
│ ├── ui/ # Primitives
|
|
64
|
+
│ └── layout/ # Layout components
|
|
65
|
+
│
|
|
66
|
+
├── prisma/
|
|
67
|
+
│ ├── schema.prisma # Database schema
|
|
68
|
+
│ └── migrations/ # Database migrations
|
|
69
|
+
│
|
|
70
|
+
├── public/ # Static assets
|
|
71
|
+
├── .env.example # Environment template
|
|
72
|
+
├── .eslintrc.json # ESLint config
|
|
73
|
+
├── .prettierrc # Prettier config
|
|
74
|
+
├── next.config.mjs # Next.js config
|
|
75
|
+
├── tsconfig.json # TypeScript config (strict!)
|
|
76
|
+
├── vitest.config.ts # Vitest config
|
|
77
|
+
└── package.json
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## API Route Handler Pattern
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// src/app/api/users/route.ts
|
|
84
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
85
|
+
import { CreateUserSchema } from '@/modules/user/user.schema';
|
|
86
|
+
import { userService } from '@/modules/user/user.service';
|
|
87
|
+
import { handleApiError } from '@/shared/errors/error-handler';
|
|
88
|
+
|
|
89
|
+
export async function GET(request: NextRequest) {
|
|
90
|
+
try {
|
|
91
|
+
const searchParams = request.nextUrl.searchParams;
|
|
92
|
+
const page = Number(searchParams.get('page') ?? '1');
|
|
93
|
+
const limit = Number(searchParams.get('limit') ?? '20');
|
|
94
|
+
|
|
95
|
+
const users = await userService.findAll({ page, limit });
|
|
96
|
+
return NextResponse.json({ data: users });
|
|
97
|
+
} catch (error) {
|
|
98
|
+
return handleApiError(error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export async function POST(request: NextRequest) {
|
|
103
|
+
try {
|
|
104
|
+
const body = await request.json();
|
|
105
|
+
const parsed = CreateUserSchema.safeParse(body);
|
|
106
|
+
|
|
107
|
+
if (!parsed.success) {
|
|
108
|
+
return NextResponse.json(
|
|
109
|
+
{ error: { code: 'VALIDATION_ERROR', details: parsed.error.flatten() } },
|
|
110
|
+
{ status: 400 },
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const user = await userService.create(parsed.data);
|
|
115
|
+
return NextResponse.json({ data: user }, { status: 201 });
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return handleApiError(error);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Environment Validation Pattern
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// src/shared/config/env.ts
|
|
126
|
+
import { z } from 'zod';
|
|
127
|
+
|
|
128
|
+
const envSchema = z.object({
|
|
129
|
+
NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
|
|
130
|
+
DATABASE_URL: z.string().url(),
|
|
131
|
+
NEXTAUTH_SECRET: z.string().min(32),
|
|
132
|
+
NEXTAUTH_URL: z.string().url(),
|
|
133
|
+
PORT: z.coerce.number().default(3000),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
export const env = envSchema.parse(process.env);
|
|
137
|
+
export type Env = z.infer<typeof envSchema>;
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Error Handler Pattern
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// src/shared/errors/error-handler.ts
|
|
144
|
+
import { NextResponse } from 'next/server';
|
|
145
|
+
import { AppError } from './app-error';
|
|
146
|
+
import { logger } from '@/shared/lib/logger';
|
|
147
|
+
|
|
148
|
+
export function handleApiError(error: unknown): NextResponse {
|
|
149
|
+
if (error instanceof AppError) {
|
|
150
|
+
logger.warn('Application error', {
|
|
151
|
+
code: error.code,
|
|
152
|
+
message: error.message,
|
|
153
|
+
context: error.context,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return NextResponse.json(
|
|
157
|
+
{ error: { code: error.code, message: error.message } },
|
|
158
|
+
{ status: error.statusCode },
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
logger.error('Unhandled error', {
|
|
163
|
+
error: error instanceof Error ? error.message : String(error),
|
|
164
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
return NextResponse.json(
|
|
168
|
+
{ error: { code: 'INTERNAL_ERROR', message: 'An unexpected error occurred' } },
|
|
169
|
+
{ status: 500 },
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Scaffolding Checklist
|
|
175
|
+
|
|
176
|
+
When using this blueprint, verify:
|
|
177
|
+
- [ ] `tsconfig.json` has `"strict": true` and all recommended flags
|
|
178
|
+
- [ ] `.env.example` exists with ALL required variables (placeholder values only)
|
|
179
|
+
- [ ] Prisma client is a singleton (not re-created per request)
|
|
180
|
+
- [ ] All API routes use Zod validation at the boundary
|
|
181
|
+
- [ ] Error handler is used in every route (no unhandled errors)
|
|
182
|
+
- [ ] Logger is configured (not `console.log`)
|
|
183
|
+
- [ ] Path aliases (`@/`) are configured in tsconfig AND next.config
|
|
184
|
+
- [ ] API documentation is generated or maintained alongside routes
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# Blueprint: ASP.NET Minimal API (.NET 10)
|
|
2
|
+
|
|
3
|
+
> Minimal APIs are not "simple APIs". They're production-ready APIs with less ceremony.
|
|
4
|
+
> Controller bloat is not a feature.
|
|
5
|
+
|
|
6
|
+
## Tech Stack
|
|
7
|
+
|
|
8
|
+
| Layer | Choice | Why |
|
|
9
|
+
|-------|--------|-----|
|
|
10
|
+
| Runtime | .NET 10 LTS | Latest LTS (Nov 2025) |
|
|
11
|
+
| Language | C# 14 | Records, primary constructors, required members |
|
|
12
|
+
| API Style | Minimal APIs with `MapGroup` | Less boilerplate, same power |
|
|
13
|
+
| Validation | FluentValidation | Fluent, testable, powerful |
|
|
14
|
+
| ORM | EF Core 10 | Mature, LINQ-to-SQL, migrations |
|
|
15
|
+
| Auth | ASP.NET Identity + Passkeys | Built-in, modern auth |
|
|
16
|
+
| API Docs | Swashbuckle / NSwag + Scalar | OpenAPI 3.1 generation |
|
|
17
|
+
| Testing | xUnit + NSubstitute + Verify | Community standard |
|
|
18
|
+
| Logging | Serilog + OpenTelemetry | Structured, correlated |
|
|
19
|
+
| Cloud | .NET Aspire (optional) | Service orchestration, dev containers |
|
|
20
|
+
|
|
21
|
+
## Project Structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
MyApp.sln
|
|
25
|
+
├── src/
|
|
26
|
+
│ ├── MyApp.Api/ # Presentation layer
|
|
27
|
+
│ │ ├── Program.cs # Entry point + DI + middleware
|
|
28
|
+
│ │ ├── Endpoints/ # Minimal API endpoint groups
|
|
29
|
+
│ │ │ ├── UserEndpoints.cs
|
|
30
|
+
│ │ │ └── OrderEndpoints.cs
|
|
31
|
+
│ │ ├── Filters/ # Endpoint filters (auth, validation)
|
|
32
|
+
│ │ ├── Models/ # Request/response DTOs
|
|
33
|
+
│ │ │ ├── Requests/
|
|
34
|
+
│ │ │ └── Responses/
|
|
35
|
+
│ │ ├── appsettings.json
|
|
36
|
+
│ │ └── MyApp.Api.csproj
|
|
37
|
+
│ │
|
|
38
|
+
│ ├── MyApp.Application/ # Business logic layer
|
|
39
|
+
│ │ ├── Services/
|
|
40
|
+
│ │ │ ├── IUserService.cs
|
|
41
|
+
│ │ │ └── UserService.cs
|
|
42
|
+
│ │ ├── Validators/
|
|
43
|
+
│ │ │ └── CreateUserValidator.cs
|
|
44
|
+
│ │ ├── Mappings/ # Entity ↔ DTO mapping
|
|
45
|
+
│ │ └── MyApp.Application.csproj
|
|
46
|
+
│ │
|
|
47
|
+
│ ├── MyApp.Domain/ # Core domain (zero dependencies)
|
|
48
|
+
│ │ ├── Entities/
|
|
49
|
+
│ │ │ ├── User.cs
|
|
50
|
+
│ │ │ └── Order.cs
|
|
51
|
+
│ │ ├── ValueObjects/
|
|
52
|
+
│ │ ├── Enums/
|
|
53
|
+
│ │ ├── Errors/
|
|
54
|
+
│ │ │ └── DomainErrors.cs
|
|
55
|
+
│ │ └── MyApp.Domain.csproj
|
|
56
|
+
│ │
|
|
57
|
+
│ └── MyApp.Infrastructure/ # Data access + external services
|
|
58
|
+
│ ├── Persistence/
|
|
59
|
+
│ │ ├── AppDbContext.cs
|
|
60
|
+
│ │ ├── Configurations/ # EF Core entity configs
|
|
61
|
+
│ │ │ └── UserConfiguration.cs
|
|
62
|
+
│ │ ├── Repositories/
|
|
63
|
+
│ │ │ └── UserRepository.cs
|
|
64
|
+
│ │ └── Migrations/
|
|
65
|
+
│ ├── Services/ # External service adapters
|
|
66
|
+
│ └── MyApp.Infrastructure.csproj
|
|
67
|
+
│
|
|
68
|
+
├── tests/
|
|
69
|
+
│ ├── MyApp.UnitTests/
|
|
70
|
+
│ ├── MyApp.IntegrationTests/
|
|
71
|
+
│ └── MyApp.ArchitectureTests/ # Enforce layer boundaries
|
|
72
|
+
│
|
|
73
|
+
├── Directory.Build.props # Central package versions
|
|
74
|
+
├── .editorconfig
|
|
75
|
+
└── Dockerfile
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Key Patterns
|
|
79
|
+
|
|
80
|
+
### Endpoint Groups with MapGroup
|
|
81
|
+
|
|
82
|
+
```csharp
|
|
83
|
+
// Endpoints/UserEndpoints.cs
|
|
84
|
+
public static class UserEndpoints
|
|
85
|
+
{
|
|
86
|
+
public static RouteGroupBuilder MapUserEndpoints(this IEndpointRouteBuilder app)
|
|
87
|
+
{
|
|
88
|
+
var group = app.MapGroup("/api/users")
|
|
89
|
+
.WithTags("Users")
|
|
90
|
+
.RequireAuthorization();
|
|
91
|
+
|
|
92
|
+
group.MapGet("/", GetAllUsers)
|
|
93
|
+
.WithName("GetAllUsers")
|
|
94
|
+
.WithSummary("Get all users with pagination")
|
|
95
|
+
.Produces<PagedResponse<UserResponse>>(200);
|
|
96
|
+
|
|
97
|
+
group.MapGet("/{id:guid}", GetUserById)
|
|
98
|
+
.WithName("GetUserById")
|
|
99
|
+
.Produces<UserResponse>(200)
|
|
100
|
+
.ProducesProblem(404);
|
|
101
|
+
|
|
102
|
+
group.MapPost("/", CreateUser)
|
|
103
|
+
.WithName("CreateUser")
|
|
104
|
+
.Produces<UserResponse>(201)
|
|
105
|
+
.ProducesValidationProblem();
|
|
106
|
+
|
|
107
|
+
return group;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private static async Task<IResult> GetUserById(
|
|
111
|
+
Guid id,
|
|
112
|
+
IUserService userService,
|
|
113
|
+
CancellationToken ct)
|
|
114
|
+
{
|
|
115
|
+
var user = await userService.GetByIdAsync(id, ct);
|
|
116
|
+
return user is not null
|
|
117
|
+
? TypedResults.Ok(user.ToResponse())
|
|
118
|
+
: TypedResults.Problem(statusCode: 404, title: "User not found");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private static async Task<IResult> CreateUser(
|
|
122
|
+
CreateUserRequest request,
|
|
123
|
+
IValidator<CreateUserRequest> validator,
|
|
124
|
+
IUserService userService,
|
|
125
|
+
CancellationToken ct)
|
|
126
|
+
{
|
|
127
|
+
var validation = await validator.ValidateAsync(request, ct);
|
|
128
|
+
if (!validation.IsValid)
|
|
129
|
+
return TypedResults.ValidationProblem(validation.ToDictionary());
|
|
130
|
+
|
|
131
|
+
var user = await userService.CreateAsync(request, ct);
|
|
132
|
+
return TypedResults.Created($"/api/users/{user.Id}", user.ToResponse());
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Program.cs (Clean Composition Root)
|
|
138
|
+
|
|
139
|
+
```csharp
|
|
140
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
141
|
+
|
|
142
|
+
// Service registration (extension methods from each layer)
|
|
143
|
+
builder.Services.AddApplicationServices();
|
|
144
|
+
builder.Services.AddInfrastructureServices(builder.Configuration);
|
|
145
|
+
builder.Services.AddApiServices();
|
|
146
|
+
|
|
147
|
+
// OpenTelemetry
|
|
148
|
+
builder.Services.AddOpenTelemetry()
|
|
149
|
+
.WithTracing(tracing => tracing
|
|
150
|
+
.AddAspNetCoreInstrumentation()
|
|
151
|
+
.AddEntityFrameworkCoreInstrumentation()
|
|
152
|
+
.AddOtlpExporter())
|
|
153
|
+
.WithMetrics(metrics => metrics
|
|
154
|
+
.AddAspNetCoreInstrumentation()
|
|
155
|
+
.AddOtlpExporter());
|
|
156
|
+
|
|
157
|
+
var app = builder.Build();
|
|
158
|
+
|
|
159
|
+
// Middleware pipeline
|
|
160
|
+
app.UseExceptionHandler();
|
|
161
|
+
app.UseAuthentication();
|
|
162
|
+
app.UseAuthorization();
|
|
163
|
+
|
|
164
|
+
// Map endpoints
|
|
165
|
+
app.MapUserEndpoints();
|
|
166
|
+
app.MapOrderEndpoints();
|
|
167
|
+
app.MapHealthChecks("/health");
|
|
168
|
+
|
|
169
|
+
// Scalar API docs
|
|
170
|
+
app.MapScalarApiReference();
|
|
171
|
+
|
|
172
|
+
app.Run();
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Domain Entity (Record-Based)
|
|
176
|
+
|
|
177
|
+
```csharp
|
|
178
|
+
// Domain/Entities/User.cs
|
|
179
|
+
public sealed class User
|
|
180
|
+
{
|
|
181
|
+
public required Guid Id { get; init; }
|
|
182
|
+
public required string Email { get; init; }
|
|
183
|
+
public required string DisplayName { get; set; }
|
|
184
|
+
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
|
|
185
|
+
public DateTimeOffset? DeletedAt { get; private set; }
|
|
186
|
+
|
|
187
|
+
public void SoftDelete() => DeletedAt = DateTimeOffset.UtcNow;
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### FluentValidation
|
|
192
|
+
|
|
193
|
+
```csharp
|
|
194
|
+
// Application/Validators/CreateUserValidator.cs
|
|
195
|
+
public sealed class CreateUserValidator : AbstractValidator<CreateUserRequest>
|
|
196
|
+
{
|
|
197
|
+
public CreateUserValidator()
|
|
198
|
+
{
|
|
199
|
+
RuleFor(x => x.Email)
|
|
200
|
+
.NotEmpty()
|
|
201
|
+
.EmailAddress()
|
|
202
|
+
.MaximumLength(256);
|
|
203
|
+
|
|
204
|
+
RuleFor(x => x.DisplayName)
|
|
205
|
+
.NotEmpty()
|
|
206
|
+
.MinimumLength(1)
|
|
207
|
+
.MaximumLength(100);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## .NET Aspire (Optional, for Multi-Service)
|
|
213
|
+
|
|
214
|
+
For projects with multiple services, databases, and caches:
|
|
215
|
+
|
|
216
|
+
```csharp
|
|
217
|
+
// AppHost/Program.cs
|
|
218
|
+
var builder = DistributedApplication.CreateBuilder(args);
|
|
219
|
+
|
|
220
|
+
var postgres = builder.AddPostgres("db")
|
|
221
|
+
.AddDatabase("myapp");
|
|
222
|
+
|
|
223
|
+
var redis = builder.AddRedis("cache");
|
|
224
|
+
|
|
225
|
+
builder.AddProject<Projects.MyApp_Api>("api")
|
|
226
|
+
.WithReference(postgres)
|
|
227
|
+
.WithReference(redis);
|
|
228
|
+
|
|
229
|
+
builder.Build().Run();
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Scaffolding Checklist
|
|
233
|
+
|
|
234
|
+
- [ ] Create solution with 4 projects (Api, Application, Domain, Infrastructure)
|
|
235
|
+
- [ ] Configure `Directory.Build.props` for shared package versions
|
|
236
|
+
- [ ] Set up `Program.cs` with clean service registration
|
|
237
|
+
- [ ] Create endpoint groups using `MapGroup` pattern
|
|
238
|
+
- [ ] Configure EF Core with typed `DbContext` and entity configurations
|
|
239
|
+
- [ ] Add FluentValidation with automatic registration
|
|
240
|
+
- [ ] Set up Serilog with structured logging
|
|
241
|
+
- [ ] Configure OpenTelemetry tracing and metrics
|
|
242
|
+
- [ ] Add Scalar or Swagger for OpenAPI documentation
|
|
243
|
+
- [ ] Create health check endpoint (`/health`)
|
|
244
|
+
- [ ] Set up xUnit test projects with NSubstitute
|
|
245
|
+
- [ ] Add architecture tests (enforce layer boundaries)
|
|
246
|
+
- [ ] Create `Dockerfile` (multi-stage build)
|
|
247
|
+
- [ ] Enable nullable reference types project-wide
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Blueprint: GitHub Actions CI/CD Pipeline
|
|
2
|
+
|
|
3
|
+
> Automate everything. Trust nothing. Ship with confidence.
|
|
4
|
+
|
|
5
|
+
## Tech Stack
|
|
6
|
+
|
|
7
|
+
| Layer | Tool |
|
|
8
|
+
|-------|------|
|
|
9
|
+
| CI/CD | GitHub Actions |
|
|
10
|
+
| Runners | GitHub-hosted (ubuntu-latest) |
|
|
11
|
+
| Caching | actions/cache, setup-node cache |
|
|
12
|
+
| Security | OIDC for cloud auth, pinned action SHAs |
|
|
13
|
+
| Artifacts | actions/upload-artifact |
|
|
14
|
+
|
|
15
|
+
## Pipeline Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌─────────────────────────────────────────────────────────┐
|
|
19
|
+
│ PR / Push Trigger │
|
|
20
|
+
├──────────┬──────────┬──────────┬──────────┬─────────────┬─────────────┤
|
|
21
|
+
│ Lint │ Build │ Test │ Security │ Docs │ LLM Judge │
|
|
22
|
+
│ (ESLint/ │ (tsc / │ (Vitest/ │ (Audit / │ (OpenAPI │ (Checklist │
|
|
23
|
+
│ ruff) │ build) │ pytest) │ Trivy) │ validate) │ enforcement)│
|
|
24
|
+
├──────────┴──────────┴──────────┴──────────┴─────────────┴─────────────┤
|
|
25
|
+
│ Gate: All jobs must pass │
|
|
26
|
+
├─────────────────────────────────────────────────────────┤
|
|
27
|
+
│ Deploy (on main only) │
|
|
28
|
+
│ Staging → Smoke Tests → Production (manual approval) │
|
|
29
|
+
└─────────────────────────────────────────────────────────┘
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Required Workflows
|
|
33
|
+
|
|
34
|
+
### 1. CI Workflow (`ci.yml`)
|
|
35
|
+
|
|
36
|
+
Runs on every PR and push to main.
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
name: CI
|
|
40
|
+
|
|
41
|
+
on:
|
|
42
|
+
pull_request:
|
|
43
|
+
branches: [main]
|
|
44
|
+
push:
|
|
45
|
+
branches: [main]
|
|
46
|
+
|
|
47
|
+
permissions:
|
|
48
|
+
contents: read
|
|
49
|
+
|
|
50
|
+
concurrency:
|
|
51
|
+
group: ci-${{ github.ref }}
|
|
52
|
+
cancel-in-progress: true
|
|
53
|
+
|
|
54
|
+
jobs:
|
|
55
|
+
lint:
|
|
56
|
+
runs-on: ubuntu-latest
|
|
57
|
+
timeout-minutes: 10
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@<pin-sha>
|
|
60
|
+
- uses: actions/setup-node@<pin-sha>
|
|
61
|
+
with:
|
|
62
|
+
node-version-file: '.nvmrc'
|
|
63
|
+
cache: 'npm'
|
|
64
|
+
- run: npm ci
|
|
65
|
+
- run: npm run lint
|
|
66
|
+
- run: npm run type-check
|
|
67
|
+
|
|
68
|
+
test:
|
|
69
|
+
runs-on: ubuntu-latest
|
|
70
|
+
timeout-minutes: 15
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@<pin-sha>
|
|
73
|
+
- uses: actions/setup-node@<pin-sha>
|
|
74
|
+
with:
|
|
75
|
+
node-version-file: '.nvmrc'
|
|
76
|
+
cache: 'npm'
|
|
77
|
+
- run: npm ci
|
|
78
|
+
- run: npm run test -- --coverage
|
|
79
|
+
- uses: actions/upload-artifact@<pin-sha>
|
|
80
|
+
with:
|
|
81
|
+
name: coverage
|
|
82
|
+
path: coverage/
|
|
83
|
+
|
|
84
|
+
security:
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
timeout-minutes: 10
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/checkout@<pin-sha>
|
|
89
|
+
- run: npm audit --audit-level=high
|
|
90
|
+
# Add Trivy, CodeQL, or Snyk as needed
|
|
91
|
+
|
|
92
|
+
build:
|
|
93
|
+
needs: [lint, test, security]
|
|
94
|
+
runs-on: ubuntu-latest
|
|
95
|
+
timeout-minutes: 15
|
|
96
|
+
steps:
|
|
97
|
+
- uses: actions/checkout@<pin-sha>
|
|
98
|
+
- uses: actions/setup-node@<pin-sha>
|
|
99
|
+
with:
|
|
100
|
+
node-version-file: '.nvmrc'
|
|
101
|
+
cache: 'npm'
|
|
102
|
+
- run: npm ci
|
|
103
|
+
- run: npm run build
|
|
104
|
+
- uses: actions/upload-artifact@<pin-sha>
|
|
105
|
+
with:
|
|
106
|
+
name: build
|
|
107
|
+
path: dist/
|
|
108
|
+
|
|
109
|
+
llm-judge:
|
|
110
|
+
needs: [lint, test, security, build]
|
|
111
|
+
runs-on: ubuntu-latest
|
|
112
|
+
timeout-minutes: 12
|
|
113
|
+
env:
|
|
114
|
+
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
|
115
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
116
|
+
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
|
117
|
+
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
118
|
+
GITHUB_HEAD_SHA: ${{ github.sha }}
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@<pin-sha>
|
|
121
|
+
with:
|
|
122
|
+
fetch-depth: 0 # Full history required for accurate git diff
|
|
123
|
+
- uses: actions/setup-node@<pin-sha>
|
|
124
|
+
with:
|
|
125
|
+
node-version: '22'
|
|
126
|
+
- name: Run LLM Judge
|
|
127
|
+
run: node scripts/llm-judge.mjs
|
|
128
|
+
- name: Upload LLM Judge machine report
|
|
129
|
+
if: always()
|
|
130
|
+
uses: actions/upload-artifact@<pin-sha>
|
|
131
|
+
with:
|
|
132
|
+
name: llm-judge-report
|
|
133
|
+
path: .agent-context/state/llm-judge-report.json
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### 2. Deploy Workflow (`deploy.yml`)
|
|
137
|
+
|
|
138
|
+
Runs on push to main (after CI passes).
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
name: Deploy
|
|
142
|
+
|
|
143
|
+
on:
|
|
144
|
+
workflow_run:
|
|
145
|
+
workflows: [CI]
|
|
146
|
+
types: [completed]
|
|
147
|
+
branches: [main]
|
|
148
|
+
|
|
149
|
+
permissions:
|
|
150
|
+
id-token: write # OIDC
|
|
151
|
+
contents: read
|
|
152
|
+
|
|
153
|
+
jobs:
|
|
154
|
+
deploy-staging:
|
|
155
|
+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
|
156
|
+
runs-on: ubuntu-latest
|
|
157
|
+
environment: staging
|
|
158
|
+
steps:
|
|
159
|
+
# Authenticate via OIDC — no static secrets
|
|
160
|
+
# Deploy to staging
|
|
161
|
+
# Run smoke tests against staging
|
|
162
|
+
|
|
163
|
+
deploy-production:
|
|
164
|
+
needs: deploy-staging
|
|
165
|
+
runs-on: ubuntu-latest
|
|
166
|
+
environment:
|
|
167
|
+
name: production
|
|
168
|
+
url: https://your-app.com
|
|
169
|
+
steps:
|
|
170
|
+
# Deploy to production
|
|
171
|
+
# Run health checks
|
|
172
|
+
# Notify team (Slack, Discord)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Security Rules
|
|
176
|
+
|
|
177
|
+
1. **Pin actions to commit SHA** — not `@v3`, not `@latest`
|
|
178
|
+
2. **Use OIDC** for cloud provider auth — delete static credentials
|
|
179
|
+
3. **Minimal permissions** — set `permissions:` at workflow level, least privilege
|
|
180
|
+
4. **Never print secrets** — GitHub masks them in logs, but don't `echo` them
|
|
181
|
+
5. **Restrict self-hosted runners** — ephemeral containers only, never persistent VMs
|
|
182
|
+
6. **Require PR approval** for workflows from forks
|
|
183
|
+
7. **Minimize prompt scope** — send diff + checklist only, never full secret-bearing config
|
|
184
|
+
|
|
185
|
+
## LLM Judge Annotation Contract
|
|
186
|
+
|
|
187
|
+
The judge emits a machine-friendly payload line and artifact that can be consumed by annotation scripts:
|
|
188
|
+
|
|
189
|
+
- Log line: `JSON_REPORT: { ... }`
|
|
190
|
+
- Artifact file: `.agent-context/state/llm-judge-report.json`
|
|
191
|
+
- Normalized severity values: `critical`, `high`, `medium`, `low`
|
|
192
|
+
- Override artifact path (optional): `LLM_JUDGE_OUTPUT_PATH`
|
|
193
|
+
|
|
194
|
+
## Efficiency Rules
|
|
195
|
+
|
|
196
|
+
1. **Cache dependencies** — `actions/cache` or setup-action built-in cache
|
|
197
|
+
2. **Use concurrency** — cancel previous runs on the same branch
|
|
198
|
+
3. **Set timeouts** — prevent stuck jobs from burning minutes
|
|
199
|
+
4. **Matrix builds** for multi-platform/version testing
|
|
200
|
+
5. **Reusable workflows** — centralize common pipelines in a `.github` repo
|
|
201
|
+
6. **Skip unnecessary jobs** — use path filters for targeted CI
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
# Example: Only run frontend tests when frontend code changes
|
|
205
|
+
on:
|
|
206
|
+
push:
|
|
207
|
+
paths:
|
|
208
|
+
- 'src/frontend/**'
|
|
209
|
+
- 'package.json'
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Scaffolding Checklist
|
|
213
|
+
|
|
214
|
+
When setting up GitHub Actions for a new project:
|
|
215
|
+
|
|
216
|
+
- [ ] Create `.github/workflows/ci.yml` with lint, test, build, security
|
|
217
|
+
- [ ] Create `.github/workflows/deploy.yml` with staging + production
|
|
218
|
+
- [ ] Pin ALL third-party actions to commit SHA
|
|
219
|
+
- [ ] Set `permissions: contents: read` at workflow level
|
|
220
|
+
- [ ] Configure `concurrency` to cancel in-progress runs
|
|
221
|
+
- [ ] Add `timeout-minutes` to every job
|
|
222
|
+
- [ ] Set up caching for package manager
|
|
223
|
+
- [ ] Configure environment protection rules for production
|
|
224
|
+
- [ ] Create `.nvmrc` or `.tool-versions` for runtime version
|
|
225
|
+
- [ ] Configure branch protection: require CI pass before merge
|
|
226
|
+
- [ ] Add `llm-judge` job that evaluates PR against `pr-checklist.md`
|