feat(geschichten): add /geschichten routes (index, detail, new, edit)

- /geschichten — published-stories index with filter pills + "+ Neue Geschichte"
  for BLOG_WRITERs; supports ?personId and ?documentId pre-filtering
- /geschichten/[id] — reader detail with sanitised {@html} body, person and
  document chip sections, BLOG_WRITER edit/delete with confirm dialog
- /geschichten/new — editor with optional ?personId and ?documentId pre-fill
  (silent ignore on unknown IDs to avoid leaking entity existence)
- /geschichten/[id]/edit — editor populated from existing story; BLOG_WRITE
  guard redirects readers to the detail page

All routes load via createApiClient(fetch) with !response.ok error handling
following the project pattern; PATCH/DELETE go through raw fetch which the
Vite dev proxy / Caddy production proxy authenticates via cookie.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-05-02 17:54:31 +02:00
parent 9e6efacbcb
commit fe1014a08a
8 changed files with 492 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
import { error } from '@sveltejs/kit';
import { createApiClient } from '$lib/api.server';
import { getErrorMessage } from '$lib/errors';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ url, fetch }) => {
const api = createApiClient(fetch);
const personId = url.searchParams.get('personId') ?? undefined;
const documentId = url.searchParams.get('documentId') ?? undefined;
const [listResult, personResult] = await Promise.all([
api.GET('/api/geschichten', {
params: {
query: {
status: 'PUBLISHED',
personId,
documentId
}
}
}),
personId
? api.GET('/api/persons/{id}', { params: { path: { id: personId } } })
: Promise.resolve(null)
]);
if (!listResult.response.ok) {
const code = (listResult.error as unknown as { code?: string })?.code;
throw error(listResult.response.status, getErrorMessage(code));
}
return {
geschichten: listResult.data ?? [],
personFilter: personResult && personResult.response.ok ? personResult.data! : null,
documentFilter: documentId ?? null
};
};