tokenhash parameter
This commit is contained in:
@@ -12,25 +12,39 @@ import type { NextRequest } from 'next/server'
|
||||
export async function GET(request: NextRequest) {
|
||||
const requestUrl = new URL(request.url)
|
||||
const code = requestUrl.searchParams.get('code')
|
||||
const token = requestUrl.searchParams.get('token') // Fallback for older templates
|
||||
const token_hash = requestUrl.searchParams.get('token_hash') // Supabase uses this for email links
|
||||
const type = requestUrl.searchParams.get('type') // recovery, signup, etc
|
||||
const next = requestUrl.searchParams.get('next') ?? '/epd/clients'
|
||||
|
||||
// Debug logging
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// Debug logging - ALWAYS log to diagnose redirect issues
|
||||
console.log('🔍 Auth Callback Debug:', {
|
||||
url: request.url,
|
||||
code: !!code,
|
||||
token: !!token,
|
||||
token_hash: !!token_hash,
|
||||
codeValue: code?.substring(0, 10) + '...',
|
||||
type,
|
||||
next,
|
||||
allParams: Object.fromEntries(requestUrl.searchParams)
|
||||
})
|
||||
}
|
||||
|
||||
if (code) {
|
||||
// Use code, token, or token_hash (different Supabase versions use different params)
|
||||
const authCode = code || token || token_hash
|
||||
|
||||
if (authCode) {
|
||||
const supabase = await createClient()
|
||||
|
||||
// Exchange code for session
|
||||
const { data, error } = await supabase.auth.exchangeCodeForSession(code)
|
||||
const { data, error } = await supabase.auth.exchangeCodeForSession(authCode)
|
||||
|
||||
if (error) {
|
||||
console.error('❌ Auth Callback Exchange Error:', {
|
||||
message: error.message,
|
||||
status: error.status,
|
||||
code: error.code
|
||||
})
|
||||
}
|
||||
|
||||
if (!error && data.user) {
|
||||
// PRIORITY: If next is /update-password, ALWAYS go there (password reset flow)
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
|
||||
<tr>
|
||||
<td align="center" style="padding: 0 0 30px;">
|
||||
<a href="{{ .ConfirmationURL }}" style="display: inline-block; padding: 14px 32px; background-color: #0D9488; color: #FFFFFF; text-decoration: none; border-radius: 6px; font-weight: 500; font-size: 16px; line-height: 1.5;">
|
||||
<a href="{{ .SiteURL }}/auth/callback?token_hash={{ .TokenHash }}&type=recovery&next=/update-password" style="display: inline-block; padding: 14px 32px; background-color: #0D9488; color: #FFFFFF; text-decoration: none; border-radius: 6px; font-weight: 500; font-size: 16px; line-height: 1.5;">
|
||||
Wachtwoord opnieuw instellen
|
||||
</a>
|
||||
</td>
|
||||
@@ -54,7 +54,7 @@
|
||||
Werkt de knop niet? Kopieer en plak deze link in je browser:
|
||||
</p>
|
||||
<p style="margin: 0 0 30px; font-size: 12px; line-height: 1.6; color: #0D9488; word-break: break-all;">
|
||||
{{ .ConfirmationURL }}
|
||||
{{ .SiteURL }}/auth/callback?token_hash={{ .TokenHash }}&type=recovery&next=/update-password
|
||||
</p>
|
||||
|
||||
<!-- Security Warning -->
|
||||
|
||||
681
docs/specs/fo-live-transcriptie-v1.md
Normal file
681
docs/specs/fo-live-transcriptie-v1.md
Normal file
@@ -0,0 +1,681 @@
|
||||
# 🧩 Functioneel Ontwerp (FO) — Live Transcriptie & AI Verslag
|
||||
|
||||
**Projectnaam:** Mini-ECD - Live Transcriptie Feature
|
||||
**Versie:** v1.0
|
||||
**Datum:** 19-11-2024
|
||||
**Auteur:** Colin van der Heijden (AI Speedrun)
|
||||
|
||||
---
|
||||
|
||||
## 1. Doel en relatie met het PRD
|
||||
🎯 **Doel van dit document:**
|
||||
Het Functioneel Ontwerp beschrijft **hoe** de live transcriptie en AI-verslag functionaliteit werkt binnen het Mini-ECD systeem. Dit document vertaalt de behoefte uit het PRD ("behandelaars willen minder tijd kwijt zijn aan typen") naar concrete gebruikerservaringen en schermflows.
|
||||
|
||||
📘 **Toelichting aan de lezer:**
|
||||
Dit FO beschrijft twee nauw verbonden features:
|
||||
1. **Live Transcriptie** - Real-time spraak-naar-tekst tijdens gesprekken (Deepgram)
|
||||
2. **AI Verslag Structurering** - Transformatie van ruwe transcriptie naar gestructureerd verslag (Claude)
|
||||
|
||||
Deze features zijn dé showcase van "Software on Demand" - waar traditionele EPD's 30 minuten handmatig typen vereisen, doen wij dit in 2 minuten AI-tijd.
|
||||
|
||||
**Relatie met PRD v1.2:**
|
||||
- User Story US-02: "Intakeverslag schrijven met AI-ondersteuning"
|
||||
- Epic E4: "AI Integration" (Week 3)
|
||||
- Succes criterium: "<5s AI response time"
|
||||
|
||||
---
|
||||
|
||||
## 2. Overzicht van de belangrijkste onderdelen
|
||||
🎯 **Doel:** Inzicht in de nieuwe componenten binnen de bestaande EPD-structuur.
|
||||
|
||||
**Nieuwe componenten:**
|
||||
1. **Live Opname Interface** - Microfoon controles, timer, real-time feedback
|
||||
2. **Transcriptie Editor** - TipTap editor met live text streaming
|
||||
3. **AI Verslag Generator** - Claude-powered structurering
|
||||
4. **Audio Management** - Opslaan/deleten opnames (privacy)
|
||||
|
||||
**Bestaande componenten (aangepast):**
|
||||
- Intake Editor - uitgebreid met opname-functionaliteit
|
||||
- AI Rail - nieuwe actie "Structureer Verslag"
|
||||
- Client Dashboard - toon opname-status
|
||||
|
||||
---
|
||||
|
||||
## 3. User Stories
|
||||
|
||||
🎯 **Doel:** Beschrijven wat gebruikers moeten kunnen doen vanuit hun perspectief.
|
||||
|
||||
| ID | Rol | Doel / Actie | Verwachte waarde | Prioriteit |
|
||||
|----|------|---------------|------------------|-------------|
|
||||
| US-10 | Behandelaar | Live opname starten tijdens gesprek | Handen vrij, focus op cliënt | Hoog |
|
||||
| US-11 | Behandelaar | Real-time zien wat er getranscribeerd wordt | Vertrouwen dat het werkt | Hoog |
|
||||
| US-12 | Behandelaar | Opname pauzeren (telefoon, onderbreking) | Geen irrelevante tekst in verslag | Middel |
|
||||
| US-13 | Behandelaar | Transcriptie handmatig corrigeren | Controle over eindresultaat | Hoog |
|
||||
| US-14 | Behandelaar | AI laten structureren tot verslag | Geen handmatig herstructureren | Hoog |
|
||||
| US-15 | Behandelaar | Audio bewaren voor verificatie | Terughoren bij onduidelijkheid | Laag |
|
||||
| US-16 | Demo-bezoeker | Live demo zien werken | Geloven dat het echt werkt | Kritiek |
|
||||
| US-17 | Privacy Officer | Audio auto-delete na X dagen | AVG compliance | Middel |
|
||||
|
||||
---
|
||||
|
||||
## 4. Functionele werking per onderdeel
|
||||
|
||||
### 4.1 Live Opname Interface
|
||||
|
||||
**Functionaliteit:**
|
||||
* Microfoon permissie vragen (browser native)
|
||||
* Audio stream naar Deepgram websocket
|
||||
* Real-time transcriptie ontvangen
|
||||
* Visual feedback (recording indicator, timer)
|
||||
|
||||
**Schermopbouw:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ Intake: Lisa de Jong [🎤 OPNAME 00:12:34] │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────────┐ │
|
||||
│ │ 🔴 Aan het opnemen... │ │
|
||||
│ │ │ │
|
||||
│ │ Laatst: "...moeilijk weer inslapen" │ │
|
||||
│ └──────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ [TipTap Editor - Real-time transcriptie] │
|
||||
│ │
|
||||
│ Client geeft aan dat ze al 3 maanden last heeft van │
|
||||
│ slaapproblemen. Ze wordt 's nachts wakker en kan │
|
||||
│ moeilijk weer inslapen...█ │
|
||||
│ │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ [⏸️ Pauzeer] [⏹️ Stop & Bewaar] [🗑️ Annuleer] │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**States:**
|
||||
- **Initieel**: Knop "🎤 Start Opname" boven editor
|
||||
- **Permission gevraagd**: Modal "Geef toegang tot microfoon"
|
||||
- **Recording**: Rode indicator, timer loopt, tekst verschijnt
|
||||
- **Paused**: Gele indicator, timer gestopt, "Hervatten" knop
|
||||
- **Stopped**: Transcriptie volledig, "Bewerken" of "AI Structureren"
|
||||
|
||||
**Interacties:**
|
||||
1. **Start Opname**
|
||||
- Klik 🎤 Start Opname
|
||||
- Browser vraagt mic permission
|
||||
- Websocket verbinding naar Deepgram
|
||||
- Timer start (00:00:00)
|
||||
- Rode 🔴 indicator verschijnt
|
||||
|
||||
2. **Tijdens Opname**
|
||||
- Gebruiker praat
|
||||
- Deepgram stuurt tekst chunks terug
|
||||
- TipTap editor append tekst real-time
|
||||
- Laatste paar woorden highlighted (fade effect)
|
||||
- Handmatig typen/corrigeren is mogelijk
|
||||
|
||||
3. **Pauzeren**
|
||||
- Klik ⏸️ Pauzeer
|
||||
- Websocket blijft open maar stuurt geen audio
|
||||
- Timer stopt
|
||||
- Indicator wordt geel 🟡
|
||||
- Klik opnieuw → Hervatten
|
||||
|
||||
4. **Stoppen**
|
||||
- Klik ⏹️ Stop & Bewaar
|
||||
- Websocket sluit
|
||||
- Final transcriptie in editor
|
||||
- Audio lokaal opgeslagen (optioneel)
|
||||
- Overschakeling naar "Bewerk Modus"
|
||||
|
||||
5. **Annuleren**
|
||||
- Klik 🗑️ Annuleer
|
||||
- Confirmation: "Weet je het zeker?"
|
||||
- Bij ja: transcriptie verwijderen
|
||||
- Bij nee: doorgaan met opname
|
||||
|
||||
**Error Scenarios:**
|
||||
- **Geen mic permission**: "Geef toegang tot microfoon om op te nemen"
|
||||
- **Internet weg**: "Verbinding verbroken. Opname gepauzeerd."
|
||||
- **Deepgram quota**: "Opname limiet bereikt. Schakel over naar typen?"
|
||||
- **Browser niet ondersteund**: "Je browser ondersteunt geen opname"
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Transcriptie Editor
|
||||
|
||||
**Functionaliteit:**
|
||||
* TipTap editor met live text streaming
|
||||
* Highlight recent toegevoegde tekst
|
||||
* Manual editing tijdens/na opname
|
||||
* Auto-save elke 30 seconden
|
||||
* Undo/redo werkt met live input
|
||||
|
||||
**Schermopbouw:**
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ [TipTap Toolbar: B I U • 1. " ] │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Hoofdklacht: │
|
||||
│ Client geeft aan dat ze al 3 maanden last heeft van │
|
||||
│ slaapproblemen. Ze wordt gemiddeld 3-4 keer per nacht │
|
||||
│ wakker en kan dan moeilijk weer inslapen. │
|
||||
│ │
|
||||
│ Context: │
|
||||
│ De klachten zijn begonnen na een stressvolle periode │
|
||||
│ op het werk. [LIVE: Client vertelt dat...]█ │
|
||||
│ │
|
||||
│ [Laatste update: zojuist • Auto-save actief] │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- **Live highlighting**: Laatste 20 woorden in lichtblauw, fade naar normaal
|
||||
- **Typing indicator**: █ cursor pulseert tijdens transcriptie
|
||||
- **Manual override**: Behandelaar kan tijdens opname typen/corrigeren
|
||||
- **Smart paragraphs**: Deepgram smart formatting maakt alinea's
|
||||
- **Timestamps** (optioneel): [00:12:34] markers voor navigatie
|
||||
|
||||
**States:**
|
||||
- **Live transcriptie**: Tekst append + highlight
|
||||
- **Paused**: Editor blijft bewerkbaar
|
||||
- **Stopped**: Normale editor modus
|
||||
- **Saving**: "Opslaan..." indicator
|
||||
- **Saved**: "✓ Opgeslagen om 14:32"
|
||||
|
||||
---
|
||||
|
||||
### 4.3 AI Verslag Generator
|
||||
|
||||
**Functionaliteit:**
|
||||
* Claude analyseert ruwe transcriptie
|
||||
* Structureert in standaard verslag format
|
||||
* Behoudt feitelijke informatie
|
||||
* Voegt professionele tone toe
|
||||
|
||||
**Workflow:**
|
||||
```
|
||||
[Ruwe Transcriptie]
|
||||
↓
|
||||
[Klik "✨ AI Structureer Verslag"]
|
||||
↓
|
||||
[Claude verwerking 5-10s]
|
||||
↓
|
||||
[Preview in AI Rail]
|
||||
↓
|
||||
[Accepteren → Vervangt origineel]
|
||||
[OF]
|
||||
[Aanpassen → Handmatig bewerken]
|
||||
```
|
||||
|
||||
**AI Rail Layout:**
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ ✨ AI VERSLAG │
|
||||
├─────────────────────────────────────┤
|
||||
│ │
|
||||
│ HOOFDKLACHT │
|
||||
│ Cliënt presenteert zich met │
|
||||
│ slaapproblemen sinds 3 maanden. │
|
||||
│ Nachtelijk ontwaken 3-4x, moeilijk │
|
||||
│ hervatten slaap. │
|
||||
│ │
|
||||
│ ANAMNESE │
|
||||
│ • Onset na werkstress │
|
||||
│ • Geen eerdere slaapklachten │
|
||||
│ • Normale slaaphygiëne │
|
||||
│ │
|
||||
│ OBSERVATIES │
|
||||
│ • Alert en helder │
|
||||
│ • Vermoeidheid zichtbaar │
|
||||
│ │
|
||||
│ PLAN │
|
||||
│ • Vervolgafspraak over 2 weken │
|
||||
│ • Slaapdagboek bijhouden │
|
||||
│ │
|
||||
├─────────────────────────────────────┤
|
||||
│ [✓ Accepteer & Vervang] │
|
||||
│ [📋 Kopieer] │
|
||||
│ [✏️ Handmatig Aanpassen] │
|
||||
│ [❌ Annuleer] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Prompt Strategie (voor Claude):**
|
||||
```
|
||||
Systeem: Je bent een ervaren GGZ-behandelaar die transcripties
|
||||
omzet naar professionele verslagen.
|
||||
|
||||
Instructies:
|
||||
- Structureer in: Hoofdklacht, Anamnese, Observaties, Plan
|
||||
- Behoud alle feitelijke informatie
|
||||
- Gebruik professionele maar toegankelijke taal (B1)
|
||||
- Geen interpretaties, alleen feiten
|
||||
- Max 400 woorden
|
||||
|
||||
Input: [ruwe transcriptie]
|
||||
Output: [gestructureerd verslag in markdown]
|
||||
```
|
||||
|
||||
**States:**
|
||||
- **Idle**: Knop "✨ Structureer Verslag" beschikbaar
|
||||
- **Processing**: Spinner + "AI analyseert..." (5-10s)
|
||||
- **Preview**: Gestructureerd verslag in rail
|
||||
- **Accepted**: Vervangt editor content
|
||||
- **Error**: "Kon niet verwerken. Probeer opnieuw."
|
||||
|
||||
**Acties:**
|
||||
- **Accepteer & Vervang**: Overschrijft originele transcriptie
|
||||
- **Kopieer**: Naar clipboard (voor elders plakken)
|
||||
- **Handmatig Aanpassen**: Opent in split-view (links origineel, rechts AI)
|
||||
- **Annuleer**: Verwerpt AI-versie, behoudt origineel
|
||||
|
||||
---
|
||||
|
||||
### 4.4 Audio Management
|
||||
|
||||
**Functionaliteit:**
|
||||
* Originele audio opslaan (optioneel)
|
||||
* Replay functionaliteit
|
||||
* Privacy-compliant auto-delete
|
||||
* Storage in Supabase
|
||||
|
||||
**UI Elementen:**
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ AUDIO OPNAME │
|
||||
├─────────────────────────────────────┤
|
||||
│ 📁 opname-2024-11-19-14-32.webm │
|
||||
│ Duur: 12:34 • 5.2 MB │
|
||||
│ │
|
||||
│ [▶️ Afspelen] [📥 Download] │
|
||||
│ │
|
||||
│ ⚠️ Privacy: │
|
||||
│ [ ] Audio bewaren voor verificatie │
|
||||
│ [ ] Auto-delete na 7 dagen │
|
||||
│ │
|
||||
│ [💾 Opslaan] [🗑️ Verwijderen] │
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Privacy Flow:**
|
||||
1. **Tijdens opname**: Audio lokaal in browser
|
||||
2. **Streaming**: Naar Deepgram (niet bewaard door hen)
|
||||
3. **Na stop**:
|
||||
- Optie 1: Direct deleten (default)
|
||||
- Optie 2: Uploaden naar Supabase Storage
|
||||
4. **Auto-delete**: Cron job verwijdert na X dagen
|
||||
|
||||
**Database Schema:**
|
||||
```typescript
|
||||
interface AudioRecording {
|
||||
id: uuid
|
||||
intake_note_id: uuid // FK naar intake_notes
|
||||
storage_path: string // Supabase Storage path
|
||||
duration_seconds: number
|
||||
file_size_bytes: number
|
||||
created_at: timestamp
|
||||
expires_at: timestamp // Auto-delete datum
|
||||
deleted: boolean
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. UI-overzicht (visuele structuur)
|
||||
|
||||
### 5.1 Intake met Live Opname (Volledig scherm)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Logo | Intake: Lisa de Jong | [🎤 00:12:34] [⚙️] │
|
||||
├──────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌────────────────────┐ ┌─────────────────────────────────────┐ │
|
||||
│ │ SIDEBAR NAV │ │ EDITOR GEBIED │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ > Overzicht │ │ [🔴 AAN HET OPNEMEN] │ │
|
||||
│ │ • Intakes │ │ │ │
|
||||
│ │ Profiel │ │ [TipTap Editor met live tekst] │ │
|
||||
│ │ Plan │ │ │ │
|
||||
│ │ Afspraken │ │ Client geeft aan dat ze al... │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ │ │
|
||||
│ │ │ │ [⏸️ Pauzeer] [⏹️ Stop] [🗑️ Annuleer]│ │
|
||||
│ │ │ │ │ │
|
||||
│ └────────────────────┘ └─────────────────────────────────────┘ │
|
||||
│ │
|
||||
├──────────────────────────────────────────────────────────────────┤
|
||||
│ [Toast Area: "✓ Auto-save om 14:32" ] │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 5.2 AI Verslag Generatie (Split View)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────┐
|
||||
│ Mini-ECD Logo | Intake: Lisa de Jong | [✨ AI Actief] [⚙️]│
|
||||
├──────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ ┌──────────────────────────────────┬─────────────────────────────┐
|
||||
│ │ EDITOR (Originele Transcriptie) │ AI RAIL (Verslag) │
|
||||
│ │ │ │
|
||||
│ │ Client geeft aan dat ze al 3 │ ✨ GESTRUCTUREERD VERSLAG │
|
||||
│ │ maanden last heeft van slaap- │ │
|
||||
│ │ problemen. Ze wordt gemiddeld │ HOOFDKLACHT │
|
||||
│ │ 3-4 keer per nacht wakker... │ Cliënt presenteert zich... │
|
||||
│ │ │ │
|
||||
│ │ [250+ woorden ruwe tekst] │ ANAMNESE │
|
||||
│ │ │ • Onset na werkstress │
|
||||
│ │ │ • Geen eerdere klachten │
|
||||
│ │ │ │
|
||||
│ │ │ OBSERVATIES │
|
||||
│ │ │ • Alert en helder │
|
||||
│ │ │ │
|
||||
│ │ │ PLAN │
|
||||
│ │ │ • Vervolgafspraak │
|
||||
│ │ │ │
|
||||
│ │ │ [✓ Accepteer & Vervang] │
|
||||
│ │ │ [📋 Kopieer] │
|
||||
│ │ │ [❌ Annuleer] │
|
||||
│ └──────────────────────────────────┴─────────────────────────────┘
|
||||
│ │
|
||||
└──────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Interacties met AI (functionele beschrijving)
|
||||
|
||||
### 6.1 Deepgram (Speech-to-Text)
|
||||
|
||||
| Aspect | Detail |
|
||||
|--------|--------|
|
||||
| **Trigger** | Klik "🎤 Start Opname" |
|
||||
| **Input** | Live audio stream van microfoon |
|
||||
| **Verwerking** | Deepgram Nova-2 model, Nederlands, smart formatting |
|
||||
| **Output** | Real-time text chunks → append in editor |
|
||||
| **Latency** | <500ms per chunk |
|
||||
| **Feedback** | Live typing indicator + highlight recent text |
|
||||
| **Cost** | €0,0043/min = €0,19 per 45-min gesprek |
|
||||
|
||||
**Technische flow:**
|
||||
```
|
||||
Browser Mic → Websocket → Deepgram API
|
||||
↓
|
||||
Text chunks
|
||||
↓
|
||||
TipTap Editor
|
||||
```
|
||||
|
||||
### 6.2 Claude (Verslag Structurering)
|
||||
|
||||
| Aspect | Detail |
|
||||
|--------|--------|
|
||||
| **Trigger** | Klik "✨ Structureer Verslag" |
|
||||
| **Input** | Ruwe transcriptie (TipTap JSON) |
|
||||
| **Verwerking** | Claude 3.5 Sonnet met GGZ-verslag prompt |
|
||||
| **Output** | Markdown gestructureerd verslag (4 secties) |
|
||||
| **Latency** | 5-10 seconden |
|
||||
| **Feedback** | Spinner → Preview in AI Rail → Accept/Edit |
|
||||
| **Cost** | ~2000 tokens = €0,006 per verslag |
|
||||
|
||||
**Prompt template:**
|
||||
```typescript
|
||||
const PROMPT = `
|
||||
Je bent een ervaren GGZ-behandelaar. Structureer deze
|
||||
transcriptie in een professioneel verslag.
|
||||
|
||||
STRUCTUUR:
|
||||
1. HOOFDKLACHT - Waarom komt cliënt?
|
||||
2. ANAMNESE - Achtergrond, ontstaan, context
|
||||
3. OBSERVATIES - Wat viel op tijdens gesprek
|
||||
4. PLAN - Vervolgstappen
|
||||
|
||||
REGELS:
|
||||
- Behoud alle feiten
|
||||
- B1 taalniveau (professioneel maar helder)
|
||||
- Geen interpretaties
|
||||
- Max 400 woorden
|
||||
|
||||
TRANSCRIPTIE:
|
||||
${transcriptText}
|
||||
|
||||
OUTPUT (markdown format):
|
||||
`;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Gebruikersrollen en rechten
|
||||
|
||||
| Rol | Toegang | Beperkingen |
|
||||
|-----|---------|-------------|
|
||||
| **Behandelaar** | Volledige opname + AI features | Alleen eigen cliënten |
|
||||
| **Demo User** | Volledige opname + AI features | Alleen demo-data (fictief) |
|
||||
| **Manager** | Alleen transcripties lezen | Geen opname starten |
|
||||
| **Auditor** | Toegang tot audio (indien bewaard) | Read-only |
|
||||
|
||||
**Privacy niveau per rol:**
|
||||
- Behandelaar: Kan audio bewaren/deleten
|
||||
- Demo: Audio auto-delete na sessie
|
||||
- Manager: Geen audio toegang
|
||||
- Auditor: Alleen bij specifieke permissie
|
||||
|
||||
---
|
||||
|
||||
## 8. Demo Scenario (10 minuten)
|
||||
|
||||
### Scenario: GGZ Professional Demo
|
||||
|
||||
**Setup:**
|
||||
- Demo account ingelogd
|
||||
- Client "Demo Persoon" vooraf aangemaakt
|
||||
- Microfoon getest (backup: pre-recorded audio)
|
||||
|
||||
**Flow:**
|
||||
|
||||
**[0:00 - 1:00] Intro & Context**
|
||||
> "Traditioneel EPD: 30 minuten typen na gesprek. Wij: 2 minuten AI-tijd. Laten we het live zien."
|
||||
|
||||
**[1:00 - 3:00] Live Opname Demo**
|
||||
1. Navigeer naar Intakes tab
|
||||
2. Klik "🎤 Start Opname"
|
||||
3. Browser vraagt microfoon → Toestaan
|
||||
4. Begin praten (vooraf script):
|
||||
```
|
||||
"Client geeft aan dat ze de afgelopen 3 maanden
|
||||
last heeft van slaapproblemen. Ze wordt gemiddeld
|
||||
3 tot 4 keer per nacht wakker en kan dan moeilijk
|
||||
weer inslapen. De klachten zijn begonnen na een
|
||||
stressvolle periode op het werk..."
|
||||
```
|
||||
5. Toon live verschijnende tekst in editor
|
||||
6. Demonstreer Pauzeer functie (5 sec stilte)
|
||||
7. Hervatten, nog 30 seconden verder praten
|
||||
8. Stop opname
|
||||
|
||||
**[3:00 - 5:00] AI Verslag Generatie**
|
||||
1. Toon ruwe transcriptie (250+ woorden)
|
||||
2. Klik "✨ Structureer Verslag"
|
||||
3. Wacht 5 seconden (toon spinner)
|
||||
4. AI Rail toont gestructureerd verslag:
|
||||
- Hoofdklacht
|
||||
- Anamnese (bullets)
|
||||
- Observaties
|
||||
- Plan
|
||||
5. Klik "Accepteer & Vervang"
|
||||
6. Editor toont nu professioneel verslag
|
||||
|
||||
**[5:00 - 7:00] ROI Pitch**
|
||||
```
|
||||
┌────────────────────────────────────────┐
|
||||
│ TRADITIONEEL → AI SPEEDRUN │
|
||||
├────────────────────────────────────────┤
|
||||
│ 45 min gesprek 45 min gesprek │
|
||||
│ 30 min typen 2 min AI check │
|
||||
│ = 75 min totaal = 47 min totaal │
|
||||
│ │
|
||||
│ Kost: €31,25 Kost: €19,58 │
|
||||
│ (behandelaar @€25/u) (+€0,19 AI) │
|
||||
│ │
|
||||
│ BESPARING: 37% tijd, 38% kosten │
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**[7:00 - 9:00] Extra Features Tour**
|
||||
- Toon audio bewaar-optie (privacy toggle)
|
||||
- Toon auto-delete na 7 dagen
|
||||
- Toon handmatig correctie tijdens opname
|
||||
- Toon pause/resume workflow
|
||||
|
||||
**[9:00 - 10:00] Q&A & Next Steps**
|
||||
> "Dit is week 2 van de build. Volgende week: behandelplan AI-generatie. Follow op LinkedIn!"
|
||||
|
||||
---
|
||||
|
||||
## 9. Edge Cases & Error Handling
|
||||
|
||||
| Scenario | Systeem Gedrag | User Feedback |
|
||||
|----------|---------------|---------------|
|
||||
| **Geen microfoon** | Disable opname-knop | "Geen microfoon gedetecteerd" |
|
||||
| **Mic permission denied** | Show instructie | "Geef toegang via browser-instellingen" |
|
||||
| **Internet valt weg** | Pause + buffer lokaal | "Verbinding verbroken, hervatten?" |
|
||||
| **Deepgram quota op** | Switch naar manual | "Opname limiet bereikt, typ handmatig" |
|
||||
| **Browser refresh tijdens opname** | Verlies opname | Warning: "Opname gaat verloren bij refresh" |
|
||||
| **Claude API timeout** | Retry 1x, dan fail | "Verwerking duurde te lang, probeer opnieuw" |
|
||||
| **Audio te groot (>25MB)** | Reject upload | "Audio te groot, max 45 minuten" |
|
||||
| **Geen spraak gedetecteerd** | Timer stopt na 30s stilte | "Geen spraak gedetecteerd, pauzeren?" |
|
||||
|
||||
---
|
||||
|
||||
## 10. Performance & Kosten
|
||||
|
||||
### 10.1 Performance Targets
|
||||
|
||||
| Metric | Target | Measurement |
|
||||
|--------|--------|-------------|
|
||||
| **Deepgram latency** | <500ms per chunk | Websocket timestamp |
|
||||
| **Editor update** | <100ms per chunk | React render time |
|
||||
| **Claude verslag** | <10s total | API call duration |
|
||||
| **Audio upload** | <5s voor 45 min | Supabase Storage speed |
|
||||
| **UI responsiveness** | 60fps tijdens opname | Chrome DevTools |
|
||||
|
||||
### 10.2 Cost Breakdown
|
||||
|
||||
**Per gesprek (45 minuten):**
|
||||
```
|
||||
Deepgram transcriptie: €0,19
|
||||
Claude structurering: €0,006
|
||||
Supabase storage: €0,001 (indien bewaard)
|
||||
──────────────────────────────
|
||||
Totaal per gesprek: €0,197
|
||||
|
||||
Traditioneel alternatief:
|
||||
30 min behandelaar tijd @ €25/uur = €12,50
|
||||
|
||||
ROI: 6.244% besparing
|
||||
```
|
||||
|
||||
**Maandelijks (100 gesprekken):**
|
||||
```
|
||||
Deepgram: €19,00
|
||||
Claude: €0,60
|
||||
Storage: €0,10
|
||||
──────────────────
|
||||
Totaal: €19,70/maand
|
||||
|
||||
Traditioneel: €1.250/maand (behandelaar-tijd)
|
||||
Besparing: €1.230/maand (98%)
|
||||
```
|
||||
|
||||
**Binnen €50/maand budget?**
|
||||
✅ Ja, zelfs met 250 gesprekken/maand = €49,25
|
||||
|
||||
---
|
||||
|
||||
## 11. Privacy & AVG Compliance
|
||||
|
||||
### 11.1 Data Flow
|
||||
|
||||
```
|
||||
1. Audio opname → Browser (lokaal)
|
||||
2. Stream → Deepgram (real-time, niet bewaard)
|
||||
3. Transcriptie → Supabase EU (bewaard)
|
||||
4. Audio → Optioneel Supabase Storage (bewaard)
|
||||
5. Auto-delete → Cron job (na X dagen)
|
||||
```
|
||||
|
||||
### 11.2 Privacy Measures
|
||||
|
||||
| Aspect | Implementatie |
|
||||
|--------|---------------|
|
||||
| **Audio storage** | Opt-in (default: niet bewaren) |
|
||||
| **Deepgram policy** | Audio niet bewaard, GDPR compliant |
|
||||
| **Supabase region** | EU (Frankfurt/London) |
|
||||
| **Encryption** | At-rest + in-transit (TLS) |
|
||||
| **Auto-delete** | Configureerbaar (7/14/30 dagen) |
|
||||
| **Access control** | RLS policies (alleen eigen data) |
|
||||
| **Audit log** | Wie heeft wanneer audio beluisterd |
|
||||
|
||||
### 11.3 Disclaimer (demo)
|
||||
|
||||
> **Demo Privacy Notice:**
|
||||
> Deze demo gebruikt fictieve data. Voor productie:
|
||||
> - Audio wordt niet bewaard door Deepgram
|
||||
> - Opslag in EU-regio servers
|
||||
> - Automatische verwijdering na [X] dagen
|
||||
> - Volledige AVG-compliance
|
||||
|
||||
---
|
||||
|
||||
## 12. Technische Dependencies
|
||||
|
||||
| Component | Library/Service | Version | Kritiek |
|
||||
|-----------|----------------|---------|---------|
|
||||
| **Speech-to-Text** | Deepgram Nova-2 | Latest | Ja |
|
||||
| **Editor** | TipTap (ProseMirror) | v2.x | Ja |
|
||||
| **AI Structuur** | Claude 3.5 Sonnet | Latest | Ja |
|
||||
| **Websocket** | Native Browser API | - | Ja |
|
||||
| **Audio Storage** | Supabase Storage | - | Nee |
|
||||
| **UI Components** | shadcn/ui | - | Nee |
|
||||
|
||||
**Fallback strategie:**
|
||||
- Deepgram down → Manual typing
|
||||
- Claude down → Save transcriptie, later structureren
|
||||
- Websocket fail → Polling fallback (degraded UX)
|
||||
|
||||
---
|
||||
|
||||
## 13. Bijlagen & Referenties
|
||||
|
||||
**Gerelateerde documenten:**
|
||||
- PRD v1.2 (Product Requirements Document)
|
||||
- TO v1.2 (Technisch Ontwerp) - wordt aangevuld met dit FO
|
||||
- UX Stylesheet - kleuren voor recording UI
|
||||
- Bouwplan v1.1 - Epic E4 (Week 3)
|
||||
|
||||
**Externe referenties:**
|
||||
- [Deepgram Docs](https://developers.deepgram.com/docs/getting-started-with-live-streaming-audio)
|
||||
- [TipTap Docs](https://tiptap.dev/docs/editor/getting-started)
|
||||
- [Claude API](https://docs.anthropic.com/claude/reference)
|
||||
- [Web Speech API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API)
|
||||
|
||||
**Demo assets:**
|
||||
- Intake script (Nederlands, 3 minuten)
|
||||
- Pre-recorded backup audio
|
||||
- ROI calculator spreadsheet
|
||||
- LinkedIn post templates (Week 2-3)
|
||||
|
||||
---
|
||||
|
||||
**Versiehistorie:**
|
||||
|
||||
| Versie | Datum | Auteur | Wijziging |
|
||||
|--------|-------|--------|-----------|
|
||||
| v1.0 | 19-11-2024 | Colin | Initiële versie - Live Transcriptie & AI Verslag |
|
||||
|
||||
---
|
||||
|
||||
**Einde Functioneel Ontwerp - Live Transcriptie Feature**
|
||||
@@ -128,10 +128,12 @@ export async function signUpWithPassword(email: string, password: string) {
|
||||
*/
|
||||
export async function resetPasswordForEmail(email: string) {
|
||||
const supabase = createClient()
|
||||
// Redirect to callback route - Supabase will automatically add type=recovery parameter
|
||||
// The callback route will detect type=recovery and redirect to /update-password
|
||||
// Force Supabase to bounce back via the auth callback with next=/update-password
|
||||
const params = new URLSearchParams({ next: '/update-password' })
|
||||
const redirectTo = `${window.location.origin}/auth/callback?${params.toString()}`
|
||||
|
||||
const { error } = await supabase.auth.resetPasswordForEmail(email, {
|
||||
redirectTo: `${window.location.origin}/auth/callback`
|
||||
redirectTo
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
|
||||
Reference in New Issue
Block a user