docs(swift): update bouwplan met E5.S2 completion

Bouwplan progress update: 66 SP / 82 SP (80%)

Updates:
- Epic 5 status: 1/5 → 2/5 stories (8 SP compleet)
- Total progress: 23/31 stories (was 22/31)
- Story points: 66/82 SP = 80% (was 63/82 = 77%)
- E5.S2 status: 

E5.S2 Deliverables section:
-  Alle implementation details gedocumenteerd
- Git commit hash toegevoegd (adf6c3f)
- Code voorbeelden: LinkedEvidence + enrichWithSourceData
- File change statistics toegevoegd (+231/-4)
- 10 acceptatiecriteria gedocumenteerd

Voortgang: 80% compleet - Epic 5 2/5 stories done!

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
colinislit
2025-12-27 18:39:54 +01:00
parent adf6c3fb96
commit 41acfabe4b

View File

@@ -223,11 +223,11 @@ const useChatStore = create<ChatState>((set) => ({
| E2 | Chat Panel & Messages | Chat UI zonder AI | ✅ **Compleet** | 5/5 | 13 SP | Scrolling, input, shortcuts | | E2 | Chat Panel & Messages | Chat UI zonder AI | ✅ **Compleet** | 5/5 | 13 SP | Scrolling, input, shortcuts |
| E3 | Chat API & Medical Scribe | AI conversatie werkend | ✅ **Compleet** | 6/6 | 21 SP | Artifact opening werkend! | | E3 | Chat API & Medical Scribe | AI conversatie werkend | ✅ **Compleet** | 6/6 | 21 SP | Artifact opening werkend! |
| E4 | Artifact Area & Tabs | Meerdere artifacts mogelijk | ✅ **Compleet** | 3/4 | 10 SP | E4.S4 geskipt (placeholder in E4.S1) | | E4 | Artifact Area & Tabs | Meerdere artifacts mogelijk | ✅ **Compleet** | 3/4 | 10 SP | E4.S4 geskipt (placeholder in E4.S1) |
| E5 | AI-Filtering & Polish | Psychiater filtering, polish | ⏳ In Progress | 1/5 | 13 SP (5 SP compleet) | Week 6 | | E5 | AI-Filtering & Polish | Psychiater filtering, polish | ⏳ In Progress | 2/5 | 13 SP (8 SP compleet) | Week 6 |
| E6 | Testing & Refinement | QA, bugs, performance | ⏳ To Do | 0/4 | 8 SP | Week 7-8 | | E6 | Testing & Refinement | QA, bugs, performance | ⏳ To Do | 0/4 | 8 SP | Week 7-8 |
**Totaal:** 31 stories, **82 Story Points** (~7 weken à 12 SP/week, 3 SP geannuleerd door E4.S4 skip) **Totaal:** 31 stories, **82 Story Points** (~7 weken à 12 SP/week, 3 SP geannuleerd door E4.S4 skip)
**Voortgang:** ✅ 22/31 stories compleet, 3 geskipt (63 SP / 82 SP = **77%**) **Voortgang:** ✅ 23/31 stories compleet, 3 geskipt (66 SP / 82 SP = **80%**)
**Belangrijk:** **Belangrijk:**
- ⚠️ Voer niet in 1x het volledige plan uit. Bouw per epic en per story. - ⚠️ Voer niet in 1x het volledige plan uit. Bouw per epic en per story.
@@ -815,7 +815,7 @@ E4.S4 (Placeholder state) is geskipt omdat:
| Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points | | Story ID | Beschrijving | Acceptatiecriteria | Status | Afhankelijkheden | Story Points |
|----------|--------------|---------------------|--------|------------------|--------------| |----------|--------------|---------------------|--------|------------------|--------------|
| E5.S1 | AI-filtering psychiater | `/api/overdracht/generate` filtert op behandelrelevantie | ✅ | E4.S4 | 5 | | E5.S1 | AI-filtering psychiater | `/api/overdracht/generate` filtert op behandelrelevantie | ✅ | E4.S4 | 5 |
| E5.S2 | Linked evidence UI | Bronnotitie links in OverdrachtBlock, hover preview | | E5.S1 | 3 | | E5.S2 | Linked evidence UI | Bronnotitie links in OverdrachtBlock, hover preview | | E5.S1 | 3 |
| E5.S3 | Voice input integratie | Bestaande Deepgram blijft werken in chat input | ⏳ | E2.S4 | 2 | | E5.S3 | Voice input integratie | Bestaande Deepgram blijft werken in chat input | ⏳ | E2.S4 | 2 |
| E5.S4 | Error states & offline | Chat error messages, offline banner margin fix | ⏳ | E3.S2 | 2 | | E5.S4 | Error states & offline | Chat error messages, offline banner margin fix | ⏳ | E3.S2 | 2 |
| E5.S5 | Polish & animations | Smooth transitions, loading states, toast confirmations | ⏳ | E5.S4 | 1 | | E5.S5 | Polish & animations | Smooth transitions, loading states, toast confirmations | ⏳ | E5.S4 | 1 |
@@ -1075,35 +1075,107 @@ Output:
--- ---
**E5.S2 - Linked evidence:** **E5.S2 - Linked evidence (COMPLEET):**
**Doel:** Bronverwijzingen klikbaar maken met hover preview van volledige source content.
**Implementatie:**
```tsx ```tsx
// components/swift/shared/linked-evidence.tsx // components/swift/shared/linked-evidence.tsx
interface LinkedEvidenceProps { interface LinkedEvidenceProps {
sourceNotes: Report[]; bron: Aandachtspunt['bron'];
highlightedText: string; sourceData?: Aandachtspunt['sourceData'];
className?: string;
} }
export function LinkedEvidence({ sourceNotes, highlightedText }: LinkedEvidenceProps) { export function LinkedEvidence({ bron, sourceData, className }: LinkedEvidenceProps) {
// If no source data, just show label without popover
if (!sourceData) return <span>{bron.label} • {bron.datum}</span>;
return ( return (
<Popover> <Popover>
<PopoverTrigger className="underline decoration-dotted cursor-pointer"> <PopoverTrigger asChild>
{highlightedText} <button className="underline decoration-dotted cursor-help">
<Icon /> {bron.label} <ExternalLink />
</button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent> <PopoverContent className="w-96 p-4" side="top">
<div className="space-y-2"> {/* Type-specific content display */}
{sourceNotes.map((note) => ( {bron.type === 'observatie' && (
<div key={note.id} className="text-sm"> <div>
<div className="font-medium">{note.author} - {note.timestamp}</div> <span className="text-2xl">{sourceData.value} {sourceData.unit}</span>
<div className="text-slate-600">{note.content}</div> <div className={getInterpretationColor(sourceData.interpretation)}>
Interpretatie: {sourceData.interpretation}
</div> </div>
))} </div>
</div> )}
{/* ... other types ... */}
</PopoverContent> </PopoverContent>
</Popover> </Popover>
); );
} }
``` ```
**Source Data Enrichment:**
```typescript
// app/api/overdracht/generate/route.ts
function enrichWithSourceData(
aandachtspunten: Aandachtspunt[],
context: OverdrachtContext
): Aandachtspunt[] {
return aandachtspunten.map((punt) => {
const { bron } = punt;
let sourceData: Aandachtspunt['sourceData'];
switch (bron.type) {
case 'observatie':
const vital = context.vitals.find((v) => v.id === bron.id);
if (vital) sourceData = { value: vital.value_quantity_value, ... };
break;
case 'rapportage':
case 'verpleegkundig':
const report = context.reports.find((r) => r.id === bron.id);
if (report) sourceData = { content: report.content, ... };
break;
case 'risico':
const risk = context.risks.find((r) => r.id === bron.id);
if (risk) sourceData = { riskLevel: risk.risk_level, ... };
break;
}
return { ...punt, sourceData };
});
}
```
**Deliverables (E5.S2 - COMPLEET):**
- ✅ `lib/types/overdracht.ts` (+12 regels) — Aandachtspunt type extended met sourceData field
- ✅ `components/swift/shared/linked-evidence.tsx` (+160 regels NEW) — LinkedEvidence component met Popover
- ✅ `app/api/overdracht/generate/route.ts` (+58 regels) — enrichWithSourceData() functie
- ✅ `components/swift/blocks/overdracht-block.tsx` (+1/-3 regels) — LinkedEvidence integration in AandachtspuntItem
- ✅ Type-specific content display (observaties, rapportages, risico's)
- ✅ Color-coded interpretations (HH/LL red, H/L amber, N teal)
- ✅ Color-coded risk levels (hoog/zeer_hoog red, gemiddeld amber, laag teal)
- ✅ Hover popover met volledige source content
- ✅ Icons per type (Activity, FileText, AlertTriangle, ExternalLink)
- ✅ Build succesvol zonder errors
- ✅ Backwards compatible (werkt met/zonder sourceData)
**Acceptatiecriteria:**
1. ✅ Bronverwijzingen zijn klikbaar/hoverable in OverdrachtBlock
2. ✅ Hover toont popover met volledige source content
3. ✅ Observaties tonen: value + unit + interpretation met kleuren
4. ✅ Rapportages tonen: content + createdBy
5. ✅ Risico's tonen: riskLevel + rationale met severity kleuren
6. ✅ Popover positioneert correct (side="top" align="start")
7. ✅ Visual feedback: underline-dotted, ExternalLink icon, cursor-help
8. ✅ Accessible: keyboard navigable, asChild trigger pattern
9. ✅ API enricht aandachtspunten met sourceData uit context
10. ✅ Build succesvol, geen type errors
**Git Commits:**
- `adf6c3f` — E5.S2 (Linked evidence UI, 231 insertions, 4 deletions)
**E5.S3 - Voice input:** **E5.S3 - Voice input:**
- Bestaande `use-swift-voice.ts` hook blijft werken - Bestaande `use-swift-voice.ts` hook blijft werken
- Integreren in ChatInput component - Integreren in ChatInput component