Files
triqura-ecd/docs/swift/bouwplan-swift-v3.md
2025-12-27 13:17:00 +01:00

36 KiB

🚀 Mission Control — Bouwplan Swift v3.0

💡 Transformatie: Van Command Center naar Medical Scribe Chatbot Interface


Projectnaam: Swift Medical Scribe v3.0 Versie: v3.0 Datum: 27-12-2024 Auteur: Colin Lit


1. Doel en context

🎯 Doel: Swift transformeren van een command-line style interface naar een conversational medical scribe chatbot met split-screen layout (chat links, artifacts rechts).

📘 Context: De huidige Swift v2.1 werkt met een command-line paradigma waar gebruikers kort commando's typen ("notitie jan medicatie"). Dit werkt goed, maar voelt transactioneel aan. Gebruikers willen doorvragen, context behouden, en natuurlijker interacteren met het systeem.

De transformatie:

  • Van: Command-line input → Centered blocks → Recent strip
  • Naar: Chat conversation → Split-screen (40/60) → Artifacts rechts

Waarom deze verandering:

  1. Natuurlijkere interactie — Voelt als praten met collega i.p.v. commando's typen
  2. Context behoud — Conversatiegeschiedenis blijft zichtbaar
  3. Follow-up mogelijk — Gebruiker kan doorvragen zonder opnieuw te beginnen
  4. Bekende UX — Lijkt op ChatGPT Canvas / Claude Artifacts (bekend voor gebruikers)

Referenties:

  • FO v3.0: fo-swift-medical-scribe-v3.md — Functioneel ontwerp medical scribe
  • Haalbaarheid: haalbaarheidsanalyse-v3.md — Feasibility analysis (6-8 weken, haalbaar)
  • UX Analyse: v3-redesign-met-huidige-styling.md — Wat blijft vs. wijzigt
  • UX v2.1: archive/swift-ux-v2.1.md — Huidige UX/styling

2. Uitgangspunten

2.1 Technische Stack

Frontend:

  • Next.js 14 (App Router) Bestaand
  • React 18 met TypeScript Bestaand
  • Tailwind CSS + shadcn/ui Bestaand
  • Lucide Icons Bestaand
  • Zustand (state management) Bestaand

Backend & Database:

  • Supabase (PostgreSQL + Auth) Bestaand
  • FHIR-inspired datamodel Bestaand
  • Row Level Security (RLS) Bestaand

AI/ML Services:

  • Anthropic Claude API (Sonnet 4.5) Bestaand
  • Deepgram (speech-to-text) Bestaand
  • Streaming API responses (SSE) 🆕 Nieuw patroon voor chat

Hosting & Deploy:

  • Vercel (production deployment) Bestaand
  • Environment variables via .env.local Bestaand

Nieuwe Dependencies:

  • Geen nieuwe externe libraries nodig
  • Hergebruik van bestaande /api/docs/chat streaming pattern

2.2 Projectkaders

Tijd:

  • Totaal: 6-8 weken bouwtijd
  • Fase 1 (Foundation): Week 1-2
  • Fase 2 (Chat API): Week 3-4
  • Fase 3 (Artifacts & Polish): Week 5-6
  • Fase 4 (Testing): Week 7-8

Team:

  • 1 developer (full-time)
  • AI assistant (Claude Code) voor development support

Scope:

  • In scope: Alle P1 intents (dagnotitie, zoeken, overdracht, patient context)
  • Out of scope: P2/P3 intents blijven werken maar geen redesign
  • Feature flag: v3.0 achter feature flag zodat v2.1 beschikbaar blijft

Data:

  • Alle bestaande Supabase data blijft werken
  • Geen database migraties nodig
  • Alleen nieuwe API endpoints + frontend components

Risicomanagement:

  • Incremental rollout via feature flag
  • v2.1 blijft beschikbaar als fallback
  • A/B testing mogelijk voor user feedback

2.3 Programmeer Uitgangspunten

