Sprint 001 전체 구현: Foundation: - package.json (pnpm + Node 22 + TypeScript strict) - tsconfig.json (strict + noUncheckedIndexedAccess) - .env.example (DATABASE_URL, DISCORD_TOKEN, etc.) - vitest.config.ts Core: - src/env.ts — Zod 환경변수 검증 - src/logger.ts — pino 구조화 로거 - src/orchestrator/events.ts — Zod discriminated union 이벤트 스키마 - src/orchestrator/context.ts — PipelineContext 타입 + 팩토리 - src/orchestrator/machine.ts — XState v5 결정론적 FSM States: idle → planning → implementing → reviewing → deploying → done + retrying (exponential backoff 준비) + escalated + aborted - src/orchestrator/persist.ts — Prisma 기반 상태 영속화 - prisma/schema.prisma — MariaDB 스키마 (pipelines, state_transitions, actor_spawns, contracts) CLI (citty): - rails start <project> — 파이프라인 생성 - rails status [id] — 상태 조회 + 타임라인 - rails serve — 오케스트레이터 서버 (Sprint 004 에서 완성) Tests (9/9 pass): - happy path (idle → done) - REQUEST_CHANGES 재작업 루프 + max review round escalation - retryable/non-retryable 에러 분기 - RESUME / ABORT - context 추적 검증: pnpm tsc --noEmit ✓ | pnpm vitest run 9/9 ✓ | pnpm build ✓ | rails --help ✓ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75 lines
2.0 KiB
Plaintext
75 lines
2.0 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "mysql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model Pipeline {
|
|
id String @id @db.VarChar(26) // ULID
|
|
projectName String @db.VarChar(255)
|
|
requirements String @db.Text
|
|
currentState String @db.VarChar(50) @default("idle")
|
|
contextJson String @db.LongText
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
transitions StateTransition[]
|
|
actorSpawns ActorSpawn[]
|
|
contracts Contract[]
|
|
|
|
@@index([currentState])
|
|
@@index([createdAt])
|
|
@@map("pipelines")
|
|
}
|
|
|
|
model StateTransition {
|
|
id Int @id @default(autoincrement())
|
|
pipelineId String @db.VarChar(26)
|
|
fromState String @db.VarChar(50)
|
|
toState String @db.VarChar(50)
|
|
eventType String @db.VarChar(50)
|
|
eventPayload String @db.LongText
|
|
timestamp DateTime @default(now())
|
|
|
|
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([pipelineId, timestamp])
|
|
@@index([eventType])
|
|
@@map("state_transitions")
|
|
}
|
|
|
|
model ActorSpawn {
|
|
id Int @id @default(autoincrement())
|
|
pipelineId String @db.VarChar(26)
|
|
actorName String @db.VarChar(100)
|
|
stage String @db.VarChar(50)
|
|
spawnedAt DateTime @default(now())
|
|
exitCode Int?
|
|
exitedAt DateTime?
|
|
resultJson String? @db.LongText
|
|
|
|
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([pipelineId, spawnedAt])
|
|
@@map("actor_spawns")
|
|
}
|
|
|
|
model Contract {
|
|
id String @id @db.VarChar(26) // ULID
|
|
pipelineId String @db.VarChar(26)
|
|
sprintId String @db.VarChar(100)
|
|
version String @db.VarChar(20) @default("v1")
|
|
bodyJson String @db.LongText
|
|
frozenAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
|
|
pipeline Pipeline @relation(fields: [pipelineId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([pipelineId])
|
|
@@index([sprintId])
|
|
@@map("contracts")
|
|
}
|