# rikx-beheer Beheerportaal voor de Rikx-methodiek. Beheert de sociaal ondernemers (accounts in de ZRM-platformdatabase) en de projecten van Module 1 (Projects flow). ## Pagina's - `/tenants` — sociaal ondernemers aanmaken, bewerken, verwijderen, auto-inlog (leest/schrijft de platformdatabase via `lib/platform-db.ts`) - `/projecten` — projecten als pipeline (standaard, kolom per status) of tabel (`?weergave=tabel`), met filter op status, Rikx Ronde en zoeken. De knop "+ Project toevoegen" maakt direct een project aan ("Nieuw project", status Aanvraag) en opent de projectpagina - `/waardebepaling` — Waardebepaling projecten: tabel met projecten in status Waardebepaling (projectnaam, impactmaker, kosten/impact), gerangschikt op kosten/impact van laag naar hoog, filter op Rikx Ronde. Alleen bij een gekozen Rikx ronde (niet bij Alle/Zonder ronde) een dikke oranje lijn onder het 75%-project: plek ⌈0,75 × n⌉ van de projecten met een berekende kosten/impact (zie `index75Procent`), volgens de Waarderingssystematiek; erboven de 75% meest efficiënte. Bovenaan een Rikx Waarde-veld: rekent live door met Rikx prijs = 10% voor de getoonde projecten met een ronde, en slaat waarde en prijs (na 0,8 s of bij verlaten van het veld) op in de Rikx ronde(s) van die projecten (`app/waardebepaling/actions.ts`) - Impactmaker van een project = sociaal ondernemer: `projects.impactmaker_account_id` verwijst naar `accounts.id` in de platformdatabase (geen foreign key; namen via `listAccountNames()` in `lib/platform-db.ts`) - `/rondes` — Rikx rondes beheren (label, Rikx waarde, Rikx prijs, gekoppelde experts; dezelfde koppeling `expert_rondes` als op `/experts`); een project hoort optioneel bij één ronde (`projects.ronde_id`) - `/projecten/[id]` — projectpagina met tabs: Project plan (velden en keuzelijsten gedefinieerd in `lib/projectPlan.ts`) en Rikx calculatie (alleen zichtbaar vanaf status Waardebepaling, zie `RIKX_CALCULATIE_VANAF_STATUS` in `lib/projectStatus.ts`; rekenmethode `arbeid`, `jeugd` is zichtbaar maar nog niet beschikbaar). Onderaan de tab: Beoordeling (`beoordeling`: goedgekeurd/afgekeurd/leeg) met `beoordeling_reden`. Kolom `rikx_calculatie_aan` is van de oude schuif en wordt niet meer gebruikt. Uitkomsten worden live berekend met `lib/rikxCalculatie.ts` - `/experts` (CRM → Experts) — experts uitnodigen, rondes koppelen, opnieuw uitnodigen (ook voor een vergeten wachtwoord), verwijderen, en "Inloggen als": een admin bekijkt `/expert` als die expert (alleen lezen; sessie met `impersonatorId`, terug via "Terug naar beheer"). Uitnodiging per e-mail via SendGrid of SMTP; zonder beide toont de pagina de link om zelf door te geven - `/uitnodiging/[token]` — openbaar: expert stelt wachtwoord in (token 7 dagen geldig, eenmalig; alleen de SHA-256-hash staat in de database) - `/expert` — de enige pagina voor experts: projecten in Waardebepaling uit hun rondes, project plan (alleen lezen) en hun eigen beoordeling (3 scores 1–10, advies Bonus/Malus, toelichting). Experts zien elkaars beoordeling niet - `/website` (Publieke Website → Pagina's) — CMS, overgenomen van rikx-org (`/portaal/paginas`) maar daar los van (eigen tabellen in deze database): pagina's aanmaken/verwijderen, hoofdmenu (naam + volgorde met pijltjes), SEO (meta-titel/-omschrijving, canonical, og:image, noindex) en per pagina content-blokken (`hero`, `richtext` met weergave standaard/oranje balk/kaart, `testimonial`, `benefits`, `cta`) toevoegen, bewerken (Quill), herordenen en verwijderen. NL/EN/DE: NL is de basis, EN/DE per veld met terugval op NL; een taal is "ingevuld" zodra ≥1 blok vertaald is. Er zijn hier geen vaste pagina's en (nog) geen publieke weergave, sitemap of bezoekteller. Logica in `lib/cms.ts`, acties in `app/website/actions.ts`; rich text wordt vóór opslag gesaniteerd (`lib/sanitize.ts`) - `/media/[filename]` — openbare route voor via het CMS geüploade afbeeldingen (png/jpg/webp/svg, max 10 MB) uit `MEDIA_DIR`; met CSP-sandbox zodat een SVG geen script kan uitvoeren op het beheerdomein - Rollen: `users.role` = `admin` of `expert`. Elke beheerpagina en -actie begint met `requireAdmin()`, de expertpagina met `requireExpert()` (`lib/auth.ts`); de rol komt uit de database, niet uit de cookie - Gedeelde kop met navigatie: `app/AppHeader.tsx` (oranje Rikx-balk, menu per module; items zonder pagina tonen "binnenkort") - Huisstijlkleuren als Tailwind-tokens in `app/globals.css`: `rikx-orange`, `rikx-purple` (actief menu-item), `rikx-maroon` (primaire knop). Statuskleuren in `lib/projectStatus.ts` - Conventie: server actions in `actions.ts` per map, geen API-routes (behalve `app/api/auto-login` en de mediaroute) ## Stack - Next.js 16 + TypeScript + Tailwind CSS - SQLite via `node:sqlite` (ingebouwd in Node 22, geen extra package) - HMAC-signed sessie-cookie auth (geen externe auth-provider) - E-mail via SendGrid (zoals het ZRM-platform) of Nodemailer/SMTP — `lib/mail.ts` ## Lokaal draaien ```bash npm install cp .env.example .env.local # Vul SESSION_SECRET in (.env.local) — minimaal 32 tekens willekeurig mkdir -p data npm run dev # http://localhost:3000 # Lokaal de platformdatabase gebruiken: RIKX_PLATFORM_DB_PATH=./data/platform.db ``` ## Admin aanmaken ```bash npm run create-admin maarten@rikx.nl wachtwoord "Maarten" ``` ## Database - Locatie lokaal: `./data/app.db` - Locatie productie: `/data/app.db` (absoluut pad — Next.js standalone doet process.chdir bij start) - Schema: `lib/db.ts` — migraties draaien automatisch bij eerste verbinding - Tabellen: `users`, `projects` (`name`, `status`; statussen in `lib/projectStatus.ts`, standaard `aanvraag`; plus de velden uit de rekenmethode als kolommen; overige project plan-velden als JSON in `project_plan`), `expert_beoordelingen` (per project en expert; Impactscore M = gemiddelde over de experts; de Rikx calculatie-tab toont ze alleen-lezen), `expert_rondes`, `expert_uitnodigingen`. `project_expert_scores` (oude handmatige scores) wordt niet meer gebruikt maar blijft staan, `pages`, `content_blocks`, `page_translations`, `block_translations` (CMS, zie `/website`), `rikx_rondes` (Rikx waarde en prijs per ronde; de calculatie haalt ze uit de ronde van het project, prijs standaard waarde / 10) - Rekenmethode (Rikx Waardeberekening Arbeid): `_doc/Rikx rekenmethode uitleg.xlsx`, tabblad Uitleg; achtergrond in `_doc/Waarderingssystematiek Rikx juni 2023.pdf`. Afwijkingen van de sheet: N-score = ((werk×5)+skills)/6 (sheet mist haakjes), Bonus/Malus `-` = 0,9 en `--` = 0,8 (sheet heeft typefouten) - De oude offerte-tabellen (`clients`, `projects` met `client_id`, `quotes`, `quote_items`) worden bij de migratie verwijderd als ze leeg zijn; met gegevens worden ze hernoemd naar `legacy_*` - Tweede database (alleen-platform): `RIKX_PLATFORM_DB_PATH` (standaard `/rikx-platform-data/app.db`) met `accounts` en `users` van het ZRM-platform ## Infrastructuur (mx-platform.com) - **Platform:** Coolify v4 op mx-platform.com (37.97.203.131) - **Git repo:** https://git.mx-platform.com/admin/rikx-beheer - **Dockerfile:** `/Dockerfile` (Node 22 Alpine, Next.js standalone) - **Port:** 3000 - **URL:** https://beheer.rikxplatform.nl ## Environment variables | Variabele | Standaard | Uitleg | |-----------|-----------|--------| | `SESSION_SECRET` | — | HMAC-secret voor sessie-cookies — per omgeving uniek genereren | | `DB_PATH` | `./data/app.db` | **In productie: `/data/app.db`** (absoluut pad) | | `MEDIA_DIR` | `/media` | Geüploade CMS-afbeeldingen (productie: `/data/media`, op hetzelfde volume) | | `RIKX_PLATFORM_DB_PATH` | `/rikx-platform-data/app.db` | Database van het ZRM-platform (sociaal ondernemers) | | `NODE_ENV` | `development` | In productie: `production` | | `SENDGRID_API_KEY` | — | E-mail via SendGrid (uitnodigingen voor experts); zelfde key als het Rikx ZRM-platform. Nooit committen. Leeg én geen SMTP = geen e-mail, link wordt in beeld getoond | | `SENDGRID_FROM_EMAIL` | `no-reply@rikxplatform.nl` | Afzender bij SendGrid (domein is daar al geverifieerd voor ZRM) | | `SENDGRID_FROM_NAME` | `Rikx` | Afzendernaam | | `SMTP_HOST` | — | Alternatief voor SendGrid: SMTP server (alleen gebruikt als `SENDGRID_API_KEY` leeg is) | | `SMTP_PORT` | `587` | SMTP poort | | `SMTP_USER` | — | SMTP gebruikersnaam | | `SMTP_PASS` | — | SMTP wachtwoord | | `SMTP_FROM` | `noreply@rikx.nl` | Afzenderadres | ## Auto-deploy Gitea webhook → Coolify. Na elke push naar `main` automatisch live. ## Collega's Wijzigingen alleen via Git. Push naar `main` → automatisch live.