Code Quality Principles:

  • DRY (Don't Repeat Yourself)

    • Herbruikbare chat components (ChatMessage, ChatBubble)
    • Centrale config voor message types
    • Shared utilities voor streaming responses
  • KISS (Keep It Simple, Stupid)

    • Geen overengineering van chat state
    • Eenvoudige Zustand store uitbreiding
    • Geen nieuwe frameworks/libraries indien niet nodig
  • SOC (Separation of Concerns)

    • Chat UI gescheiden van artifact logic
    • Message rendering gescheiden van streaming logic
    • API calls in dedicated /lib/swift/chat-api.ts
  • YAGNI (You Aren't Gonna Need It)

    • Bouw alleen conversation features die in FO staan
    • Geen "nice to have" features (bijv. message editing, reactions)
    • Start met max 3 artifacts, niet meer

Development Practices:

  • Code Organization

    components/swift/
    ├── chat/                    # 🆕 Nieuwe chat components
    │   ├── chat-panel.tsx
    │   ├── chat-message.tsx
    │   ├── chat-input.tsx
    │   └── streaming-indicator.tsx
    ├── artifacts/               # 🆕 Nieuwe artifact wrapper
    │   ├── artifact-container.tsx
    │   └── artifact-tab.tsx
    ├── blocks/                  # ✅ Bestaand, blijft werken
    │   ├── dagnotitie-block.tsx
    │   ├── zoeken-block.tsx
    │   └── overdracht-block.tsx
    └── command-center/          # 🔄 Wijzigt naar split-screen
        ├── command-center.tsx
        ├── context-bar.tsx      # ✅ Blijft ongewijzigd
        └── offline-banner.tsx   # ✅ Blijft ongewijzigd
    
  • Error Handling

    • Hergebruik bestaande lib/swift/error-handler.ts
    • Chat-specific error states (connection lost, stream interrupted)
    • User-friendly foutmeldingen in chat ("Er ging iets mis, probeer opnieuw")
  • Security

    • API keys blijven server-side (Claude API key)
    • Chat messages niet persistent opgeslagen (alleen in session state)
    • RLS rules blijven gelden voor artifacts
  • Performance

    • Virtual scrolling voor lange chat histories (>100 messages)
    • Debounce op typing indicator (300ms)
    • Lazy load artifacts (alleen renderen wanneer actief)
    • Streaming responses via SSE (Server-Sent Events)
  • Testing

    • Manual smoke tests voor alle chat flows
    • Integration tests voor /api/swift/chat endpoint
    • Edge case testing (stream interruption, long messages, etc.)

Voorbeeld implementatie:

// ✅ DRY - Herbruikbare message component
interface ChatMessageProps {
  type: 'user' | 'assistant' | 'system' | 'error';
  content: string;
  timestamp?: Date;
}

export function ChatMessage({ type, content, timestamp }: ChatMessageProps) {
  const styles = MESSAGE_STYLES[type]; // Centrale config
  return (
    <div className={cn('message', styles.container)}>
      {/* ... */}
    </div>
  );
}

// ✅ SOC - API logic gescheiden
// In /lib/swift/chat-api.ts
export async function sendChatMessage(
  message: string,
  history: ChatMessage[]
): Promise<ReadableStream> {
  const response = await fetch('/api/swift/chat', {
    method: 'POST',
    body: JSON.stringify({ message, history }),
  });
  return response.body!;
}

// ✅ KISS - Simpele state management
interface ChatState {
  messages: ChatMessage[];
  isStreaming: boolean;
  addMessage: (msg: ChatMessage) => void;
}

const useChatStore = create<ChatState>((set) => ({
  messages: [],
  isStreaming: false,
  addMessage: (msg) => set((s) => ({
    messages: [...s.messages, msg]
  })),
}));

3. Epics & Stories Overzicht

🎯 Doel: De bouw opdelen in 6 logische epics met concrete deliverables.

Epic Structuur:

Epic ID Titel Doel Status Stories Story Points Opmerkingen
E0 Pre-work & Planning Design tokens, component audit, system prompt To Do 3 5 SP Voorbereiding
E1 Foundation - Split-screen Layout naar 40/60 split To Do 4 13 SP Week 1-2
E2 Chat Panel & Messages Chat UI zonder AI To Do 5 13 SP Week 2-3
E3 Chat API & Medical Scribe AI conversatie werkend To Do 6 21 SP Week 3-4
E4 Artifact Area & Tabs Meerdere artifacts mogelijk To Do 4 13 SP Week 5
E5 AI-Filtering & Polish Psychiater filtering, polish To Do 5 13 SP Week 6
E6 Testing & Refinement QA, bugs, performance To Do 4 8 SP Week 7-8

Totaal: 31 stories, 86 Story Points (~7 weken à 12 SP/week)

Belangrijk:

  • ⚠️ Voer niet in 1x het volledige plan uit. Bouw per epic en per story.
  • ⚠️ Dependencies/migraties moeten eerst aan Colin worden gemeld.
  • Feature flag vanaf E1: FEATURE_FLAG_SWIFT_V3=true in .env.local

4. Epics & Stories (Uitwerking)

Epic 0 — Pre-work & Planning

Epic Doel: Voorbereiding werk voordat development start. Design tokens verificatie, component audit, medical scribe system prompt.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden Story Points
E0.S1 Design tokens audit Alle kleuren/spacing/typography gedocumenteerd in v3 doc 1
E0.S2 Component inventory Lijst van alle blocks die herbruikbaar zijn 2
E0.S3 Medical scribe system prompt Eerste versie prompt voor /api/swift/chat, getest met Claude 2

Technical Notes:

  • E0.S1: Check of alle tokens uit v2.1 nog kloppen voor v3.0
  • E0.S2: Maak lijst van blocks die NIET wijzigen vs. die WEL wijzigen
  • E0.S3: Prompt moet Nederlands zijn, vriendelijk maar professioneel, intent detection

Deliverable: Planning document met component lijst + prompt v1


Epic 1 — Foundation - Split-screen Layout

Epic Doel: CommandCenter omzetten naar split-screen layout (40% chat, 60% artifacts).

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden Story Points
E1.S1 Feature flag setup FEATURE_FLAG_SWIFT_V3 in .env + conditional rendering E0.S2 1
E1.S2 CommandCenter layout wijzigen Split-screen grid (40/60), context bar blijft E1.S1 5
E1.S3 Placeholder componenten ChatPanel (lege div), ArtifactArea (lege div) E1.S2 2
E1.S4 Responsive breakpoints Desktop/tablet/mobile toggle tussen chat/artifact E1.S3 5

Technical Notes:

// E1.S2 - Layout structuur
<div className="flex flex-col h-screen">
  <ContextBar /> {/* Blijft ongewijzigd */}

  <div className="flex flex-1 overflow-hidden">
    {/* Chat Panel - 40% */}
    <div className="w-[40%] border-r">
      <ChatPanel /> {/* Placeholder in E1.S3 */}
    </div>

    {/* Artifact Area - 60% */}
    <div className="w-[60%]">
      <ArtifactArea /> {/* Placeholder in E1.S3 */}
    </div>
  </div>
</div>

Responsive breakpoints (E1.S4):

  • Desktop (>1200px): 40/60 split zichtbaar
  • Tablet (768-1200px): 45/55 split
  • Mobile (<768px): Toggle tussen chat en artifact (full screen)

Deliverable: Split-screen layout zichtbaar, feature flag werkt, v2.1 nog beschikbaar


Epic 2 — Chat Panel & Messages

Epic Doel: Chat UI werkend krijgen zonder AI (hardcoded responses voor testing).

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden Story Points
E2.S1 Store uitbreiding chatMessages, isStreaming in swift-store.ts E1.S4 2
E2.S2 ChatMessage component User/assistant/system/error message types met styling E2.S1 3
E2.S3 ChatPanel component Scrollable message list, auto-scroll, scroll-lock E2.S2 5
E2.S4 ChatInput component Tekst input onderaan chat (40% width), enter to send E2.S3 2
E2.S5 Keyboard shortcuts ⌘K focus, Escape clear, Enter submit E2.S4 1

Technical Notes:

E2.S1 - Store uitbreiding:

// stores/swift-store.ts
interface SwiftStore {
  // Bestaand
  activePatient: Patient | null;
  activeBlock: BlockType | null;
  shift: ShiftType;

  // Nieuw voor chat
  chatMessages: ChatMessage[];
  isStreaming: boolean;
  pendingAction: Action | null;

  // Actions
  addChatMessage: (message: ChatMessage) => void;
  clearChat: () => void;
  setStreaming: (streaming: boolean) => void;
}

E2.S2 - Message styling:

// components/swift/chat/chat-message.tsx
const MESSAGE_STYLES = {
  user: {
    container: 'self-end bg-amber-50 border-amber-200',
    borderRadius: 'rounded-2xl rounded-tr-sm',
  },
  assistant: {
    container: 'self-start bg-slate-100 border-slate-200',
    borderRadius: 'rounded-2xl rounded-tl-sm',
  },
  system: {
    container: 'self-center bg-transparent text-slate-500 text-sm',
    borderRadius: '',
  },
  error: {
    container: 'self-start bg-red-50 border-red-200',
    borderRadius: 'rounded-2xl',
  },
};

E2.S3 - Auto-scroll gedrag:

  • Auto-scroll naar laatste message bij nieuwe message
  • Scroll-lock wanneer user omhoog scrollt (detecteer scroll position)
  • "↓ Scroll to bottom" knop verschijnt bij nieuwe messages tijdens scroll-lock

E2.S4 - Chat input:

  • Onderaan chat panel (40% width)
  • Multi-line support (Shift+Enter voor new line)
  • Enter submit (tenzij Shift pressed)
  • Placeholder: "Typ of spreek..."

Deliverable: Werkende chat UI (zonder AI), gebruiker kan typen en ziet messages verschijnen


Epic 3 — Chat API & Medical Scribe

Epic Doel: AI conversatie werkend krijgen met intent detection en artifact opening.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden Story Points
E3.S1 Chat API endpoint skeleton /api/swift/chat route met SSE setup E2.S5 3
E3.S2 Streaming response logic Claude API streaming werkt, chunks naar frontend E3.S1 5
E3.S3 Medical scribe system prompt Prompt met role, intents, examples, Nederlands E3.S2 3
E3.S4 Intent detection in response AI genereert action objects (intent + entities) E3.S3 5
E3.S5 Frontend streaming handling useChatStream hook, message chunks renderen E3.S4 3
E3.S6 Artifact opening from chat Action object opent juiste block met prefill E3.S5 2

Technical Notes:

E3.S1 - API Route:

// app/api/swift/chat/route.ts
export async function POST(req: Request) {
  const { message, messages, context } = await req.json();

  // Streaming response
  const encoder = new TextEncoder();
  const stream = new ReadableStream({
    async start(controller) {
      // Claude API streaming logic
    },
  });

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
    },
  });
}

