From 34e6334051414b2a08f39cbe7867238f0cc013f1 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Sun, 26 Apr 2026 19:46:53 +0200 Subject: [PATCH 01/13] fix(ST-507): remount email Input on prop change to silence base-ui uncontrolled warning Co-Authored-By: Claude Opus 4.7 (1M context) --- components/settings/profile-editor.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/settings/profile-editor.tsx b/components/settings/profile-editor.tsx index 5c81963..8eedb51 100644 --- a/components/settings/profile-editor.tsx +++ b/components/settings/profile-editor.tsx @@ -113,6 +113,7 @@ export function ProfileEditor({ email, bio, bioDetail, hasAvatar, avatarVersion E-mailadres Date: Sun, 26 Apr 2026 19:53:56 +0200 Subject: [PATCH 02/13] feat(ST-004): force M3.5 stories and tasks to not-done in seed regardless of backlog checkbox Co-Authored-By: Claude Opus 4.7 (1M context) --- prisma/seed.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/prisma/seed.ts b/prisma/seed.ts index e5a56a8..8888ecb 100644 --- a/prisma/seed.ts +++ b/prisma/seed.ts @@ -145,11 +145,15 @@ async function main() { ` PBI ${pbi.title} (priority ${pbi.priority}) + sprint ${ms.sprint_status}`, ) + // M3.5 = de huidige sprint die nog moet beginnen — alle stories en taken + // worden geforceerd op niet-uitgevoerd, ongeacht de checkbox in de backlog. + const forceOpen = ms.key === 'M3.5' + for (const s of ms.stories) { const isActive = ms.sprint_status === 'ACTIVE' - const inSprint = isActive || s.status === 'DONE' - const storyStatus = - s.status === 'DONE' ? 'DONE' : isActive ? 'IN_SPRINT' : 'OPEN' + const effectivelyDone = !forceOpen && s.status === 'DONE' + const inSprint = isActive || effectivelyDone + const storyStatus = effectivelyDone ? 'DONE' : isActive ? 'IN_SPRINT' : 'OPEN' const storySummary = s.tasks.map((t) => t.title).join('; ') const story = await prisma.story.create({ @@ -175,7 +179,7 @@ async function main() { description: t.description, priority: ms.priority, sort_order: t.sort_order, - status: s.status === 'DONE' ? 'DONE' : 'TO_DO', + status: effectivelyDone ? 'DONE' : 'TO_DO', }, }) } From 318cb1e1f9954ee7c93a930d35667b97af8a600b Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Sun, 26 Apr 2026 19:59:52 +0200 Subject: [PATCH 03/13] feat(ST-509): add optional description column (max 2000 chars) to Todo Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/erd.svg | 2 +- .../20260426195800_add_todo_description/migration.sql | 2 ++ prisma/schema.prisma | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 prisma/migrations/20260426195800_add_todo_description/migration.sql diff --git a/docs/erd.svg b/docs/erd.svg index c5b5866..7011ffd 100644 --- a/docs/erd.svg +++ b/docs/erd.svg @@ -1 +1 @@ -

user

enum:role

user

user

product

pbi

product

sprint

assignee

enum:status

story

enum:type

enum:status

product

enum:status

story

sprint

enum:status

product

user

user

product

Role

PRODUCT_OWNER

PRODUCT_OWNER

SCRUM_MASTER

SCRUM_MASTER

DEVELOPER

DEVELOPER

StoryStatus

OPEN

OPEN

IN_SPRINT

IN_SPRINT

DONE

DONE

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

description

String

repo_url

String

definition_of_done

Boolean

archived

DateTime

created_at

DateTime

updated_at

pbis

String

id

🗝️

String

title

String

description

Int

priority

Float

sort_order

DateTime

created_at

DateTime

updated_at

stories

String

id

🗝️

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

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

product_members

String

id

🗝️

DateTime

created_at

todos

String

id

🗝️

String

title

Boolean

done

Boolean

archived

DateTime

created_at

DateTime

updated_at

\ No newline at end of file +

user

enum:role

user

user

product

pbi

product

sprint

assignee

enum:status

story

enum:type

enum:status

product

enum:status

story

sprint

enum:status

product

user

user

product

Role

PRODUCT_OWNER

PRODUCT_OWNER

SCRUM_MASTER

SCRUM_MASTER

DEVELOPER

DEVELOPER

StoryStatus

OPEN

OPEN

IN_SPRINT

IN_SPRINT

DONE

DONE

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

description

String

repo_url

String

definition_of_done

Boolean

archived

DateTime

created_at

DateTime

updated_at

pbis

String

id

🗝️

String

title

String

description

Int

priority

Float

sort_order

DateTime

created_at

DateTime

updated_at

stories

String

id

🗝️

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

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

product_members

String

id

🗝️

DateTime

created_at

todos

String

id

🗝️

String

title

String

description

Boolean

done

Boolean

archived

DateTime

created_at

DateTime

updated_at

\ No newline at end of file diff --git a/prisma/migrations/20260426195800_add_todo_description/migration.sql b/prisma/migrations/20260426195800_add_todo_description/migration.sql new file mode 100644 index 0000000..22fbd81 --- /dev/null +++ b/prisma/migrations/20260426195800_add_todo_description/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "todos" ADD COLUMN "description" VARCHAR(2000); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index aa13b4e..bf68dba 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -226,6 +226,7 @@ model Todo { product Product? @relation(fields: [product_id], references: [id], onDelete: SetNull) product_id String? title String + description String? @db.VarChar(2000) done Boolean @default(false) archived Boolean @default(false) created_at DateTime @default(now()) From 856a051b2ffe76a61b86808f5a3b3d5583084a0c Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Sun, 26 Apr 2026 19:59:53 +0200 Subject: [PATCH 04/13] feat(ST-509): persist Todo description in create and update actions Co-Authored-By: Claude Opus 4.7 (1M context) --- actions/todos.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/actions/todos.ts b/actions/todos.ts index c4252f5..ecfde5f 100644 --- a/actions/todos.ts +++ b/actions/todos.ts @@ -18,10 +18,12 @@ export async function createTodoAction(_prevState: unknown, formData: FormData) if (session.isDemo) return { error: 'Niet beschikbaar in demo-modus' } const title = (formData.get('title') as string)?.trim() + const description = (formData.get('description') as string)?.trim() || null const raw = (formData.get('productId') as string)?.trim() const productId = (raw && raw !== 'all') ? raw : null if (!title) return { error: 'Titel is verplicht' } + if (description && description.length > 2000) return { error: 'Beschrijving is langer dan 2000 tekens' } if (productId) { const product = await prisma.product.findFirst({ @@ -30,7 +32,9 @@ export async function createTodoAction(_prevState: unknown, formData: FormData) if (!product) return { error: 'Product niet gevonden' } } - await prisma.todo.create({ data: { user_id: session.userId, product_id: productId, title } }) + await prisma.todo.create({ + data: { user_id: session.userId, product_id: productId, title, description }, + }) revalidatePath('/todos') return { success: true } } @@ -66,12 +70,14 @@ export async function updateTodoAction(_prevState: unknown, formData: FormData) const id = (formData.get('id') as string)?.trim() const title = (formData.get('title') as string)?.trim() + const description = (formData.get('description') as string)?.trim() || null const raw = (formData.get('productId') as string)?.trim() const productId = raw || null const done = formData.get('done') === 'on' if (!id) return { error: 'Ongeldige todo' } if (!title) return { error: 'Titel is verplicht' } + if (description && description.length > 2000) return { error: 'Beschrijving is langer dan 2000 tekens' } const todo = await prisma.todo.findFirst({ where: { id, user_id: session.userId }, @@ -87,7 +93,7 @@ export async function updateTodoAction(_prevState: unknown, formData: FormData) await prisma.todo.update({ where: { id }, - data: { title, product_id: productId, done }, + data: { title, description, product_id: productId, done }, }) revalidatePath('/todos') return { success: true } From c45ba1d0c27dbf70aeffec2c8cd2838d51e5a901 Mon Sep 17 00:00:00 2001 From: Madhura68 Date: Sun, 26 Apr 2026 19:59:55 +0200 Subject: [PATCH 05/13] feat(ST-509): add description textarea to Todo create and edit cards Co-Authored-By: Claude Opus 4.7 (1M context) --- app/(app)/todos/page.tsx | 1 + components/todos/todo-list.tsx | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/app/(app)/todos/page.tsx b/app/(app)/todos/page.tsx index b2c6fd3..27f07f4 100644 --- a/app/(app)/todos/page.tsx +++ b/app/(app)/todos/page.tsx @@ -29,6 +29,7 @@ export default async function TodosPage() { todos={todos.map(t => ({ id: t.id, title: t.title, + description: t.description ?? null, done: t.done, created_at: t.created_at.toISOString(), product_id: t.product_id ?? null, diff --git a/components/todos/todo-list.tsx b/components/todos/todo-list.tsx index 2eb7497..40f2af3 100644 --- a/components/todos/todo-list.tsx +++ b/components/todos/todo-list.tsx @@ -17,6 +17,7 @@ import { cn } from '@/lib/utils' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' +import { Textarea } from '@/components/ui/textarea' import { DemoTooltip } from '@/components/shared/demo-tooltip' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { @@ -30,6 +31,7 @@ import { interface Todo { id: string title: string + description: string | null done: boolean created_at: string product_id: string | null @@ -292,6 +294,13 @@ function TodoCard({ autoComplete="off" /> +