Ga naar inhoud

Domeinmodel I See You

Ontworpen conform Domain-Driven Design (DDD) principes. Zie ook: Functionele beschrijving en Termen.

Dit domeinmodel is afgeleid uit het functioneel ontwerp en de prototype-implementatie (Express-backend met JSON-stores). Het is de bron van waarheid: de implementatie in app/ conformeert zich hieraan. De huidige modelversie staat bovenaan het Wijzigingslog.


ContextVerantwoordelijkheid
BeoordelingDe kern-cyclus: een Vraag (video/foto) met het vaste aantal beoordelingen uit de Systeeminstellingen → evenveel slots (Opdracht) die opiniegevers pull-gewijs kiezen en tijdelijk reserveren → Opinies (scores en/of een reactie — verplicht als de maker er om vroeg) → de maker waardeert elke ontvangen beoordeling met 0–5; blijft een vraag te lang open, dan vult een AI-persona af (die nu óók een onderbouwde reactie geeft)
Gebruiker & ToegangGebruiker (met optioneel e-mailadres, waarderingsstatistieken en credits), AnoniemeGebruiker, Sessie en het Profiel
Beloning & Financieel (vastgesteld per 2026-07-08b)De verdiende Ster-reputatie (met de consensus-ranking per vraag), het Adviesniveau (1–4 + Expert) met betaald advies, het euro-saldo/Inleg met Betaling via iDeal (incl. welkomstbonus), de teaser-ontgrendeling per opinie en de terugkerende Uitbetaling
Moderatie & RetentieMelding van ongepaste vragen (reactief), de proactieve tekstmoderatie (IModeratieDienst, OpenAI) en het retentie-/anonimiteitsbeleid
BeheerSysteem met Systeeminstellingen (instelbare aantallen/termijnen/drempels/prijzen), Verdeelstatistieken (monitoring) en statistieken, de beheerbare AIPersona’s, Keuzelijst (stamdata, incl. land, beoordelings­secties én -attributen), Bericht en EmailSjabloon (beheerbare e-mailteksten per mailtype)

De Beoordeling-context is het hart. De overige contexten leveren deelnemers, belonen kwaliteit, bewaken de privacy en bevatten stamdata. De waardering (0–5 op de smiley-schaal) is een kwaliteitsoordeel, geen valuta — maar sinds het voorstel 2026-07-05 weegt zij wél mee in de ster-ranking, en is er (ter verificatie) weer geld in het systeem: een euro-saldo voor betaald advies, strikt gescheiden van de credits.


flowchart LR
    subgraph Toegang["Gebruiker & Toegang"]
        Gebruiker
        Sessie
    end
    subgraph Kern["Beoordeling"]
        Vraag
        Opdracht
        Opinie
    end
    subgraph Beloning["Beloning & Financieel"]
        Ster
        Adviesniveau
        Betaling
        Uitbetaling
    end
    subgraph Mod["Moderatie & Retentie"]
        Melding
        Moderatie["IModeratieDienst"]
        Retentie["Retentiebeleid"]
    end
    subgraph Beheer["Beheer"]
        Keuzelijst
        Systeem
        Bericht
        AIPersona
    end

    Gebruiker -->|maakt| Vraag
    Vraag -->|levert slots| Opdracht
    Gebruiker -->|kiest & reserveert| Opdracht
    Opdracht -->|leidt tot opinie| Opinie
    AIPersona -.->|vangnet-opinie| Opinie
    Gebruiker -->|waardeert 0-5| Opinie
    Opinie -.->|consensus-ranking per vraag| Ster
    Ster -.->|ontsluit| Adviesniveau
    Adviesniveau -.->|prijst betaald advies| Opinie
    Gebruiker -->|laadt euro-saldo op via iDeal| Betaling
    Betaling -.->|ontgrendelt teaser| Opinie
    Ster -.->|op termijn| Uitbetaling
    Moderatie -.->|keurt vrije tekst| Vraag
    Moderatie -.->|keurt vrije tekst| Opinie
    Melding -->|meldingen-drempel| Vraag
    Retentie -.->|verwijdert na beoordeling| Vraag
    Systeem -.->|instellingen| Vraag
    Keuzelijst -.->|levert opties| Gebruiker

De kern van I See You. Een gebruiker legt een vraag voor; het vaste aantal beoordelingen (de instelling aantalOpiniegevers uit de Systeeminstellingen) levert evenveel slots (Opdracht) op die door opiniegevers pull-gewijs worden opgepakt: een opiniegever vraagt werk en krijgt een Keuzeset van vragen tijdelijk gereserveerd, kiest er één en levert zijn opinie (scores op de gekozen secties en/of een vrije tekstreactie). Wat de maker gevraagd krijgt bepaalt hij bij zijn Beoordelingsselectie: hij kiest de te scoren secties/attributen (minstens één). Vrije (tekst)reacties zijn per 2026-07-10h geen maker-keuze meer maar komen uit vrije-reactie-slots: maximaal maxVrijeReactiesZonderBetaald slots exclusief voor beoordelaars met adviesniveau ≥ 1, waar de reactie verplicht is (bij betaald advies zijn de niveaueisen leidend). Blijft een vraag te lang onbeantwoord, dan vult een AI-persona aan (die naast scores óók een onderbouwde reactie geeft). Ná afloop waardeert de maker elke ontvangen beoordeling met 0–5 op de smiley-schaal als kwaliteitsoordeel; hij ziet daarbij niet of een beoordeling van een mens of een AI-persona komt (de herkomst is voor hem verborgen, wél zichtbaar voor de beheerder). Alleen een waardering op een menselijke beoordeling telt mee in de reviewer-statistieken. De vraag bestaat na afronding nog een resultaat-retentievenster en wordt daarna verwijderd. De verdeel-, reserverings- en timeout-logica staat in de toestandsmachine en de Opdrachtverdeler hieronder.

classDiagram
    class Vraag {
        <<AggregateRoot>>
        +UUID id
        +MediaType mediaType
        +string bestandsnaam
        +Vraagtype type
        +string toelichting
        +string notificatieEmail
        +string makerId
        +bool makerIsGeregistreerd
        +ProfielSnapshot makerSnapshot
        +SelectieCriteria selectieCriteria
        +Beoordelingsselectie beoordelingsselectie
        +OpenVraag[] openVragen
        +int aantalOpiniegevers
        +NiveauEis[] niveaueisen
        +decimal adviesTotaalprijs
        +datetime timestamp
        +int creditkosten
        +datetime aiDeadline
        +datetime beoordeeldOp
        +bool resultaatOntgrendeld
        +bool isBeoordeeld()
        +int openPlekken()
        +void markeerBeoordeeld()
        +void ontgrendelResultaat()
    }
    class Opdracht {
        <<AggregateRoot>>
        +UUID id
        +UUID vraagId
        +OpdrachtStatus status
        +UUID reserveringId
        +string voorgesteldAan
        +datetime voorgesteldOp
        +Reviewer reviewer
        +ProfielSnapshot reviewerSnapshot
        +SelectieCriteria criteriaSnapshot
        +Adviesniveau minimumNiveau
        +datetime assignedAt
        +datetime verlooptOp
        +datetime completedAt
        +int herverdelingen
    }
    class Opinie {
        <<AggregateRoot>>
        +UUID id
        +UUID vraagId
        +Doelgebruiker targetGebruiker
        +Reviewer reviewer
        +OpinieBron bron
        +UUID personaId
        +string aiHerkomst
        +Scores scores
        +SectieGemiddelden sectieGemiddelden
        +string reactie
        +Adviesniveau adviesniveauSnapshot
        +decimal prijsSnapshot
        +bool ontgrendeld
        +int waardering
        +datetime timestamp
        +int Waardeer(score)
    }
    class Beoordelingsselectie {
        <<ValueObject>>
        +SectieKeuze[] secties
    }
    class SectieKeuze {
        <<ValueObject>>
        +string sectie
        +string[] attributen
    }
    class OpenVraag {
        <<ValueObject>>
        +string sleutel
        +string titel
        +OpenSubvraag[] subvragen
    }
    class OpenSubvraag {
        <<ValueObject>>
        +string sleutel
        +string tekst
    }
    class Scores {
        <<ValueObject>>
        +SectieScores[] secties
    }
    class SectieScores {
        <<ValueObject>>
        +string sectie
        +AttribuutScore[] attributen
    }
    class AttribuutScore {
        <<ValueObject>>
        +string attribuut
        +int score
    }
    class SectieGemiddelden {
        <<ValueObject>>
        +SectieGemiddelde[] perSectie
    }
    class SectieGemiddelde {
        <<ValueObject>>
        +string sectie
        +decimal gemiddelde
    }
    class SelectieCriteria {
        <<ValueObject>>
        +int minLeeftijd
        +int maxLeeftijd
        +string gender
        +string regio
        +string achtergrond
    }
    class ProfielSnapshot {
        <<ValueObject>>
        +int leeftijd
        +string gender
        +string regio
        +string achtergrond
    }
    class MediaType {
        <<enumeration>>
        Video
        Foto
    }
    class Vraagtype {
        <<enumeration>>
        Algemeen
        Specifiek
    }
    class OpdrachtStatus {
        <<enumeration>>
        Open
        Voorgesteld
        Gekozen
        Voltooid
        AIVoltooid
    }
    class OpinieBron {
        <<enumeration>>
        Mens
        AI
    }
    class Keuzeset {
        <<ValueObject>>
        +UUID reserveringId
        +string opiniegever
        +UUID[] opdrachtIds
        +datetime verlooptOp
    }
    class OpdrachtUitsluiting {
        <<Entity>>
        +UUID opdrachtId
        +string gebruikersnaam
        +datetime uitsluitenTot
    }
    class NiveauEis {
        <<ValueObject>>
        +Adviesniveau niveau
        +int aantal
    }

    Vraag "1" --> "1..N" Opdracht : wijst toe
    Vraag "1" --> "0..N" Opinie : ontvangt
    Opdracht "1" --> "0..1" Opinie : leidt tot (mens of AI)
    Vraag --> MediaType
    Vraag --> Vraagtype
    Vraag --> ProfielSnapshot
    Vraag --> SelectieCriteria
    Vraag --> Beoordelingsselectie
    Vraag --> OpenVraag
    OpenVraag --> OpenSubvraag
    Vraag --> NiveauEis
    Beoordelingsselectie --> SectieKeuze
    Opdracht --> OpdrachtStatus
    Keuzeset "1" --> "1..N" Opdracht : groepeert (Voorgesteld)
    Opdracht "1" --> "0..N" OpdrachtUitsluiting : weert reviewer
    Opdracht --> ProfielSnapshot
    Opinie --> OpinieBron
    Opinie --> Scores
    Opinie --> SectieGemiddelden
    Scores --> SectieScores
    SectieScores --> AttribuutScore
    SectieGemiddelden --> SectieGemiddelde

Het centrale aggregate. Een video (max. 10 sec) of foto die een gebruiker voorlegt voor opinies.

