Commit Graph
10 Commits
Author SHA1 Message Date
Nick Szaunig 6e328cdacb feat(frontend): Voelker-Views (Modul 3) + Refresh-Token-Race-Fix
/colonies: Liste; /colonies/new: Anlegeformular mit Bienenstand-/
Volkstyp-Auswahl; /colonies/[id]: Bearbeiten, Aktionen (Umsetzen,
Ableger bilden, Vereinigen, Aufloesen je als Dialog/Button) und
Historie-Anzeige. Aktionen deaktiviert, sobald das Volk nicht mehr
ACTIVE ist (Frontend-Pendant zum neuen Backend-Guard).

Beim Live-Testen im Browser gefunden und behoben:
- Echter Root-Cause fuer den fruehren Session-Abbruch nach Reload: der
  Refresh-Token ist einmalig/rotierend, und React StrictMode ruft den
  Session-Restore-Effect im Dev-Modus doppelt auf. Der vorherige
  AbortController-Fix verhinderte nur, dass der Client die verworfene
  Antwort nutzt - er verhinderte NICHT, dass die zweite Anfrage bereits
  serverseitig verarbeitet wurde, bevor abort() griff. Fix: echtes
  Request-Deduplizieren in refreshRequest() (gemeinsames In-Flight-
  Promise) statt Abbruchversuch - der Standardansatz fuer rotierende
  Refresh-Token.
- Historie-Text beim Vereinigen war fuer die aufnehmende Seite falsch
  ("Entstanden durch Vereinigung" impliziert Neuanlage) - jetzt
  "Anderes Volk eingegliedert".

Nav-Leiste und proxy.ts-Matcher um /colonies erweitert.

9 Vitest-Tests, Lint, Typecheck und Build gruen. Kompletter Flow
(Anlegen, Umsetzen, Ableger bilden, Vereinigen, Aufloesen, Historie)
live im Browser gegen den echten Server verifiziert, inkl. Rollen-
filterung in den Aktions-Dialogen.
2026-08-21 18:21:10 +02:00
Nick Szaunig a71b31df38 fix(backend): Status-Guard fuer Move/Split/Merge auf inaktiven Voelkern
Beim Live-Test im Browser gefunden: move/split/merge liessen sich auch
auf einem bereits DISSOLVED/MERGED-Volk aufrufen und wuerden dort
klaglos durchlaufen - ein Datenintegritaetsproblem, kein reines
UI-Detail. assertActive() wirft jetzt ConflictException (409), wenn
das betroffene Volk (bzw. bei merge: Ziel- und alle zu vereinigenden
Voelker) nicht ACTIVE ist.

Neuer Unit-Test + neuer e2e-Test (dissolve, danach move -> 409).
2026-08-21 18:20:48 +02:00
Nick Szaunig d3f321f1b5 feat(backend): Voelker-Modul (Modul 3)
ColoniesModule: CRUD + Move/Split/Merge/Dissolve/History, entsprechend
Lastenheft §4.4 (Lebenszyklus eines Volkes):
- move: Standortwechsel, protokolliert in ColonyApiaryHistory.
- split: erzeugt Ableger als neues Volk, Abstammung ueber
  ColonyLineage(SPLIT, von Mutter- zu Ablegervolk).
- merge: vereinigtes Volk bleibt historisch erhalten (status MERGED,
  deactivatedAt gesetzt statt geloescht), ColonyLineage(MERGE) je
  vereinigtem Volk zum Zielvolk.
- dissolve: Volk wird deaktiviert (status DISSOLVED), Dokumentation
  bleibt erhalten.
- history: aggregiert Standort-Historie, Koeniginnen-Historie und
  Abstammungslinien (als Quelle und als Ergebnis).

Move/Split/Merge laufen transaktional (prisma.$transaction). Rollen wie
bei Apiaries: Lesen offen, Schreiben auf ADMIN/BEEKEEPER beschraenkt.

9 Unit-Tests + 6 e2e-Tests (inkl. vollstaendigem Move->Split->Merge->
Dissolve-Flow und Rollenpruefung), Lint, Typecheck und Build gruen.
2026-08-21 09:06:51 +02:00
Nick Szaunig d59153a697 feat(frontend): Bienenstaende-Views (Modul 2)
/apiaries: Liste mit Status-Badge; /apiaries/new: Anlegen-Formular;
/apiaries/[id]: Bearbeiten (Name/Standort/Adresse/Notizen) + Deaktivieren.
Editierbares Formular liest den Ausgangszustand direkt aus der geladenen
Apiary (kein useEffect+setState-Sync, React-Key-Reset-Pattern statt
Effect - vermeidet kaskadierende Renders).

