Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions src/app/api/tasks/[id]/prd/route.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NextRequest, NextResponse } from 'next/server';
import { and, eq } from 'drizzle-orm';
import { db } from '@/lib/db';
import { tasks } from '@/db/schema';
import { taskPrdVersions, tasks } from '@/db/schema';
import { getTenantId } from '@/lib/tenant';
import { readWorkspaceMarkdown, writeWorkspaceMarkdown } from '@/lib/prd-files';

Expand Down Expand Up @@ -43,7 +43,12 @@ export async function PUT(req: NextRequest, context: { params: Promise<{ id: str
const taskId = Number(id);
if (!Number.isFinite(taskId) || taskId <= 0) return NextResponse.json({ error: 'Invalid task id' }, { status: 400 });

const body = (await req.json().catch(() => null)) as null | { content?: string };
const body = (await req.json().catch(() => null)) as null | {
content?: string;
source?: 'manual' | 'restored' | 'new_version' | 'generate';
changeNote?: string;
createdBy?: string;
};
if (!body || typeof body.content !== 'string') {
return NextResponse.json({ error: 'Missing content' }, { status: 400 });
}
Expand All @@ -63,10 +68,30 @@ export async function PUT(req: NextRequest, context: { params: Promise<{ id: str
return NextResponse.json({ error: 'Write failed' }, { status: 500 });
}

const now = new Date();
const nextVersion = (task.prdVersion ?? 1) + 1;

await db
.update(taskPrdVersions)
.set({ isCurrent: false })
.where(and(eq(taskPrdVersions.taskId, taskId), eq(taskPrdVersions.tenantId, tenantId), eq(taskPrdVersions.isCurrent, true)));

await db.insert(taskPrdVersions).values({
tenantId,
taskId,
versionNumber: nextVersion,
path: task.prdPath,
source: body.source ?? 'manual',
isCurrent: true,
changeNote: body.changeNote ?? null,
createdBy: body.createdBy ?? 'user',
createdAt: now,
});

await db
.update(tasks)
.set({ prdLastUpdatedAt: new Date(), updatedAt: new Date() })
.set({ prdVersion: nextVersion, prdLastUpdatedAt: now, updatedAt: now })
.where(and(eq(tasks.id, taskId), eq(tasks.tenantId, tenantId)));

return NextResponse.json({ ok: true });
return NextResponse.json({ ok: true, prdVersion: nextVersion });
}
14 changes: 6 additions & 8 deletions src/components/VersionHistoryPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,15 @@ export function VersionHistoryPanel({ taskId, onRestored }: VersionHistoryPanelP
return;
}

// Write content as current PRD, then create a new version
// Restore by writing as current PRD; backend creates a new version row.
await fetch(`/api/tasks/${taskId}/prd`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content }),
});

await fetch(`/api/tasks/${taskId}/prd/new-version`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ source: 'restored', changeNote: `Restored from v${version.versionNumber}` }),
body: JSON.stringify({
content,
source: 'restored',
changeNote: `Restored from v${version.versionNumber}`,
}),
});

await fetchVersions();
Expand Down
Loading