From 00ca0263826d8effea632f19b097fa8a1d9ca8fd Mon Sep 17 00:00:00 2001 From: colinislit Date: Sun, 23 Nov 2025 11:42:40 +0100 Subject: [PATCH] fix: stabilize build and archive configs --- .eslintignore | 1 + app/api/intakes/[intakeId]/route.ts | 2 +- app/api/intakes/route.ts | 6 +- .../documents/[documentId]/route.ts | 14 +- .../[screeningId]/documents/route.ts | 2 +- .../[id]/intakes/[intakeId]/layout.tsx | 2 +- components/ui/hero-section-2.tsx | 10 +- components/ui/sign-in.tsx | 52 +- .../code-review-build-failures-20251123.md | 511 ++++++++++++++++++ next.config.mjs | 6 + tsconfig.json | 3 +- 11 files changed, 573 insertions(+), 36 deletions(-) create mode 100644 .eslintignore create mode 100644 docs/reports/code-review-build-failures-20251123.md diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a779f5e --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +app/epd/_archive/ diff --git a/app/api/intakes/[intakeId]/route.ts b/app/api/intakes/[intakeId]/route.ts index ca9e7f7..a9b2a13 100644 --- a/app/api/intakes/[intakeId]/route.ts +++ b/app/api/intakes/[intakeId]/route.ts @@ -102,7 +102,7 @@ export async function PUT( return NextResponse.json( { error: 'Validatiefout', - details: result.error.errors.map(e => ({ + details: result.error.issues.map(e => ({ field: e.path.join('.'), message: e.message, })), diff --git a/app/api/intakes/route.ts b/app/api/intakes/route.ts index f601f0c..4d4a4b6 100644 --- a/app/api/intakes/route.ts +++ b/app/api/intakes/route.ts @@ -13,9 +13,7 @@ import { z } from 'zod'; const CreateIntakeSchema = z.object({ patient_id: z.string().uuid('Patient ID moet een geldige UUID zijn'), title: z.string().min(1, 'Titel is verplicht'), - department: z.enum(['Volwassenen', 'Jeugd', 'Ouderen'], { - errorMap: () => ({ message: 'Afdeling moet Volwassenen, Jeugd of Ouderen zijn' }), - }), + department: z.enum(['Volwassenen', 'Jeugd', 'Ouderen']), start_date: z.string().min(1, 'Startdatum is verplicht'), psychologist_id: z.string().uuid().optional(), notes: z.string().optional(), @@ -96,7 +94,7 @@ export async function POST(request: NextRequest) { return NextResponse.json( { error: 'Validatiefout', - details: result.error.errors.map(e => ({ + details: result.error.issues.map(e => ({ field: e.path.join('.'), message: e.message, })), diff --git a/app/api/screenings/[screeningId]/documents/[documentId]/route.ts b/app/api/screenings/[screeningId]/documents/[documentId]/route.ts index 29f4681..f471443 100644 --- a/app/api/screenings/[screeningId]/documents/[documentId]/route.ts +++ b/app/api/screenings/[screeningId]/documents/[documentId]/route.ts @@ -38,13 +38,15 @@ export async function DELETE( return NextResponse.json({ error: 'Document niet gevonden' }, { status: 404 }); } - const { error: deleteError } = await supabaseAdmin.storage - .from(BUCKET) - .remove([document.file_path]); + if (document.file_path) { + const { error: deleteError } = await supabaseAdmin.storage + .from(BUCKET) + .remove([document.file_path]); - if (deleteError) { - console.error('Storage delete error:', deleteError); - // Don't stop here; attempt DB delete even if storage failed + if (deleteError) { + console.error('Storage delete error:', deleteError); + // Don't stop here; attempt DB delete even if storage failed + } } const { error: dbError } = await supabase diff --git a/app/api/screenings/[screeningId]/documents/route.ts b/app/api/screenings/[screeningId]/documents/route.ts index a73f91e..fe5ad70 100644 --- a/app/api/screenings/[screeningId]/documents/route.ts +++ b/app/api/screenings/[screeningId]/documents/route.ts @@ -14,7 +14,7 @@ async function ensureBucket() { if (createError && !createError.message.includes('already exists')) { throw createError; } - } else if (error && !error.message.includes('not found')) { + } else if (error) { throw error; } } diff --git a/app/epd/_archive/clients_backup_20251122/[id]/intakes/[intakeId]/layout.tsx b/app/epd/_archive/clients_backup_20251122/[id]/intakes/[intakeId]/layout.tsx index 2b584a0..fecca63 100644 --- a/app/epd/_archive/clients_backup_20251122/[id]/intakes/[intakeId]/layout.tsx +++ b/app/epd/_archive/clients_backup_20251122/[id]/intakes/[intakeId]/layout.tsx @@ -1,4 +1,4 @@ -import { getIntakeById } from '../../actions'; +import { getIntakeById } from '../actions'; import { IntakeHeader } from './components/intake-header'; import { IntakeTabs } from './components/intake-tabs'; import { notFound } from 'next/navigation'; diff --git a/components/ui/hero-section-2.tsx b/components/ui/hero-section-2.tsx index f6842cb..f55ec1d 100644 --- a/components/ui/hero-section-2.tsx +++ b/components/ui/hero-section-2.tsx @@ -1,6 +1,7 @@ 'use client' import React from 'react'; +import Image from 'next/image'; import { cn } from "@/lib/utils"; import { motion } from 'framer-motion'; @@ -105,7 +106,14 @@ const HeroSection = React.forwardRef( {logo && (
- {logo.alt} + {logo.alt}
{logo.text &&

{logo.text}

} {slogan &&

{slogan}

} diff --git a/components/ui/sign-in.tsx b/components/ui/sign-in.tsx index 2dd0ea2..7709f3d 100644 --- a/components/ui/sign-in.tsx +++ b/components/ui/sign-in.tsx @@ -1,6 +1,7 @@ 'use client' import React, { useState, useEffect } from 'react'; +import Image from 'next/image'; import { Eye, EyeOff, LogIn } from 'lucide-react'; const AnimatedSignIn: React.FC = () => { @@ -66,12 +67,15 @@ const AnimatedSignIn: React.FC = () => {
{/* Top left - Person working */} -
- Person working + Person working
@@ -92,22 +96,26 @@ const AnimatedSignIn: React.FC = () => {
{/* Middle left - Person at computer */} -
- Person at computer + Person at computer
{/* Middle right - Office space */} -
- Office space + Modern office
@@ -128,12 +136,14 @@ const AnimatedSignIn: React.FC = () => {
{/* Bottom right - Library */} -
- Desk setup + Team collaboration
diff --git a/docs/reports/code-review-build-failures-20251123.md b/docs/reports/code-review-build-failures-20251123.md new file mode 100644 index 0000000..2d58196 --- /dev/null +++ b/docs/reports/code-review-build-failures-20251123.md @@ -0,0 +1,511 @@ +# Code Review Rapport: Build Failures en Architectuur Analyse + +**Datum:** 2025-11-23 +**Reviewer:** Lead Developer +**Project:** Mini EPD Prototype (v0.1.0) +**Branch:** intake +**Status:** πŸ”΄ CRITICAL - Build gefaald + +--- + +## Executive Summary + +De `pnpm build` commando faalt doordat gearchiveerde TypeScript bestanden in `/app/epd/_archive/` worden meegecompileerd door de TypeScript compiler, ondanks dat deze code niet meer actief gebruikt wordt. De root cause is een ontbrekende configuratie in `tsconfig.json` om de archive directory uit te sluiten van compilatie. + +**Impact:** Build failures blokkeren deployment naar productie en CI/CD pipelines. + +**Prioriteit:** P0 - Kritisch +**Geschatte Fix Tijd:** 5 minuten +**Complexiteit:** Laag + +--- + +## 1. Probleem Analyse + +### 1.1 Symptomen + +```bash +Failed to compile. + +./app/epd/_archive/clients_backup_20251122/[id]/intakes/actions.ts:3:10 +Type error: Module '"@/lib/supabase/server"' declares 'createClient' locally, +but it is not exported. + + 3 | import { createClient } from '@/lib/supabase/server'; + | ^ +``` + +**Aantal BeΓ―nvloede Bestanden:** 28 TypeScript bestanden in archive +**Fout Type:** Type error (TS2305 - Export niet gevonden) +**Build Tool:** Next.js 15 + TypeScript 5.x + +### 1.2 Root Cause Analyse + +#### Primaire Oorzaak +De `tsconfig.json` exclude list bevat alleen `node_modules`, maar **niet** de `app/epd/_archive/` directory: + +```json +// tsconfig.json:39-41 +"exclude": [ + "node_modules" +] +``` + +Dit betekent dat alle `.ts` en `.tsx` bestanden in de archive **nog steeds worden gecompileerd** tijdens `pnpm build`. + +#### Secundaire Oorzaken + +1. **API Breaking Change in `lib/supabase/server.ts`** + - **Huidige Export:** `supabaseAdmin` (service role client) + - **Oude Code Verwacht:** `createClient` functie + - **Locatie:** `lib/supabase/server.ts:20-25` + +```typescript +// lib/supabase/server.ts - Huidige export +export const supabaseAdmin = createClient(supabaseUrl, supabaseServiceRoleKey, { + auth: { + autoRefreshToken: false, + persistSession: false, + }, +}) +// ❌ Geen export van 'createClient' +``` + +2. **Incomplete Migratie Cleanup** + - Archive aangemaakt (βœ…): `app/epd/_archive/clients_backup_20251122/` + - Build configuratie niet aangepast (❌): `tsconfig.json` exclude list + - Documentatie wel bijgewerkt (βœ…): `docs/migratie-clients-naar-patients.md` + +--- + +## 2. Architectuur Review + +### 2.1 Migratie Status + +Volgens `docs/migratie-clients-naar-patients.md` (v1.0, datum: 2025-11-22) is er een volledige migratie uitgevoerd van `/clients/` naar `/patients/` route met de volgende kenmerken: + +#### Gekozen Architectuur: Custom API (Optie B) + +**Oude Aanpak (gearchiveerd):** +```typescript +// Direct Supabase access in server actions +import { createClient } from '@/lib/supabase/server'; + +export async function getIntakesByClientId(clientId: string) { + const supabase = await createClient(); + const { data } = await supabase.from('intakes').select('*') + // ... +} +``` + +**Nieuwe Aanpak (actief):** +```typescript +// API-based approach via Custom API endpoints +export async function getIntakesByPatientId(patientId: string): Promise { + const response = await fetch(`/api/intakes?patientId=${patientId}`) + const data: IntakeListResponse = await response.json() + return data.intakes +} +``` + +### 2.2 Impact Scope + +#### BeΓ―nvloede Modules + +| Module | Gearchiveerd | Actief | Status | +|--------|-------------|---------|--------| +| Patient List | `/clients/` | `/patients/` | βœ… Gemigreerd | +| Patient CRUD | `/clients/actions.ts` | `/patients/actions.ts` | βœ… Gemigreerd | +| Intake Module | `/clients/[id]/intakes/` | `/patients/[id]/intakes/` | βœ… Gemigreerd | +| Intake API | N/A | `/api/intakes/` | βœ… Nieuw gebouwd | + +#### Statistieken + +- **Gearchiveerde LOC:** ~538 lijnen (Intake module) + ~400 lijnen (Client module) = **~938 LOC** +- **Aantal gearchiveerde bestanden:** 28 TypeScript bestanden +- **Actieve imports naar `createClient`:** 0 (correct) +- **Gearchiveerde imports naar `createClient`:** 2 bestanden (foutief) + +### 2.3 Git Status Review + +**Modified Files (uncommitted):** +``` +M app/api/intakes/[intakeId]/route.ts +M app/api/intakes/route.ts +M app/api/screenings/[screeningId]/documents/[documentId]/route.ts +M app/api/screenings/[screeningId]/documents/route.ts +M app/epd/_archive/clients_backup_20251122/[id]/intakes/[intakeId]/layout.tsx +M components/ui/hero-section-2.tsx +M components/ui/sign-in.tsx +M next.config.mjs +``` + +**Observaties:** +- βœ… API routes zijn recent aangepast (intake + screening modules) +- ⚠️ Archive bestand is modified (`layout.tsx`) - waarschijnlijk post-archive edit +- βœ… UI componenten zijn aangepast (onafhankelijk van deze issue) +- βœ… Next.js config aangepast (performance optimizations) + +--- + +## 3. Code Quality Assessment + +### 3.1 Positieve Aspecten βœ… + +1. **Goede Architectuur Keuze** + - Custom API benadering is pragmatisch en past bij MVP fase + - Scheiding tussen FHIR (Patient/Practitioner) en Custom (Intakes) is logisch + - Future-proof: FHIR Encounter migratie is nog mogelijk + +2. **Uitstekende Documentatie** + - `docs/migratie-clients-naar-patients.md` is zeer gedetailleerd (656 regels) + - Story point breakdown en risk analysis aanwezig + - API documentatie in `docs/api/intakes-api.md` + +3. **Type Safety** + - Strikte TypeScript configuratie (`strict: true`) + - Zod validatie in nieuwe API endpoints + - Dedicated type definitions in `lib/types/intake.ts` + +4. **Error Handling** + - Auth redirect detection in API calls + - Proper HTTP status codes (200, 201, 404, 400) + - Validation error messages in Dutch (UX friendly) + +### 3.2 Verbeterpunten ⚠️ + +1. **Build Configuratie (CRITICAL)** + - Archive directory niet uitgesloten in `tsconfig.json` + - Geen `.eslintignore` of `.prettierignore` voor archive + - Geen build-time verificatie dat archive wordt genegeerd + +2. **Git Hygiene** + - 8 uncommitted modified files op feature branch + - Archive bestand is modified na archivering + - Geen `.gitattributes` voor linguist om archive te negeren + +3. **Testing Gap** + - Volgens migratieplan: Tests nog niet uitgevoerd (checkboxes unchecked) + - Geen geautomatiseerde tests voor API endpoints + - Geen regression tests gedraaid + +4. **Incomplete Cleanup** + - Archive bevat nog modificaties (zie git status) + - Documentatie verwijst naar nog uit te voeren taken + - Fase 5 (Testing & Validatie) nog niet afgerond + +--- + +## 4. Beveiligingsanalyse + +### 4.1 PotentiΓ«le Risico's + +1. **Service Role Key Exposure (LOW RISK - Gemitigeerd)** + ```typescript + // lib/supabase/server.ts:4 + const supabaseServiceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY! + ``` + - βœ… Correct: Alleen server-side gebruik + - βœ… Bypass RLS is gedocumenteerd en intentioneel + - βœ… Warning in comments: "NEVER expose to client!" + +2. **Authentication Handling (GOOD)** + ```typescript + // Cookies worden correct doorgegeven in nieuwe API calls + const cookieHeader = await getCookieHeader(); + const response = await fetch(url, { + headers: { Cookie: cookieHeader } + }); + ``` + - βœ… Auth cookies worden forwarded naar API + - βœ… HTML redirect detection voor unauthorized access + +3. **Input Validatie (GOOD)** + - βœ… Zod schemas in nieuwe API endpoints + - βœ… UUID validatie voor patient/intake IDs + - βœ… SQL injection risico laag (prepared statements via Supabase) + +### 4.2 Recommendations + +- Voeg `SUPABASE_SERVICE_ROLE_KEY` toe aan `.env.example` met duidelijke warning +- Implementeer rate limiting op `/api/intakes` endpoints +- Overweeg CSRF protection voor POST/PUT/DELETE operations + +--- + +## 5. Performance Review + +### 5.1 Current Implementation + +**Next.js Config Optimizations:** +```javascript +// next.config.mjs +experimental: { + optimizePackageImports: ['lucide-react', '@react-three/fiber', '@react-three/drei'], +}, +webpack: { + splitChunks: { + three: { // Heavy 3D library isolated + name: 'three', + test: /[\\/]node_modules[\\/](three|@react-three)[\\/]/, + priority: 30, + }, + }, +} +``` + +**Assessment:** +- βœ… Gzip compression enabled +- βœ… Image optimization configured (AVIF/WebP) +- βœ… Code splitting voor heavy libraries +- ⚠️ Geen caching strategie voor API calls +- ⚠️ Geen lazy loading in intake components + +### 5.2 API Performance Concerns + +**Oude Aanpak (Direct Supabase):** +- 1 round trip naar database +- Latency: ~10-50ms (lokaal), ~50-150ms (remote) + +**Nieuwe Aanpak (Custom API):** +- 2 round trips: Server Action β†’ API Route β†’ Supabase +- Latency: ~20-100ms (lokaal), ~100-300ms (remote) +- **Overhead:** ~10-150ms extra + +**Mitigatie Opties:** +1. Implementeer response caching (SWR of React Query) +2. Gebruik `cache: 'force-cache'` voor static data +3. Optimistic UI updates voor mutations + +--- + +## 6. Aanbevelingen + +### 6.1 Immediate Actions (P0 - Kritisch) + +#### βœ… Fix #1: Update tsconfig.json +**Priority:** P0 +**Effort:** 5 min +**Impact:** HIGH - Blokkeert alle builds + +```json +// tsconfig.json +{ + "exclude": [ + "node_modules", + "app/epd/_archive/**/*" + ] +} +``` + +**Rationale:** TypeScript compiler moet archive volledig negeren. + +#### βœ… Fix #2: Add .eslintignore +**Priority:** P0 +**Effort:** 2 min +**Impact:** MEDIUM - Voorkomt linting errors + +``` +# .eslintignore +app/epd/_archive/ +``` + +#### βœ… Fix #3: Verify Build +**Priority:** P0 +**Effort:** 5 min +**Impact:** HIGH - Valideer fix werkt + +```bash +pnpm build +# Should complete without errors +``` + +### 6.2 Short-term Actions (P1 - Hoog) + +#### πŸ“‹ Action #1: Clean Git Status +**Priority:** P1 +**Effort:** 15 min + +```bash +# Commit meaningful changes +git add app/api/intakes/ +git add app/api/screenings/ +git commit -m "feat: update intake and screening API endpoints" + +# Review and commit UI changes +git add components/ui/ +git commit -m "chore: update UI components" + +# Commit config changes +git add next.config.mjs +git commit -m "chore: add performance optimizations" + +# Reset archive modifications (if accidental) +git checkout -- app/epd/_archive/ +``` + +#### πŸ“‹ Action #2: Complete Migration Testing +**Priority:** P1 +**Effort:** 2-4 hours + +Volgens `docs/migratie-clients-naar-patients.md` Fase 5: +- [ ] Run functional tests (5.1) +- [ ] Run API tests (5.2) +- [ ] Run regression tests (5.3) +- [ ] Document results + +#### πŸ“‹ Action #3: Add .gitattributes +**Priority:** P1 +**Effort:** 5 min + +``` +# .gitattributes +app/epd/_archive/** linguist-vendored +``` + +**Rationale:** GitHub telt archive niet mee in repository statistics. + +### 6.3 Medium-term Actions (P2 - Medium) + +#### πŸ”§ Enhancement #1: API Response Caching +**Priority:** P2 +**Effort:** 4-8 hours + +Implementeer SWR of TanStack Query voor intake data: +```typescript +// Example with SWR +import useSWR from 'swr' + +export function useIntakes(patientId: string) { + const { data, error, mutate } = useSWR( + `/api/intakes?patientId=${patientId}`, + fetcher, + { revalidateOnFocus: false } + ) + return { intakes: data?.intakes, error, refresh: mutate } +} +``` + +#### πŸ”§ Enhancement #2: Automated Testing +**Priority:** P2 +**Effort:** 1-2 days + +- Unit tests voor API routes (Jest/Vitest) +- Integration tests voor server actions +- E2E tests voor kritische flows (Playwright) + +#### πŸ”§ Enhancement #3: CI/CD Pipeline +**Priority:** P2 +**Effort:** 4-8 hours + +```yaml +# .github/workflows/ci.yml +name: CI +on: [push, pull_request] +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: pnpm install + - run: pnpm build + - run: pnpm test # When tests exist +``` + +--- + +## 7. Conclusies + +### 7.1 Overall Assessment + +**Code Kwaliteit:** β­β­β­β­β˜† (4/5) +- Goede architectuur keuzes +- Uitstekende documentatie +- Type-safe implementatie +- Kleine configuratie issues + +**Migratie Uitvoering:** β­β­β­β˜†β˜† (3/5) +- Feature implementatie volledig +- Testing fase nog niet afgerond +- Cleanup incomplete (archive in build) +- Git hygiene kan beter + +**Beveiligingspositie:** β­β­β­β­β˜† (4/5) +- Goede auth handling +- Input validatie aanwezig +- Service role key correct gebruikt +- Kleine verbeterpunten (rate limiting, CSRF) + +### 7.2 Blockers voor Productie + +1. ❌ **Build failures** - Moet gefixed voor deployment +2. ⚠️ **Ontbrekende tests** - Verhoogt risico op regressies +3. ⚠️ **Uncommitted changes** - Moeilijk om release te taggen + +### 7.3 Aanbevolen Roadmap + +**Vandaag (2-3 uur):** +1. Fix tsconfig.json + eslintignore +2. Verify build succeeds +3. Clean git status + commit changes +4. Tag release candidate: `v0.2.0-rc.1` + +**Deze Week (1-2 dagen):** +1. Complete Fase 5 testing (volgens migratieplan) +2. Document test results +3. Deploy to staging environment +4. Tag stable release: `v0.2.0` + +**Volgende Sprint:** +1. Implement API caching (SWR/React Query) +2. Add automated tests +3. Setup CI/CD pipeline +4. Plan FHIR Encounter migration (indien gewenst) + +--- + +## 8. Appendix + +### 8.1 Betrokken Bestanden + +**Configuratie:** +- `tsconfig.json` (REQUIRES CHANGE) +- `.eslintignore` (TO BE CREATED) +- `.gitattributes` (TO BE CREATED) +- `next.config.mjs` (OK) + +**Archive (28 bestanden):** +- `app/epd/_archive/clients_backup_20251122/**/*` + +**Actieve Implementatie:** +- `app/epd/patients/[id]/intakes/` (OK) +- `app/api/intakes/` (OK) +- `lib/types/intake.ts` (OK) +- `lib/supabase/server.ts` (OK - nieuwe export) + +### 8.2 Referenties + +- Migratie Documentatie: `docs/migratie-clients-naar-patients.md` +- API Documentatie: `docs/api/intakes-api.md` +- Bouwplan v1.0: `docs/specs/UI/bouwplan-mini-epd-v1.0.md` +- CHANGELOG: `CHANGELOG.md` + +### 8.3 Metrics + +**Code Coverage:** +- Archive LOC: ~938 lijnen (deprecated) +- Active LOC: ~1200+ lijnen (geschat) +- API Routes: 2 endpoints (GET/POST/PUT/DELETE) +- Test Coverage: 0% (geen tests) + +**Build Metrics:** +- Build tijd: N/A (fails currently) +- Bundle size: N/A (geen successful build) +- Type errors: 1 (createClient import in archive) + +--- + +**Rapport Versie:** 1.0 +**Gegenereerd op:** 2025-11-23 +**Review Status:** βœ… Compleet +**Actie Vereist:** Ja - Zie Sectie 6.1 (Immediate Actions) diff --git a/next.config.mjs b/next.config.mjs index b4fddd3..81905b8 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -8,6 +8,12 @@ const nextConfig = { formats: ['image/avif', 'image/webp'], deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], + remotePatterns: [ + { + protocol: 'https', + hostname: 'images.unsplash.com' + } + ] }, // Experimental features for better performance diff --git a/tsconfig.json b/tsconfig.json index 2627c60..76c5943 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -37,6 +37,7 @@ "**/*.mts" ], "exclude": [ - "node_modules" + "node_modules", + "app/epd/_archive/**/*" ] }