E3.S3 - System Prompt (samenvatting):

Je bent een medische assistent (medical scribe) voor Swift, een Nederlands GGZ EPD.

Je rol:
- Help zorgmedewerkers met documentatie en administratie
- Voer natuurlijke gesprekken in het Nederlands
- Herken intents en voer acties uit wanneer nodig
- Stel verduidelijkingsvragen bij onduidelijkheid
- Wees vriendelijk maar professioneel

Intents die je herkent:
- dagnotitie: notitie maken voor patiënt
- zoeken: patiënt zoeken
- rapportage: behandelrapportage schrijven
- overdracht: dienst overdracht maken

Wanneer je een intent herkent, voeg een JSON action object toe:
{
  "type": "action",
  "intent": "dagnotitie",
  "entities": { "patient": "Jan de Vries", "category": "medicatie" },
  "confidence": 0.95
}

Context:
- Actieve patiënt: {{activePatient}}
- Dienst: {{shift}}
- Recente acties: {{recentActions}}

E3.S4 - Action object format:

interface Action {
  type: 'action';
  intent: IntentType;
  entities: {
    patient?: string;
    patientId?: string;
    category?: VerpleegkundigCategory;
    content?: string;
  };
  confidence: number;
  artifact?: {
    type: BlockType;
    prefill: BlockPrefillData;
  };
}

