feat: scaffold klarbild foundation (astro+postgres+s3, auth, migrations, health)

- Astro 5 SSR (node standalone) + React, OKLCH tokens (no tailwind)
- migrations/001_init.sql: full schema per 03-datenmodell-api
- lib: db+migrations, crypto (AES-256-GCM), auth (argon2+signed session, ratelimit),
  storage (S3/MinIO, presigned URLs), openrouter (POST /v1/images, cost)
- middleware: init-once + session guard + admin gate; /api/health (db+storage)
- login + studio placeholder; seeds (till/lea, default recipes); Dockerfile
- verified: astro build passes
This commit is contained in:
2026-07-23 11:11:08 +00:00
commit b46dbbe889
26 changed files with 9651 additions and 0 deletions
+64
View File
@@ -0,0 +1,64 @@
/* Klarbild — Design-Tokens (OKLCH). Eigenständige, ruhige Produkt-Identität.
Kein Tailwind. Feinschliff folgt in der Design-Phase. */
:root {
/* Flächen */
--paper: oklch(98.5% 0.006 95); /* warmes Off-White */
--surface: oklch(100% 0 0);
--surface-2: oklch(96.5% 0.008 95);
--line: oklch(89% 0.008 95);
/* Text */
--ink: oklch(24% 0.02 260); /* warmes Fast-Schwarz */
--ink-soft: oklch(45% 0.02 260);
--ink-mute: oklch(62% 0.015 260);
/* Akzent — klares Petrol/Teal */
--accent: oklch(62% 0.12 210);
--accent-ink: oklch(30% 0.07 210);
--accent-bg: oklch(95% 0.03 210);
/* Sekundär — warmer Sand */
--sand: oklch(85% 0.05 75);
/* Zustände */
--ok: oklch(65% 0.14 150);
--warn: oklch(75% 0.14 75);
--err: oklch(58% 0.17 25);
/* Form */
--radius: 14px;
--radius-sm: 9px;
--shadow: 0 1px 2px oklch(24% 0.02 260 / 0.06), 0 8px 24px oklch(24% 0.02 260 / 0.06);
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--font-display: "Fraunces", Georgia, serif;
--maxw: 1160px;
}
@media (prefers-color-scheme: dark) {
:root {
--paper: oklch(22% 0.012 260);
--surface: oklch(26% 0.014 260);
--surface-2: oklch(30% 0.014 260);
--line: oklch(36% 0.014 260);
--ink: oklch(96% 0.006 95);
--ink-soft: oklch(82% 0.01 95);
--ink-mute: oklch(66% 0.012 95);
--accent: oklch(72% 0.11 210);
--accent-bg: oklch(32% 0.05 210);
--shadow: 0 1px 2px oklch(0% 0 0 / 0.3), 0 10px 30px oklch(0% 0 0 / 0.35);
}
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
background: var(--paper); color: var(--ink);
font-family: var(--font-sans);
font-size: 16px; line-height: 1.55;
-webkit-font-smoothing: antialiased;
}
a { color: var(--accent-ink); }
@media (prefers-reduced-motion: reduce) {
* { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }