Add FastAPI backend and React frontend subprojects

Backend:
- FastAPI app with 17 REST endpoints covering dashboard, monitoring,
  media index, file browser, and jobs
- Reuses existing clients/domain/services unchanged
- pydantic-settings config, dependency injection, CORS setup
- Auto-generated OpenAPI docs at /docs

Frontend:
- Vite + React + TypeScript SPA
- @tanstack/react-query for data fetching with polling
- ag-grid-react for media table and file browser
- recharts for monitoring charts
- Tailwind CSS styling
- 4 pages: Dashboard, Monitoring, Media, File Browser
- Typed API client matching all backend endpoints

Also:
- docs/MIGRATION_PLAN.md with full architecture plan
- Updated .gitignore for both subprojects
- Streamlit app preserved for now (can coexist)
This commit is contained in:
2026-04-30 21:40:18 +02:00
parent 1acdfbc6ba
commit 3c432473e5
63 changed files with 7778 additions and 202 deletions
+126
View File
@@ -0,0 +1,126 @@
/**
* Shared TypeScript interfaces matching backend API responses.
*/
export interface MediaCounts {
movies: number;
series: number;
episodes: number;
}
export interface LibraryCount {
library: string;
type: string;
movies: number;
series: number;
episodes: number;
total: number;
}
export interface NowPlayingSession {
user: string;
title: string;
type: string;
state: string;
transcoding: string;
transcoding_type: string;
device: string;
session_id: string;
}
export interface MonitoringStatus {
status: string;
}
export interface MonitoringSample {
ts: number;
cpu_pct: number;
iowait_pct?: number;
mem_pct: number;
net_rx_bytes_per_sec: number;
net_tx_bytes_per_sec: number;
disk_read_bps: number;
disk_write_bps: number;
}
export interface MonitoringMetrics {
samples: MonitoringSample[];
total_samples: number;
filtered_samples: number;
cutoff_ts: number;
}
export interface DiskSpace {
filesystem: string;
size: number;
used: number;
available: number;
used_pct: string;
mount: string;
}
export interface MediaIndexStatus {
exists: boolean;
item_count: number;
updated_at: number | null;
updated_at_label: string;
build_duration_seconds: number | null;
}
export interface MediaItem {
id: string;
title: string;
series: string;
season: string;
episode: number | null;
type: string;
year: number | null;
runtime_min: number | null;
size: string;
bitrate: string;
hdr: string;
video: string;
resolution: string;
date_added: string;
library: string;
path: string;
}
export interface MediaQueryResponse {
items: MediaItem[];
total: number;
limit: number;
offset: number;
}
export interface FileEntry {
type: string;
size: number;
mtime: number;
name: string;
}
export interface DirectoryListing {
path: string;
entries: FileEntry[];
count: number;
}
export interface JobTemplate {
key: string;
name: string;
description: string;
}
export interface JobResult {
job_key: string;
path: string;
exit_status: number;
stdout: string;
stderr: string;
}
export interface ResolvedPath {
original: string;
resolved: string;
}