E3.S5 - Frontend streaming:

// lib/swift/use-chat-stream.ts
export function useChatStream() {
  const addMessage = useSwiftStore((s) => s.addChatMessage);
  const setStreaming = useSwiftStore((s) => s.setStreaming);

  const sendMessage = async (message: string) => {
    setStreaming(true);
    const response = await fetch('/api/swift/chat', {
      method: 'POST',
      body: JSON.stringify({ message, messages: /* ... */ }),
    });

    const reader = response.body!.getReader();
    let accumulatedText = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = new TextDecoder().decode(value);
      accumulatedText += chunk;

      // Update message in UI
      addMessage({ type: 'assistant', content: accumulatedText });
    }

    setStreaming(false);
  };

  return { sendMessage };
}

E3.S6 - Artifact opening:

  • Parse action object uit AI response
  • Open juiste block via openBlock(artifact.type, artifact.prefill)
  • Block verschijnt rechts in artifact area

Deliverable: Werkende conversatie met AI, intents worden herkend, blocks openen


Epic 4 — Artifact Area & Tabs

Epic Doel: Meerdere artifacts tegelijk mogelijk met tabs, slide-in animaties.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden Story Points
E4.S1 ArtifactContainer component Wrapper met tabs bovenaan, max 3 artifacts E3.S6 5
E4.S2 Artifact lifecycle management Open/close/switch tussen artifacts in store E4.S1 3
E4.S3 Slide-in animatie Artifact slide-in van rechts (200ms ease-out) E4.S2 2
E4.S4 Placeholder state "Artifacts verschijnen hier" met voorbeelden E4.S3 3

Technical Notes:

E4.S1 - ArtifactContainer:

// components/swift/artifacts/artifact-container.tsx
interface Artifact {
  id: string;
  type: BlockType;
  prefill: BlockPrefillData;
  title: string;
}

export function ArtifactContainer() {
  const { openArtifacts, activeArtifactId } = useSwiftStore();

  if (openArtifacts.length === 0) {
    return <ArtifactPlaceholder />;
  }

  return (
    <div className="h-full flex flex-col">
      {/* Tabs - alleen tonen bij >1 artifact */}
      {openArtifacts.length > 1 && (
        <div className="flex border-b">
          {openArtifacts.map((artifact) => (
            <ArtifactTab key={artifact.id} artifact={artifact} />
          ))}
        </div>
      )}

      {/* Active artifact */}
      <div className="flex-1 overflow-auto">
        {renderArtifact(activeArtifact)}
      </div>
    </div>
  );
}

