diff --git a/app/(app)/products/[id]/page.tsx b/app/(app)/products/[id]/page.tsx index 647d8c6..85519dd 100644 --- a/app/(app)/products/[id]/page.tsx +++ b/app/(app)/products/[id]/page.tsx @@ -92,14 +92,8 @@ export default async function ProductBacklogPage({ params, searchParams }: Props return (
- {/* Product header */} -
-
-

{product.name}

- {product.description && ( -

{product.description}

- )} -
+ {/* Product header — actions only; product-naam zit al in NavBar */} +
{user?.active_product_id !== id && ( diff --git a/components/backlog/pbi-list.tsx b/components/backlog/pbi-list.tsx index 8f79138..3995102 100644 --- a/components/backlog/pbi-list.tsx +++ b/components/backlog/pbi-list.tsx @@ -24,7 +24,6 @@ import { toast } from 'sonner' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover' -import { PanelNavBar } from '@/components/shared/panel-nav-bar' import { useSelectionStore } from '@/stores/selection-store' import { usePlannerStore } from '@/stores/planner-store' import { useBacklogStore } from '@/stores/backlog-store' @@ -330,92 +329,87 @@ export function PbiList({ productId, isDemo }: PbiListProps) { return (
- - {filterPriority !== 'all' && ( - - )} - {filterStatus !== 'all' && ( - - )} - - - {`Filters${activeFilterCount > 0 ? ` (${activeFilterCount})` : ''}`} - - } - /> - - - - -
- -
-
-
- +
+ {filterPriority !== 'all' && ( + + )} + {filterStatus !== 'all' && ( + + )} + + + {`Filters${activeFilterCount > 0 ? ` (${activeFilterCount})` : ''}`} + + } + /> + + + + +
- - - } - /> +
+
+
+ + + +
{pbis.length === 0 ? ( diff --git a/docs/erd.svg b/docs/erd.svg index fd4b3eb..9c88b70 100644 --- a/docs/erd.svg +++ b/docs/erd.svg @@ -1 +1 @@ -

active_product

user

enum:role

user

user

product

enum:status

pbi

product

sprint

assignee

enum:status

story

enum:type

enum:status

product

enum:status

story

sprint

enum:status

user

product

task

enum:status

claimed_by_token

user

token

product

user

user

product

user

story

task

product

asker

answerer

Role

PRODUCT_OWNER

PRODUCT_OWNER

SCRUM_MASTER

SCRUM_MASTER

DEVELOPER

DEVELOPER

StoryStatus

OPEN

OPEN

IN_SPRINT

IN_SPRINT

DONE

DONE

PbiStatus

READY

READY

BLOCKED

BLOCKED

DONE

DONE

ClaudeJobStatus

QUEUED

QUEUED

CLAIMED

CLAIMED

RUNNING

RUNNING

DONE

DONE

FAILED

FAILED

CANCELLED

CANCELLED

TaskStatus

TO_DO

TO_DO

IN_PROGRESS

IN_PROGRESS

REVIEW

REVIEW

DONE

DONE

LogType

IMPLEMENTATION_PLAN

IMPLEMENTATION_PLAN

TEST_RESULT

TEST_RESULT

COMMIT

COMMIT

TestStatus

PASSED

PASSED

FAILED

FAILED

SprintStatus

ACTIVE

ACTIVE

COMPLETED

COMPLETED

users

String

id

🗝️

String

username

String

email

String

password_hash

Boolean

is_demo

String

bio

String

bio_detail

Bytes

avatar_data

DateTime

created_at

DateTime

updated_at

user_roles

String

id

🗝️

Role

role

api_tokens

String

id

🗝️

String

token_hash

String

label

DateTime

created_at

DateTime

revoked_at

products

String

id

🗝️

String

name

String

code

String

description

String

repo_url

String

definition_of_done

Boolean

archived

DateTime

created_at

DateTime

updated_at

pbis

String

id

🗝️

String

code

String

title

String

description

Int

priority

Float

sort_order

PbiStatus

status

DateTime

created_at

DateTime

updated_at

stories

String

id

🗝️

String

code

String

title

String

description

String

acceptance_criteria

Int

priority

Float

sort_order

StoryStatus

status

DateTime

created_at

DateTime

updated_at

story_logs

String

id

🗝️

LogType

type

String

content

TestStatus

status

String

commit_hash

String

commit_message

Json

metadata

DateTime

created_at

sprints

String

id

🗝️

String

sprint_goal

SprintStatus

status

DateTime

created_at

DateTime

completed_at

tasks

String

id

🗝️

String

title

String

description

String

implementation_plan

Int

priority

Float

sort_order

TaskStatus

status

DateTime

created_at

DateTime

updated_at

claude_jobs

String

id

🗝️

ClaudeJobStatus

status

DateTime

claimed_at

DateTime

started_at

DateTime

finished_at

String

branch

String

summary

String

error

DateTime

created_at

DateTime

updated_at

claude_workers

String

id

🗝️

String

product_id

DateTime

started_at

DateTime

last_seen_at

product_members

String

id

🗝️

DateTime

created_at

todos

String

id

🗝️

String

title

String

description

Boolean

done

Boolean

archived

DateTime

created_at

DateTime

updated_at

login_pairings

String

id

🗝️

String

secret_hash

String

desktop_token_hash

String

status

String

desktop_ua

String

desktop_ip

DateTime

created_at

DateTime

expires_at

DateTime

approved_at

DateTime

consumed_at

claude_questions

String

id

🗝️

String

question

Json

options

String

status

String

answer

DateTime

answered_at

DateTime

created_at

DateTime

expires_at

\ No newline at end of file +

active_product

user

enum:role

user

user

product

enum:status

pbi

product

sprint

assignee

enum:status

story

enum:type

enum:status

product

enum:status

story

sprint

enum:status

user

product

task

enum:status

claimed_by_token

user

token

product

user

user

product

user

story

task

product

asker

answerer

Role

PRODUCT_OWNER

PRODUCT_OWNER

SCRUM_MASTER

SCRUM_MASTER

DEVELOPER

DEVELOPER

StoryStatus

OPEN

OPEN

IN_SPRINT

IN_SPRINT

DONE

DONE

PbiStatus

READY

READY

BLOCKED

BLOCKED

DONE

DONE

ClaudeJobStatus

QUEUED

QUEUED

CLAIMED

CLAIMED

RUNNING

RUNNING

DONE

DONE

FAILED

FAILED

CANCELLED

CANCELLED

TaskStatus

TO_DO

TO_DO

IN_PROGRESS

IN_PROGRESS

REVIEW

REVIEW

DONE

DONE

LogType

IMPLEMENTATION_PLAN

IMPLEMENTATION_PLAN

TEST_RESULT

TEST_RESULT

COMMIT

COMMIT

TestStatus

PASSED

PASSED

FAILED

FAILED

SprintStatus

ACTIVE

ACTIVE

COMPLETED

COMPLETED

users

String

id

🗝️

String

username

String

email

String

password_hash

Boolean

is_demo

String

bio

String

bio_detail

Bytes

avatar_data

DateTime

created_at

DateTime

updated_at

user_roles

String

id

🗝️

Role

role

api_tokens

String

id

🗝️

String

token_hash

String

label

DateTime

created_at

DateTime

revoked_at

products

String

id

🗝️

String

name

String

code

String

description

String

repo_url

String

definition_of_done

Boolean

archived

DateTime

created_at

DateTime

updated_at

pbis

String

id

🗝️

String

code

String

title

String

description

Int

priority

Float

sort_order

PbiStatus

status

DateTime

created_at

DateTime

updated_at

stories

String

id

🗝️

String

code

String

title

String

description

String

acceptance_criteria

Int

priority

Float

sort_order

StoryStatus

status

DateTime

created_at

DateTime

updated_at

story_logs

String

id

🗝️

LogType

type

String

content

TestStatus

status

String

commit_hash

String

commit_message

Json

metadata

DateTime

created_at

sprints

String

id

🗝️

String

sprint_goal

SprintStatus

status

DateTime

created_at

DateTime

completed_at

tasks

String

id

🗝️

String

title

String

description

String

implementation_plan

Int

priority

Float

sort_order

TaskStatus

status

DateTime

created_at

DateTime

updated_at

claude_jobs

String

id

🗝️

ClaudeJobStatus

status

DateTime

claimed_at

DateTime

started_at

DateTime

finished_at

String

plan_snapshot

String

branch

String

summary

String

error

DateTime

created_at

DateTime

updated_at

claude_workers

String

id

🗝️

String

product_id

DateTime

started_at

DateTime

last_seen_at

product_members

String

id

🗝️

DateTime

created_at

todos

String

id

🗝️

String

title

String

description

Boolean

done

Boolean

archived

DateTime

created_at

DateTime

updated_at

login_pairings

String

id

🗝️

String

secret_hash

String

desktop_token_hash

String

status

String

desktop_ua

String

desktop_ip

DateTime

created_at

DateTime

expires_at

DateTime

approved_at

DateTime

consumed_at

claude_questions

String

id

🗝️

String

question

Json

options

String

status

String

answer

DateTime

answered_at

DateTime

created_at

DateTime

expires_at

\ No newline at end of file diff --git a/docs/scrum4me-architecture.md b/docs/scrum4me-architecture.md index 6439d5f..4d0a2ce 100644 --- a/docs/scrum4me-architecture.md +++ b/docs/scrum4me-architecture.md @@ -1120,12 +1120,15 @@ Developers kunnen vanuit de Task Detail Dialog een lokale Claude Code-sessie ins ### State machine ``` -QUEUED → CLAIMED → RUNNING → DONE - → FAILED +QUEUED → CLAIMED (snapshot capture) → RUNNING → DONE + → FAILED → CANCELLED (door user) -CLAIMED → QUEUED (stale claim cleanup, >30min) +CLAIMED → QUEUED (stale claim cleanup, >30min; snapshot gewist) +QUEUED → CLAIMED (re-claim na stale reset; snapshot refreshed) ``` +**Snapshot-rationale:** bij atomic claim schrijft `wait_for_job` de dan-actuele `task.implementation_plan` naar `claude_jobs.plan_snapshot`. Dit veld blijft bevroren terwijl de job loopt — ook als een gebruiker `update_task_plan` aanroept. Zo kan een toekomstige verify-tool drift detecteren tussen de baseline (snapshot) en de actuele plan. Jobs zonder snapshot (NULL) zijn aangemaakt vóór deze feature en worden als "no baseline" gemarkeerd. + ### ClaudeJob model ``` @@ -1134,6 +1137,7 @@ claude_jobs status: ClaudeJobStatus (QUEUED|CLAIMED|RUNNING|DONE|FAILED|CANCELLED) claimed_by_token_id (FK → api_tokens, nullable) claimed_at, started_at, finished_at + plan_snapshot: String? — bevroren snapshot van task.implementation_plan bij claim branch, summary, error @@index([user_id, status]) @@index([task_id, status]) diff --git a/prisma/migrations/20260430171227_add_claude_job_plan_snapshot/migration.sql b/prisma/migrations/20260430171227_add_claude_job_plan_snapshot/migration.sql new file mode 100644 index 0000000..b578c1a --- /dev/null +++ b/prisma/migrations/20260430171227_add_claude_job_plan_snapshot/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "claude_jobs" ADD COLUMN "plan_snapshot" TEXT; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6586980..898b87e 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -260,6 +260,7 @@ model ClaudeJob { claimed_at DateTime? started_at DateTime? finished_at DateTime? + plan_snapshot String? branch String? summary String? error String?