React-Frontend: Grundgerüst (Vite, TypeScript, Router, TanStack Query)

- frontend/ mit Vite 8, React 19, React Router 8, TanStack Query 5, TS 7
- api.ts: Fehler allein über HTTP-Status (ApiError), errMsg wie bisher
- types.ts: API-Antworten laut notes/api.md
- Layout mit unverändertem Header-Markup, app.css als Kopie
- Dev-Proxy für /api und /static aufs Go-Backend
- Containerfile: HEALTHCHECK auf /api/stats

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TiXsPUqw7oeomZ8wZrQW5q
This commit is contained in:
irrlicht
2026-09-26 23:18:56 +02:00
co-authored by Claude Opus 5.5
parent 030a5bd943
commit 37279ac90d
18 changed files with 2091 additions and 1 deletions
+86
View File
@@ -0,0 +1,86 @@
// Typen der JSON-API; Referenz ist notes/api.md. Zeitstempel sind
// Unix-Sekunden.
export interface Entry {
pid: number;
uid: number;
created_at: number;
content: string;
filepath: string;
reply_to: number;
reply_count: number;
last_activity: number;
deleted: number;
bump_count: number;
last_bump: number;
username: string;
avatar: string;
}
export interface Thread {
entry: Entry;
ancestors: Entry[];
replies: Entry[];
}
export type VoteMode = "left" | "right";
export interface VoteTally {
pid: number;
left: number;
right: number;
selected: VoteMode | "none";
}
export interface BumpResult {
pid: number;
bump_count: number;
last_bump: number;
last_activity: number;
retry_after: number;
}
export interface CreatedEntry {
pid: number;
content: string;
filepath: string;
reply_to: number;
}
// GET /api/user/info -- das eigene Konto.
export interface Me {
uid: number;
username: string;
created_at: number;
last_login: number;
avatar: string;
}
// GET /api/u/{username}/info -- öffentliches Profil.
export interface Profile {
uid: number;
username: string;
created_at: number;
avatar: string;
}
export interface StatsDetail {
users: number;
entries: number;
toplevel: number;
replies: number;
votes: { left: number; right: number };
impressions_total: number;
visitors_total: number;
daily: { day: string; impressions: number; visitors: number }[];
top_asns: { asn: string; hits: number; networks: number }[];
}
// Fehlerformat: {"error": {...}}, bei manchen Fehlern mit Zusatzfeldern
// daneben (Repost-Cooldown: retry_after, bump_count).
export interface ApiErrorBody {
code: string;
message: string;
field?: string;
fields?: Record<string, string>;
}