E4.S2 - Store uitbreiding:

interface SwiftStore {
  // ... bestaand

  // Artifact state
  openArtifacts: Artifact[];  // Max 3
  activeArtifactId: string | null;

  // Actions
  openArtifact: (artifact: Artifact) => void;
  closeArtifact: (id: string) => void;
  switchArtifact: (id: string) => void;
}

// Logic: max 3 artifacts, oudste wordt gesloten bij 4e
const openArtifact = (artifact: Artifact) => {
  set((state) => {
    let artifacts = [...state.openArtifacts];
    if (artifacts.length >= 3) {
      artifacts = artifacts.slice(1); // Remove oldest
    }
    return {
      openArtifacts: [...artifacts, artifact],
      activeArtifactId: artifact.id,
    };
  });
};

E4.S3 - Animatie:

/* globals.css */
@keyframes artifact-enter {
  from {
    transform: translateX(100%);
    opacity: 0;
  }
  to {
    transform: translateX(0);
    opacity: 1;
  }
}

.artifact-enter {
  animation: artifact-enter 200ms ease-out;
}

E4.S4 - Placeholder:

function ArtifactPlaceholder() {
  return (
    <div className="flex flex-col items-center justify-center h-full text-slate-500">
      <div className="text-4xl mb-4">💬</div>
      <h3 className="text-lg font-medium mb-2">Artifacts verschijnen hier</h3>
      <p className="text-sm mb-4">Vraag me iets, bijvoorbeeld:</p>
      <ul className="text-sm space-y-1">
        <li> "Notitie voor Jan: medicatie gegeven"</li>
        <li> "Zoek Marie van den Berg"</li>
        <li> "Maak overdracht voor deze dienst"</li>
      </ul>
    </div>
  );
}

Deliverable: Meerdere artifacts mogelijk, smooth transitions, placeholder state


Epic 5 — AI-Filtering & Polish

Epic Doel: AI-filtering voor psychiater overdracht, linked evidence, final polish.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden Story Points
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.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.S5 Polish & animations Smooth transitions, loading states, toast confirmations E5.S4 1

Technical Notes:

E5.S1 - AI-filtering:

// app/api/overdracht/generate/route.ts
// Uitbreiden met filtering parameter
interface GenerateOverdrachtRequest {
  shift: ShiftType;
  filterForRole?: 'psychiater' | 'verpleegkundige';
}

// AI prompt voor filtering
const FILTER_PROMPT = `
Analyseer deze verpleegkundige notities en selecteer ALLEEN behandelrelevante informatie voor de psychiater:

WEL relevant:
- Medicatie-issues (weigering, bijwerkingen)
- Stemming/gedrag veranderingen
- Risico-signalen (suïcidale uitingen, agressie)
- Psychotische symptomen

NIET relevant:
- Routine medicatie ("volgens schema")
- ADL activiteiten ("gedoucht", "ontbijt")
- Standaard observaties ("rustige dag")
`;

E5.S2 - Linked evidence:

// components/swift/shared/linked-evidence.tsx
interface LinkedEvidenceProps {
  sourceNotes: Report[];
  highlightedText: string;
}

export function LinkedEvidence({ sourceNotes, highlightedText }: LinkedEvidenceProps) {
  return (
    <Popover>
      <PopoverTrigger className="underline decoration-dotted cursor-pointer">
        {highlightedText}
      </PopoverTrigger>
      <PopoverContent>
        <div className="space-y-2">
          {sourceNotes.map((note) => (
            <div key={note.id} className="text-sm">
              <div className="font-medium">{note.author} - {note.timestamp}</div>
              <div className="text-slate-600">{note.content}</div>
            </div>
          ))}
        </div>
      </PopoverContent>
    </Popover>
  );
}

E5.S3 - Voice input:

  • Bestaande use-swift-voice.ts hook blijft werken
  • Integreren in ChatInput component
  • Mic icon rechts van input field
  • Live transcript verschijnt in input tijdens recording

E5.S4 - Error states:

// Error message types in chat
const ERROR_MESSAGES = {
  network: "Er ging iets mis met de verbinding. Probeer het opnieuw.",
  stream_interrupted: "De verbinding werd onderbroken. Probeer je bericht opnieuw te versturen.",
  rate_limit: "Even geduld, er zijn te veel aanvragen. Wacht 30 seconden.",
  unknown: "Er is een fout opgetreden. Probeer het later opnieuw.",
};

Deliverable: AI-filtering werkt, linked evidence klikbaar, voice input geïntegreerd


Epic 6 — Testing & Refinement

Epic Doel: Volledige QA, bug fixes, performance tuning, documentatie.

