Files
triqura-ecd/docs/intent/noshow-case/epics/NS-E5-integration.md
colinislit 924988dd15 feat(cortex): no-show casus — intent flow, brief-rescript en document artifact
Cortex handelt een no-show af vanuit één chatcommando: afspraak
annuleren (declarabiliteits-nudge), en de openstaande concept-
huisartsbrief wordt via LLM herschreven en ter review aangeboden
in een document artifact (human-in-the-loop, PATCH dispatch zet
status op verzendklaar).

- API-routes: context, rescript, cancel, dispatch
- NoShowDocumentBlock: review/edit UI met origineel-vergelijk
- Mock-data voor concept huisartsbrief
- PRD, FO, bouwplan en epics in docs/intent/noshow-case/

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 23:14:55 +02:00

300 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NS.E5 — Integration & Demo Polish
**Casus:** Cortex No Show Afhandeling
**Epic doel:** De volledige end-to-end flow werkend krijgen, edge cases afvangen, en de demo valideren aan de succescriteria uit het PRD.
**Geschatte tijd:** ~2 uur
**Afhankelijkheden:** NS.E1 t/m NS.E4 volledig afgerond
---
## Context
Na NS.E1NS.E4 zijn alle individuele onderdelen gebouwd:
- Intent wordt herkend (E1)
- Nudges triggeren en lopen sequentieel (E2)
- API routes werken (E3)
- Artifact component toont de brief (E4)
Dit epic zorgt dat alles correct samenwerkt, fouten netjes worden afgevangen, en de demo vloeiend loopt.
---
## NS.E5.S1 — Volledige `chat-panel.tsx` integratie valideren
**Bestand:** `components/cortex/chat/chat-panel.tsx`
### Checklist: zijn alle functies aanwezig en correct verbonden?
Na NS.E2 en NS.E4 moeten de volgende functies bestaan in `ChatPanel`:
| Functie | Aangemaakt in | Doet |
|---|---|---|
| `handleNoShowCancelStep` | NS.E2.S3 | Cancel API → context check → nudge 2 of done |
| `handleNoShowRescriptStep` | NS.E4.S3 | Rescript API → openArtifact |
| `handleAcceptNudge` (uitgebreid) | NS.E2.S3 | Brancht op `trigger.intent` en `suggestion.rationale` |
### Verbinding `handleAcceptNudge` → `handleNoShowRescriptStep`
Controleer dat de stap-5 check correct is geïmplementeerd:
```typescript
const handleAcceptNudge = useCallback(async (
suggestionId: string,
suggestion: ChatMessageType['nudge']
) => {
acceptSuggestion(suggestionId);
if (!suggestion) return;
// Stap 2→3: declarabiliteitscheck geaccepteerd → annuleer + check brief
if (suggestion.trigger.intent === 'register_no_show') {
await handleNoShowCancelStep(suggestion);
return;
}
// Stap 4→5: brief-check geaccepteerd → herschrijf brief
if (suggestion.suggestion.rationale === 'noshow-brief-check') {
await handleNoShowRescriptStep();
return;
}
// Generieke flow voor alle andere nudges
const artifact = routeIntentToArtifact(
suggestion.suggestion.intent,
suggestion.suggestion.entities,
0.9
);
if (artifact) {
openArtifact({ type: artifact.type, prefill: artifact.prefill, title: artifact.title });
}
}, [
acceptSuggestion,
openArtifact,
handleNoShowCancelStep,
handleNoShowRescriptStep,
]);
```
**Belangrijk:** `handleNoShowCancelStep` en `handleNoShowRescriptStep` moeten in de `useCallback` dependency array staan. Als ze er niet in staan, kan je stale closures krijgen.
### `onSend` handler: no-show nudge trigger
Controleer dat de `onDone` callback de no-show nudge triggert. Dit blok moet aanwezig zijn in de `onDone`:
```typescript
// No-show nudge trigger na register_no_show classificatie
if (parsed.action?.intent === 'register_no_show' && isFeatureEnabled('CORTEX_NUDGE')) {
const suggestions = evaluateNudge({
intent: 'register_no_show',
actionId: crypto.randomUUID(),
entities: parsed.action.entities,
content: message,
});
suggestions.forEach((suggestion) => {
addChatMessage({
type: 'nudge',
content: suggestion.suggestion.message,
nudge: suggestion,
});
});
}
```
### Done criteria
- Volledige flow doorloopbaar zonder errors in de browser console
- `[ChatPanel]` log berichten verschijnen op de juiste momenten
- Geen `TypeError` of `undefined is not a function` errors
---
## NS.E5.S2 — Loading states en dubbele submits voorkomen
**Bestand:** `components/cortex/chat/chat-panel.tsx` + `stores/cortex-store.ts`
### Probleem
Tussen de API calls (cancel → context → rescript) zit latentie. Als de gebruiker snel klikt, kunnen er dubbele calls ontstaan. Ook moet de UI duidelijk maken dat er iets "bezig" is.
### Oplossing A — `isNoShowProcessing` flag in store
Voeg toe aan store (in `CortexStore` interface, `initialState`, en actions):
```typescript
// In interface:
isNoShowProcessing: boolean;
// In initialState:
isNoShowProcessing: false,
// Actions:
setNoShowProcessing: (processing: boolean) => void;
```
Implementatie:
```typescript
setNoShowProcessing: (processing) =>
set({ isNoShowProcessing: processing }, false, 'setNoShowProcessing'),
```
### Oplossing B — Gebruik in `handleNoShowCancelStep` en `handleNoShowRescriptStep`
Wrap elke async functie:
```typescript
const handleNoShowCancelStep = useCallback(async (...) => {
const { isNoShowProcessing } = useCortexStore.getState();
if (isNoShowProcessing) return; // Dubbele klik preventie
setNoShowProcessing(true);
try {
// ... bestaande logica
} finally {
setNoShowProcessing(false);
}
}, [..., setNoShowProcessing]);
```
### Oplossing C — Nudge knop disablen tijdens processing
In `NudgeChatMessage` is de accept/dismiss knop al aanwezig. We moeten de accept knop disablen tijdens `isNoShowProcessing`:
**Bestand:** `components/cortex/chat/nudge-chat-message.tsx`
Voeg toe:
```typescript
const isNoShowProcessing = useCortexStore((s) => s.isNoShowProcessing);
```
Voeg `disabled={isNoShowProcessing}` toe aan de accept-knop als de nudge een no-show nudge is (`suggestion.trigger.intent === 'register_no_show'` of `suggestion.suggestion.rationale === 'noshow-brief-check'`).
### Done criteria
- Snel twee keer klikken op `[Ja, annuleer]` triggert de API maar één keer
- Knop is visueel disabled tijdens verwerking
- Na voltooiing is de knop weer actief (relevant voor de "Nee" knop)
---
## NS.E5.S3 — Cleanup bij unmount
**Bestand:** `components/cortex/chat/chat-panel.tsx`
Als de gebruiker weg navigeert tijdens een lopende no-show flow, moet de state worden opgeruimd.
Voeg toe in `ChatPanel`:
```typescript
const resetNoShowFlow = useCortexStore((s) => s.resetNoShowFlow);
// Cleanup bij unmount
useEffect(() => {
return () => {
// Reset no-show flow als component unmount tijdens actieve flow
const { noShowFlow } = useCortexStore.getState();
if (noShowFlow.step !== 'idle' && noShowFlow.step !== 'done') {
resetNoShowFlow();
}
};
}, [resetNoShowFlow]);
```
### Done criteria
- Navigeren weg van het dashboard tijdens een actieve no-show flow reset de state
- Bij terugkeren: flow begint opnieuw (geen "stuck" state)
---
## NS.E5.S4 — Demo Validatie Checklist
Doorloop de volledige flow handmatig en vink elk punt af:
### Classificatie
- [ ] Input `"patiënt is niet verschenen"``register_no_show` intent herkend (zichtbaar in console)
- [ ] Input `"no show vandaag"``register_no_show` intent herkend
- [ ] Input `"cliënt was er niet"` → AI classificeert als `register_no_show`
- [ ] Input `"patiënt niet verschenen volgende week"` → escaleert naar AI (relative_time)
### Nudge 1 — Declarabiliteitscheck
- [ ] Na no-show input: nudge bubble verschijnt met declarabiliteits-waarschuwing
- [ ] Nudge heeft prioriteit badge `high` (rode kleur)
- [ ] `[Nee]` klik: nudge verdwijnt, geen verdere actie, flow eindigt
- [ ] `[Ja, annuleer]` klik: loading state actief (knop disabled)
### Stap 3 — Annulering
- [ ] Cancel API aangeroepen: `POST /api/cortex/noshow/cancel` → 200 response
- [ ] Context API aangeroepen: `GET /api/cortex/noshow/context``hasConceptBrief: true`
- [ ] Chat toont "Bezig met annuleren..." tijdens verwerking
- [ ] Na voltooiing: nudge 2 verschijnt met brief-vraag
### Nudge 2 — Brief check
- [ ] Nudge 2 toont correcte message over conceptbrief
- [ ] `[Nee]` klik: nudge verdwijnt, chat bevestigt annulering
- [ ] `[Ja, pas brief aan]` klik: rescript API aangeroepen
### Stap 4 — Rescript
- [ ] Rescript API aangeroepen: `POST /api/cortex/noshow/rescript` → herschreven inhoud
- [ ] Artifact paneel opent met `NoShowDocumentBlock`
- [ ] Chat toont "Huisartsbrief is aangepast. Kijk of je hiermee akkoord bent."
- [ ] Herschreven brief is NIET alleen de originele tekst met "no show" erachter geplakt
### Stap 5 — Accordering
- [ ] Textarea is bewerkbaar — gebruiker kan aanpassingen maken
- [ ] "Originele brief bekijken" toggle werkt
- [ ] `[Akkoord & Verzendklaar]` roept dispatch API aan
- [ ] Na dispatch: knop verandert naar "✓ Verzendklaar"
- [ ] Chat ontvangt bevestigingsbericht
### Technische criteria
- [ ] Volledige flow doorloopbaar in < 30 seconden (excl. LLM latency ~3-5s)
- [ ] Geen schermwissels nodig gedurende de hele flow
- [ ] `pnpm build` slaagt zonder errors
- [ ] `pnpm lint` slaagt zonder errors
- [ ] Geen rode console errors in de browser
### Edge cases
- [ ] Offline/netwerk fout tijdens cancel → error message in chat, flow herstelbaar
- [ ] LLM fout in rescript → originele brief getoond + gele waarschuwingsbalk
- [ ] Dubbele klik op `[Ja, annuleer]` → slechts één API call
---
## NS.E5.S5 — Commit strategie
Commitvolgorde die logisch werkt voor code review:
```
feat(cortex): NS.E1 — register_no_show intent type + reflex patterns
feat(cortex): NS.E2.S1 — no-show flow state in cortex store
feat(cortex): NS.E2.S2 — nudge rule: declarabiliteitscheck
feat(cortex): NS.E2.S3 — chat panel: no-show nudge trigger + handlers
feat(cortex): NS.E3 — no-show API routes (cancel, context, rescript, dispatch)
feat(cortex): NS.E4.S1 — NoShowDocumentBlock component
feat(cortex): NS.E4.S2 — artifact-container: register_no_show case
feat(cortex): NS.E4.S3 — chat panel: rescript step + artifact koppeling
feat(cortex): NS.E5 — loading states, cleanup, demo polish
```
Elke commit moet `pnpm build` laten slagen.
---
## Overzicht gewijzigde bestanden (totaal)
| Bestand | Wijziging |
|---|---|
| `lib/cortex/types.ts` | `register_no_show` in union + BLOCK_CONFIGS |
| `lib/cortex/reflex-classifier.ts` | Patronen voor register_no_show |
| `app/api/cortex/chat/route.ts` | System prompt uitgebreid |
| `lib/cortex/nudge.ts` | Nudge rule 1 toegevoegd |
| `stores/cortex-store.ts` | NoShowFlowState + actions + isNoShowProcessing |
| `lib/cortex/mock-data/noshow.ts` | **Nieuw** |
| `app/api/cortex/noshow/cancel/route.ts` | **Nieuw** |
| `app/api/cortex/noshow/context/route.ts` | **Nieuw** |
| `app/api/cortex/noshow/rescript/route.ts` | **Nieuw** |
| `app/api/cortex/noshow/dispatch/route.ts` | **Nieuw** |
| `components/cortex/blocks/noshow-document-block.tsx` | **Nieuw** |
| `components/cortex/artifacts/artifact-container.tsx` | Case + import + getArtifactTitle |
| `components/cortex/chat/chat-panel.tsx` | Nudge trigger + handlers + cleanup |
| `components/cortex/chat/nudge-chat-message.tsx` | isNoShowProcessing check |
**Totaal: 14 bestanden** — 5 nieuw, 9 aangepast