gantt-board/src/app/api/tasks/route.ts
OpenClaw Bot 7710167eb2 Add sprint support to data model and API
- Added Sprint type and interface
- Updated Task to include sprintId
- Added sprint actions to task store (addSprint, updateSprint, deleteSprint, selectSprint)
- Updated API to handle sprints
- Updated all sync calls to include sprints
2026-02-19 17:21:21 -06:00

137 lines
3.5 KiB
TypeScript

import { NextResponse } from "next/server";
import { readFileSync, writeFileSync, existsSync } from "fs";
import { join } from "path";
const DATA_FILE = join(process.cwd(), "data", "tasks.json");
interface Task {
id: string;
title: string;
description?: string;
type: 'idea' | 'task' | 'bug' | 'research' | 'plan';
status: 'backlog' | 'in-progress' | 'review' | 'done' | 'archived';
priority: 'low' | 'medium' | 'high' | 'urgent';
projectId: string;
sprintId?: string;
createdAt: string;
updatedAt: string;
dueDate?: string;
comments: { id: string; text: string; createdAt: string; author: 'user' | 'assistant' }[];
tags: string[];
}
interface Project {
id: string;
name: string;
description?: string;
color: string;
createdAt: string;
}
interface Sprint {
id: string;
name: string;
goal?: string;
startDate: string;
endDate: string;
status: 'planning' | 'active' | 'completed';
projectId: string;
createdAt: string;
}
interface DataStore {
projects: Project[];
tasks: Task[];
sprints: Sprint[];
lastUpdated: number;
}
const defaultData: DataStore = {
projects: [
{ id: '1', name: 'OpenClaw iOS', description: 'Main iOS app development', color: '#8b5cf6', createdAt: new Date().toISOString() },
{ id: '2', name: 'Web Projects', description: 'Web tools and dashboards', color: '#3b82f6', createdAt: new Date().toISOString() },
{ id: '3', name: 'Research', description: 'Experiments and learning', color: '#10b981', createdAt: new Date().toISOString() },
],
tasks: [],
sprints: [],
lastUpdated: Date.now(),
};
function getData(): DataStore {
if (!existsSync(DATA_FILE)) {
return defaultData;
}
try {
const data = readFileSync(DATA_FILE, "utf-8");
return JSON.parse(data);
} catch {
return defaultData;
}
}
function saveData(data: DataStore) {
const dir = join(process.cwd(), "data");
if (!existsSync(dir)) {
require("fs").mkdirSync(dir, { recursive: true });
}
data.lastUpdated = Date.now();
writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
}
// GET - fetch all tasks, projects, and sprints
export async function GET() {
const data = getData();
return NextResponse.json(data);
}
// POST - create or update tasks, projects, or sprints
export async function POST(request: Request) {
try {
const { task, projects, sprints } = await request.json();
const data = getData();
// Update projects if provided
if (projects) {
data.projects = projects;
}
// Update sprints if provided
if (sprints) {
data.sprints = sprints;
}
// Update or add task
if (task) {
const existingIndex = data.tasks.findIndex((t) => t.id === task.id);
if (existingIndex >= 0) {
data.tasks[existingIndex] = { ...task, updatedAt: new Date().toISOString() };
} else {
data.tasks.push({
...task,
id: task.id || Date.now().toString(),
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
});
}
}
saveData(data);
return NextResponse.json({ success: true, data });
} catch (error) {
return NextResponse.json({ error: "Failed to save" }, { status: 500 });
}
}
// DELETE - remove a task
export async function DELETE(request: Request) {
try {
const { id } = await request.json();
const data = getData();
data.tasks = data.tasks.filter((t) => t.id !== id);
saveData(data);
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json({ error: "Failed to delete" }, { status: 500 });
}
}