Story ID Beschrijving Acceptatiecriteria Status Afhankelijkheden Story Points
E6.S1 Manual smoke tests Alle P1 flows werken zonder crashes (checklist) E5.S5 3
E6.S2 Performance optimalisatie Chat scroll performance, virtual scrolling >100 msgs E6.S1 3
E6.S3 Bug fixes Alle gemelde bugs opgelost, edge cases getest E6.S2 1
E6.S4 Documentatie update README, CLAUDE.md, migration guide E6.S3 1

Technical Notes:

E6.S1 - Test checklist:

### P1 Flow Tests

**Dagnotitie via conversatie:**
- [ ] User typt "Ik heb medicatie gegeven aan Jan"
- [ ] AI herkent intent (dagnotitie) en patient (Jan)
- [ ] DagnotatieBlock opent met prefill
- [ ] User kan opslaan → Toast confirmation
- [ ] Chat toont "✓ Notitie opgeslagen"

**Patiënt zoeken:**
- [ ] User typt "Zoek Marie van den Berg"
- [ ] ZoekenBlock opent rechts
- [ ] Patient search werkt
- [ ] Selecteren patient → PatientContextCard opent

**Overdracht maken:**
- [ ] User typt "Maak overdracht"
- [ ] OverdrachtBlock opent
- [ ] AI genereert samenvattingen
- [ ] Psychiater ziet alleen behandelrelevante info
- [ ] Linked evidence klikbaar

**Follow-up conversatie:**
- [ ] User typt "Voeg toe: goed geslapen"
- [ ] AI begrijpt context (laatste artifact = dagnotitie)
- [ ] Tekst wordt toegevoegd aan artifact

**Meerdere artifacts:**
- [ ] User opent 3 artifacts achter elkaar
- [ ] Tabs verschijnen bovenaan
- [ ] Switching tussen artifacts werkt
- [ ] 4e artifact openen → oudste sluit automatisch

**Voice input:**
- [ ] Mic icon werkt
- [ ] Deepgram transcriptie verschijnt live
- [ ] Pauze detectie → auto-submit
- [ ] Voice message wordt verwerkt zoals typed message

**Error handling:**
- [ ] Offline → banner verschijnt
- [ ] Stream interrupted → error message in chat
- [ ] Rate limit → friendly message + retry suggestion
- [ ] Network error → retry button

E6.S2 - Performance:

  • Virtual scrolling met react-window of @tanstack/react-virtual (>100 messages)
  • Debounce typing indicator (300ms)
  • Memoize message components (React.memo)
  • Lazy load artifacts (niet renderen tot actief)

E6.S3 - Edge cases:

  • Zeer lange messages (>1000 chars)
  • Special characters in patient names
  • Concurrent artifact opening
  • Browser back/forward navigation
  • Tab close tijdens streaming

E6.S4 - Documentatie:

  • Update CLAUDE.md met v3.0 architecture
  • Migration guide voor users (v2.1 → v3.0)
  • Developer README met chat API docs
  • Prompt versioning doc

Deliverable: Production-ready v3.0, alle tests passed, gedocumenteerd


5. Kwaliteit & Testplan

🎯 Doel: Borgen kwaliteit van v3.0 via gestructureerd testplan.

Test Types

Test Type Scope Tools Verantwoordelijke
Manual Smoke Tests Alle P1 flows + edge cases Checklist (zie E6.S1) Developer
Integration Tests /api/swift/chat endpoint Playwright / Jest Developer
Performance Tests Chat scroll, streaming latency Chrome DevTools, Lighthouse Developer
User Acceptance Real-world flows met zorgmedewerkers User feedback sessie PM + Developer
Security Tests API keys, RLS, XSS in chat Manual audit Developer

Test Coverage Targets

  • Manual smoke tests: 100% van P1 flows (dagnotitie, zoeken, overdracht, patient context)
  • Integration tests: /api/swift/chat endpoint (streaming, action generation)
  • Performance: Chat scroll <16ms frame time, streaming latency <500ms

Manual Test Checklist

Pre-deployment checklist:

  • Feature flag FEATURE_FLAG_SWIFT_V3=true werkt
  • v2.1 nog steeds beschikbaar (fallback)
  • Alle P1 flows getest (zie E6.S1)
  • Edge cases getest (lange messages, concurrent actions, etc.)
  • Mobile responsive (toggle tussen chat/artifact)
  • Keyboard shortcuts werken (⌘K, Escape, Enter)
  • Voice input geïntegreerd en werkend
  • Error states tonen user-friendly messages
  • Offline banner werkt
  • Performance: scroll smooth, streaming <500ms latency
  • AI-filtering psychiater werkt (alleen behandelrelevante info)
  • Linked evidence klikbaar en toont bronnotities
  • Toast notifications bij save/error
  • Browser back/forward navigation werkt

