Files
triqura-ecd/docs/architecture/component-organization.md
colinislit dce3943963 feat: rapportage UI refactor, speech streaming, docs & seed data
Rapportage:
- Refactor workspace into modular components (quick-actions, timeline-card, timeline-sidebar)
- Add updateReport action for inline editing
- Improve report timeline with better UX

Speech:
- Add Deepgram token API endpoint
- Add use-deepgram-streaming hook
- Add confidence-text component

Docs:
- Add architecture documentation
- Add performance optimization plan
- Add speech specs and seed data docs

Scripts & Data:
- Add seed-reports script and migration
- Update AGENTS.md guidelines

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 14:07:08 +01:00

305 lines
10 KiB
Markdown

# Component Organisatie Strategie
## Overzicht
Dit project gebruikt de **colocation pattern** voor component organisatie, een best practice in Next.js App Router architectuur.
## Twee Component Locaties
### 1. Centrale Components (`/components`)
**Doel:** Herbruikbare, generieke components die door meerdere delen van de app gebruikt worden.
**Structuur:**
```
components/
├── ui/ # Algemene UI componenten (shadcn/ui)
│ ├── button.tsx
│ ├── dialog.tsx
│ ├── dropdown-menu.tsx
│ └── ...
├── speech-recorder-streaming.tsx # Herbruikbare feature component
├── confidence-text.tsx # Herbruikbare display component
└── rich-text-editor.tsx # Herbruikbare editor component
```
**Criteria voor centrale components:**
- ✅ Gebruikt in 2+ verschillende features/routes
- ✅ Geen specifieke business logic voor één feature
- ✅ Generiek en configureerbaar via props
- ✅ Zou in een component library kunnen zitten
**Voorbeelden:**
```typescript
// ✅ Gebruikt in behandeladvies, rapportage, en andere features
import { SpeechRecorderStreaming } from '@/components/speech-recorder-streaming';
// ✅ Generieke UI component
import { Button } from '@/components/ui/button';
```
### 2. Route-Specifieke Components (`/app/.../components`)
**Doel:** Feature-specifieke components die alleen gebruikt worden binnen één route of feature.
**Structuur:**
```
app/
└── epd/
├── components/ # Gedeeld binnen EPD module
│ └── epd-sidebar.tsx
└── patients/
├── components/ # Gedeeld binnen patients feature
│ ├── patient-list.tsx
│ └── patient-form.tsx
└── [id]/
└── rapportage/
└── components/ # Specifiek voor rapportage feature
├── report-composer.tsx
├── report-timeline.tsx
└── rapportage-workspace.tsx
```
**Criteria voor route-specifieke components:**
- ✅ Gebruikt alleen binnen één feature/route
- ✅ Bevat feature-specifieke business logic
- ✅ Tight coupling met de parent route
- ✅ Geen hergebruik in andere features
**Voorbeelden:**
```typescript
// ✅ Alleen gebruikt in rapportage feature
import { ReportComposer } from './components/report-composer';
// ✅ Specifieke business logic voor behandeladvies
import { TreatmentAdviceForm } from './components/treatment-advice-form';
```
## Hiërarchie & Scope
Components worden georganiseerd op basis van hun **reuse scope**:
```
┌─────────────────────────────────────────────────────────┐
│ /components │
│ ↳ App-wide herbruikbare components │
│ (gebruikt in 2+ features) │
└─────────────────────────────────────────────────────────┘
↓ imports van
┌─────────────────────────────────────────────────────────┐
│ /app/epd/components │
│ ↳ EPD module-wide components │
│ (gedeeld tussen patient, intake, rapportage) │
└─────────────────────────────────────────────────────────┘
↓ imports van
┌─────────────────────────────────────────────────────────┐
│ /app/epd/patients/components │
│ ↳ Patient feature components │
│ (gedeeld tussen patient routes) │
└─────────────────────────────────────────────────────────┘
↓ imports van
┌─────────────────────────────────────────────────────────┐
│ /app/epd/patients/[id]/rapportage/components │
│ ↳ Rapportage page-specifieke components │
│ (alleen gebruikt in rapportage) │
└─────────────────────────────────────────────────────────┘
```
## Statistieken (Huidige State)
- **Centrale components**: 18 components
- **Route-specifieke components**: 56 components
- **Duplicaten**: 0 ✅
## Voordelen van Deze Aanpak
### 1. **Betere Code Organisation**
- Components staan dichtbij waar ze gebruikt worden
- Makkelijker te vinden en te onderhouden
- Duidelijke scope en ownership
### 2. **Betere Performance**
- Kleinere bundles per route (code splitting)
- Alleen relevante components worden geladen
- Tree-shaking werkt beter
### 3. **Betere Developer Experience**
- Minder zoeken in grote component directories
- Duidelijk wanneer een component herbruikbaar is
- Makkelijker refactoren
### 4. **Schaalbaarheid**
- Nieuwe features kunnen onafhankelijk components toevoegen
- Geen "god component folder" met 100+ bestanden
- Teams kunnen parallel werken zonder conflicts
## Decision Tree: Waar plaats ik een component?
```
Wordt de component gebruikt in 2+ verschillende features?
├─ Ja → Is het een generieke UI component (button, dialog, etc)?
│ │
│ ├─ Ja → /components/ui/{name}.tsx
│ │
│ └─ Nee → /components/{name}.tsx
└─ Nee → Wordt het gedeeld binnen een feature module?
├─ Ja → /app/{feature}/components/{name}.tsx
└─ Nee → /app/{feature}/{subfeature}/components/{name}.tsx
```
## Voorbeelden
### ✅ Goed: SpeechRecorderStreaming in centrale folder
**Waarom?** Gebruikt in meerdere features:
```typescript
// app/epd/patients/[id]/rapportage/components/report-composer.tsx
import { SpeechRecorderStreaming } from '@/components/speech-recorder-streaming';
// app/epd/patients/[id]/intakes/[intakeId]/behandeladvies/components/treatment-advice-form.tsx
import { SpeechRecorderStreaming } from '@/components/speech-recorder-streaming';
```
### ✅ Goed: ReportComposer in rapportage/components
**Waarom?** Alleen gebruikt in rapportage feature:
```typescript
// app/epd/patients/[id]/rapportage/page.tsx
import { ReportComposer } from './components/report-composer';
```
### ❌ Fout: Generieke Button in route folder
```typescript
// ❌ NIET DOEN
// app/epd/patients/components/button.tsx
export function Button() { ... }
// ✅ WEL DOEN
// components/ui/button.tsx
export function Button() { ... }
```
### ❌ Fout: Feature-specifieke component in centrale folder
```typescript
// ❌ NIET DOEN
// components/report-composer.tsx (alleen gebruikt in rapportage)
// ✅ WEL DOEN
// app/epd/patients/[id]/rapportage/components/report-composer.tsx
```
## Refactoring Workflow
### Wanneer een route-component herbruikbaar wordt:
1. **Identificeer hergebruik**
```bash
# Check waar component gebruikt wordt
grep -r "import.*ComponentName" app/
```
2. **Verplaats naar centrale folder**
```bash
mv app/feature/components/component.tsx components/
```
3. **Update alle imports**
```typescript
// Van:
import { Component } from '../components/component';
// Naar:
import { Component } from '@/components/component';
```
4. **Generaliseer indien nodig**
- Verwijder feature-specifieke logic
- Maak configureerbaar via props
- Update TypeScript types
### Wanneer een centrale component feature-specifiek wordt:
(Dit komt zelden voor, maar kan gebeuren)
1. Check of component echt nergens anders gebruikt wordt
2. Verplaats naar meest specifieke route waar het gebruikt wordt
3. Update imports
## Related Patterns
### Server vs Client Components
```typescript
// Server Component (default in app/)
export default function ReportPage() { ... }
// Client Component (expliciet markeren)
'use client';
export function ReportComposer() { ... }
```
Route-specifieke components kunnen zowel server als client components zijn.
Centrale components zijn meestal client components (interactief).
### Composition Pattern
Route-specifieke components kunnen centrale components gebruiken:
```typescript
// app/epd/patients/[id]/rapportage/components/report-composer.tsx
import { SpeechRecorderStreaming } from '@/components/speech-recorder-streaming';
import { Button } from '@/components/ui/button';
export function ReportComposer() {
return (
<div>
<SpeechRecorderStreaming />
<Button>Save</Button>
</div>
);
}
```
## Best Practices
1. **Start route-specifiek** - Begin met components in route folders, verplaats alleen naar centraal als er echt hergebruik is
2. **Gebruik absolute imports** - `@/components/...` voor centrale, relative voor route-specifieke
3. **Avoid premature abstraction** - Wacht tot een component 2x gebruikt wordt voordat je het generaliseert
4. **Keep it colocated** - Plaats components zo dichtbij mogelijk bij waar ze gebruikt worden
5. **Document reusability** - Als een component generiek is, documenteer dan het gebruik in JSDoc
## Tools & Commands
### Find all components in a route:
```bash
find app/epd/patients/[id]/rapportage -name "*.tsx" -type f
```
### Check component usage:
```bash
grep -r "import.*ComponentName" app/
```
### Count components per location:
```bash
find components -name "*.tsx" | wc -l
find app -path "*/components/*" -name "*.tsx" | wc -l
```
## References
- [Next.js App Router: Project Organization](https://nextjs.org/docs/app/building-your-application/routing/colocation)
- [React: Thinking in React](https://react.dev/learn/thinking-in-react)
- [Component Composition Patterns](https://www.patterns.dev/react/compound-pattern)
---
**Last Updated:** 2024-11-24
**Status:** Active pattern in gebruik