{"stories": [{"id": "US-CAL-1", "epic": "Kalender Integratie - Tentative Events", "role": "Teamlid", "title": "Tentative events in agenda zien", "story": "Als teamlid wil ik kandidaatdatums als tentative afspraken in mijn agenda zien", "why": "zodat ik potentiële meetings zie zonder handmatige invoer", "functionality": ["Elke kandidaatdatum verschijnt als apart VEVENT met STATUS:TENTATIVE", "VEVENT bevat: titel (polltitel + kandidaatlabel), beschrijving met stemtotaal en stemlink", "URL-veld wijst naar persoonlijke stempagina", "Events hebben stabiele UID per kandidaatdatum"], "acceptance_criteria": ["Events verschijnen na volgende polling-cyclus van feed", "Geen duplicaten op opeenvolgende feed-vernieuwingen", "Alle tentative events zijn zichtbaar als grijze (tentative) entries", "Stemlink verwijst naar juiste persoonlijke stempagina"], "milestone": "M1", "feedback": []}, {"id": "US-CAL-2", "epic": "Kalender Integratie - Tentative Events", "role": "Teamlid", "title": "Feed updates na stemactie ontvangen", "story": "Als teamlid wil ik zien dat mijn kalenderevents bijgewerkt worden met nieuwe stemopdrachten", "why": "zodat ik op de hoogte blijf van de voortgang van stemming", "functionality": ["Na elke stem worden alle teamleden feeds opnieuw gegenereerd", "VEVENT SEQUENCE wordt opgehoogd bij elke update", "Beschrijving toont: ja/misschien/nee-tellingen, wie nog niet hebben gestemd", "Calendar client haalt wijzigingen op volgende polling-cyclus"], "acceptance_criteria": ["Stemtotaal wordt binnen minuten bijgewerkt zichtbaar", "SEQUENCE-nummer neemt toe", "Wie niet gestemd hebben is zichtbaar in event-beschrijving", "Oude en nieuwe stemmingen tonen zich consistent"], "milestone": "M2", "feedback": []}, {"id": "US-CLOSE-1", "epic": "Beslissing en Afsluiting", "role": "Teamleider", "title": "Winnende datum bevestigen als CONFIRMED", "story": "Als teamleider wil ik een winnende datum bevestigen zodat alle agendas het finale moment tonen", "why": "zodat iedereen weet welke datum definitief is gekozen", "functionality": ["Teamleider kiest één kandidaatdatum als bevestigd", "Bevestigde datum VEVENT verandert naar STATUS:CONFIRMED in alle feeds", "Alle andere kandidaatdatums krijgen STATUS:CANCELLED in alle feeds", "Poll-status verandert naar CLOSED — geen verdere stemming mogelijk"], "acceptance_criteria": ["Bevestigde datum verschijnt als CONFIRMED event", "Andere datums krijgen CANCELLED status", "Poll kan niet meer worden gestemd", "Cancelled VEVENTs blijven minstens twee polling-cycli zichtbaar"], "milestone": "M1", "feedback": []}, {"id": "US-CLOSE-2", "epic": "Beslissing en Afsluiting", "role": "Teamleider", "title": "Poll annuleren met optionele reden", "story": "Als teamleider wil ik een volledige poll annuleren zodat alle tentative events verdwijnen", "why": "zodat leden geen verwarrende instellingen in hun agenda behouden", "functionality": ["Alle kandidaat-VEVENTs krijgen STATUS:CANCELLED in alle feeds", "Poll-status verandert naar CANCELLED", "Annulerings-reden (optioneel) verschijnt in VEVENT-beschrijving voordat verwijdering"], "acceptance_criteria": ["Alle tentative events verdwijnen na twee polling-cycli", "Poll kan niet meer worden gestemd", "Annuleringsbericht is zichtbaar in feed gedurende retention-periode"], "milestone": "M2", "feedback": []}, {"id": "US-CLOSE-3", "epic": "Beslissing en Afsluiting", "role": "Systeem", "title": "Verlopen poll markeren als EXPIRED", "story": "Als systeem wil ik een poll markeren als EXPIRED wanneer deadline verstrijkt zonder beslissing", "why": "zodat verlaten polls niet in agenda's blijven hangen", "functionality": ["Poll kan optioneel deadline-datum hebben bij creatie", "Wanneer deadline verstrijkt zonder CLOSED status, systeem stelt poll in op EXPIRED", "EXPIRED triggert hetzelfde CANCELLED VEVENT-gedrag als annulering", "Teamleider krijgt zichtbare melding op organizer-dashboard"], "acceptance_criteria": ["Deadline-check loopt automatisch af", "EXPIRED deadline produceert CANCELLED events", "Teamleider ziet EXPIRED-status op dashboard", "Geen handmatige tussenkomst vereist"], "milestone": "M3", "feedback": []}, {"id": "US-DASH-1", "epic": "Organizer Dashboard", "role": "Teamleider", "title": "Actieve polls beheren en monitoren", "story": "Als teamleider wil ik een overzicht van al mijn actieve polls hebben", "why": "zodat ik voortgang kan monitoren en actie kan ondernemen", "functionality": ["Dashboard toont per poll: titel, team, stemvordering (X van Y geantwoord), kandidaatdatums, status", "Toegankelijk via teamleider token-URL — geen login", "Acties beschikbaar per poll: datum bevestigen, kandidaat toevoegen/verwijderen, poll annuleren"], "acceptance_criteria": ["Dashboard toont alle actieve polls voor deze teamleider", "Stemtotaal is duidelijk (bijv. '7 van 9 gestemd')", "Acties zijn één klik beschikbaar per poll", "Dashboard is responsive op mobiel"], "milestone": "M2", "feedback": []}, {"id": "US-MERGE-1", "epic": "Identiteit en Merge", "role": "Systeem", "title": "Globale persoonsregistratie handhaven", "story": "Als systeem wil ik ervoor zorgen dat elke persoon exact eenmaal globaal bestaat", "why": "zodat één mens nooit twee keer wordt vertegenwoordigd", "functionality": ["Elke persoon heeft exact één UUID (intern, nooit blootgesteld) en één profile_token (hoog-entropie URL-safe)", "Profiel-URL is https://app/p/{profile_token} — geen UUID in URLs", "Een persoon kan lid zijn van meerdere teams tegelijk met eenzelfde identiteit", "Weergavenaam en handle kunnen editable zijn zonder tokens te veranderen"], "acceptance_criteria": ["UUID is altijd stabiel en uniek", "profile_token verandert nooit (behalve bij merge)", "UUID staat nooit in URL of feed", "Één persoon kan in meerdere teams tegelijk"], "milestone": "M3", "feedback": []}, {"id": "US-MERGE-2", "epic": "Identiteit en Merge", "role": "Teamleider", "title": "Bekende persoon van gedeeld team uitnodigen", "story": "Als teamleider wil ik iemand van een ander team uitnodigen die ik al ken", "why": "zodat zij in mijn nieuw team kunnen zonder dubbele identiteiten", "functionality": ["Bij team-creatie of -beheer ziet leider zoeken-lijst van alle personen uit gedeelde team(s)", "Selecteren van bekende persoon crëert TeamMembership voor bestaande UUID — geen nieu Person-record", "Dat persoon's profielpagina krijgt onmiddellijk nieuw team en polls", "Geen uitnodiging-link — persoon ontdekt team op volgende bezoek"], "acceptance_criteria": ["Bekende persoon verschijnt in zoeklijst", "Selectie voegt hen toe zonder nieuwe UUID", "Nieuw team is onmiddellijk zichtbaar op hun profiel", "Geen e-mail of notif"], "milestone": "M3", "feedback": []}, {"id": "US-MERGE-3", "epic": "Identiteit en Merge", "role": "Teamleider", "title": "Onbekende persoon uitnodigen met uitnodigingslink", "story": "Als teamleider wil ik iemand niet op het platform uitnodigen", "why": "zodat zij een profielpagina krijgen zonder mij hun e-mailadres te hoeven vragen", "functionality": ["Leider voert weergavenaam en optionele handle in voor nieuwe persoon", "Systeem crëert provisorische Persoon-record: nieuwe UUID, nieuwe profile_token, status PROVISIONAL", "Systeem genera profiel-URL: https://app/p/{profile_token}", "Leider kopieert URL en verdeelt via out-of-band kanaal (Signal, WhatsApp, in-persoon)", "Provisorische persoon kan onmiddellijk stemmen — PROVISIONAL status onzichtbaar"], "acceptance_criteria": ["Uitnodigingslink is gemakkelijk te kopiëren", "Nieuwe persoon kan onmiddellijk stemmen", "PROVISIONAL status is onzichtbaar", "Link werkt via Signal/externe kanalen"], "milestone": "M3", "feedback": []}, {"id": "US-MERGE-4", "epic": "Identiteit en Merge", "role": "Teamlid", "title": "Identiteit merge initiëren van bestaande profiel", "story": "Als teamlid wil ik een new provisorische identiteit absorberen in mijn bestaande profiel", "why": "zodat ik niet twee profielen heb", "functionality": ["Op provisorische profielpagina staat: 'Al op platform? Kopieer deze link en plak in bestaand profiel'", "Persoon navigeert naar bestaand profielpagina (al gebookmarkt)", "Bestand profielpagina toont merge-veld: plak new profiel-URL hier", "Bij indienen: systeem merkt TEAM-lidschappen van new → bestaande UUID", "Provisorische profiel-URL stuurt door naar bestaand profiel"], "acceptance_criteria": ["Merge kan alleen van bestaand profiel initiaal worden", "Alle teams van new profiel zijn onmiddellijk zichtbaar", "Alde stemmen blijven behouden", "Merge kan niet ongedaan worden via UI"], "milestone": "M3", "feedback": []}, {"id": "US-MERGE-5", "epic": "Identiteit en Merge", "role": "Systeem", "title": "Merge-aanvraag valideren alvorens uit te voeren", "story": "Als systeem wil ik merge-aanvragen valideren voordat ik ze uitvoer", "why": "zodat accidentele of schadelijke merges voorkomen worden", "functionality": ["Systeem controlit dat token PROVISIONAL is — merging twee geéstableerde identiteiten weigeren", "Systeem controleert dat twee tokens niet dezelfde persoon zijn", "Systeem controleert dat absorberen geen duplicate TeamMembership crëert — bestaand blijft, duplicate verwijderd", "Merge is atomaire database-transactie — gebeurde-merges onmogelijk"], "acceptance_criteria": ["Twee bestaande identiteiten kunnen niet mergen", "Zelfmering wordt geweigerd", "Duplicate team-lidmaatschappen veroorzaken geen fouten", "Transactie-faling verandert niets"], "milestone": "M3", "feedback": []}, {"id": "US-POLL-1", "epic": "Poll Creatie en Beheer", "role": "Teamleider", "title": "Poll aanmaken met titel en datums", "story": "Als teamleider wil ik een datumpoll aanmaken voor mijn team", "why": "zodat teamleden kunnen stemmen op kandidaatdatums", "functionality": ["Poll heeft titel, optionele beschrijving en behoort tot één team", "Minstens twee kandidaatdatums vereist om poll aan te maken", "Poll is onmiddellijk actief na creatie", "Elke kandidaatdatum heeft datum + optionele starttijd + optionele duur"], "acceptance_criteria": ["Poll titel is verplicht en niet leeg", "Minimaal twee verschillende datums moeten worden ingesteld", "Status van poll is OPEN onmiddellijk na creatie", "Feed-regeneratie vindt plaats voor alle teamleden"], "milestone": "M1", "feedback": []}, {"id": "US-POLL-2", "epic": "Poll Creatie en Beheer", "role": "Teamleider", "title": "Kandidaatdatum toevoegen aan actieve poll", "story": "Als teamleider wil ik een kandidaatdatum aan een actieve poll toevoegen", "why": "zodat ik de stemopties kan uitbreiden", "functionality": ["Datums kunnen alleen worden toegevoegd als poll OPEN is", "Toevoegen van datum triggert feed-regeneratie voor alle teamleden", "Duplicate datums (zelfde datetime) worden afgewezen"], "acceptance_criteria": ["Nieuwe datum verschijnt in feeds van alle leden", "Duplicate datums krijgen duidelijke foutmelding", "Bestaande stemmen worden niet beïnvloed"], "milestone": "M2", "feedback": []}, {"id": "US-POLL-3", "epic": "Poll Creatie en Beheer", "role": "Teamleider", "title": "Kandidaatdatum uit poll verwijderen", "story": "Als teamleider wil ik een kandidaatdatum uit een open poll verwijderen", "why": "zodat ik fouten kan corrigeren en ongewenste opties kan verwijderen", "functionality": ["Verwijderde datum produceert STATUS:CANCELLED VEVENT in alle feeds", "CANCELLED VEVENT blijft minimaal twee polling-cycli in feed", "Bestaande stemmen voor deze datum worden verwijderd", "Verwijderen van laatste kandidaat wordt geweigerd"], "acceptance_criteria": ["Datum met aanwijs verdwijnt na twee polling-cycli", "STATUS:CANCELLED event verschijnt onmiddellijk", "Kan niet alle datums verwijderen", "Bestaande stemmen zijn verwijderd"], "milestone": "M2", "feedback": []}, {"id": "US-PROFILE-1", "epic": "Web-only Profiel Toegang", "role": "Teamlid", "title": "Persoonlijke profielpagina openen en bekijken", "story": "Als teamlid wil ik mijn persoonlijke profielpagina openen zonder login", "why": "zodat ik al mijn polls kan zien en erop kan stemmen zonder kalenderapps", "functionality": ["Pagina is toegankelijk via persoonlijke token-URL — geen afzonderlijke login", "Pagina toont: lidnaam, team(s), alle actieve polls met kandidaatdatums", "Jouw huidige stem per kandidaat is zichtbaar", "Pagina werkt volledig op mobiel"], "acceptance_criteria": ["Profielpagina laadt zonder login", "Alle actieve polls zijn zichtbaar", "Naam en teams zijn correct weergegeven", "Link delen geeft vol toegang — lijkt verantwoordelijk voor geheimhouding"], "milestone": "M1", "feedback": []}, {"id": "US-PROFILE-2", "epic": "Web-only Profiel Toegang", "role": "Teamlid", "title": "Poll details en tally op profielpagina zien", "story": "Als teamlid wil ik poll-details op mijn profielpagina zien", "why": "zodat ik begrijp wat ik stem", "functionality": ["Poll toont: titel, optionele beschrijving, aangemaakt door, deadline (indien ingesteld)", "Elke kandidaatdatum toont: datum/tijd, huidge stem-tally (ja/misschien/nee-tellingen), eigen huide stem", "Link naar volledige stem-overzicht beschikbaar per poll", "Visuele onderscheid tussen OPEN, CLOSED, CANCELLED polls"], "acceptance_criteria": ["Poll-titel en beschrijving zijn duidelijk", "Steltotaal wordt bijgewerkt op pagina-verniewing", "OPEN polls tonen stem-opties", "CLOSED/CANCELLED polls tonen geslotenheid"], "milestone": "M2", "feedback": []}, {"id": "US-PROFILE-3", "epic": "Web-only Profiel Toegang", "role": "Teamlid", "title": "Stemmen rechtstreeks van profielpagina", "story": "Als teamlid wil ik rechtstreeks van mijn profielpagina op polls stemmen", "why": "zodat ik kan stemmen zonder een kalenderapps te gebruiken", "functionality": ["Stem-UI op profielpagina is identiek in gedrag aan webpagina (dezelfde eindpunt, hetzelfde token)", "Alle kandidaatdatums van poll worden tegelijkertijd weergegeven — één inzendactie voor alle stemmen", "Huige stem-status is voorgevuld op pagina-laden", "Na indienen verversen pagina's met bijgewerkte tellingen — geen omleiding"], "acceptance_criteria": ["Alle stemopties (ja/misschien/nee) zijn selecteerbaar", "Huidge stem staat voorgeselecteerd", "Inzenden slaat alle stemmen tegelijk op", "Tellingen worden onmiddellijk bijgewerkt"], "milestone": "M1", "feedback": []}, {"id": "US-PROFILE-4", "epic": "Web-only Profiel Toegang", "role": "Teamleider", "title": "Lidprofiellink delen via externe kanalen", "story": "Als teamleider wil ik elk lids profiellink kunnen delen via externe kanalen", "why": "zodat ik leden kan bereiken die geen kalenderapps gebruiken", "functionality": ["Profiel-URL is platte HTTPS-link — geen app vereist", "Pagina rendert zonder JavaScript indien mogelijk (progressieve verbetering)", "Pagina-titel en meta-beschrijving identificeren dit als persoonlijk", "Teamleider kan elk lids profiellink ophalen van dashboard"], "acceptance_criteria": ["Link werkt in alle browsers", "Pagina laadt snel zonder JavaScript afhankelijk", "Meta-tags voorkomen verwarring bij onopzettelijk delen", "Dashboard toont alle lid-links"], "milestone": "M2", "feedback": []}, {"id": "US-PROFILE-5", "epic": "Web-only Profiel Toegang", "role": "Teamlid", "title": "iCal feed-URL op profielpagina zien en kopiëren", "story": "Als teamlid wil ik mijn iCal feed-URL op mijn profielpagina zien", "why": "zodat ik later altijd kan overstappen op een calendarpps als ik wil", "functionality": ["Profielpagina toont iCal feed-URL prominent met copy-knop", "Pagina bevat korte instructie (één regel) voor abonnementen in Google Calendar, Apple Calendar, Outlook", "Feed-URL is dezelfde als in US-TEAM-3 — geen duplicatie"], "acceptance_criteria": ["Feed-URL is zichtbaar en makkelijk te kopiëren", "Instructies zijn kort en duidelijk", "URL werkt met standaard calendarapps"], "milestone": "M2", "feedback": []}, {"id": "US-RECUR-1", "epic": "Terugkerende Events en Series", "role": "Teamleider", "title": "Terugkerende series aanmaken met patroon", "story": "Als teamleider wil ik een terugkerende serie aanmaken met een herhaalpatroon", "why": "zodat ik niet elke week ook polls handmatig hoef aan te maken", "functionality": ["Teamleider selecteert herhalingspatroon: bijv. 'Elke maandag en donderdag, afwisselend om de twee weken'", "Teamleider voert startdatum in en optioneel een einddatum", "Systeem slaat serie op met patroon als tekst (geen RRULE)", "Serie kan gedeactiveerd worden door teamleider"], "acceptance_criteria": ["Patroon kan eenvoudig in taal worden beschreven", "Patroon wordt opgeslagen als leesbare tekst", "Serie heeft status ACTIVE of INACTIVE", "Startdatum is verplicht, einddatum optioneel"], "milestone": "M2", "feedback": []}, {"id": "US-RECUR-2", "epic": "Terugkerende Events en Series", "role": "Systeem", "title": "Terugkerende occurrences genereren", "story": "Als systeem wil ik terugkerende occurrences vooraf genereren voor een reeks", "why": "zodat teamleden al hun toekomstige polls kunnen zien en abonneren", "functionality": ["Wanneer serie wordt aangemaakt of geactiveerd, genereert systeem alle occurrences voor volgende periode (bijv. 3 maanden)", "Elke occurrence wordt onafhankelijke poll met eigen votes/lifecycle", "Voor nu: alle occurrences zijn RSVP mode (vaste datum bekend, vraag is 'wie komt?')", "Webhooks worden gefired voor elke gegenereerde occurrence (webhook per occurrence)"], "acceptance_criteria": ["Alle toekomstige occurrences zijn zichtbaar als aparte polls", "Occurrences zijn onafhankelijk (stemmen påbij ander poll)", "Occurrence-titel bevat serienaam en datum", "Dashboard toont serie met alle occurrences"], "milestone": "M2", "feedback": []}, {"id": "US-RECUR-3", "epic": "Terugkerende Events en Series", "role": "Teamleider", "title": "Occurrence converteer naar scheduling-poll", "story": "Als teamleider wil ik een occurrence van RSVP naar scheduling-poll converteren", "why": "zodat ik kan overschakelen naar datum-selectie als de vaste datum problematisch wordt", "functionality": ["Van poll-pagina: teamleider kan 'Converteer naar scheduling' selecteren", "Huidge RSVP poll wordt inactief gemaakt, nieuwe scheduling-poll wordt aangemaakt", "Nieuwe poll erft origine geschiedenis maar reset stemmen", "Occurrence blijft deel van dezelfde serie"], "acceptance_criteria": ["Conversie-knop is beschikbaar op actieve poll", "Oude RSVP poll krijgt status REPLACED", "Nieuwe scheduling-poll is onmiddellijk actief", "Teamleden zien nieuwe scheduling-poll in hun feeds"], "milestone": "M2", "feedback": []}, {"id": "US-TEAM-1", "epic": "Team en Membership Management", "role": "Teamleider", "title": "Team aanmaken met naam", "story": "Als teamleider wil ik een team met een naam en optionele beschrijving aanmaken", "why": "zodat ik een groep kan vormen om polls te organiseren", "functionality": ["Team krijgt een unieke interne identifier", "Teamleider wordt automatisch als eigenaar ingesteld", "Leeg team kan worden aangemaakt; leden kunnen later worden toegevoegd"], "acceptance_criteria": ["Teamnaam is verplicht en uniek per instantie", "Teamleider is automatisch lid van het team", "Team kan onmiddellijk polls ontvangen", "Team beschrijving is optioneel"], "milestone": "M1", "feedback": []}, {"id": "US-TEAM-2", "epic": "Team en Membership Management", "role": "Teamleider", "title": "Teamlid toevoegen met feed-token", "story": "Als teamleider wil ik een teamlid toevoegen zodat zij een persoonlijke iCal feed-token krijgen", "why": "zodat ik teamleden kan uitnodigen en zij automatisch hun eigen feed kunnen abonneren", "functionality": ["Nieuwe lid krijgt een unieke, niet-gissbare, permanente feed-token", "Persoonlijke iCal feed-URL is onmiddellijk beschikbaar na creatie", "Hetzelfde persoon twee keer toevoegen wordt afgewezen"], "acceptance_criteria": ["Feed-token is minstens 32 karakters en URL-safe", "Lid kan onmiddellijk hun feed-URL benaderen zonder login", "Duplicate naam + handle wordt geweigerd in dezelfde team", "Feed-token verandert nooit"], "milestone": "M1", "feedback": []}, {"id": "US-TEAM-3", "epic": "Team en Membership Management", "role": "Teamlid", "title": "Persoonlijke feed-URL ophalen en delen", "story": "Als teamlid wil ik mijn persoonlijke iCal feed-URL kunnen ophalen en delen", "why": "zodat ik deze URL in mijn agenda-app kan abonneren en alle polls automatisch zie", "functionality": ["URL is uniek per lid en stabiel", "URL vereist geen authenticatie om te benaderen", "URL verandert niet wanneer polls worden toegevoegd of bijgewerkt", "Feed-URL is zichtbaar op persoonlijke profielpagina"], "acceptance_criteria": ["Feed-URL is toegankelijk via persoonlijke profielpagina", "URL vereist enkel token-identificatie, geen login", "URL blijft werken na polls toevoegen/wijzigen", "Copy-knop maakt delen gemakkelijk"], "milestone": "M1", "feedback": []}, {"id": "US-TEAM-4", "epic": "Team en Membership Management", "role": "Teamleider", "title": "Teamlid uit team verwijderen", "story": "Als teamleider wil ik een teamlid uit het team kunnen verwijderen", "why": "zodat zij geen nieuwe polls meer in hun feed ontvangen", "functionality": ["Feed-URL van verwijderd lid stopt direct met nieuwe polls", "Bestaande stem van verwijderde lid blijft in historisch record", "Feed-URL van verwijderde lid wordt inactief"], "acceptance_criteria": ["Verwijderd lid ziet onmiddellijk geen nieuwe polls meer", "Historische stemgegevens blijven behouden", "Feed-URL geeft 404 of leeg antwoord"], "milestone": "M2", "feedback": []}, {"id": "US-VOTE-1", "epic": "Stemmen en Voorkeuren", "role": "Teamlid", "title": "Stemmen via webpagina zonder login", "story": "Als teamlid wil ik op mijn stempagina van de kalenderlink stemmen zonder in te loggen", "why": "zodat ik snel mijn voorkeur kan aangeven", "functionality": ["URL codeert lid-identiteit (token) — geen login vereist", "Pagina toont alle kandidaatdatums voor de poll", "Huidige eigen stem is voorgeselecteerd per datum (ja/misschien/nee)", "Lid kan alle stemmen wijzigen en in één actie indienen"], "acceptance_criteria": ["Stempagina laadt zonder login-prompt", "Alle opties (ja/misschien/nee) zijn zichtbaar en selecteerbaar", "Huidige stem staat al geselecteerd", "Pagina werkt goed op mobiel"], "milestone": "M1", "feedback": []}, {"id": "US-VOTE-2", "epic": "Stemmen en Voorkeuren", "role": "Teamlid", "title": "Stem wijzigen zolang poll open is", "story": "Als teamlid wil ik mijn stem op elk moment kunnen wijzigen terwijl poll open is", "why": "zodat ik mijn voorkeur kan bijstellen op basis van nieuwe informatie", "functionality": ["Gewijzigde stem triggert onmiddellijke feed-regeneratie", "Eerdere stem wordt overschreven, niet opgestapeld", "Wijziging is mogelijk zolang poll-status OPEN is", "Geen bevestigings-e-mail — feed is feedback-kanaal"], "acceptance_criteria": ["Stem-wijziging wordt onmiddellijk doorgevoerd", "Andere stemmen worden niet beïnvloed", "Nadat poll sluit, kunnen stemmen niet meer wijzigen", "Wijziging is zichtbaar in feed binnen minuten"], "milestone": "M1", "feedback": []}, {"id": "US-VOTE-3", "epic": "Stemmen en Voorkeuren", "role": "Teamlid", "title": "Stem-overzicht van poll bekijken", "story": "Als teamlid wil ik het volledige stem-overzicht van een poll zien", "why": "zodat ik iedereen's voorkeuren kan zien voordat ik stem", "functionality": ["Overzicht toont alle kandidaatdatums met per-persoon stemmen (naam + ja/misschien/nee/niet gestemd)", "Toegankelijk via persoonlijke token-URL — geen login", "Alleen-lezen voor non-teamleiders", "Updates live (of op vernieuwing) om meest recente staat weer te geven"], "acceptance_criteria": ["Alle namen en stemmen zijn zichtbaar in tabel", "Niet-gestemdde leden zijn duidelijk gemarkeerd", "Tabel toont alle kandidaatdatums in kolommen", "Gegevens worden live bijgewerkt op browser-refresh"], "milestone": "M2", "feedback": []}, {"id": "US-WEBHOOK-1", "epic": "Webhooks en Externe Integraties", "role": "Teamleider", "title": "Team webhook URL registreren", "story": "Als teamleider wil ik een webhook URL voor mijn team registreren", "why": "zodat ik team-events naar externe systemen kan sturen", "functionality": ["Teamleider voert webhook URL in via dashboard", "URL wordt opgeslagen met TEAM scope — alleen team-events vuren deze webhook af", "Webhook URL vereist geen authenticatie-header — URL zelf is het token (no-login model)", "Teamleider kan webhook URL te alle tijden wijzigen of verwijderen"], "acceptance_criteria": ["Webhook URL is optioneel per team", "Updates aan polls/votes triggeren webhook-payload naar geconfigureerde URL", "URL-based authentication: geen API-sleutels vereist", "URL kan meer dan eenmaal gewijzigd worden"], "milestone": "M1", "feedback": []}, {"id": "US-WEBHOOK-2", "epic": "Webhooks en Externe Integraties", "role": "Teamlid", "title": "Persoonlijke webhook URL registreren", "story": "Als teamlid wil ik een persoonlijke webhook URL registreren voor al mijn teams", "why": "zodat ik persoonlijke events naar externe systemen kan sturen", "functionality": ["Teamlid voert webhook URL in via profiel configuratie", "URL wordt opgeslagen met PERSON scope — alleen events van deze persoon vuren deze webhook af", "Persoonlijke webhook-events bevatten geen stemmen van andere teamleden", "Zelf-events (eigen stemactie) vuren NIET de persoonlijke webhook af"], "acceptance_criteria": ["Persoonlijke webhook URL is optioneel", "Events uit alle teams waar lid lid is triggeren deze webhook", "Persoonlijke stemming triggers geen eigen webhook", "URL kan op profiel page ingesteld en verwijderd worden"], "milestone": "M1", "feedback": []}, {"id": "US-WEBHOOK-3", "epic": "Webhooks en Externe Integraties", "role": "Systeem", "title": "Webhook payloads voor poll en stem events", "story": "Als systeem wil ik gestandaardiseerde webhook payloads sturen voor alle events", "why": "zodat externe systemen een consistent interface hebben voor integratie", "functionality": ["Payload bevat: event_type, timestamp, team_id/person_id, poll details, vote details (indien van toepassing)", "Event types: poll.created, poll.confirmed, poll.cancelled, vote.submitted, vote.changed, date.added, date.removed", "Payload is JSON met stabiele veldstructuur", "Retry-logica: webhook mislukking wordt gelogd maar blokkeert geen poll/vote operatie"], "acceptance_criteria": ["Alle events hebben consistent JSON-format", "Event-payload bevat genoeg informatie voor integratie", "Timestamp is ISO8601 format", "Payload-delivery is asynchrone background job"], "milestone": "M1", "feedback": []}]}