Acceptance Criteria (MVP)

Minimaal werkend voor release:

  1. Split-screen layout werkend (desktop/tablet/mobile)
  2. Conversatie met medical scribe voelt natuurlijk (niet robotisch)
  3. Artifacts openen binnen 2 sec na intent detection
  4. AI-filtering psychiater >85% accuracy (behandelrelevante info)
  5. Voice input geïntegreerd en werkend
  6. P1 flows (dagnotitie, zoeken, overdracht, patient context) 100% werkend
  7. Error handling: netwerk errors, offline, stream interrupted
  8. Performance: <500ms streaming latency, smooth scroll

6. Demo & Presentatieplan

🎯 Doel: Presenteren van v3.0 aan stakeholders en users voor feedback.

Demo Scenario

Duur: 15 minuten Doelgroep: Zorgmedewerkers (verpleegkundigen + psychiaters), product team Locatie: Vercel staging environment (swift-v3-staging.vercel.app)

Flow:

  1. Intro (2 min):

    • Context: "We hebben Swift getransformeerd naar een conversational interface"
    • Toon v2.1 vs. v3.0 screenshot (voor/na)
  2. Dagnotitie flow (3 min):

    • Typ: "Ik heb net medicatie gegeven aan Jan de Vries"
    • AI herkent intent, DagnotatieBlock opent rechts met prefill
    • Toon follow-up: "Voeg toe: hij voelt zich beter vandaag"
    • Opslaan → Chat confirmation
  3. Patiënt zoeken + context (3 min):

    • Typ: "Wie is Marie van den Berg?"
    • ZoekenBlock opent, selecteer patient
    • PatientContextCard toont laatste notities, vitals, diagnose
    • Chat vraag: "Wat was er gisteren met Marie?"
    • AI antwoordt met context uit notities
  4. Overdracht met AI-filtering (4 min):

    • Typ: "Maak overdracht voor deze dienst"
    • OverdrachtBlock opent
    • Toon psychiater view: alleen behandelrelevante info
    • Klik op linked evidence → bronnotitie preview
    • Toon verschil tussen verpleegkundige vs. psychiater view
  5. Voice input (2 min):

    • Klik mic icon
    • Spreek: "Notitie voor Jan: bloeddruk gemeten, 135 over 85"
    • Live transcript verschijnt
    • DagnotatieBlock opent met prefill
  6. Q&A (1 min):

    • Vragen beantwoorden
    • Feedback verzamelen

Backup Plan:

  • Lokale versie klaar bij internet/API issues
  • Pre-recorded video als complete fallback
  • Screenshots voor elk stap

7. Risico's & Mitigatie

🎯 Doel: Risico's vroeg signaleren en mitigeren.

Risico Kans Impact Mitigatie Owner
AI prompt niet natuurlijk genoeg Hoog Hoog Iteratief testen met users, prompt versioning, A/B testing Developer
Streaming latency >1s Middel Hoog Claude Haiku model overwegen (sneller), caching, local patterns voor snelle acties Developer
Performance bij >100 messages Middel Middel Virtual scrolling, pagination, max 100 messages in view Developer
Chat state memory leak Middel Middel Proper cleanup in useEffect, memory profiling Developer
AI kosten te hoog Middel Middel Rate limiting, local pattern matching eerst, cache responses PM
Mobile UX awkward Hoog Middel Extensive mobile testing, toggle UX refinement Developer
v2.1 users niet willen switchen Hoog Laag Feature flag (optioneel), user onboarding, feedback loop PM
Intent detection accuracy <80% Middel Hoog Hybrid approach (local + AI), confidence thresholds, fallback picker Developer
Browser compatibility issues Laag Middel Test Chrome/Safari/Firefox, SSE polyfill if needed Developer
Concurrent artifact state bugs Middel Middel Thorough testing, max 3 artifacts enforced, state validation Developer

Top 3 Risks & Mitigation:

  1. AI Prompt Engineering (Kans: Hoog, Impact: Hoog)

    • Mitigatie: Start met simpele prompt v1 in E0.S3, iteratief verfijnen met user feedback, prompt versioning (v1, v2, v3), A/B testing tussen prompts
    • Success metric: >80% user satisfaction "voelt natuurlijk aan"
  2. Performance - Streaming Latency (Kans: Middel, Impact: Hoog)

    • Mitigatie: Local patterns voor P1 intents (dagnotitie, zoeken) → <100ms, AI alleen voor complex/conversational, Claude Haiku overwegen, response caching
    • Success metric: <500ms tot eerste AI token, <2s tot artifact open
  3. Mobile UX Toggle (Kans: Hoog, Impact: Middel)

    • Mitigatie: Extensive mobile testing, bottom sheet voor artifact (native feel), swipe gestures, user testing met zorgmedewerkers
    • Success metric: >70% mobile users vindt toggle intuïtief