(app)/layout.tsx: einfache Nav-Leiste (Bienenstände fuer alle, Benutzer
nur fuer Admins) - Platzhalter bis zur echten Bottom-Nav/Sidebar aus
Modul 15. proxy.ts-Matcher um /apiaries/* erweitert.

Live im Browser gefunden+behoben: Base-UI-Button meldete fehlende
native Button-Semantik beim Rendern als Link (`nativeButton={false}`
noetig, wenn Button auf ein <a> zeigt).

8 Vitest-Tests, Lint, Typecheck und Build gruen. Kompletter Flow
(Anlegen, Liste, Bearbeiten, Deaktivieren, Navigation) live verifiziert.
2026-08-21 08:59:18 +02:00
Nick Szaunig 5c92c810e1 feat(backend): Bienenstaende-Modul (Modul 2)
ApiariesModule: CRUD + Deactivate. Lesen fuer alle authentifizierten
Rollen offen, Schreiben (Anlegen/Aendern/Deaktivieren) auf ADMIN und
BEEKEEPER beschraenkt (Lastenheft §3.2: Imker verwaltet Bienenstaende).
Audit-Log-Eintraege bei Create/Update/Deactivate ueber AuditLogService.

4 Unit-Tests + 4 e2e-Tests (inkl. Rollenpruefung READONLY vs. BEEKEEPER),
Lint, Typecheck und Build gruen.
2026-08-21 08:50:50 +02:00
Nick Szaunig 029484f9d5 feat(frontend): Login + Benutzerverwaltung (Modul 1)
/login: Formular gegen AuthProvider (Access-Token im Memory, Refresh
per httpOnly-Cookie), Fehlermeldung bei falschen Zugangsdaten.

(app)/layout.tsx: geschuetztes Layout, leitet ohne Session zu /login um,
Header mit Nutzer-E-Mail + Abmelden. settings/layout.tsx: zusaetzliches
Admin-Gate fuer /settings/users.

/settings/users: Liste, Anlegen-Dialog (shadcn/Base UI Dialog+Select),
Deaktivieren - alles ueber TanStack Query gegen die Users-API.

proxy.ts (Next 16 Nachfolger von middleware.ts): optimistische
Cookie-Praesenz-Pruefung fuer /login und /settings/*, echte
Autorisierung bleibt serverseitig (RolesGuard).

Backend-Fixes waehrend Browser-Verifikation gefunden und behoben:
- CORS fehlte komplett (app.enableCors, FRONTEND_ORIGIN) - jeder
  Cross-Origin-Request von :3000 nach :3001 wurde geblockt.
- React-StrictMode-Doppel-Effect liess zwei parallele Refresh-Aufrufe
  laufen; da Refresh-Tokens rotierend/einmalig sind, gewann einer und
  der andere bekam 401 -> Nutzer flog nach jedem Reload aus der Session.
  Fix: AbortController im Session-Restore-Effect.
- Manifest verwies auf nicht existente PNG-Icons (404); durch
  public/icon.svg ersetzt.

7 Vitest-Tests (Login-Formular, Users-Liste, JWT-Decode), Lint,
Typecheck und Build gruen. Kompletter Flow (Login, Reload-Persistenz,
Benutzer anlegen/deaktivieren, Abmelden, Redirect ohne Session) live
im Browser gegen den echten Server verifiziert.
2026-08-21 08:45:37 +02:00
Nick Szaunig 370102387f fix(backend): Refresh-Token als httpOnly-Cookie statt Response-Body
ARCHITECTURE.md §3 legt fest: Access-Token im Memory/Context, Refresh-Token
als httpOnly-Cookie. Vorherige Implementierung gab beide Tokens im JSON-Body
zurueck - vor dem Frontend-Aufbau (das genau gegen diesen Vertrag baut)
korrigiert.

/api/v1/auth/login und /refresh setzen jetzt ein httpOnly-Cookie
(Path /api/v1/auth, SameSite=Lax, secure in production) und liefern nur
noch { accessToken } im Body. /refresh und /logout lesen den Refresh-Token
aus dem Cookie statt aus dem Request-Body.

e2e-Tests und Live-Smoke-Test (curl mit Cookie-Jar) verifizieren
Login/Rotation/Logout-Invalidierung. 12 e2e- + 26 Unit-Tests, Lint,
Typecheck und Build gruen.
2026-08-21 08:27:58 +02:00
Nick Szaunig ae8f6d4435 feat(backend): Auth/Users/Audit-Modul (Modul 1)
AuthModule: Login/Refresh/Logout mit JWT-Access-Token + rotierendem,
gehashtem Refresh-Token (RefreshToken-Tabelle). JwtAuthGuard + RolesGuard
global via APP_GUARD registriert (gilt fuer jeden kuenftigen Endpunkt),
@Public()-Decorator als Ausnahme (Auth-Endpunkte, /health).

UsersModule: CRUD + Deactivate, nur ADMIN-Rolle, Passwoerter mit bcrypt
gehasht, nie im Response enthalten.

AuditModule: AuditLogService (Grundstruktur), wird von UsersService bei
create/update/deactivate injiziert und geschrieben.

Geteilte App-Konfiguration (Prefix/Versioning/Pipes/Helmet) aus main.ts
in src/app.config.ts extrahiert; e2e-Tests nutzten das vorher nicht und
bekamen dadurch 404 auf jede /api/v1/... Route - jetzt ueber
test/utils/create-test-app.ts geteilt, betrifft alle kuenftigen
e2e-Tests gleichermassen.

prisma/seed.ts legt einen Admin-User fuer lokale Entwicklung an.

26 Unit-Tests + 11 e2e-Tests (gegen echte Postgres-Testdatenbank) gruen,
Lint/Typecheck/Build gruen, Login/Refresh/Logout/Rollenpruefung manuell
gegen laufenden Server verifiziert.
2026-08-21 08:22:16 +02:00
Nick Szaunig eae3fea957 feat: Grundgeruest fertigstellen (Backend/Frontend/K8s)
Backend: Prisma-Client auf prisma-client-js + Driver-Adapter (@prisma/adapter-pg)
umgestellt (Prisma 7 verlangt Adapter, ESM-Client brach an Jest), erste Migration
erzeugt und angewendet, /api/v1 Versioning, Swagger unter /api/v1/docs, Helmet,
globale ValidationPipe, PrismaModule, HealthModule (/health, /health/ready mit
DB-Check), tsconfig.build.json Root-Dir-Fix (dist/main.js statt dist/src/main.js).

Frontend: Tailwind v4 + shadcn/ui initialisiert, TanStack Query Provider, PWA
Manifest (app/manifest.ts), Vitest + Testing Library Setup, next.config output
standalone.

deploy/k8s: Dockerfiles (Backend/Frontend, Multi-Stage) + Deployment/Service/
Ingress/ConfigMap/Secret-Vorlagen fuer beide Projekte.

Lokale Dev-/Test-Postgres-Instanz unter ApiCore-Backend/.devdb angelegt (eigene
Rolle, kein bestehendes Passwort noetig), .env/.env.test lokal befuellt.

Lint, Typecheck, Tests und Build sind fuer Backend und Frontend gruen; Server
wurde lokal gestartet und /health, /health/ready, /api/v1/docs manuell verifiziert.
2026-08-21 05:17:26 +02:00
Nick Szaunig c4a2d0648e chore: planning docs + backend/frontend scaffold + MVP Prisma schema
- CLAUDE.md, ARCHITECTURE.md, TASKS.md per Lastenheft-Vorgabe
- ApiCore-Backend: NestJS scaffold, Prisma 7 (DATABASE_URL via prisma.config.ts)
- ApiCore-Frontend: Next.js App Router scaffold (TS, Tailwind, ESLint)
- prisma/schema.prisma: alle MVP-Entitaeten aus Abschnitt 13/4.2-4.22/26,
  validiert und Client generiert

Grundgeruest (TASKS.md #0) noch nicht vollstaendig: shadcn/ui, TanStack Query,
PWA-Manifest, deploy/k8s/, Dockerfiles fehlen noch.
2026-08-21 04:48:16 +02:00