feat: add SPA, serve at /app/, update Dockerfile and README

- React + TanStack Router + shadcn/ui SPA under spa/
- serve spa/dist at /app/ with index.html fallback for client routing
- Dockerfile: node build stage for SPA, copy dist into runtime image
- README: document SPA, CORS_ORIGINS env var, architecture entry
- vite base set to /app/, manifest.json paths fixed
This commit is contained in:
2026-06-04 04:20:15 +02:00
parent 15dc0e526b
commit b9c0b10740
153 changed files with 24329 additions and 1 deletions

44
spa/src/lib/api/common.ts Normal file
View File

@@ -0,0 +1,44 @@
import { z } from "zod"
export const movieDtoSchema = z.object({
id: z.string().uuid(),
title: z.string(),
release_year: z.number(),
director: z.string().optional(),
poster_path: z.string().optional(),
genres: z.array(z.string()),
runtime_minutes: z.number().optional(),
original_language: z.string().optional(),
overview: z.string().optional(),
collection_name: z.string().optional(),
})
export type MovieDto = z.infer<typeof movieDtoSchema>
export const reviewDtoSchema = z.object({
id: z.string().uuid(),
rating: z.number(),
comment: z.string().optional(),
watched_at: z.string(),
})
export type ReviewDto = z.infer<typeof reviewDtoSchema>
export const diaryEntryDtoSchema = z.object({
movie: movieDtoSchema,
review: reviewDtoSchema,
})
export type DiaryEntryDto = z.infer<typeof diaryEntryDtoSchema>
export function paginatedSchema<T extends z.ZodType>(itemSchema: T) {
return z.object({
items: z.array(itemSchema),
total_count: z.number(),
limit: z.number(),
offset: z.number(),
})
}
export type Paginated<T> = {
items: T[]
total_count: number
limit: number
offset: number
}