8. Evaluatie & Lessons Learned

🎯 Doel: Reflecteren na elke epic en einde project.

Na elke epic (weekly retro):

  • Wat ging goed deze week?
  • Welke blockers hadden we?
  • Welke AI-prompts werkten het beste?
  • Waar liepen we vertraging op?
  • Wat passen we aan voor volgende epic?

Na project (final retro):

Te documenteren:

  1. Successen:

    • Welke componenten zijn herbruikbaar voor volgende projecten?
    • Welke development patterns werkten goed?
    • Welke AI-prompts waren meest effectief?
  2. Uitdagingen:

    • Waar liepen we vast?
    • Welke technical debt ontstond?
    • Welke estimates waren te optimistisch/pessimistisch?
  3. Metrics:

    • Actual time spent vs. estimated (story points)
    • User satisfaction score (survey)
    • Performance metrics (latency, scroll FPS)
    • AI kosten (Claude API usage)
  4. Next Steps:

    • P2/P3 features roadmap
    • Technical debt payoff plan
    • User feedback integration plan

Template voor lessons learned:

## Epic X - Lessons Learned

### What went well
- ...

### What didn't go well
- ...

### Action items for next epic
- ...

### Reusable components/patterns
- ...

9. Referenties

🎯 Doel: Koppelen aan overige Mission Control-documenten.

Mission Control Documents:

  • PRD Ephemeral UI: docs/swift/archive/nextgen-epd-prd-ephemeral-ui-epd.md — Product vision
  • FO v3.0: docs/swift/fo-swift-medical-scribe-v3.md — Functioneel ontwerp medical scribe
  • Haalbaarheid: docs/swift/haalbaarheidsanalyse-v3.md — Feasibility analysis
  • UX v2.1: docs/swift/archive/swift-ux-v2.1.md — Huidige UX/styling
  • UX Analyse v3: docs/swift/v3-redesign-met-huidige-styling.md — Wat blijft vs. wijzigt
  • Bouwplan v2: docs/swift/bouwplan-swift-v2.md — Previous roadmap (v2.1)

Technical Resources:

  • Repository: https://github.com/[org]/mini-epd-prototype
  • Staging: https://swift-v3-staging.vercel.app (to be created)
  • Production: https://mini-epd.vercel.app (existing)
  • Component Library: components/swift/ folder
  • API Documentation: /docs/api/ (to be created)

External References:


10. Glossary & Abbreviations

Term Betekenis
Epic Grote feature of fase in development (bevat meerdere stories)
Story Kleine, uitvoerbare taak binnen een epic
Story Points Schatting van complexiteit (Fibonacci: 1, 2, 3, 5, 8, 13, 21)
SP Story Points (afkorting)
MVP Minimum Viable Product
P1/P2/P3 Priority tiers (P1 = kritiek, P2 = belangrijk, P3 = waardevol)
SSE Server-Sent Events (streaming protocol)
DRY Don't Repeat Yourself
KISS Keep It Simple, Stupid
SOC Separation of Concerns
YAGNI You Aren't Gonna Need It
RLS Row Level Security (Supabase)
Intent Gebruikersintentie (dagnotitie, zoeken, overdracht, etc.)
Artifact UI-component die verschijnt in artifact area (block)
Block Herbruikbare UI-component (DagnotatieBlock, ZoekenBlock, etc.)
Prefill Vooringevulde data in artifact o.b.v. AI entity extraction
Medical Scribe AI-assistent die medische documentatie ondersteunt
Linked Evidence Klikbare links naar bronnotities in AI-samenvatting

11. Story Points Reference

Fibonacci schaal voor story points:

Points Complexiteit Geschatte tijd Voorbeelden
1 Trivial 1-2 uur Feature flag setup, config wijziging
2 Simple 2-4 uur Component skeleton, store uitbreiding (1 field)
3 Small 4-8 uur Simpele component met state, basic API endpoint
5 Medium 1-2 dagen Complex component, API met business logic
8 Large 2-3 dagen Feature met meerdere componenten, integrations
13 Very Large 3-5 dagen Epic-level feature, major refactor
21 Extra Large 1 week+ Waarschijnlijk te groot, split in kleinere stories

Velocity tracking:

  • Target velocity: ~12 SP per week (1 developer)
  • Sprint length: 1 week
  • Total project: 86 SP ≈ 7 weken (met buffer = 8 weken)

Versiehistorie:

Versie Datum Auteur Wijziging
v1.0 27-12-2024 Colin Lit Initiële versie - complete bouwplan v3.0