Resterend werk & rapportage fase 3
Van inventarisatie naar plan. Al het werk dat nog open staat ten opzichte van het oorspronkelijke design, in volgorde gezet — met de maandrapportage als grootste brok volledig uitontworpen.
Roadmap
Eén overkoepelende route die elke resterende brok in volgorde zet, met per brok de aanpak, afhankelijkheden en beslismomenten. Elke grote brok krijgt later zijn eigen spec.
Quick-win-batch
Klein, geïsoleerd, geen schema-impact. Samen uitvoerbaar in één PR.
- Dubbele opgeleverd-datum weg. Bij
task.doneAtrendert nu zowel het "Voortgang"-blok in de hoofdkolom als de "Opgeleverd"-kaart in de rail dezelfde datum. Het hoofdkolom-blok vervalt; de rail-kaart blijft. De echte status-tijdlijn op die plek komt in Brok 3. - Assignee als initiaal-badge. Toegewezen personen tonen nu als kommalijst. Vervangen door initiaal-badges, consistent met de thread-avatars.
- Geel-token afronden.
--brand-yellowexact naar#F9C10F(officieel merkgeel) voor het logo; UI-highlight#f9bf2cblijft ongemoeid.
Eerste deploy / productie-omgeving
Er is nu geen productie-omgeving (alleen ci.yml, geen deploy-config). De rapportage-sync-job moet ergens dagelijks draaien, dus dit gaat eraan vooraf.
- Provider-agnostisch ontworpen. App, Postgres en een beveiligde trigger-route worden zo opgezet dat de host-keuze los staat van de code.
- Definitieve keuze (Laravel Forge + DigitalOcean Droplet vs DO App Platform) valt bij uitvoering — zie de host-afweging.
- Omvat: deploy-pipeline, productie-
TOKEN_ENCRYPTION_KEY+ secrets, migraties in productie, een beveiligde cron-trigger-route.
Fase 3 — Rapportage
De grootste brok en de oorspronkelijke kern-businessreden: de maandrapportage automatiseren. Volledig uitgewerkt verderop op deze pagina.
Bevat: statushistorie-sync-job, monthly_reports-datamodel met uren-accordering en audit-trail, admin-editor, concept → gepubliceerd → un-publish-flow, klant rapportage-overzicht + detail. De status-tijdlijn uit Brok 1 landt hier.
afhankelijk van Brok 2 (deploy + cron-trigger)
Fase 4 — AI-assistentie
AI-conceptverhaal voor het kwalitatieve deel van de rapportage, met governance en handmatige fallback. Volgt ná Brok 3 (heeft de rapportage-aggregaties als input).
afhankelijk van Brok 3
Bewust geparkeerd
Deze stonden in het oorspronkelijke design of de fase-1-spec, maar zijn bewust buiten de MVP. Hier expliciet vastgelegd zodat het geen "vergeten gaten" meer zijn.
| Item | Reden | Bron |
|---|---|---|
| Algemene thread (taak-onafhankelijk) | YAGNI; per-taak reacties dekken de behoefte. Heroverwegen op klant-feedback. | fase-1-spec, fase 2 |
| Notificatie-centrum (frame 16) | YAGNI; "Wacht op jou"-KPI dekt de behoefte | schermen-audit |
| E-mailnotificatie bij klant-reactie | Team checkt het portaal; uitbreidbaar later | klant-reacties-spec |
| PDF-export rapportage | Latere toevoeging | fase-1-spec |
| Meerdere accounts per klant (frame 17) | Buiten MVP | fase-1-spec |
| Slack, feature-toggles, lange-termijn-analytics | Buiten MVP | fase-1-spec |
Host-afweging
Provider-agnostisch ontworpen; de definitieve keuze valt bij de eerste deploy (Brok 2). Vastgelegde opties met hun trade-offs.
| Aspect | Forge + DO Droplet | DO App Platform |
|---|---|---|
| Serverbeheer | Jij / Forge (OS, patches, Postgres) | DO regelt het |
| Postgres | lokaal, $0 extra | aparte Managed DB (~+$15/mnd) |
| Cron / sync-job | native, geen timeout | scheduled job, timeout-grens |
| Long-running sync | geen probleem | kan knellen |
| Kosten | ~$24–32/mnd, vast | ~$20–27/mnd |
| Forge-workflow | ja (voorkeur) | n.v.t. |
Rapportage — fase 3 design
De maandelijkse klant-rapportage automatiseren: Congos stelt per klant per maand een rapportage op (kwantitatief uit ClickUp-historie, uren als geaccordeerd bevroren cijfer, kwalitatief verhaal), publiceert die, en de klant ziet hem als pagina in het dashboard.
Architectuur op hoofdlijnen
Drie onafhankelijk testbare onderdelen, elk met een eigen datamodel-grens:
task_status_history. Idempotent per dag.Onderdeel A · Statushistorie-sync
Dagelijkse rij per taak — behoudt ruwe data zodat we later nieuwe metrics kunnen afleiden. De UNIQUE-constraint maakt de job veilig herhaalbaar.
task_status_history id uuid pk client_id uuid -- fk clients, RLS-scoping + cache-isolatie list_id text -- welke gekoppelde lijst task_id text -- ClickUp-taak-id snapshot_date date -- dag van de snapshot (Europe/Amsterdam) status text -- ruwe ClickUp-status op die dag task_name text -- momentopname, leesbaarheid created_at timestamptz UNIQUE (task_id, snapshot_date) -- idempotent per dag
- De job
runStatusSnapshot()loopt over alle klanten met gekoppelde lijsten, haalt per lijst de taken op via de bestaande guest-token-flow, en schrijft voor vandaag een rij per taak. - Provider-agnostische trigger: route
POST /api/cron/status-snapshot, beveiligd met een gedeeld geheim (CRON_SECRET). - Fail-safe: per lijst een
try/catch— één falende lijst blokkeert de rest niet. Falen wordt gelogd; de job rapporteert hoeveel lijsten slaagden of faalden (geen stille skip). - Tijd-in-status & doorlooptijd worden afgeleid door opeenvolgende snapshots te vergelijken, niet opgeslagen. Bij gaten: best-effort met eerlijke kwalificatie.
Onderdeel B · Rapportage opstellen (admin)
monthly_reports id uuid pk client_id uuid year int month int -- 1-12 status text -- 'concept' | 'gepubliceerd' metrics_json jsonb -- afgeleid bij opstellen, bevroren bij publiceren suggested_hours numeric -- wat ClickUp gaf approved_hours numeric -- wat Congos ervan maakte narrative_md text -- Congos schrijft (markdown) published_at timestamptz null UNIQUE (client_id, year, month) monthly_report_history -- audit-trail na publicatie report_id uuid · field text · old_value text · new_value text · changed_at
Flow
- Aanmaken concept. Admin kiest klant + maand. Systeem bouwt
metrics_jsonuit de historie en haaltsuggested_hoursals momentopname uit ClickUp.approved_hoursstart gelijk. Status = concept. - Editor (frame 5). Kwantitatieve blokken read-only afgeleid; admin muteert de uren en schrijft het kwalitatieve verhaal. Niets zichtbaar voor de klant zolang concept.
- Publiceren (frame 6). Bevestiging-modal.
metrics_json+approved_hoursbevriezen; latere ClickUp-mutaties raken een gepubliceerde rapportage niet meer. - Un-publish. Terug naar concept voor herziening; klant ziet de maand dan tijdelijk niet. Elke wijziging na de eerste publicatie schrijft een audit-trail-rij.
Onderdeel C · Rapportage tonen (klant)
- Overzicht (frame 1): lijst van gepubliceerde maanden, server-side gescoped op
client_iduit de sessie. Alleen gepubliceerd zichtbaar. Route/rapportages. - Detail (frame 2): één maand — KPI-blokken + trend + uren (
approved_hours) + het verhaal via de bestaande<Markdown>-pipeline. Route/rapportages/[year]-[month]. - Uren uitsluitend hier zichtbaar — nergens anders in de klant-view.
- Trendgrafiek: hergebruik de bestaande
Sparkline-component; geen nieuwe zware chart-dependency tenzij echt nodig (YAGNI).
Beveiliging & tenant-isolatie
task_status_historyenmonthly_reportskrijgen RLS-policies gescoped opclient_id(zelfde patroon als bestaande tabellen). Klant-rol leest alleen eigen gepubliceerde rapportages; schrijven viaapp_service.- De cron-route is geen klant-route: aparte auth via
CRON_SECRET, niet via sessie. Aggregatie en publicatie draaien onderrequireAdminSession. - ClickUp-comments en interne notities komen nooit in de rapportage of historie — alleen status, taaknaam en uren-momentopname.
Testing
| Onderdeel | Wat de test bewijst |
|---|---|
| Sync | Idempotentie (twee keer dezelfde dag = geen dubbele rij), één falende lijst blokkeert de rest niet, juiste velden. |
| Aggregatie | Doorlooptijd / tijd-in-status correct uit snapshots; gaten geven eerlijke kwalificatie; maand-zonder-activiteit geeft lege-staat. |
| Publiceren | metrics_json + approved_hours bevriezen; un-publish verbergt voor de klant; audit-trail per wijziging. |
| Tenant-isolatie | Klant ziet nooit andermans rapportage of een concept (RLS). |
| Uren-zichtbaarheid | Uren verschijnen alleen in een gepubliceerde rapportage. |
Faseringsvolgorde binnen deze spec
- Onderdeel A (sync + datamodel + cron-route) — levert de databron.
- Onderdeel B (datamodel + aggregatie + admin-editor + publiceren).
- Onderdeel C (klant-overzicht + detail).
- Status-tijdlijn op de taak-detailpagina (Brok 1.1, nu er historie is).
Elk onderdeel is apart mergebaar met een eigen exit-criterium.
Klant-dashboard · roadmap & rapportage fase-3 design · 4 juni 2026
Bronnen: openstaand-werk-inventarisatie.md · 2026-06-04-roadmap-design.md · 2026-06-04-rapportage-fase-3-design.md