feat(books): édition des métadonnées livres et séries + champ authors multi-valeurs

- Nouveaux endpoints PATCH /books/:id et PATCH /libraries/:id/series/:name pour éditer les métadonnées
- GET /libraries/:id/series/:name/metadata pour récupérer les métadonnées de série
- Ajout du champ `authors` (Vec<String>) sur les structs Book/BookDetails
- 3 migrations : table series_metadata, colonne authors sur series_metadata et books
- Composants EditBookForm et EditSeriesForm dans le backoffice
- Routes API Next.js correspondantes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-16 17:21:55 +01:00
parent a085924f8a
commit bc98067871
15 changed files with 1061 additions and 8 deletions

View File

@@ -62,6 +62,7 @@ export type BookDto = {
format: string | null;
title: string;
author: string | null;
authors: string[];
series: string | null;
volume: number | null;
language: string | null;
@@ -484,6 +485,54 @@ export async function fetchStats() {
return apiFetch<StatsResponse>("/stats");
}
export type UpdateBookRequest = {
title: string;
author: string | null;
authors: string[];
series: string | null;
volume: number | null;
language: string | null;
};
export async function updateBook(bookId: string, data: UpdateBookRequest) {
return apiFetch<BookDto>(`/books/${bookId}`, {
method: "PATCH",
body: JSON.stringify(data),
});
}
export type SeriesMetadataDto = {
authors: string[];
description: string | null;
publishers: string[];
start_year: number | null;
book_author: string | null;
book_language: string | null;
};
export async function fetchSeriesMetadata(libraryId: string, seriesName: string) {
return apiFetch<SeriesMetadataDto>(
`/libraries/${libraryId}/series/${encodeURIComponent(seriesName)}/metadata`
);
}
export type UpdateSeriesRequest = {
new_name: string;
authors: string[];
author?: string | null;
language?: string | null;
description: string | null;
publishers: string[];
start_year: number | null;
};
export async function updateSeries(libraryId: string, seriesName: string, data: UpdateSeriesRequest) {
return apiFetch<{ updated: number }>(`/libraries/${libraryId}/series/${encodeURIComponent(seriesName)}`, {
method: "PATCH",
body: JSON.stringify(data),
});
}
export async function markSeriesRead(seriesName: string, status: "read" | "unread" = "read") {
return apiFetch<{ updated: number }>("/series/mark-read", {
method: "POST",