fix: stabilize build and archive configs
This commit is contained in:
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@@ -0,0 +1 @@
|
|||||||
|
app/epd/_archive/
|
||||||
@@ -102,7 +102,7 @@ export async function PUT(
|
|||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
error: 'Validatiefout',
|
error: 'Validatiefout',
|
||||||
details: result.error.errors.map(e => ({
|
details: result.error.issues.map(e => ({
|
||||||
field: e.path.join('.'),
|
field: e.path.join('.'),
|
||||||
message: e.message,
|
message: e.message,
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ import { z } from 'zod';
|
|||||||
const CreateIntakeSchema = z.object({
|
const CreateIntakeSchema = z.object({
|
||||||
patient_id: z.string().uuid('Patient ID moet een geldige UUID zijn'),
|
patient_id: z.string().uuid('Patient ID moet een geldige UUID zijn'),
|
||||||
title: z.string().min(1, 'Titel is verplicht'),
|
title: z.string().min(1, 'Titel is verplicht'),
|
||||||
department: z.enum(['Volwassenen', 'Jeugd', 'Ouderen'], {
|
department: z.enum(['Volwassenen', 'Jeugd', 'Ouderen']),
|
||||||
errorMap: () => ({ message: 'Afdeling moet Volwassenen, Jeugd of Ouderen zijn' }),
|
|
||||||
}),
|
|
||||||
start_date: z.string().min(1, 'Startdatum is verplicht'),
|
start_date: z.string().min(1, 'Startdatum is verplicht'),
|
||||||
psychologist_id: z.string().uuid().optional(),
|
psychologist_id: z.string().uuid().optional(),
|
||||||
notes: z.string().optional(),
|
notes: z.string().optional(),
|
||||||
@@ -96,7 +94,7 @@ export async function POST(request: NextRequest) {
|
|||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
{
|
{
|
||||||
error: 'Validatiefout',
|
error: 'Validatiefout',
|
||||||
details: result.error.errors.map(e => ({
|
details: result.error.issues.map(e => ({
|
||||||
field: e.path.join('.'),
|
field: e.path.join('.'),
|
||||||
message: e.message,
|
message: e.message,
|
||||||
})),
|
})),
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export async function DELETE(
|
|||||||
return NextResponse.json({ error: 'Document niet gevonden' }, { status: 404 });
|
return NextResponse.json({ error: 'Document niet gevonden' }, { status: 404 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (document.file_path) {
|
||||||
const { error: deleteError } = await supabaseAdmin.storage
|
const { error: deleteError } = await supabaseAdmin.storage
|
||||||
.from(BUCKET)
|
.from(BUCKET)
|
||||||
.remove([document.file_path]);
|
.remove([document.file_path]);
|
||||||
@@ -46,6 +47,7 @@ export async function DELETE(
|
|||||||
console.error('Storage delete error:', deleteError);
|
console.error('Storage delete error:', deleteError);
|
||||||
// Don't stop here; attempt DB delete even if storage failed
|
// Don't stop here; attempt DB delete even if storage failed
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const { error: dbError } = await supabase
|
const { error: dbError } = await supabase
|
||||||
.from('screening_documents')
|
.from('screening_documents')
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ async function ensureBucket() {
|
|||||||
if (createError && !createError.message.includes('already exists')) {
|
if (createError && !createError.message.includes('already exists')) {
|
||||||
throw createError;
|
throw createError;
|
||||||
}
|
}
|
||||||
} else if (error && !error.message.includes('not found')) {
|
} else if (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { getIntakeById } from '../../actions';
|
import { getIntakeById } from '../actions';
|
||||||
import { IntakeHeader } from './components/intake-header';
|
import { IntakeHeader } from './components/intake-header';
|
||||||
import { IntakeTabs } from './components/intake-tabs';
|
import { IntakeTabs } from './components/intake-tabs';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
|
|
||||||
@@ -105,7 +106,14 @@ const HeroSection = React.forwardRef<HTMLDivElement, HeroSectionProps>(
|
|||||||
<motion.header className="mb-12" variants={itemVariants}>
|
<motion.header className="mb-12" variants={itemVariants}>
|
||||||
{logo && (
|
{logo && (
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<img src={logo.url} alt={logo.alt} className="mr-3 h-8" />
|
<Image
|
||||||
|
src={logo.url}
|
||||||
|
alt={logo.alt}
|
||||||
|
width={120}
|
||||||
|
height={32}
|
||||||
|
className="mr-3 h-8 w-auto"
|
||||||
|
unoptimized
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
{logo.text && <p className="text-lg font-bold text-foreground">{logo.text}</p>}
|
{logo.text && <p className="text-lg font-bold text-foreground">{logo.text}</p>}
|
||||||
{slogan && <p className="text-xs tracking-wider text-muted-foreground">{slogan}</p>}
|
{slogan && <p className="text-xs tracking-wider text-muted-foreground">{slogan}</p>}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import Image from 'next/image';
|
||||||
import { Eye, EyeOff, LogIn } from 'lucide-react';
|
import { Eye, EyeOff, LogIn } from 'lucide-react';
|
||||||
|
|
||||||
const AnimatedSignIn: React.FC = () => {
|
const AnimatedSignIn: React.FC = () => {
|
||||||
@@ -66,12 +67,15 @@ const AnimatedSignIn: React.FC = () => {
|
|||||||
<div className="hidden md:block w-full md:w-3/5 bg-gray-100 p-6 animate-fade-in">
|
<div className="hidden md:block w-full md:w-3/5 bg-gray-100 p-6 animate-fade-in">
|
||||||
<div className="grid grid-cols-2 grid-rows-3 gap-4 h-full overflow-hidden">
|
<div className="grid grid-cols-2 grid-rows-3 gap-4 h-full overflow-hidden">
|
||||||
{/* Top left - Person working */}
|
{/* Top left - Person working */}
|
||||||
<div className="overflow-hidden rounded-xl">
|
<div className="relative overflow-hidden rounded-xl aspect-[4/3]">
|
||||||
<img
|
<Image
|
||||||
src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d"
|
src="https://images.unsplash.com/photo-1486312338219-ce68d2c6f44d"
|
||||||
alt="Person working"
|
alt="Person working"
|
||||||
className="w-full h-full object-cover"
|
fill
|
||||||
|
className="object-cover"
|
||||||
style={{ opacity: 0.9 }}
|
style={{ opacity: 0.9 }}
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
|
priority
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -92,22 +96,26 @@ const AnimatedSignIn: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Middle left - Person at computer */}
|
{/* Middle left - Person at computer */}
|
||||||
<div className="overflow-hidden rounded-xl">
|
<div className="relative overflow-hidden rounded-xl aspect-[4/3]">
|
||||||
<img
|
<Image
|
||||||
src="https://images.unsplash.com/photo-1581091226825-a6a2a5aee158"
|
src="https://images.unsplash.com/photo-1581091226825-a6a2a5aee158"
|
||||||
alt="Person at computer"
|
alt="Person at computer"
|
||||||
className="w-full h-full object-cover"
|
fill
|
||||||
|
className="object-cover"
|
||||||
style={{ opacity: 0.9 }}
|
style={{ opacity: 0.9 }}
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Middle right - Office space */}
|
{/* Middle right - Office space */}
|
||||||
<div className="overflow-hidden rounded-xl">
|
<div className="relative overflow-hidden rounded-xl aspect-[4/3]">
|
||||||
<img
|
<Image
|
||||||
src="https://images.unsplash.com/photo-1605810230434-7631ac76ec81"
|
src="https://images.unsplash.com/photo-1605810230434-7631ac76ec81"
|
||||||
alt="Office space"
|
alt="Modern office"
|
||||||
className="w-full h-full object-cover"
|
fill
|
||||||
style={{ opacity: 0.9 }}
|
className="object-cover"
|
||||||
|
style={{ opacity: 0.95 }}
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -128,12 +136,14 @@ const AnimatedSignIn: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Bottom right - Library */}
|
{/* Bottom right - Library */}
|
||||||
<div className="overflow-hidden rounded-xl">
|
<div className="relative overflow-hidden rounded-xl aspect-[4/3]">
|
||||||
<img
|
<Image
|
||||||
src="https://images.unsplash.com/photo-1498050108023-c5249f4df085"
|
src="https://images.unsplash.com/photo-1498050108023-c5249f4df085"
|
||||||
alt="Desk setup"
|
alt="Team collaboration"
|
||||||
className="w-full h-full object-cover"
|
fill
|
||||||
|
className="object-cover"
|
||||||
style={{ opacity: 0.9 }}
|
style={{ opacity: 0.9 }}
|
||||||
|
sizes="(max-width: 768px) 100vw, 50vw"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
511
docs/reports/code-review-build-failures-20251123.md
Normal file
511
docs/reports/code-review-build-failures-20251123.md
Normal file
@@ -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<Intake[]> {
|
||||||
|
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)
|
||||||
@@ -8,6 +8,12 @@ const nextConfig = {
|
|||||||
formats: ['image/avif', 'image/webp'],
|
formats: ['image/avif', 'image/webp'],
|
||||||
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
|
||||||
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
|
||||||
|
remotePatterns: [
|
||||||
|
{
|
||||||
|
protocol: 'https',
|
||||||
|
hostname: 'images.unsplash.com'
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Experimental features for better performance
|
// Experimental features for better performance
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
"**/*.mts"
|
"**/*.mts"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules"
|
"node_modules",
|
||||||
|
"app/epd/_archive/**/*"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user