Verantwoordelijkheden:

  • Vasthouden van het media-bestand (bestandsnaam) en het type media (MediaType { Video, Foto }).
  • Een optionele toelichting (nullable): een stukje begeleidende tekst dat de maker bij de opname typt. Wordt vóór opslaan door de tekstmoderatie gecontroleerd.
  • Een optioneel notificatieEmail (nullable): een e-mailadres dat de maker bij het stellen kan achterlaten om één seintje te krijgen zodra zijn uitslag klaar is. Staat volledig los van het optionele account-e-mailadres voor wachtwoordherstel (dat op de Gebruiker staat) en van het gebruikerstype: ook een anonieme maker kan een notificatie-adres opgeven. Zie de uitslagnotificatie-poort.
  • Een snapshot van het profiel van de maker (ProfielSnapshot) en de gekozen SelectieCriteria voor de opiniegevers.
  • De Beoordelingsselectie: de secties/attributen die de maker na de opname kiest, zodat de opiniegevers alléén beoordelen waar de maker behoefte aan heeft (zie ontwerpbeslissing 11). Een vraag is geldig zodra er minstens één sectie is. (De vlag vrijeTekstGevraagd is per 2026-07-10h vervallen — of er een vrije tekstreactie komt, is geen keuze van de maker meer maar volgt uit de vrije-reactie-slots: een beoordelaar met adviesniveau ≥ 1 levert op zo’n slot verplicht tekst; niveau 0 levert géén tekst. Zie ontwerpbeslissing 34.)
  • Optionele openVragen (per 2026-07-13d; twee-niveau sinds 2026-07-14a, issue #20, ADR-043): eigen beoordelingscategorieën die de maker zelf formuleert. Elke OpenVraag is een categorie-kop ({ sleutel (q1, q2, …), titel, subvragen }) met daaronder eigen OpenSubvraag-items ({ sleutel (s1, s2, …), tekst }). Elke opiniegever scoort elke sub-vraag op dezelfde smiley-schaal 1–5 als de vaste attributen (géén vrije tekst; anders dan de in 2026-07-04d geschrapte open antwoorden); de kop zelf wordt niet gescoord. Beheerinstellingen: maxOpenVragen (max. categorieën, standaard 3; 0 = uit) en maxOpenSubvragen (max. sub-vragen per categorie, standaard 5); de hulptekst is beheerbare stamdata (Keuzelijst-type uitleg, sleutel open-vragen). Titel én sub-vraagteksten lopen vóór opslag door de tekstmoderatie. Technisch wordt elke categorie als een aparte synthetische sectie open:<sleutel> (attributen = de sub-vraag-sleutels) aan de Beoordelingsselectie toegevoegd, zodat verdeling, verplichte scoring, AI-vangnet en aggregatie ongewijzigd werken — precies zoals een gewone sectie; alleen de labels komen uit openVragen.
  • Het aantal beoordelingen (aantalOpiniegevers): een bevroren snapshot van de gelijknamige instelling (uit de Systeeminstellingen, standaard 10 — per 2026-07-05 terug van de test-instelling 1) op het moment van stellen — geen keuze van de maker. Er ontstaan net zoveel slots, en de bevroren inzage-prijs creditkosten = aantalOpiniegevers × creditkostenPerBeoordeling (zie credits-poort); een latere wijziging van de instelling raakt bestaande vragen niet.
  • Betaald advies (vastgesteld per 2026-07-08b): de vraagsteller kiest één of meerdere adviesniveaus en geeft per niveau aan hoeveel van de tien beoordelaars daaraan moeten voldoen — vastgelegd als niveaueisen (een verzameling NiveauEis = { niveau, aantal }). De totaalprijs = de som van (aantal × niveauprijs) wordt vooraf getoond en als adviesTotaalprijs op de vraag bevroren, en gaat van het euro-saldo van de vraagsteller af. ⚠️ De som van de gevraagde aantallen is ≤ 10; de overige slots zijn gewone gratis-/AI-beoordelaars (interpretatie). Stelt hij niets in (geen account/saldo/niveau), dan reserveert de verdeling maximaal maxVrijeReactiesZonderBetaald (standaard 3) vrije-reactie-slots voor beoordelaars met adviesniveau ≥ 1, wier tekst in de uitslag geblurd verschijnt en waarvan de vraagsteller er hoogstens één kan kopen (per 2026-07-10h; dit vervangt de eerdere best-effort-instelling minTeaserNiveauBeoordelaars) (zie Beloning & Financieel en Betaald advies).
  • Het bewaken van de eigen levenscyclus: een vraag is beoordeeld zodra alle opinies binnen zijn (isBeoordeeld()), waarna beoordeeldOp wordt gezet. Is er op dat moment een notificatieEmail achtergelaten, dan verstuurt het systeem eenmalig een kort notificatie-seintje met alleen een link naar het gebruikersportaal (zie de uitslagnotificatie-poort); direct na de verzendpoging wordt notificatieEmail op null gezet, zodat er geen adres achterblijft. De opname wordt bij afronding niet meer direct verwijderd: het resultaat + de opname blijven in een resultaat-retentievenster dat alleen de maker kan terugzien (zie Retentiebeleid). De opname verdwijnt zodra de maker die zelf verwijdert, of automatisch zodra resultaatRetentieUren (uit de Systeeminstellingen) verstrijkt. Een instelbare veiligheids-timeout ruimt daarnaast vragen op die nooit afgerond raken.

Video óf foto. Beide media-typen volgen dezelfde opinie-flow. Het verschil zit in de capture (opname van maximaal 10 seconden vs. één foto) en niet in de beoordeling. Zie Vraag stellen met foto en Media & opname.

Eén slot van één Vraag: precies één benodigde opinie. Per vraag bestaan er zoveel slots als het vaste aantal beoordelingen (Vraag.aantalOpiniegevers — de bij het stellen bevroren gelijknamige instelling uit de Systeeminstellingen). Het slot draagt de volledige reserveringslevenscyclus via OpdrachtStatus (zie de toestandsmachine hieronder).

Slot-typen (per 2026-07-10h, ontwerpbeslissing 34): elk slot heeft een minimumNiveau (Adviesniveau, standaard Geen) dat bij het aanmaken wordt bepaald:

  • Zonder betaald advies (geen niveaueisen op de vraag) krijgen maximaal maxVrijeReactiesZonderBetaald (instelling, standaard 3, altijd < het aantal beoordelaars) slots minimumNiveau = Niveau1 — de vrije-reactie-slots. De overige slots houden Geen en scoren alleen smileys.
  • Met betaald advies zijn de niveaueisen leidend: per NiveauEis { niveau, aantal } krijgen aantal slots dat niveau als minimumNiveau; de rest houdt Geen. Er komen dan géén extra vrije-reactie-slots bij.

Een slot met minimumNiveau ≠ Geen is exclusief voor beoordelaars met minstens dat adviesniveau (niveau 1–4 of Expert): de verdeling biedt het alleen aan hen aan, en op zo’n slot is de reactie verplicht (het wordt een betaald/geblurd advies — de teaser- of niveaueisen-flow). Op een gewoon slot (Geen) wordt géén tekst gevraagd of opgeslagen — óók niet van een beoordelaar met een niveau die zo’n slot oppakt (zijn opinie is dan een gewone gratis smiley-beoordeling). Zo is het maximum aantal vrije (tekst)reacties per vraag gegarandeerd en komt tekstadvies alleen van ervaren beoordelaars.

  • Een slot wordt niet vooraf aan een vaste reviewer geduwd. Het ontstaat altijd Open (stellen is gratis; de credits-poort staat op het inzien van de uitslag, niet op de slots — zie de credits-poort) en wordt pull-gewijs gereserveerd: een opiniegever vraagt werk, krijgt een Keuzeset van slots tijdelijk gereserveerd (Voorgesteld, met verlooptOp = nu + keuzetermijnMin), kiest er één (Gekozen, waarna verlooptOp opnieuw wordt gezet op nu + antwoordtermijnMin) en levert de opinie (Voltooid).
  • reviewer is daarom leeg zolang het slot Open is. voorgesteldAan/reserveringId leggen vast aan wie en in welke keuzeset het slot is aangeboden; herverdelingen telt hoe vaak het verliep.
  • Nooit vastlopen. Beide reserveringsfasen hebben een server-side deadline. Verloopt de keuze- of beoordeel-termijn, dan keert het slot terug naar Open (niet naar een terminale status) en komt het opnieuw beschikbaar — ongeacht of de reviewer nog online is. De reviewer die liet verlopen krijgt een korte anti-thrash-uitsluiting (OpdrachtUitsluiting) zodat hij hetzelfde slot niet meteen weer aangeboden krijgt.
  • Houdt snapshots van de reviewer en de gebruikte criteria vast (gezet bij Gekozen), zodat de toewijzing herleidbaar blijft als profielen later wijzigen.
  • AI-vangnet (automatisch) én handmatige AI-opinie. Een Open slot kan op twee manieren door een AI-persona worden ingevuld (terminale status AIVoltooid, Opinie.bron = AI). Automatisch: blijft een slot te lang Open (de vraag bereikt aiDeadline = timestamp + maxOnbeantwoordMin, of het slot is aan alle kandidaten aangeboden-en-verlopen), dan vult het vangnet het in. Handmatig: de beheerder kan vanuit het beheerportaal, met een gekozen persona, direct een AI-opinie op een Open slot laten genereren (zie handmatige beheer-actie). In beide gevallen vult de AI alleen Open slots — nooit een door een mens vastgehouden Voorgesteld/Gekozen slot (zie ontwerpbeslissing 18). Op een vrije-reactie-/betaald-advies-slot (minimumNiveau ≥ Niveau1) bepaalt de instelling aiVangnetVultVrijeReactieSlots (per 2026-07-10h, default true) of de AI-opinie daar een tekstreactie meelevert; bij false vult de AI zo’n slot alleen met scores. Een AI-opinie is altijd gratis en direct leesbaar — hij telt niet als betaald advies. Op een gewoon slot levert de AI géén tekst (consistent met “niveau 0 geeft geen tekst”).

De oprechte opinie van één opiniegever over één vraag.

  • scores bevat alleen de secties en attributen uit de Beoordelingsselectie van de vraag — niet langer drie vaste secties. De beschikbare secties/attributen zijn beheerbare stamdata (Keuzelijst); standaard zijn dat Gezicht, Kleding en Accessoires. Scoren is verplicht: elk gevraagd attribuut krijgt een score op de schaal 1–5 (1 = slecht/kan beter, 5 = uitstekend). (“Geen mening” (score 0) is per 2026-07-05 vervallen — aanscherping 3-7-2026, inmiddels zo gebouwd. Zie ontwerpbeslissing 33.)
  • sectieGemiddelden is een afgeleid gemiddelde per beoordeelde sectie, berekend over álle scores — iedereen heeft immers elk gevraagd attribuut gescoord (de eerdere “alleen scores > 0”-regel is per 2026-07-05 vervallen).
  • bron geeft aan of de opinie van een mens (Mens) of van een AI-persona (AI) komt (OpinieBron). Bij een AI-opinie wijst personaId naar de AIPersona die hem leverde; bij een mens is personaId leeg. Een AI-opinie maakt een vraag wel compleet en levert geen credits op. Sinds 2026-07-04g levert een AI-opinie wél een reactie (een korte, onderbouwde tekst), zodat ook een alleen-vrije-tekst-vraag door de AI beantwoord kan worden (zie AI-persona’s). De herkomst (mens/AI) wordt niet aan de maker getoond (sinds 2026-07-04h): bron is intern en zichtbaar voor de beheerder, maar zit niet in de user-facing uitslag; de maker ziet elke ontvangen beoordeling gelijk. Sinds 2026-07-04h is elke ontvangen beoordeling — ook een AI-opinie — waardeerbaar door de maker; een waardering op een AI-opinie wordt wél op de opinie vastgelegd, maar beïnvloedt geen reviewer-profiel (een AI-persona heeft er geen).
  • Verdienen. Een voltooide menselijke opinie levert de opiniegever creditsPerBeoordeling credits op (deelname-valuta om je eigen uitslag in te zien) — bij élke beoordeling. Een beoordeling die door de tekstmoderatie wordt afgekeurd (ongepaste reactie) wordt niet opgeslagen en levert geen credit op.
  • reactie (nullable string) is één vrije tekstreactie van de reviewer naast zijn scores — de tegenhanger van de toelichting van de maker. Of ze er komt, volgt per 2026-07-10h uit het slot-type (zie Opdracht): op een vrije-reactie-/betaald-advies-slot (minimumNiveau ≥ Niveau1) is de reactie verplicht (een lege reactie wordt geweigerd) en komt ze per definitie van een beoordelaar met adviesniveau 1–4/Expert; op een gewoon slot wordt géén tekst gevraagd of opgeslagen (niveau 0 levert geen tekst). (De eerdere maker-keuze vrijeTekstGevraagd is vervallen; zie ontwerpbeslissing 34.) Met een goede reactie kan een reviewer zich onderscheiden en een hoge waardering verdienen. De ingetypte reactie wordt vóór opslaan door de tekstmoderatie gecontroleerd.
  • waardering (nullable int, 0..5) is het kwaliteitsoordeel van de maker over déze ontvangen beoordeling: 0 = slechtste, 5 = beste. Het meet de kwaliteit van de beoordeling, niet de inhoud van de opname. Waardeer(score) zet de waardering en geeft de vorige waarde terug (voor herwaardering, zodat de afgeleide totalen op de reviewer kloppen). Sinds 2026-07-04h is elke ontvangen opinie waardeerbaar — óók een AI-opinie (de maker ziet immers niet wat AI is). Een waardering op een menselijke opinie werkt door in de reviewer-statistieken; een waardering op een AI-opinie wordt wel op de opinie vastgelegd maar beïnvloedt geen reviewer-profiel (een AI-persona heeft er geen). Sinds het voorstel 2026-07-05 weegt de waardering bovendien (met een instelbaar gewicht) mee in de consensus-ranking die per vraag de beste opiniegever bepaalt.
  • Betaald advies (voorgesteld per 2026-07-05; per 2026-07-10h slot-gedreven): wordt de opinie geleverd op een niveau-slot (Opdracht.minimumNiveau ≥ Niveau1), dan worden het adviesniveau van de beoordelaar en de prijs bij het indienen op de opinie bevroren (adviesniveauSnapshot, prijsSnapshot — bij een niveaueisen-slot de bevroren eis-prijs, bij een teaser-slot de prijs van het eigen niveau) en is de reactie verplicht. De vlag ontgrendeld start dan false: de uitslag toont een geblurde tekst met niveau + prijs totdat de vraagsteller per beoordeling betaalt/bevestigt. Een opinie op een gewoon slot is altijd gratis en direct leesbaar (geen tekst, adviesniveauSnapshot = Geen) — ook als de beoordelaar zelf een niveau heeft.
  • targetGebruiker is de maker van de vraag; reviewer (optioneel) is de opiniegever.

Altijd een beoordeling — twee timeouts + AI-vangnet. Geen enkele vraag mag te lang onbeantwoord blijven. Een opiniegever houdt een slot maar tijdelijk vast: eerst tijdens het kiezen (keuzetermijnMin), daarna tijdens het beoordelen (antwoordtermijnMin). Verloopt een van beide, dan keert het slot terug naar Open. Bereikt een vraag de maximale onbeantwoord-tijd (maxOnbeantwoordMin), dan vult een AI-persona de resterende Open slots af. Zo krijgt elke vraag opinies, ook bij weinig actieve gebruikers — belangrijk bij de lancering.

Waardering: de maker beoordeelt de beoordelingen

Section titled “Waardering: de maker beoordeelt de beoordelingen”

Nadat een vraag is afgerond, waardeert de maker elke ontvangen (menselijke) beoordeling met 0 t/m 5 op de smiley-schaal als kwaliteitsoordeel — hoe nuttig/oprecht vond hij die beoordeling. Dit is een aparte, optionele stap in Mijn vragen en staat volledig los van de smiley-scores die de reviewer zelf gaf.

  • Een waardering op een menselijke opinie wordt vastgelegd als Opinie.waardering en beïnvloedt de afgeleide statistieken op de reviewer (Gebruiker): AantalBeoordelingen, WaarderingSom/WaarderingAantal en de daaruit afgeleide GemiddeldeWaardering.
  • Herwaarderen mag: Waardeer(score) geeft de vorige waarde terug zodat de som/telling op de reviewer correct wordt bijgesteld.
  • Sinds 2026-07-04h is elke ontvangen beoordeling waardeerbaar, óók een AI-opinie — bewust, omdat de maker niet ziet welke beoordeling van een mens en welke van een AI komt (de herkomst zit niet in de user-facing uitslag). Een waardering op een AI-opinie wordt wél op de opinie vastgelegd, maar beïnvloedt geen reviewer-profiel (een AI-persona is geen gebruiker en heeft geen statistieken).
  • Tweede functie: wegingsfactor in de ster-ranking (voorgesteld per 2026-07-05). De waardering weegt — met het instelbare gewicht gewichtMakerWaardering (ook 0 = niet meewegen mogelijk) — mee in de consensus-ranking die per vraag de beste opiniegever bepaalt en zo sterren toekent.

Van vooruitblik naar voorstel. De eerdere vage “privileges”-vooruitblik is per 2026-07-05 concreet gemaakt (ter verificatie): kwaliteit levert sterren op, en sterren ontsluiten het adviesniveau waarmee een reviewer via betaald advies echt geld kan verdienen.

Een Opdracht cyclet tussen de statussen; timeouts gaan altijd terug naar Open (nooit naar een terminale “verlopen”-status), zodat een slot nooit permanent gelockt raakt. Terminaal zijn alleen Voltooid (mens) en AIVoltooid (AI). Vraag-verwijdering (moderatie/retentie/afronding) verwijdert de rijen via cascade en is daarom geen statusovergang.

stateDiagram-v2
    [*] --> Open : verdeler maakt slot (stellen is gratis)
    Open --> Voorgesteld : pull reserveert slot voor reviewer (SKIP LOCKED)
    Voorgesteld --> Gekozen : reviewer kiest dit slot (antwoordtermijn start)
    Voorgesteld --> Open : keuzetermijn verlopen (sweeper, anti-thrash uitsluiting)
    Voorgesteld --> Open : sibling gekozen of keuzeset teruggegeven (geen uitsluiting)
    Gekozen --> Voltooid : opinie opgeslagen (bron = Mens)
    Gekozen --> Open : antwoordtermijn verlopen (sweeper, anti-thrash uitsluiting)
    Open --> AIVoltooid : AI-vangnet vult Open slot (vraag-deadline of uitgeput)
    Voltooid --> [*]
    AIVoltooid --> [*]
VanGebeurtenisNaarNeveneffectenSweeper/timeout
(geen)Vraag geplaatst (gratis)Open ×aantalOpiniegeversgeldig bij ≥1 sectie OF vrijeTekstGevraagd; toelichting gemodereerd; criteriaSnapshot bevroren; aantalOpiniegevers = gelijknamige instelling bevroren; creditkosten = aantalOpiniegevers × creditkostenPerBeoordeling (inzage-prijs) bevroren; push OpdrachtBeschikbaarsynchroon
Voltooid/AIVoltooid (alle slots)Maker ontgrendelt zijn uitslag(geen slot-overgang)de bevroren creditkosten eenmalig afgeschreven; resultaatOntgrendeld = truesynchroon (maker-actie)
OpenReviewer pullt werkVoorgesteldreserveringId/voorgesteldAan/voorgesteldOp/verlooptOp gezet; FOR UPDATE SKIP LOCKEDsynchroon
VoorgesteldReviewer kiest dit slotGekozenreviewer/reviewerSnapshot/assignedAt gezet; verlooptOp = +antwoordtermijnMin; siblings → Opensynchroon
VoorgesteldKeuzetermijn verlopen, niets gekozenOpenvelden gewist; herverdelingen++; uitsluiting voor voorgesteldAan; push SlotIngetrokkenkeuzetermijn-sweep
VoorgesteldSibling gekozen / keuzeset teruggegevenOpenvelden gewist; geen uitsluitingsynchroon (zelfde tx als kiezen)
GekozenOpinie opgeslagen (bron = Mens)Voltooidreactie gemodereerd en — als vrijeTekstGevraagdverplicht (lege reactie geweigerd, geen credit); completedAt; tellers++; vraag-compleet-checksynchroon
GekozenAntwoordtermijn verlopenOpenvelden gewist; herverdelingen++; uitsluiting voor reviewer; push ToewijzingVerlopenantwoordtermijn-sweep
OpenAI-vangnet triggert (automatisch) of beheerder voegt handmatig een AI-opinie toeAIVoltooidOpinie{bron=AI, personaId, scores + reactie}; completedAt; tellers++; vraag-compleet-checkAI-vangnet-sweep (auto) / synchroon (beheer-actie)
Gekozen/OpenLaatste opinie binnen → vraag beoordeeld(slot Voltooid/AIVoltooid)beoordeeldOp op de Vraag gezet; opname blijft (retentievenster); is er een notificatieEmail, dan eenmalig een uitslag-seintje verzonden (IUitslagNotificaties, fail-graceful) en notificatieEmail daarna op null gezet; push VraagBeoordeeldsynchroon
elke statusVraag verwijderd (maker zelf / resultaat-retentie / melding / veiligheids-timeout)(rij weg)cascade-delete opinies+slots; media weg; push VraagVerwijderdsynchroon (maker/melding) / retentie-sweep

Idempotentie (rode draad). Elke overgang is een conditionele UPDATE … WHERE status = <bron> [AND reviewer = @rev]; raakt die 0 rijen, dan is het een no-op (de andere actor was eerder). Zo serialiseren gelijktijdige acties (mens vs. AI, kiezen vs. keuzetermijn-verloop, afronden vs. moderatie) veilig op de rij-lock.

De verdeel-logica zit in één domain service Opdrachtverdeler (Beoordeling-context, gelaagd conform ADR-003). De pure regels zitten in sub-policies (Kandidaatselectie, PersonaKiezer) en zijn volledig unit-testbaar; de transactionele rand zit achter een poort IReserveringspoort die de slots atomair claimt met PostgreSQL SELECT … FOR UPDATE SKIP LOCKED (ADR-002). De credits-poort (genoeg credits om je uitslag in te zien) is een aparte check bij het ontgrendelen van de uitslag (zie credits-poort), niet in de verdeler; het stellen zelf is gratis. Verantwoordelijkheden:

MethodeDoet
maakSlots(vraag, instellingen)Maakt aantalOpiniegevers slots Open (het vaste aantal uit de gelijknamige instelling, bij het stellen op de vraag bevroren; stellen is gratis, de credits-poort staat op het inzien van de uitslag).
stelKeuzesetVoor(reviewer, instellingen)Pull: reserveert tot keuzesetGrootte geschikte Open slots (één per vraag) als Voorgesteld voor de reviewer en geeft een Keuzeset terug. Idempotent: een nog geldige bestaande keuzeset wordt teruggegeven i.p.v. een tweede aangemaakt.
kies(reserveringId, slotId, reviewer)Zet het gekozen slot Voorgesteld → Gekozen (antwoordtermijn start); geeft de overige slots van die keuzeset direct vrij (→ Open).
geefKeuzesetVrij(reserveringId, reviewer)Geeft een hele keuzeset vrij (reviewer maakt geen keuze / verlaat het scherm).
bepaalAIvangnet(openSlot, vraag, actievePersonas, instellingen)Bepaalt of (en welke) AIPersona automatisch een Open slot afvult (bij de vraag-deadline of uitputting). Een handmatige AI-opinie kiest de persona daarentegen expliciet (de beheerder), niet via deze policy — zie handmatige beheer-actie.

Kandidaatselectie filtert op de SelectieCriteria, sluit de maker en reeds door deze reviewer beoordeelde of uitgesloten slots uit, verbreedt land → UN M49-subregio → werelddeel, en sorteert oudste-open-eerst (FIFO) zodat geen enkele vraag verhongert. Eén actieve keuzeset per reviewer wordt afgedwongen (partiële unieke index op voorgesteldAan bij status = Voorgesteld); een net-verlopen slot wordt via OpdrachtUitsluiting (antiThrashCooldownMin) niet meteen weer aan dezelfde reviewer aangeboden. Een slot dat maxVoorstelHerhaling keer is aangeboden-en-verlopen escaleert naar het AI-vangnet i.p.v. eeuwig rond te gaan.

Sweepers (achtergrondtaken, ADR-005; allemaal SKIP LOCKED-batchclaims, geen leader-election nodig): een keuzetermijn-sweep en antwoordtermijn-sweep geven verlopen reserveringen vrij, een AI-vangnet-sweep vult Open slots van vragen voorbij hun aiDeadline, naast de bestaande retentie-sweep (ADR-010).

Je verdient credits door andermans vragen te beoordelen (creditsPerBeoordeling per voltooide opinie) en je betaalt ze om je eigen uitslag in te zien. Een vraag stellen is gratis: de slots gaan direct Open (geen Geblokkeerd-fase) en de opname levert meteen beoordeelbaar werk op. De poort zit op het inzien van het resultaat: is de vraag beoordeeld, dan ontgrendelt de maker de uitslag door eenmalig de op de Vraag bevroren creditkosten af te schrijven; heeft hij te weinig, dan moet hij eerst meer verdienen (beoordelen). Dit vervangt de eerdere twee poorten aantalEerstZelfBeoordelen én reciprociteitDrempel door één heldere valuta (zie ontwerpbeslissing 17).

De poort staat bewust op het inzien, niet op het insturen. Een gestelde vraag is geen kostenpost maar werk (een verdien-kans) voor anderen; het schaarse goed is beoordeel-inspanning. Gratis kunnen posten borgt dat er altijd werk in de pool komt, waardoor de credit-economie zichzelf bootstrapt en er geen cold-start deadlock is (iedereen start op 0). Dit is de credit-vorm van de oorspronkelijke wederkerigheid: “om je vraag beantwoord te krijgen, beoordeel je eerst een ander.”

  • Prijs volgt het vaste aantal beoordelingen. De inzage-prijs creditkosten wordt bij het stellen bevroren als aantalOpiniegevers × creditkostenPerBeoordeling (creditkostenPerBeoordeling standaard 1), waarbij Vraag.aantalOpiniegevers de bij het stellen bevroren gelijknamige instelling is. De prijs is dus voor elke vraag gelijk zolang de beheerinstellingen niet wijzigen, en wordt vóór het versturen getoond.
  • Credits ≠ waardering ≠ euro’s. Credits zijn de deelname-valuta (je uitslag mogen inzien); de waardering 0–5 die de maker geeft is een kwaliteitsoordeel over een ontvangen beoordeling — geen valuta. Het euro-saldo voor betaald advies staat er strikt los van: geen omwisselkoers. Alle drie staan volledig los van elkaar.
  • Saldo per actor. Een geregistreerde Gebruiker houdt zijn credits persistent. Een anonieme gebruiker bouwt credits op binnen zijn sessie; bij het verlopen van de sessie (anoniemeSessieMin) vervallen de credits — de volgende keer verdien je opnieuw.
  • Nieuw account start op 0 credits: dat blokkeert niets — je kunt meteen (gratis) posten en verdient credits door te beoordelen; daarna ontgrendel je je uitslag.
  • Een AI-opinie levert geen credits op (een AI is geen gebruiker).
Value objectOmschrijving
BeoordelingsselectieDe door de maker gekozen secties + attributen die voor déze vraag gelden. Bepaalt welke velden de opiniegever scoort. Een vraag is geldig zodra er minstens één sectie is. (De vlag vrijeTekstGevraagd is per 2026-07-10h vervallen: of er een vrije reactie komt volgt uit de vrije-reactie-slots, niet uit een maker-keuze.) (Per 2026-07-13d, issue #20:) eventuele openVragen worden hier als een synthetische sectie open bijgevoegd (attributen = de open-vraag-sleutels), zodat scoring/verdeling/aggregatie ongewijzigd blijven.
OpenVraag(Per 2026-07-13d; twee-niveau sinds 2026-07-14a, issue #20.) Een eigen beoordelingscategorie die de maker zelf formuleert: een titel (categorie-kop) + eigen subvragen. { sleutel (q1, q2, …), titel, subvragen }. Wordt als sectie open:<sleutel> meegenomen; de kop zelf wordt niet gescoord. Max. maxOpenVragen categorieën per vraag; titel door de tekstmoderatie.
OpenSubvraag(Per 2026-07-14a, issue #20.) Eén sub-vraag binnen een OpenVraag-categorie: { sleutel (s1, s2, …), tekst }. De opiniegever scoort haar op de smiley-schaal 1–5 (net als een attribuut) — géén vrije-tekst-antwoord. Max. maxOpenSubvragen per categorie; de tekst gaat door de tekstmoderatie.
ScoresPer geselecteerde sectie een set attribuut-scores 1–5, verplicht voor elk gevraagd attribuut (“geen mening” is per 2026-07-05 vervallen). Dekt alleen de attributen uit de Beoordelingsselectie.
SectieEen beoordeelbare sectie met attributen — beheerbare stamdata (Keuzelijst, typen sectie en attribuut). Standaard: Gezicht, Kleding, Accessoires.
SectieGemiddeldenAfgeleid gemiddelde per beoordeelde sectie, over alle scores (de “alleen scores > 0”-regel is per 2026-07-05 vervallen).
SelectieCriteriaDe doelgroep voor de opiniegevers: gender, regio (per 2026-07-10d; beheerbare, vlakke keuzelijst, bv. de 12 NL-provincies — geen landprefix meer sinds 2026-07-11m), achtergrond en leeftijdsrange. Een regio-criterium verbreedt niet mee. Online-zijn is géén criterium meer — online kandidaten krijgen alleen voorrang. (Het criterium Land is per 2026-07-11m vervallen — ADR-037.)
ProfielSnapshotBevroren profiel van maker/reviewer op het moment van de vraag/toewijzing.
KeuzesetEen tijdelijk voor één reviewer gereserveerde set van maximaal keuzesetGrootte slots (van verschillende vragen), gegroepeerd via reserveringId, waaruit hij er één kiest. Transient (read-projection over de Voorgesteld-slots), met een eigen verlooptOp (de keuzetermijn).
OpdrachtUitsluiting(entity) Korte uitsluiting van één (slot, reviewer)-combinatie (uitsluitenTot) nadat die reviewer dat slot liet verlopen — tegen thrash en starvation.
EnumWaardenToelichting
MediaTypeVideo, FotoEen vraag is óf een video van maximaal 10 seconden óf een foto.
VraagtypeAlgemeen, SpecifiekAlgemene opinie of een specifieke vraag.
OpdrachtStatusOpen, Voorgesteld, Gekozen, Voltooid, AIVoltooidDe reserveringslevenscyclus van een slot; timeouts recyclen naar Open, terminaal zijn Voltooid/AIVoltooid. Zie de toestandsmachine.
OpinieBronMens, AIOf de opinie van een mens of van een AI-persona komt (personaId wijst dan naar de persona).
Score1..5Smiley-schaal, verplicht per gevraagd attribuut: 1 = slecht/kan beter, 5 = uitstekend. (Per 2026-07-05 — “geen mening” (score 0) is vervallen; de code hanteert deze schaal.)
Waardering0..5Kwaliteitswaardering die de maker aan een ontvangen beoordeling geeft (0 = slechtste, 5 = beste). Nullable op de Opinie zolang de maker nog niet waardeerde.

Identiteit, profiel en sessies. We kennen twee soorten gebruikers: geregistreerde gebruikers (een blijvend account — Gebruiker) en anonieme gebruikers (geen account — vastgelegd als een vluchtig AnoniemeGebruiker-profiel). Alleen geregistreerde gebruikers houden gegevens; een anonieme gebruiker bestaat enkel om de demografie van een vraag of opinie aan de matching te koppelen en verdwijnt daarna weer.

classDiagram
    class Gebruiker {
        <<AggregateRoot>>
        +string gebruikersnaam
        +string wachtwoord
        +string email
        +Profiel profiel
        +int credits
        +decimal euroSaldo
        +bool welkomstbonusGebruikt
        +int aantalSterren
        +Adviesniveau adviesniveau
        +int aantalBeoordelingen
        +int waarderingSom
        +int waarderingAantal
        +decimal gemiddeldeWaardering
        +datetime laatsteBezoek
        +datetime aangemaaktOp
        +bool isOnline(vensterMin)
        +bool heeftCredits(n)
        +void registreerBeoordeling()
        +void ontvangWaardering(score, vorige)
    }
    class AnoniemeGebruiker {
        <<AggregateRoot>>
        +UUID id
        +int leeftijd
        +string gender
        +string achtergrond
        +int credits
        +int totaalVerdiendeCredits
        +datetime verlooptOp
        +datetime createdAt
        +bool heeftCredits(n)
    }
    class Sessie {
        <<AggregateRoot>>
        +string gebruikersnaam
        +UUID sessionId
        +string ip
        +datetime lastActivity
        +datetime createdAt
    }
    class Profiel {
        <<ValueObject>>
        +int leeftijd
        +string gender
        +string regio
        +string achtergrond
    }

    Gebruiker --> Profiel
    Gebruiker "1" --> "0..1" Sessie : single-device
  • Gebruiker (root) — de geregistreerde gebruiker, geïdentificeerd door gebruikersnaam. Een Gebruiker is per definitie geregistreerd (een blijvend account); er is geen isGeregistreerd-vlag meer. Bevat het Profiel, een persistent credits-saldo (deelname-valuta; zie credits-poort), (vastgesteld per 2026-07-08b) een euroSaldo (de inleg, opgeladen via iDeal; welkomstbonusGebruikt borgt dat de welkomstbonus eenmalig is), de blijvend opgeslagen sterren (aantalSterren) met het daaruit volgende adviesniveau, en de waarderingsstatistieken als reviewer: aantalBeoordelingen (teller van gegeven beoordelingen, verhoogd via registreerBeoordeling()) plus waarderingSom/waarderingAantal met de afgeleide gemiddeldeWaardering (= som/aantal, afgerond op 2 decimalen, 0 als er nog geen waarderingen zijn). ontvangWaardering(score, vorige?) verwerkt een (her)waardering van de maker. Het email-veld is optioneel en dient uitsluitend voor wachtwoordherstel (zie de notitie hieronder). isOnline() bepaalt op basis van laatsteBezoek of de gebruiker recent actief was (binnen een instelbaar online-venster) — dit geeft voorrang bij matching, het is geen harde voorwaarde meer.
  • AnoniemeGebruiker (root) — de anonieme gebruiker én de anonieme-sessie-identiteit: een minimaal, vluchtig profiel (géén gebruikersnaam/wachtwoord, alleen demografie) dat ontstaat zodra een niet-ingelogde bezoeker een sessie start. Hij kan binnen die sessie beoordelen (credits verdienen) én een vraag stellen (credits besteden); het credits-saldo is sessie-gebonden en verloopt met de sessie (verlooptOp = nu + anoniemeSessieMin). Wordt met zijn credits opgeruimd zodra de sessie verloopt. (Per 2026-07-10i, issue #9:) daarnaast een levensloop-teller totaalVerdiendeCredits (cumulatief met beoordelen verdiende credits binnen de sessie) — de basis voor het stermoment en de account-upgrade hieronder.
  • Sessie (root) — actieve login. Single-device: per gebruikersnaam is er hooguit één actieve sessie; verlopen sessies worden periodiek opgeruimd.

Account-upgrade: anoniem → geregistreerd

Section titled “Account-upgrade: anoniem → geregistreerd”

(Per 2026-07-10i, issue #9; ontwerpbeslissing 35.) Een anonieme gebruiker kan zijn sessie op elk moment omzetten naar een geregistreerd account (POST /api/anoniem/upgrade: gebruikersnaam + wachtwoord + optioneel e-mail, vanuit “Mijn profiel”). Daarbij gaan over:

  • het credit-saldo (de sessie-credits worden het startsaldo van het account);
  • de ster(ren) die hij zou hebben verdiend: voor elke gepasseerde sterCreditsMijlpaal in totaalVerdiendeCredits krijgt het nieuwe account direct een ster (bron CreditsMijlpaal) — anonieme sessies kunnen zelf géén sterren dragen, dus dit is het “neem je ster mee”-moment.

(Per 2026-07-11a — bugfix:) de upgrade is een volledige identiteitsmigratie. Naast credits + sterren gaan óók mee: de gestelde vragen (Vraag.makerId wordt de nieuwe gebruikersnaam en makerIsGeregistreerd gaat op true — de vraag blijft dus gewoon in Mijn vragen staan en het resultaat blijft inzichtbaar), de ontvangen opinies (targetGebruiker), de zelf gegeven beoordelingen (Opinie.reviewer — die tellen voortaan mee in de consensus-ranking, consistent met “neem je ster mee”), actieve slots (een vastgehouden beoordeling loopt door) en berichten. Bewust niet mee: meldingen en anti-thrash-uitsluitingen (kortlevende moderatie-/verdeeladministratie). De anonieme sessie wordt bij de upgrade verwijderd en de client krijgt een nieuw actor-token voor het account; de migratie commit in dezelfde transactie als de upgrade. UI-moment: zodra een anonieme beoordelaar de ster-mijlpaal passeert, toont het portaal een niet-opdringerige, wegklikbare uitnodiging (“maak een account en neem je tegoed + ster mee”); de upgrade blijft daarnaast altijd bereikbaar via Mijn profiel.

Gebruikerstype bepaalt retentie. Bij een geregistreerde gebruiker blijven gebruikers- en berichten-gegevens behouden. Gegevens van anonieme gebruikers (de AnoniemeGebruiker) worden verwijderd; opnames worden altijd verwijderd. Zie Anonimiteit & retentie.

Geen locatieveld meer. (Tot 2026-07-11m) koos de gebruiker een Land (ISO 3166-1) uit een Keuzelijst, met een automatisch afgeleide RegioM49 voor matching-verbreding. Dat is vervallen (ADR-037): I See You wordt per land als aparte site gehost (eigen domein), NL eerst — welk land het betreft volgt dus uit de site, niet uit een profielkeuze. Er is nog altijd geen GeoIP en geen permissieprompt; gender, leeftijd, achtergrond en het optionele Regio blijven keuzes van de gebruiker. Zie Beveiliging & privacy en Aanmelden & registratie.

Wachtwoordherstel alleen voor geregistreerde gebruikers. Een geregistreerde gebruiker kan optioneel een e-mailadres opgeven; uitsluitend daarmee is wachtwoordherstel mogelijk. Zonder e-mailadres is er geen herstel (verloren wachtwoord = verloren account). Een anonieme gebruiker heeft geen account en dus geen herstel. Zie Aanmelden & registratie.

Waarderingsstatistieken op het profiel. Voor een geregistreerde gebruiker houden aantalBeoordelingen en gemiddeldeWaardering (0–5) bij hoeveel beoordelingen hij gaf en hoe die door de makers gewaardeerd zijn. Ze worden op het profiel getoond. Toekomstige privileges kunnen hierop leunen (nog niet geïmplementeerd; zie de waardering-sectie). Een anonieme gebruiker houdt geen blijvende statistieken.

Credits — deelname-valuta. Beide gebruikerstypen hebben een credits-saldo: je verdient credits door te beoordelen (creditsPerBeoordeling per voltooide opinie) en je betaalt ze om je eigen uitslag in te zien (aantalBeoordelingen × creditkostenPerBeoordeling; stellen is gratis). Geregistreerd = persistent saldo; anoniem = sessie-gebonden (vervalt met de sessie). Zie de credits-poort en Credits. Credits staan strikt gescheiden van het euro-saldo uit Beloning & Financieel: er is géén omwisselkoers.


Kwaliteit belonen en geld verwerken. Deze context kent de Ster (verdiende, blijvende kwaliteitsreputatie), het Adviesniveau (1–4 + Expert) met betaald advies, het euro-saldo (de “inleg”) met Betaling via iDeal (incl. de eenmalige welkomstbonus), de teaser-ontgrendeling per opinie en de terugkerende Uitbetaling. Credits (deelname-valuta, context Beoordeling/Gebruiker & Toegang) en euro’s blijven strikt gescheiden — er is geen omwisselkoers.

classDiagram
    class Ster {
        <<Entity>>
        +UUID id
        +string gebruikersnaam
        +SterBron bron
        +UUID vraagId
        +datetime toegekendOp
    }
    class SterBron {
        <<enumeration>>
        BesteVanVraag
        VijfmaalTweede
        TienmaalDerde
        CreditsMijlpaal
    }
    class Adviesniveau {
        <<enumeration>>
        Geen
        Niveau1
        Niveau2
        Niveau3
        Niveau4
        Expert
    }
    class ConsensusRanking {
        <<DomainService>>
        +Ranglijst bepaalRanglijst(opinies, waarderingen, instellingen)
    }
    class Betaling {
        <<AggregateRoot>>
        +UUID id
        +string gebruikersnaam
        +decimal bedrag
        +BetalingType type
        +BetalingStatus status
        +string pspReferentie
        +UUID opinieId
        +datetime timestamp
    }
    class BetalingType {
        <<enumeration>>
        Inleg
        TeaserOntgrendeling
    }
    class BetalingStatus {
        <<enumeration>>
        Aangemaakt
        Betaald
        Mislukt
    }
    class Uitbetaling {
        <<AggregateRoot>>
        +UUID id
        +string gebruikersnaam
        +decimal bedrag
        +UitbetalingStatus status
        +datetime aangevraagdOp
    }
    class UitbetalingStatus {
        <<enumeration>>
        Aangevraagd
        Uitbetaald
        Geweigerd
    }

    Ster --> SterBron
    ConsensusRanking ..> Ster : kent toe (nr. 1 + tellers)
    Ster ..> Adviesniveau : ster-totaal ontsluit niveau
    Betaling --> BetalingType
    Betaling --> BetalingStatus
    Uitbetaling --> UitbetalingStatus

Een Ster is een blijvende onderscheiding op het account van een opiniegever (Gebruiker.aantalSterren is de afgeleide teller). Sterren worden verdiend — géén loterij — via vier routes (drempels = beheerinstellingen):

#RouteRegel
1Beste opiniegever van een vraagDe consensus-ranking wijst per vraag de nummer 1 aan.
25× als 2e geëindigdTeller per opiniegever (sterDrempelTweedePlaatsen, standaard 5).
310× als 3e geëindigdTeller per opiniegever (sterDrempelDerdePlaatsen, standaard 10).
4Elke 200 verdiende creditsElk veelvoud van sterCreditsMijlpaal (standaard 200) van de levensloop-teller totaalVerdiendeCredits: cumulatief ooit met beoordelen verdiende credits — uitgeven verlaagt de teller niet, en door beheer toegekende credits tellen niet mee (interpretatie, ter verificatie).

Een ster heeft géén directe geldwaarde (vastgesteld 2026-07-08b): hij is een kwaliteits-/schaalaanduiding en fungeert uitsluitend als de sleutel tot een hoger advies-/beloningsniveau. Het ster-totaal ontsluit het adviesniveau, en de uitbetaling per beoordeling is één-op-één gekoppeld aan het behaalde niveau (hoger niveau = hogere uitbetaling, via de niveauPrijzen). Er zijn dus geen aparte “ster-in-euro’s”-bonussen. Sterren vervallen nooit — een ster is blijvend.

De ConsensusRanking (domain service) berekent per vraag een ranglijst (1e/2e/3e/…) van de menselijke opiniegevers. Het concrete formule-voorstel (ter verificatie; rekenvoorbeeld in voorstel §1a) geeft elke beoordelaar een totaalscore 0–1 uit drie componenten:

  • C — Consensus (gewicht 50%): per gevraagd attribuut de afstand tussen de score van de beoordelaar en het groepsgemiddelde van dat attribuut — over álle gevraagde attributen, want scoren is verplicht (iedereen heeft alles gescoord; de eerdere “geen mening”-uitzondering is per 2026-07-05 vervallen); gemiddelde afwijking D (0–5) → C = 1 − D/5.
  • K — Correlatie-controle (gewicht 25%): de correlatie tussen de attribuutscores van de beoordelaar en de groepsgemiddelden per attribuut, geschaald naar 0–1 (K = (r+1)/2); geen spreiding (alles dezelfde score) of te weinig attributen → neutraal K = 0,5.
  • W — Maker-waardering (gewicht 25%): de bestaande 0–5-waardering ÷ 5; niet gewaardeerd → neutraal W = 0,5. Gewicht instelbaar via gewichtMakerWaardering (0 = niet meewegen).

Spelregels: alleen menselijke beoordelaars met account dingen mee (AI-opinies en anonieme sessies niet; hun scores tellen wél mee in het groepsgemiddelde); ranken vanaf minBeoordelaarsVoorRanking (standaard 3); uitzonderingen voor niet-gescoorde attributen zijn er niet — scoren is verplicht op elk gevraagd attribuut (de eerdere “minder dan de helft gescoord”-regel is daarmee vervallen); gelijkspel → hoogste maker-waardering, daarna vroegst ingediend; bij alleen-vrije-tekst-vragen (geen scores) rankt alleen de maker-waardering. De ranglijst wordt definitief aan het einde van het resultaat-retentievenster (of eerder bij verwijdering door de maker), zodat maker-waarderingen kunnen meetellen. Alle gewichten en drempels zijn beheerinstellingen.

Een opiniegever kan een Adviesniveau hebben (1–4 of Expert; Geen = de gratis route). Het niveau volgt uit de sterren-reputatie via vaste, instelbare drempels (vastgesteld 2026-07-08b): elke sterrenPerNiveau (standaard 30) sterren tilt de opiniegever een niveau hoger — 30★ → Niveau 1, 60★ → Niveau 2, 90★ → Niveau 3, 120★ → Niveau 4. ⚠️ Expert = Niveau 5 → 150★ (de reeks doorgetrokken; interpretatie van “Expert = 5” — ter finale check bij Han); daarnaast blijft Expert handmatig/op aanvraag toekenbaar door de beheerder (ExpertHandmatig als override, ook onder 150★). Per niveau geldt een prijs per beoordeling (beheerinstelling niveauPrijzen; start: €0,20 / €0,40 / €0,60 / €0,80 / €1,00).

  • Vanaf niveau 1 is het tekstvak in het opiniescherm vrijgegeven én verplicht: een niveau-beoordelaar schrijft altijd een reactie (gemodereerd zoals elke vrije tekst).
  • De vraagsteller kiest bij zijn vraag één of meerdere niveaus en geeft per niveau aan hoeveel van de tien beoordelaars aan dat ervaringsniveau moeten voldoen (vastgesteld 2026-07-08b) — vastgelegd als niveaueisen (een verzameling { niveau → aantal }). De totaalprijs = de som van (aantal × niveauprijs), wordt vooraf getoond en op de vraag bevroren, en gaat van zijn euro-saldo af. ⚠️ De som van de gevraagde aantallen is ≤ 10; de resterende slots van de tien zijn gewone gratis-/AI-beoordelaars (interpretatie).
  • Teaser: stelt de vraagsteller niets in (geen account/saldo/niveau), dan zorgt de verdeling voor minimaal minTeaserNiveauBeoordelaars (standaard 2) beoordelaars met niveau > 0 (best effort). Hun tekst verschijnt geblurd in de uitslag met niveau + prijs; betalen ontgrendelt per beoordeling (Opinie.ontgrendeld), waarbij de vraagsteller hoogstens één teaser koopt (vastgesteld 2026-07-08b). De betaling aan de beoordelaar volgt de ontgrendeling: geen ontgrendeling = geen betaling. De verdeelsleutel beoordelaar/platform is 50/50 (beoordelaarAandeelProcent, standaard 50) — met die verdeling kost het als bonus verdubbelen van de inleg het platform per saldo niets.
  • Het euro-saldo (“inleg”) staat op de Gebruiker (euroSaldo) en wordt opgeladen via iDeal: een Betaling (type Inleg) loopt via de payment service provider (PSP); de webhook van de PSP zet de status op Betaald en schrijft het saldo idempotent bij. Een Betaling van het type TeaserOntgrendeling ontgrendelt één opinie.
  • Welkomstbonus (eenmalig, bij het aanmaken van een account): de eerste inleg wordt verdubbeld tot maximaal welkomstbonusMaxEuro (standaard €5) bonus — stort je €5, dan €5 bonus → €10 saldo; stort je €20, dan €5 bonus → €25 saldo (vastgesteld 2026-07-08b: bonus max €5, zodat het totaal max €10 is — €5 van de gebruiker + €5 van I See You). Gebruiker.welkomstbonusGebruikt borgt de eenmaligheid.
  • Credits ≠ euro’s: strikt gescheiden, geen omwisselkoers (vastgesteld 2026-07-08b).

De Uitbetaling keert terug (was geschrapt in 2026-07-03): verdiensten uit betaald advies kunnen worden uitbetaald. De opiniegever vraagt een uitbetaling aan vanaf zijn profielscherm; dat kan pas wanneer het euro-saldo minimaal uitbetaalDrempelEuro (standaard €10) bedraagt (vastgesteld 2026-07-08b). Uitbetalen vereist een bankrekening en raakt daarmee de anonimiteitsbelofte: die is geherformuleerd als anoniem richting andere gebruikers — betaalgegevens bestaan bij de payment provider, het platform bewaart alleen de minimaal noodzakelijke transactiedata (referentie + saldo). De uitbetaal-frequentie blijft ongeregeld (geen vaste periode); bij uitbetaling hoort een KYC-noot (zie Beveiliging & privacy).


Misbruik tegengaan en anonimiteit borgen. Deze context kent twee soorten moderatie — reactieve melding-moderatie (gebruikers rapporteren een opname → automatische verwijdering bij een drempel) en proactieve tekstmoderatie (alle ingetypte vrije tekst wordt vooraf gecontroleerd) — plus het retentiebeleid.

classDiagram
    class Melding {
        <<AggregateRoot>>
        +UUID vraagId
        +string gebruiker
        +string ip
        +datetime timestamp
    }
    class Retentiebeleid {
        <<Policy>>
        +int resultaatRetentieUren
        +int meldingenDrempel
        +int veiligheidsTimeoutMin
    }
    class IModeratieDienst {
        <<Poort>>
        +ModeratieUitslag Controleer(tekst)
    }
    class ModeratieUitslag {
        <<ValueObject>>
        +bool toegestaan
        +string reden
    }
    Melding "drempel" ..> Retentiebeleid : triggert verwijdering
    IModeratieDienst ..> ModeratieUitslag : levert
  • Melding (root) — een gebruiker meldt een ongepaste vraag. Bij het bereiken van de meldingen-drempel (instelbaar, standaard 3) wordt de vraag automatisch verwijderd. Een gebruiker kan dezelfde vraag niet dubbel melden; meldingen zijn rate-limited.
  • Retentiebeleid (policy) — borgt dat een opname altijd verdwijnt, maar niet meer direct bij afronding. Na isBeoordeeld() blijft het resultaat + de opname een begrensd resultaat-retentievenster bestaan zodat de maker het kan terugzien; daarna verwijdert resultaatRetentieUren (standaard 168 = 7 dagen, geteld vanaf beoordeeldOp) de vraag + opname automatisch — tenzij de maker die eerder zelf verwijdert. Een instelbare veiligheidsTimeoutMin ruimt enkel vragen op die nooit worden afgerond; de meldingen-drempel verwijdert gemelde vragen direct. De opname is in het retentievenster uitsluitend voor de maker zichtbaar.

Naast het reactieve melden kent I See You een proactieve tekstmoderatie: alle door gebruikers ingetypte vrije tekst wordt automatisch gecontroleerd op ongepaste inhoud vóórdat ze wordt opgeslagen. Dit dekt twee plekken:

  1. de toelichting die de maker bij een Vraag typt;
  2. de reactie die een reviewer op een Opinie geeft.
  • De controle loopt via een applicatie-poort IModeratieDienst met resultaat ModeratieUitslag(Toegestaan, Reden?). De infra-implementatie OpenAiModeratieDienst roept de OpenAI Moderation API aan (POST https://api.openai.com/v1/moderations, model omni-moderation-latest). Die API is gratis.
  • Afgekeurde tekst wordt geweigerd (niet opgeslagen); de gebruiker krijgt de reden direct bij het indienen te zien en kan de tekst aanpassen. Wordt de beoordeling van een reviewer afgekeurd, dan wordt die niet opgeslagen en krijgt de reviewer geen credit.
  • Zonder geconfigureerde API-sleutel draait de moderatie fail-open (alles toegestaan — de app blijft werken). De sleutel is de Azure app-setting OpenAI__ApiKey.
  • De oude regel “vrije opmerkingen alleen voor opiniegevers met genoeg sterren” is vervallen: iedereen mag vrije tekst geven, mits die door de moderatie-check komt.

Naast de moderatie kent I See You één uitgaand kanaal: een e-mailnotificatie zodra de uitslag van een vraag klaar is. De maker kan bij het stellen optioneel een notificatieEmail achterlaten; zodra alle opinies binnen zijn (beoordeeldOp wordt gezet), stuurt het systeem daar één korte mail met alleen een link naar het gebruikersportaal (“je uitslag staat klaar”).

  • De verzending loopt via een applicatie-poort IUitslagNotificaties met de bewerking UitslagKlaarAsync(email). De infra-implementatie draait op Azure Communication Services (ACS) Email (afzender DoNotReply@…azurecomm.net), geconfigureerd via de app-settings Email__ConnectionString, Email__Afzender en App__PortaalUrl (de link in de mail).
  • Bewust geen inhoud in de mail. De mail bevat géén beoordelingsinhoud (geen scores, gemiddelden of reacties) — alleen een seintje met een link. Dat is robuust tegen aflever-/spamproblemen: de mail is enkel een trigger, de site is de bron van de uitslag (die achter de credits-poort zit).
  • Privacy: adres eenmalig. Direct na de verzendpoging wordt notificatieEmail op de vraag gewist (→ null), of de verzending nu slaagde of niet. Er blijft dus geen mailinglijst of herleidbaar adres achter; het adres verdwijnt hoe dan ook uiterlijk met de vraag (retentie).
  • Fail-graceful. Ontbreekt de configuratie of faalt de verzending, dan blijft de app gewoon werken: de uitslag is altijd in de app te zien, de mail is best-effort (een fout blokkeert het afronden van de vraag niet). Zonder configuratie is de poort een no-op.
  • Het notificatie-adres staat volledig los van het optionele account-e-mailadres voor wachtwoordherstel: dat laatste hoort bij de Gebruiker en dient enkel voor herstel, terwijl notificatieEmail bij de Vraag hoort en enkel voor dit ene seintje dient (zie ontwerpbeslissing 25).

Beheerfuncties en stamdata.

classDiagram
    class Systeem {
        <<AggregateRoot>>
        +Admin admin
        +SysteemWaarden waarden
        +Systeeminstellingen instellingen
        +Verdeelstatistieken verdeelstatistieken
    }
    class SysteemWaarden {
        <<ValueObject>>
        +date startdatum
        +int aantalOnline
        +int totaalVragen
    }
    class Systeeminstellingen {
        <<ValueObject>>
        +int aantalOpiniegevers
        +int antwoordtermijnMin
        +int creditkostenPerBeoordeling
        +int creditsPerBeoordeling
        +int onlineVensterMin
        +int veiligheidsTimeoutMin
        +int meldingenDrempel
        +int resultaatRetentieUren
        +int keuzesetGrootte
        +int keuzetermijnMin
        +int anoniemeSessieMin
        +int maxOnbeantwoordMin
        +int antiThrashCooldownMin
        +int maxVoorstelHerhaling
        +bool aiVangnetActief
        +decimal[] niveauPrijzen
        +int sterrenPerNiveau
        +int sterDrempelTweedePlaatsen
        +int sterDrempelDerdePlaatsen
        +int sterCreditsMijlpaal
        +decimal gewichtMakerWaardering
        +int minBeoordelaarsVoorRanking
        +decimal welkomstbonusMaxEuro
        +int beoordelaarAandeelProcent
        +decimal uitbetaalDrempelEuro
        +int minTeaserNiveauBeoordelaars
        +int onboardingAantalBeoordelingen
        +int auditRetentieDagen
        +int maxOpenVragen
        +int maxOpenSubvragen
    }
    class Auditgebeurtenis {
        <<AggregateRoot>>
        +long id
        +string type
        +string actor
        +string target
        +string details
        +datetime tijdstip
    }
    class Keuzelijst {
        <<AggregateRoot>>
        +string taal
        +string type
        +string sleutel
        +string omschrijving
        +int volgorde
    }
    class Bericht {
        <<AggregateRoot>>
        +UUID id
        +string ontvanger
        +string inhoud
        +datetime timestamp
    }
    class EmailSjabloon {
        <<AggregateRoot>>
        +UUID id
        +string taal
        +string sleutel
        +string onderwerp
        +string body
    }
    class Verdeelstatistieken {
        <<ValueObject>>
        +long mensVoltooidTotaal
        +long aiVoltooidTotaal
        +long aiDoorTimeout
        +long somVraagAntwoordtijdMs
        +long aantalVragenAfgerond
        +long voorstellenVervallen
        +long toewijzingenVervallen
        +long slaOverschrijdingen
    }
    class AIPersona {
        <<AggregateRoot>>
        +UUID id
        +string naam
        +string omschrijving
        +PersonaProfiel profiel
        +string instructie
        +bool actief
        +int gewicht
        +long aantalBeoordelingen
        +datetime aangemaaktOp
        +bool kanMatchen(SelectieCriteria)
    }
    class PersonaProfiel {
        <<ValueObject>>
        +int leeftijd
        +string gender
        +string achtergrond
    }
    Systeem --> SysteemWaarden
    Systeem --> Systeeminstellingen
    Systeem --> Verdeelstatistieken
    Systeem ..> AIPersona : beheert (stamdata)
    Systeem ..> Auditgebeurtenis : logt (support, admin-only)
    AIPersona --> PersonaProfiel
  • Systeem — admin-credentials, SysteemWaarden (statistieken: aantal online, ontvangen/betaald, totaal vragen, startdatum), Systeeminstellingen, de Verdeelstatistieken en het beheer van de AIPersona’s.
  • Systeeminstellingen — de instelbare parameters van het platform, beheerd via het beheerportaal. De credit-economie: creditkostenPerBeoordeling (de prijs per beoordeling die de inzage-kosten opbouwt — de op de Vraag bevroren creditkosten = aantalOpiniegevers × creditkostenPerBeoordeling, standaard 1) en creditsPerBeoordeling (wat een voltooide beoordeling oplevert, standaard 5). Verder: aantalOpiniegevers (het aantal beoordelingen per vraag, standaard 10 — per 2026-07-05 terug van de test-instelling 1; bij het stellen als gelijknamig veld op de Vraag bevroren), antwoordtermijnMin, onlineVensterMin, veiligheidsTimeoutMin, meldingenDrempel (standaard 3), resultaatRetentieUren (hoe lang na afronding het resultaat + de opname voor de maker bewaard blijven vóór automatische verwijdering, standaard 168 = 7 dagen), en de verdeel-/reserverings-parameters keuzesetGrootte (aantal vragen in de pull-keuze), keuzetermijnMin (keuze-deadline), anoniemeSessieMin (levensduur van een anonieme sessie; sessie-credits vervallen erna), maxOnbeantwoordMin (maximale onbeantwoord-tijd vóór het AI-vangnet invalt), antiThrashCooldownMin, maxVoorstelHerhaling en aiVangnetActief. (Vastgesteld per 2026-07-08b) de beloning-/financieel-parameters: niveauPrijzen (prijs per beoordeling per adviesniveau, start €0,20–€1,00), sterrenPerNiveau (het aantal sterren per adviesniveau-stap, standaard 30 → 30/60/90/120★ voor niveau 1–4, ⚠️ Expert = 150★), de ster-drempels sterDrempelTweedePlaatsen (5), sterDrempelDerdePlaatsen (10) en sterCreditsMijlpaal (200), gewichtMakerWaardering (weging van de maker-waardering in de consensus-ranking; 0 = niet meewegen), minBeoordelaarsVoorRanking (3), welkomstbonusMaxEuro (5 — bonus max €5, totaal max €10), beoordelaarAandeelProcent (de verdeelsleutel beoordelaar/platform, standaard 50 = 50/50), uitbetaalDrempelEuro (het minimale euro-saldo voor een uitbetalingsaanvraag, standaard 10), maxVrijeReactiesZonderBetaald (3 — het maximum aantal vrije-reactie-slots per vraag zonder betaald advies; gevalideerd op kleiner dan aantalOpiniegevers), aiVangnetVultVrijeReactieSlots (bool, true — bepaalt of het AI-vangnet op vrije-reactie-/betaald-advies-slots een tekstreactie levert; bij false vult het die slots alleen met scores, zodat de vraag altijd afrondt) en onboardingAantalBeoordelingen (2 — de “eerst zelf beoordelen”-poort, met cold-start-vangrail) en (per 2026-07-11n) auditRetentieDagen (365 — hoe lang een Auditgebeurtenis bewaard blijft vóór automatische opruiming, zie hieronder) en (per 2026-07-13d, issue #20; uitgebreid 2026-07-14a) maxOpenVragen (3 — max. eigen open-vragen-categorieën per vraag; 0 = uit) en maxOpenSubvragen (5 — max. sub-vragen per eigen categorie). (De instelling minTeaserNiveauBeoordelaars is per 2026-07-10h vervallen — vervangen door de exacte vrije-reactie-slots.) De verwijderde instelling sterrenDrempelOpmerkingen blijft vervallen (geen sterhouder-privilege op vrije tekst). Geen van deze waarden staat hard in de code. Er geldt een cross-veld-invariant: keuzetermijnMin + antwoordtermijnMin < maxOnbeantwoordMin < veiligheidsTimeoutMin (AI is de laag vóór de veiligheids-timeout). De volledige tabel staat in Systeembeheer.
  • Keuzelijst — beheerbare stamdata: platte opties per taal en type, elk met een sleutel, een omschrijving (label) en een volgorde. De typen: gender, achtergrond (culturele achtergrond), sectie (de beoordelings­secties, sleutels als gezicht/kleding/accessoires), (per 2026-07-08f) attribuut — de beoordeelbare attributen per sectie, met een samengestelde sleutel "<sectie>.<attribuut>" (bijv. gezicht.ogen, kleding.pasvorm, accessoires.bril) — en (per 2026-07-10d, vlak sinds 2026-07-11m) regio (sleutel is de regionaam zelf, geen landprefix meer). Zo passen ook de attributen in de bestaande platte structuur: géén schemawijziging, alleen seed + frontend. De seed volgt de drie standaardsecties met hun attributen (Gezicht: ogen, mond, haar, baard, wenkbrauwen, make-up/stijl, algeheel; Kleding: hoofd, nek, bovenstuk, taille, onderstuk, combinatie, kleuren, pasvorm, kwaliteit, algeheel; Accessoires: bril, gehoorapparaat, oorbellen, nek, pols, riem, piercing, tattoo, schoenen, algeheel). Daarnaast zijn er content-typen (onboarding-welkomsttekst, tips). (Het type land — de landenlijst — is per 2026-07-11m vervallen, samen met het Land-veld — ADR-037.)
  • Bericht — bericht aan een gebruiker; berichten blijven behouden voor geregistreerde gebruikers.
  • EmailSjabloon (per 2026-07-13c, issue #26, ADR-042)beheerbare stamdata voor de teksten van de e-mailseintjes: per taal en een vaste sleutel (het mailtype, bv. uitslag-klaar) een onderwerp en een platte-tekst-body. De body ondersteunt placeholders die de code invult ({link} voor het uitslag-seintje); een sjabloon kent alléén de placeholders die bij zijn mailtype horen — een onbekende {…} wordt bij het opslaan geweigerd zodat er niets doorlekt. De verzendende code (IUitslagNotificaties) haalt de tekst uit dit sjabloon en valt fail-graceful terug op de in code vastgelegde standaardtekst als er (nog) geen beheerde rij is of de opslag onbereikbaar is. Nieuwe mailtypes (bv. wachtwoordherstel) gebruiken hetzelfde mechanisme: een rij toevoegen aan de seed + het placeholder-contract, zónder de verzendcode te herschrijven. Respecteert ADR-023: het uitslag-seintje bevat alleen een link, nooit inhoudelijke uitslag — de beheer-UI waarschuwt daarvoor.
  • Auditgebeurtenis (per 2026-07-11n, issue #22, ADR-038) — een admin-only log-regel: type (bv. VraagGesteld, OpinieGegeven, WaarderingGegeven, SaldoOpgehoogd, UitbetalingAangevraagd, AccountUpgrade, Registratie, MeldingIngediend, VraagVervallenDoorMelding), actor (gebruikersnaam of anon:<sessie-id>), optioneel target (bv. een vraag- of opinie-id) en details (korte vrije tekst, bv. een bedrag), plus tijdstip. In tegenstelling tot de anonieme Meetgebeurtenis (ADR-036) draagt dit type bewust wél actor-identiteit — voor beheer-support, nooit zichtbaar voor de gebruiker zelf. Bevat nooit media/opnames. Eigen, instelbare retentie (auditRetentieDagen, standaard 365) via een AuditOpruimHostedService. Elke schrijfactie gaat mee in dezelfde transactie als de business-mutatie die ze beschrijft.

AIPersona is beheerbare stamdata: een persona toevoegen = een rij toevoegen. Er kunnen er meerdere zijn. Elke persona heeft een naam, een PersonaProfiel (dezelfde demografie-velden als de SelectieCriteria, zodat een AI-opinie demografisch geloofwaardig past), een instructie (de persoonlijkheid/prompt), een actief-vlag, een gewicht en een teller aantalBeoordelingen. kanMatchen(criteria) gebruikt dezelfde matchregels als mensen.

  • Het automatische AI-vangnet kiest, wanneer een Open slot moet worden afgevuld, de demografisch best-passende actieve persona (gewogen-willekeurig bij gelijke stand); bij meerdere AI-slots op één vraag bij voorkeur verschillende persona’s. Bij een handmatige AI-opinie kiest de beheerder de persona zelf.
  • De opinie-generatie zit achter de applicatie-poort IAiPersonaService (zie ADR-019, ADR-024 en ADR-025). Sinds 2026-07-04f is dit een echte, vision-gebaseerde dienst op OpenAI gpt-4o-mini (een goedkoop vision-model): de persona-instructie stuurt de “persoonlijkheid”, en het model scoort alleen — maar wel allemaal, verplicht — de door de maker gekozen secties/attributen, op de schaal 1–5 (per 2026-07-05 — een AI-opinie volgt dezelfde scoorplicht als een mens; zo gebouwd). Sinds 2026-07-04g krijgt het model óók de Vraag.toelichting mee (deed ‘ie niet) en levert het naast scores een korte vrije reactie terug (zie de poort-vorm hieronder). De foto gaat rechtstreeks als beeld mee; bij een video (max. 10s) haalt de backend met FFmpeg ~4 frames uit de opname en stuurt die als beelden mee. LLM-specifieke knoppen (model, temperatuur) blijven opaque configuratie achter de poort, niet in het aggregate.
  • Herkaderde prompt. Om binnen het contentbeleid tóch bruikbare feedback over echte mensen te geven, is de prompt herkaderd: er wordt expliciet gemaakt dat de persoon zélf, vrijwillig (opt-in), om opbouwende stijl-/uiterlijkfeedback heeft gevraagd, met de vraag om constructieve feedback in plaats van een “aantrekkelijkheidsoordeel”. (Kanttekening: dit verhoogt de bereidheid van het model, maar is geen 100%-garantie — bij echte personen kan het model nog steeds terughoudend zijn; een ander model is de mogelijke vervolgstap.)
  • De poort geeft scores + optionele reactie terug. IAiPersonaService levert voortaan een resultaat met de scores én een optionele reactie (niet alleen scores). Zo levert een AI-opinie niet meer “geen reactie” op, en kan de AI ook een alleen-vrije-tekst-vraag beantwoorden.
  • Fail-graceful. Er is altijd een deterministische fallback (regelgebaseerd, geen LLM): zonder geconfigureerde OpenAI-sleutel, bij een fout, of bij een ontbrekende chat/completions-permissie valt de dienst terug op de bestaande deterministische scores (met een generieke reactie), zodat er altijd een opinie ontstaat en de app blijft werken. Ook die terugval scoort elk gevraagd attribuut (per 2026-07-05 op de schaal 1–5 — sowieso, want ze genereert altijd een volledige set scores). De laatste actieve persona kan niet worden gedeactiveerd.
  • De AI-reactie hoeft niet door de tekstmoderatie (de tekst komt van het model, niet van een gebruiker). Een AI-opinie levert geen credits op. Sinds 2026-07-04h kan de maker haar wél waarderen (hij ziet immers niet dat ze van een AI komt); die waardering wordt op de opinie vastgelegd maar beïnvloedt geen reviewer-profiel. De herkomst wordt niet aan de maker getoond, wél aan de beheerder. Kosten: ordegrootte < $0,01 per AI-opinie (mini vision-model; foto 1 beeld, video ~4 frames).
Handmatige AI-opinie vanuit het beheerportaal
Section titled “Handmatige AI-opinie vanuit het beheerportaal”

Naast het automatische vangnet kan de beheerder vanuit het beheerportaal direct een AI-opinie op een open slot van een vraag laten genereren, met een zelfgekozen AIPersona. Dat is handig zolang een vraag nog Open slots heeft — bijvoorbeeld om een vastgelopen of trage vraag alvast (deels) af te ronden zonder op de aiDeadline te wachten.

  • De actie vult één Open slot met een AI-opinie van de gekozen persona (terminale status AIVoltooid, Opinie.bron = AI, personaId = de gekozen persona). Ze steelt nooit een door een mens vastgehouden Voorgesteld/Gekozen slot.
  • Is er geen Open slot (de vraag is al vol), dan is de actie een no-op-fout (zie het POST /api/beheer/vragen/{id}/ai-opinie-endpoint: 404/400).
  • Ze loopt door dezelfde IAiPersonaService (vision op gpt-4o-mini, met deterministische fallback) als het automatische vangnet, en is dus even fail-graceful: zonder sleutel/permissie of bij een fout ontstaat er alsnog een deterministische opinie.
  • Zoals bij elke AI-opinie: geen credits, en de herkomst is niet zichtbaar voor de maker (wél voor de beheerder). Sinds 2026-07-04g levert ze een reactie (scores + korte onderbouwing) — ook bruikbaar bij een alleen-vrije-tekst-vraag; sinds 2026-07-04h is ze door de maker waardeerbaar (zonder reviewer-profiel-effect).

Verdeelstatistieken is een value object op Systeem met geaggregeerde tellers voor het monitoren van het verdeelsysteem. Omdat een vraag na het resultaat-retentievenster alsnog verdwijnt (en dus niet blijvend beschikbaar is voor rapportage), kunnen grootheden als “gemiddelde antwoordtijd” niet betrouwbaar achteraf uit vragen worden afgeleid: ze worden op het event-moment opgehoogd (in dezelfde transactie als de overgang). Wat nog wél leeft (open vragen, gereserveerde slots) wordt als live gauge geteld. De volledige metriek-set staat in Systeembeheer → Monitoring.


#BeslissingMotivatie
1Vraag generaliseert video én foto via MediaType.Eén opinie-cyclus voor beide media; alleen de capture verschilt. Voorkomt een aparte Video- en Foto-tak.
2Snapshots op Opdracht en Vraag (maker/reviewer/criteria).Toewijzingen en opinies blijven herleidbaar, ook als profielen later wijzigen.
3Twee gebruikerstypen: geregistreerd (Gebruiker, blijvend account) vs. anoniem (AnoniemeGebruiker, vluchtig profiel). Géén aparte “ongeregistreerde” tussenvorm en géén isGeregistreerd-vlag.Anonieme deelname zonder account, met een minimaal profiel voor matching dat eenvoudig op te ruimen is. Eén heldere grens i.p.v. een verwarrende derde categorie.
4Retentie als expliciet beleid: na afronding blijft een vraag nog een instelbaar resultaat-retentievenster (resultaatRetentieUren) bestaan zodat alleen de maker het resultaat + de opname kan terugzien; daarna wordt zij automatisch verwijderd — of eerder, wanneer de maker zelf verwijdert. Een instelbare veiligheids-timeout ruimt nooit-afgeronde vragen op; de meldingen-drempel verwijdert gemelde vragen direct.Anonimiteit is een kernbelofte; verwijderen is een eersteklas regel, geen bijzaak. Het venster is kort en begrensd, zodat de maker zijn resultaat kan zien zonder dat er een blijvend beeldarchief ontstaat.
5(vervallen per 2026-07-05 — zie beslissing 33) Score 0 = “geen mening”, schaal 1–5.Sloot aan op de smiley-keuzevelden en hield sectiegemiddelden eerlijk (lege scores telden niet mee). Per 2026-07-05 (ter verificatie) is scoren verplicht op elk gevraagd attribuut en bestaat “geen mening” niet meer.
6Single-device sessies.Eén actieve sessie per gebruikersnaam voorkomt parallelle accounts en vereenvoudigt het online-begrip.
7(vervallen per 2026-07-11m — zie ADR-037) Land = keuzelijst, regio afgeleid: Land was een Keuzelijst (gevuld met ISO 3166-1), door de gebruiker gekozen; RegioM49 (werelddeel + subregio) werd automatisch afgeleid via UN M49.Was eenvoudig en privacyvriendelijk, maar overbodig zodra I See You per land een aparte site is (NL eerst) — het land volgt dan uit de site, niet uit een profielkeuze. Regio blijft, als vlakke keuzelijst zonder landprefix.
8Instelbare parameters in Systeeminstellingen i.p.v. vaste getallen: aantal beoordelingen per vraag (aantalOpiniegevers), antwoordtermijn, creditkostenPerBeoordeling/creditsPerBeoordeling, online-venster, veiligheids-timeout, meldingen-drempel.Het platform moet zonder code-wijziging bij te stellen zijn; harde getallen als “10” en “30 min” hoorden niet in het model thuis.
9Online = voorrang, geen filter: online-zijn is geen SelectieCriteria meer. Online kandidaten krijgen voorrang, maar het is geen keuze van de vrager en geen harde voorwaarde.De vrager hoeft hier niets over te beslissen; het systeem geeft online gebruikers vanzelf voorrang. Verwijdert een verwarrend, zelden zinvol filter.
10AI-persona als vangnet + antwoordtermijn/herverdeling: reageert een opiniegever niet binnen de termijn, dan valt het slot terug naar Open en wordt herverdeeld; is er geen mens, dan beoordeelt een AI-persona (Opinie.bron = AI).Garandeert dat elke vraag opinies krijgt, ook bij weinig actieve gebruikers — essentieel voor de lancering. De AI-invulling is inmiddels vision-gebaseerd ingevuld (zie beslissing 26).
11Beoordelingsselectie door de vrager: de maker kiest na de opname welke secties/attributen beoordeeld worden; de opiniegever scoort alleen die. Secties/attributen zijn beheerbare stamdata.De beoordelaar hoeft alleen te oordelen waar de vrager behoefte aan heeft; relevanter feedback, minder werk. Configureerbaar i.p.v. drie vaste secties.
12(ingetrokken) Sterren-drempel voor opmerkingen — vervallen. De loterij-ster en het sterhouder-privilege bestaan niet meer; vrije tekst is nu open voor iedereen, geborgd door tekstmoderatie (zie beslissing 22).Vervangen door proactieve OpenAI-tekstmoderatie i.p.v. een sterren-poort op vrije tekst.
13Optioneel e-mailadres voor wachtwoordherstel (alleen geregistreerde gebruikers).Maakt herstel mogelijk zonder anonimiteit te verplichten: wie wil kan een e-mailadres opgeven; anonieme gebruikers houden geen herstelbaar kanaal.
14Pull + keuze i.p.v. push-toewijzing: een opiniegever vraagt zelf werk en kiest uit een Keuzeset; een slot wordt niet vooraf aan een vaste reviewer geduwd.De opiniegever pakt werk wanneer het hém uitkomt en kiest de meest geschikte vraag, wat de betrokkenheid en kwaliteit verhoogt. De matching bepaalt nog wél de eligibility/voorrang.
15Eén Opdracht = één slot met een cyclische toestandsmachine; timeouts recyclen naar Open (de terminale status Verlopen vervalt).Eén invariant-eigenaar per slot, en de garantie “nooit vastlopen”: een reservering valt altijd terug in de pool i.p.v. dood te eindigen.
16Twee gescheiden, server-side timeouts: een keuzetermijn (Voorgesteld) en de bestaande antwoordtermijn (Gekozen, nu startend ná de keuze).De gebruiker noemde dit expliciet: een reservering mag nooit blijvend gelockt raken. Server-side deadlines werken onafhankelijk van of de reviewer online blijft.
17Credits = de enige deelname-poort, op het inzien van de uitslag (genuanceerd per 2026-07-05: voor de eerste vraag van een nieuwe gebruiker komt de onboarding-poort “eerst 2 beoordelen” terug, mét cold-start-vangrail — zie beslissing 32). Verdien credits door te beoordelen (creditsPerBeoordeling); stellen is gratis, maar je uitslag inzien kost creditkostenPerVraag (eenmalig); te weinig → eerst verdienen. Dit vervangt zowel aantalEerstZelfBeoordelen als reciprociteitDrempel/Geblokkeerd. Geregistreerd = persistent saldo; anoniem = sessie-gebonden; nieuw account start op 0.Eén heldere quid-pro-quo. De poort staat bewust op het inzien (niet het insturen): een gestelde vraag is werk/verdien-kans voor anderen, dus gratis posten borgt aanbod en voorkomt de cold-start deadlock. Slots ontstaan altijd Open (Geblokkeerd vervalt).
18AIPersona is first-class en meervoudig, met demografisch profiel + deterministische fallback; het vangnet vult alleen Open slots.Een persona toevoegen = data toevoegen; demografisch passende, geloofwaardige AI-opinies; en het vangnet steelt nooit een door een mens vastgehouden slot.
19De keuzeset toont de opname; een reservering geldt als selectie als opiniegever. Opname-toegang is gekoppeld aan een lopende reservering en wordt ingetrokken bij verloop/keuze van een ander slot.De opiniegever moet de opname zien om de “meest geschikte” vraag te kiezen. De korte, exclusieve reservering en het intrekken van toegang houden de anonimiteit binnen de perken (zie Privacy & anonimiteit).
20(ingetrokken; scheiding herleefd per 2026-07-05) Credits ≠ sterren (gescheiden valuta) — de loterij-variant is vervallen. Per 2026-07-05 bestaat er wél weer een tweede geldstroom: het euro-saldo (zie beslissing 31), strikt gescheiden van de credits.De loterij-context was geschrapt; met de herintroductie van Beloning & Financieel geldt de scheiding opnieuw — nu tussen credits en euro’s (geen omwisselkoers).
210–5 kwaliteitswaardering vervangt loterij-ster + uitbetaling (deels overruled per 2026-07-05). De waardering zelf blijft (de maker waardeert elke ontvangen beoordeling met 0..5), maar het “geen geld / geen ster / geen uitbetaling”-deel is per 2026-07-05 overruled: de Ster keert terug als verdiende reputatie (geen loterij), de context “Beloning & Financieel” is geherintroduceerd en de Uitbetaling komt terug — zie beslissingen 29–31.De loterij bleef terecht geschrapt, maar de stakeholder-notities van 3-7-2026 herintroduceren sterren als verdiende kwaliteitsreputatie, betaald advies en echt geld. De waardering krijgt daarbij een tweede functie als wegingsfactor in de ster-ranking.
22OpenAI-tekstmoderatie (gratis, fail-open) op alle vrije tekst. De toelichting (maker) en de reactie (opiniegever) worden vóór opslaan gecontroleerd via de poort IModeratieDienst (impl. OpenAiModeratieDienst, model omni-moderation-latest). Afgekeurd = geweigerd (geen credit voor een afgekeurde beoordeling); zonder API-sleutel fail-open.Vervangt de sterhouder-drempel op opmerkingen: vrije tekst mag voor iedereen open staan zolang ze geautomatiseerd op ongepaste inhoud wordt gecontroleerd. Gratis, en fail-open zodat de app ook zonder sleutel werkt.
23Eén vrije tekst per kant: toelichting (maker) en reactie (opiniegever) (herzien 2026-07-04d; de open-vragen/antwoorden-variant van 2026-07-03 is teruggedraaid). De maker geeft alleen nog de bestaande toelichting mee; de reviewer geeft naast zijn scores optioneel één vrije tekstreactie (Opinie.reactie). De openVragen in de Beoordelingsselectie en het VO OpenAntwoord zijn verwijderd; het vrije opmerkingen-veld blijft verwijderd.Eén tekst per kant is eenvoudiger uit te leggen én er hoeft maar één tekst per kant gemodereerd te worden (stakeholder-review 2-7-2026); de reviewer kan zich met een goede reactie onderscheiden voor een hoge waardering.
24Vast aantal beoordelingen per vraag (herzien 2026-07-04; de “maker kiest”-variant van 2026-07-03 is teruggedraaid). Elke vraag krijgt het aantal beoordelingen uit de instelling aantalOpiniegevers (standaard 10); Vraag.aantalOpiniegevers is een bevroren snapshot van die instelling op het moment van stellen — geen keuze van de maker. Er ontstaan evenveel slots en de bevroren inzage-prijs blijft creditkosten = aantalOpiniegevers × creditkostenPerBeoordeling (creditkostenPerVraag blijft vervangen door creditkostenPerBeoordeling).De eerdere keuze door de maker (1 t/m het maximum, met meeschalende prijs) voelde commercieel en was onduidelijk voor nieuwe gebruikers, die credits vs. kosten nog niet kennen (stakeholder-review 2-7-2026); een beheerinstelling volstaat. De snapshot houdt bestaande vragen stabiel wanneer de beheerder de instelling wijzigt.
25E-mailnotificatie met alleen een link zodra de uitslag klaar is (nieuw 2026-07-04e). Vraag krijgt een optioneel notificatieEmail; zodra beoordeeldOp wordt gezet, stuurt de poort IUitslagNotificaties (impl. op Azure Communication Services Email) één seintje met alleen een link naar het portaal — géén beoordelingsinhoud. Het adres wordt direct na de verzendpoging gewist; de poort is fail-graceful (zonder configuratie of bij een fout blijft de app werken). Staat volledig los van het account-e-mailadres voor wachtwoordherstel.”Een mailtje met een link is prima — dan bezoeken ze de site opnieuw” (stakeholder-review 2-7-2026, Han). Alleen een link is robuust tegen aflever-/spamproblemen (de site is de bron); het adres eenmalig gebruiken en wissen houdt de anonimiteit/dataminimalisatie overeind; fail-graceful borgt dat de uitslag altijd in de app te zien blijft.
26Handmatige AI-persona-opinie via het beheerportaal + echte vision-IAiPersonaService (nieuw 2026-07-04f). Naast het automatische AI-vangnet kan de beheerder handmatig, met een gekozen persona, direct een AI-opinie op een Open slot laten genereren (POST /api/beheer/vragen/{id}/ai-opinie). De poort IAiPersonaService is nu een echte, vision-gebaseerde dienst op OpenAI gpt-4o-mini: de persona-instructie stuurt de persoonlijkheid, het model scoort alleen de gekozen secties/attributen (destijds 1–5; per beslissing 33 de verplichte 1–5-schaal); foto gaat direct mee, video via ~4 FFmpeg-frames. Fail-graceful: zonder sleutel/chat-permissie of bij een fout valt de dienst terug op de deterministische scores. (De AI produceerde in deze versie nog geen vrije tekst; dat is met beslissing 27 gewijzigd.)De beheerder wil vastgelopen of trage vragen direct kunnen afvullen zonder op de aiDeadline te wachten, en het vangnet moet geloofwaardige, op de opname gebaseerde scores geven. Een goedkoop vision-model (mini, < $0,01 per opinie) maakt dat betaalbaar; de deterministische terugval borgt dat er altijd een opinie ontstaat en de app zonder OpenAI-sleutel blijft werken.
27Maker bepaalt of er een vrije reactie gevraagd wordt (verplicht wanneer gevraagd); AI geeft nu een onderbouwde reactie (nieuw 2026-07-04g; het maker-keuze-deel is per 2026-07-10h vervallen — zie beslissing 34; het AI-reactie-deel blijft). Beoordelingsselectie krijgt de vlag vrijeTekstGevraagd (bool). Een vraag is geldig zodra er ≥1 sectie is OF vrijeTekstGevraagd = true (alleen categorieën, alleen vrije tekst, of beide). Is vrijeTekstGevraagd = true, dan is de Opinie.reactie verplicht (was altijd optioneel); een lege reactie wordt geweigerd (geen credit). De reactie blijft door de tekstmoderatie lopen. De poort IAiPersonaService krijgt nu óók de Vraag.toelichting mee en levert naast scores een korte vrije reactie (herkaderde, opt-in prompt), zodat een AI-opinie geen “geen reactie” meer oplevert en de AI ook een alleen-vrije-tekst-vraag kan beantwoorden.De maker wil zelf sturen of hij een tekstreactie wil, en alleen-vrije-tekst (zonder smiley-scores) moet kunnen; is de reactie het doel, dan moet ze ook gegeven worden. Een AI-opinie zonder reactie was waardeloos voor een alleen-vrije-tekst-vraag en weinig behulpzaam elders; een herkaderde prompt (persoon vroeg zelf, vrijwillig, om opbouwende feedback) verhoogt de bereidheid van het model om bruikbare, constructieve feedback over echte mensen te geven — geen 100%-garantie, maar een duidelijke verbetering.
28Standaard 1 beoordeling; AI-herkomst verborgen voor de maker; elke beoordeling waardeerbaar (nieuw 2026-07-04h; het default-deel is per 2026-07-05 teruggedraaid naar 10 — zie beslissing 32; de AI-herkomst- en waardeerbaarheids-delen blijven gelden). De default aantalOpiniegevers ging van 10 → 1 (blijft instelbaar via Beheer; betekenis ongewijzigd: het vaste aantal beoordelingen per vraag, bevroren bij het stellen). Het veld bron (mens/AI) verdwijnt uit de user-facing uitslag (GET /api/vragen/{id}/uitslag): de maker ziet niet meer of een beoordeling van een mens of een AI-persona komt; de beheerder ziet de herkomst nog wél (beheer-endpoints). Het onderscheid blijft in het model, maar wordt niet aan de eindgebruiker getoond. De eerdere regel “AI-beoordelingen worden niet gewaardeerd” vervalt: de maker kan elke ontvangen beoordeling (0–5) waarderen, óók een AI-opinie — consistent met het verbergen van de herkomst. Een waardering op een AI-opinie wordt op de opinie vastgelegd maar beïnvloedt geen reviewer-profiel (een AI-persona heeft er geen).Eén beoordeling per vraag is een eenvoudiger, sneller-af te ronden default (stakeholder-besluit 3-7-2026); het aantal blijft instelbaar. Als de maker niet ziet wat AI is, mag hij het AI-onderscheid ook niet impliciet zien via “niet waardeerbaar” — dus moet alles waardeerbaar zijn; de reviewer-statistieken blijven zuiver doordat een AI-waardering geen profiel raakt.
29Sterren als verdiende kwaliteitsreputatie + consensus-ranking (voorgesteld 2026-07-05, ter verificatie). De Ster keert terug — géén loterij — met vier verdien-routes: beste opiniegever per vraag via de consensus-ranking (consensus + correlatie-controle, maker-waardering als instelbaar gewogen factor; pas ranken vanaf ≥3 beoordelaars — interpretatie), 5× 2e, 10× 3e, en elke 200 verdiende credits. Drempels en gewichten zijn beheerinstellingen; sterren zijn blijvend opgeslagen op het account.De handgeschreven notities van Han (3-7-2026) definiëren expliciete verdien-regels; die overrulen het eerdere “sterren bestaan niet meer”. Verdiende reputatie is eerlijk en stuurt kwaliteit, zonder de willekeur van de geschrapte loterij.
30Betaald advies met adviesniveaus + teaser-flow (voorgesteld 2026-07-05, ter verificatie). Opiniegevers kunnen een Adviesniveau (1–4/Expert) hebben — voorstel: ontsloten door de sterren-reputatie. Vanaf niveau 1 is de tekstreactie vrijgegeven én verplicht; prijzen per beoordeling (start €0,20–€1,00) zijn beheerinstellingen. De vraagsteller stelt gewenst niveau + aantal betaalde beoordelingen in (totaalprijs vooraf, bevroren). Zonder account/saldo/niveau: minimaal 2 geblurde teasers met niveau + prijs; betalen ontgrendelt per beoordeling (on-the-fly simpelste account + iDeal); betaling aan de beoordelaar volgt de ontgrendeling (voorstel). De gratis route blijft ernaast bestaan.Kwaliteitsadvies mag geld kosten en goede beoordelaars mogen verdienen (notities 3-7-2026); de teaser laat elke vraagsteller de waarde zien zonder de gratis basis te raken.
31Euro-saldo, iDeal en welkomstbonus — credits en euro’s strikt gescheiden (voorgesteld 2026-07-05, ter verificatie; overrulet het “geen geld”-besluit van 2026-07-03/ADR-019). Naast credits komt een euroSaldo (“inleg”) op de Gebruiker, opgeladen via iDeal (Betaling via een PSP, webhook-bevestigd). Eenmalige welkomstbonus bij accountcreatie: eerste inleg verdubbeld tot max. €10 bonus (interpretatie). Geen omwisselkoers credits ↔ euro’s. De Uitbetaling keert terug (mechaniek deels open); de anonimiteitsbelofte is geherformuleerd: anoniem richting andere gebruikers, betaalgegevens bij de payment provider, platform bewaart minimale transactiedata.Betaald advies vereist echt geld; iDeal is de laagdrempelige NL-standaard en de bonus verlaagt de instapdrempel. De strikte scheiding houdt de gratis credits-economie zuiver.
32Onboarding: welkomsttekst, eerst-2-beoordelen-poort met cold-start-vangrail, tips-vensters; default aantalOpiniegevers terug naar 10 (voorgesteld 2026-07-05, ter verificatie). Nieuwe gebruikers zien een welkomsttekst; hun eerste vraag gaat pas de verdeling in nadat ze 2 vragen van anderen beantwoordden (2 × 5 = 10 credits = de inzage-prijs bij 10) — mét vangrail: geen beoordeelbaar werk beschikbaar → poort vervalt tijdelijk. Klikken op een deelvraag in het opiniescherm opent een tips-venster (beheerbare content). De default aantalOpiniegevers gaat terug van 1 naar 10 (de welkomsttekst rekent met 10 mensen/10 credits); de tarieven verdienen-5/inzage-10 blijven.De welkomsttekst van blad 2 (3-7-2026) legt de wederkerigheid en de aantallen vast; de vangrail voorkomt de kip-en-ei-deadlock waarvoor de poort in 2026-06-30b eerder was afgeschaft.
33Scoren is verplicht — “geen mening” vervalt (aanscherping 3-7-2026, bij 2026-07-05; inmiddels gebouwd — de code hanteert de verplichte 1–5-schaal). De scoreschaal wordt 1–5, verplicht per gevraagd attribuut (1 = slecht/kan beter, 5 = uitstekend); beslissing 5 vervalt. Alle afgeleide “alleen scores > 0”-regels vervallen mee: SectieGemiddelden en per-attribuut-gemiddelden gaan over álle scores, en de consensus-ranking kent geen uitzonderingen meer voor niet-gescoorde attributen. Ook een AI-opinie scoort elk gevraagd attribuut 1–5 (de deterministische terugval sowieso). UI: de score-invoer heeft geen “geen mening”-optie meer en het formulier kan pas verstuurd worden als alle gevraagde attributen gescoord zijn.De vraagsteller bepaalt via de Beoordelingsselectie waarop geantwoord moet worden; wie een vraag oppakt, geeft dus op élk gevraagd attribuut een mening (beslissing product owner, 3-7-2026). Dit vereenvoudigt bovendien de gemiddelden én de ranking-formule: iedereen heeft alles gescoord.
34Vrije reacties alleen van niveau-beoordelaars, via vrije-reactie-slots; de maker-keuze vrijeTekstGevraagd vervalt (nieuw 2026-07-10h, testfeedback Han 9-7-2026, issue #17). Elk slot (Opdracht) krijgt een minimumNiveau (Adviesniveau, standaard Geen). Zonder betaald advies worden maximaal maxVrijeReactiesZonderBetaald (instelling, standaard 3, gevalideerd < aantalOpiniegevers) slots gereserveerd voor niveau ≥ 1 (vrije-reactie-slots); mét betaald advies zijn de niveaueisen leidend (per eis aantal slots op dat niveau, geen extra teaser-slots). Op een niveau-slot is de reactie verplicht en wordt de opinie een betaald/geblurd advies; op een gewoon slot wordt geen tekst gevraagd of opgeslagen (ook niet van een niveau-beoordelaar — diens opinie is daar een gewone gratis smiley-beoordeling). De verdeling biedt niveau-slots alleen aan beoordelaars met minstens dat niveau aan. Of het AI-vangnet op niveau-slots een tekst levert is de nieuwe beheerinstelling aiVangnetVultVrijeReactieSlots (default true; bij false alleen scores, zodat de vraag altijd afrondt). Een vraag is voortaan geldig met minstens één sectie (alleen-vrije-tekst-vragen vervallen).Kwaliteit van tekstadvies borgen: vrije reacties komen alleen nog van ervaren beoordelaars (niveau 1–4/Expert), met een instelbaar maximum per vraag zonder betaald advies — “anders is dat leidend” (Han, testsessie 9-7-2026). De verplichte tekst vanaf niveau 1 bestond al; door het aan het slot te hangen is het maximum hard gegarandeerd en blijft de rest van de vraag pure smiley-scoring.
35Account-upgrade anoniem → geregistreerd, met behoud van credits en het “neem je ster mee”-moment (nieuw 2026-07-10i, testfeedback Han 9-7-2026, issue #9). AnoniemeGebruiker krijgt een levensloop-teller totaalVerdiendeCredits; POST /api/anoniem/upgrade registreert een Gebruiker met hetzelfde profiel, neemt het credit-saldo mee als startsaldo en kent per gepasseerde sterCreditsMijlpaal direct een ster toe (bron CreditsMijlpaal). De anonieme sessie wordt verwijderd; de client krijgt een nieuw actor-token. Bij het passeren van de mijlpaal toont het portaal een wegklikbare uitnodiging; de upgrade kan ook altijd via Mijn profiel. (Per 2026-07-11a uitgebreid tot een volledige identiteitsmigratie: gestelde vragen, ontvangen/gegeven opinies, actieve slots en berichten gaan mee — bugfix na melding opdrachtgever.)Anonieme sessies dragen geen sterren en verlopen incl. credits; wie een ster verdient, moet die kunnen behouden door alsnog een account te maken (Han: “wanneer je een ster hebt gekregen moet je de keuze krijgen om een profiel te maken”) — zonder dwang: de uitnodiging is wegklikbaar en de gratis anonieme route blijft bestaan.

Deze beslissingen zijn verwerkt in de termen en de scenario’s. Wijzigingen worden bijgehouden in het Wijzigingslog.