chore: auto-commit (28 archivos)

- app.md
- auth.go
- chat.go
- chat.log
- db.go
- frontend/package.json
- frontend/pnpm-lock.yaml
- frontend/src/App.tsx
- frontend/src/Root.tsx
- frontend/src/api.ts
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 00:27:18 +02:00
parent c915e721af
commit bee688e574
28 changed files with 3601 additions and 300 deletions
+71 -3
View File
@@ -1,15 +1,30 @@
import type { Board, Card, Column, HistoryEntry } from "./types";
import type {
Board,
Card,
CardHistoryResponse,
Column,
Metrics,
MetricsFilter,
User,
} from "./types";
const BASE = "/api";
export class HTTPError extends Error {
constructor(public status: number, message: string) {
super(message);
}
}
async function fetchJSON<T>(path: string, init?: RequestInit): Promise<T> {
const res = await fetch(`${BASE}${path}`, {
credentials: "include",
...init,
headers: { "Content-Type": "application/json", ...(init?.headers || {}) },
});
if (!res.ok) {
const err = await res.json().catch(() => ({ Message: res.statusText }));
throw new Error(err.Message || err.message || res.statusText);
throw new HTTPError(res.status, err.Message || err.message || res.statusText);
}
if (res.status === 204) return undefined as T;
return res.json();
@@ -28,6 +43,8 @@ export interface UpdateColumnInput {
position?: number;
location?: "board" | "sidebar";
width?: number;
wip_limit?: number;
is_done?: boolean;
}
export function updateColumn(id: string, patch: UpdateColumnInput): Promise<void> {
@@ -50,6 +67,7 @@ export interface CreateCardInput {
requester?: string;
title: string;
description?: string;
assignee_id?: string | null;
}
export function createCard(input: CreateCardInput): Promise<Card> {
@@ -61,6 +79,8 @@ export interface UpdateCardInput {
title?: string;
description?: string;
color?: string;
locked?: boolean;
assignee_id?: string | null;
}
export function updateCard(id: string, patch: UpdateCardInput): Promise<void> {
@@ -71,6 +91,18 @@ export function deleteCard(id: string): Promise<void> {
return fetchJSON(`/cards/${id}`, { method: "DELETE" });
}
export function listTrash(): Promise<Card[]> {
return fetchJSON("/trash");
}
export function restoreCard(id: string): Promise<void> {
return fetchJSON(`/cards/${id}/restore`, { method: "POST" });
}
export function purgeCard(id: string): Promise<void> {
return fetchJSON(`/cards/${id}/purge`, { method: "DELETE" });
}
export function moveCard(id: string, column_id: string, ordered_ids: string[]): Promise<void> {
return fetchJSON(`/cards/${id}/move`, {
method: "POST",
@@ -78,7 +110,7 @@ export function moveCard(id: string, column_id: string, ordered_ids: string[]):
});
}
export function cardHistory(id: string): Promise<HistoryEntry[]> {
export function cardHistory(id: string): Promise<CardHistoryResponse> {
return fetchJSON(`/cards/${id}/history`);
}
@@ -103,3 +135,39 @@ export interface ChatResponse {
export function sendChat(messages: ChatMessage[]): Promise<ChatResponse> {
return fetchJSON("/chat", { method: "POST", body: JSON.stringify({ messages }) });
}
export function login(username: string, password: string): Promise<User> {
return fetchJSON("/auth/login", {
method: "POST",
body: JSON.stringify({ username, password }),
});
}
export function register(username: string, password: string, display_name?: string): Promise<User> {
return fetchJSON("/auth/register", {
method: "POST",
body: JSON.stringify({ username, password, display_name }),
});
}
export function logout(): Promise<void> {
return fetchJSON("/auth/logout", { method: "POST" });
}
export function getMe(): Promise<User> {
return fetchJSON("/me");
}
export function listUsers(): Promise<User[]> {
return fetchJSON("/users");
}
export function getMetrics(f: MetricsFilter): Promise<Metrics> {
const qs = new URLSearchParams();
if (f.from) qs.set("from", f.from);
if (f.to) qs.set("to", f.to);
if (f.assignee_id) qs.set("assignee_id", f.assignee_id);
if (f.requester) qs.set("requester", f.requester);
const q = qs.toString();
return fetchJSON(`/metrics${q ? `?${q}` : ""}`);
}