schema: add Idea + IdeaLog models, extend ClaudeJob/Question for ideas (M12 T-491)

- new enums IdeaStatus, ClaudeJobKind, IdeaLogType
- new models Idea (with @@unique([user_id, code]) + pbi_id @unique) and IdeaLog
- User.idea_code_counter Int @default(0) for IDEA-{nnn} code generation
- ClaudeJob.task_id nullable; new idea_id + kind fields + index
- ClaudeQuestion.story_id nullable; new idea_id field + index
- existing call sites narrowed to story-questions / task-jobs (idea-paths come in T-502+)
- includes the M12 plan doc copied from /Users/janpetervisser/.claude/plans

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Janpeter Visser 2026-05-04 19:25:07 +02:00
parent 90343573f3
commit 300e426a4e
6 changed files with 508 additions and 120 deletions

View file

@ -40,6 +40,7 @@ export async function getVerifyResultStats(
status: 'DONE' as const,
verify_result: { not: null as null },
finished_at: { gt: cutoff },
task_id: { not: null },
}
const [grouped, rawEmpty, rawDivergent] = await Promise.all([
@ -82,7 +83,8 @@ export async function getVerifyResultStats(
.filter(r => countMap.has(r))
.map(r => ({ result: r, count: countMap.get(r)! }))
function toTopJob(j: { id: string; finished_at: Date | null; task: { id: string; title: string }; product: { id: string; name: string } }): TopJob {
function toTopJob(j: { id: string; finished_at: Date | null; task: { id: string; title: string } | null; product: { id: string; name: string } }): TopJob | null {
if (!j.task) return null
return {
jobId: j.id,
taskId: j.task.id,
@ -95,8 +97,8 @@ export async function getVerifyResultStats(
return {
counts,
topEmpty: rawEmpty.map(toTopJob),
topDivergent: rawDivergent.map(toTopJob),
topEmpty: rawEmpty.map(toTopJob).filter((j): j is TopJob => j !== null),
topDivergent: rawDivergent.map(toTopJob).filter((j): j is TopJob => j !== null),
}
}