PLAN: Klantportaal Uitbreiding & B2B Functionaliteiten
Executive Summary
Section titled “Executive Summary”╔══════════════════════════════════════════════════════════════════════╗║ ║║ ██╗ ██╗██╗ █████╗ ███╗ ██╗████████╗ ║║ ██║ ██╔╝██║ ██╔══██╗████╗ ██║╚══██╔══╝ ║║ █████╔╝ ██║ ███████║██╔██╗ ██║ ██║ ║║ ██╔═██╗ ██║ ██╔══██║██║╚██╗██║ ██║ ║║ ██║ ██╗███████╗██║ ██║██║ ╚████║ ██║ ║║ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ║║ ║║ P O R T A A L U I T B R E I D I N G ║║ ║║ Magic e-VERSE Customer Portal ║║ B2B Features, 2FA, Invoices, Quotes, Multi-Language ║║ ║║ Ticket: Klantportaal Uitbreiding ║║ Aangemaakt: Wayne ║║ Toegewezen: Michiel ║║ Status: WACHT OP AKKOORD WAYNE ║║ ║╚══════════════════════════════════════════════════════════════════════╝Alle Magic eVerse tenants hebben in de huidige Next.js storefront al een ruwe account-structuur (Medusa starter: login, orders, adressen, profiel). Deze is echter kaal, niet gestyled in de Magic eVerse huisstijl, en mist cruciale B2B-functionaliteiten zoals facturen, offertes, 2FA en multi-language. Dit plan beschrijft de volledige uitbreiding en oppoetsing van het klantportaal.
Huidige Situatie (wat er al is)
Section titled “Huidige Situatie (wat er al is)”Bestaande Account Pagina’s
Section titled “Bestaande Account Pagina’s”src/app/[countryCode]/(main)/account/├── layout.tsx # Parallel routes: @login / @dashboard├── loading.tsx # Spinner loading state├── @login/│ └── page.tsx # LoginTemplate (login + register toggle)└── @dashboard/ ├── loading.tsx ├── page.tsx # Overview (profile completion %, recente orders) ├── profile/ │ └── page.tsx # Naam, e-mail, telefoon, facturatieadres ├── addresses/ │ └── page.tsx # Adresboek └── orders/ ├── page.tsx # Order lijst + TransferRequestForm └── details/ └── [id]/ └── page.tsx # Order detailBestaande Account Componenten
Section titled “Bestaande Account Componenten”src/modules/account/├── components/│ ├── account-info/index.tsx # Generiek info-blok met edit toggle│ ├── account-nav/index.tsx # Sidebar: Overview, Profile, Addresses, Orders, Log out│ ├── address-book/index.tsx # Adreslijst│ ├── address-card/│ │ ├── add-address.tsx # Nieuw adres toevoegen│ │ └── edit-address-modal.tsx # Adres bewerken modal│ ├── login/index.tsx # E-mail + wachtwoord login form (server action)│ ├── order-card/index.tsx # Order samenvatting card│ ├── order-overview/index.tsx # Orders lijst met empty state│ ├── overview/index.tsx # Dashboard overview│ ├── profile-billing-address/index.tsx│ ├── profile-email/index.tsx│ ├── profile-name/index.tsx│ ├── profile-password/index.tsx # Wachtwoord wijzigen (commented out in profiel)│ ├── profile-phone/index.tsx│ ├── register/index.tsx # Registratieformulier│ └── transfer-request-form/index.tsx└── templates/ ├── account-layout.tsx # Grid: 240px sidebar + content └── login-template.tsx # Toggle login/register (client component)Bestaande Authenticatie
Section titled “Bestaande Authenticatie”| Onderdeel | Status | Locatie |
|---|---|---|
| E-mail + wachtwoord login | Werkend | sdk.auth.login("customer", "emailpass", ...) |
| Registratie | Werkend | sdk.auth.register("customer", "emailpass", ...) |
| JWT cookie | Werkend | _medusa_jwt, httpOnly, 7 dagen, strict sameSite |
| Cart transfer | Werkend | Anonieme cart wordt overgedragen bij login |
| Uitloggen | Werkend | sdk.auth.logout() + cookie cleanup |
Bestaand Design System (CSS Variabelen)
Section titled “Bestaand Design System (CSS Variabelen)”Base variabelen (src/themes/base/variables.css):
:root { --theme-accent: #CF0D65; --theme-accent-dark: #388e3c; --theme-accent-light: #81c784; --theme-dark: #1f2937; --theme-gray: #6b7280; --theme-light-gray: #f3f4f6; --theme-border: #e5e7eb; --theme-radius-sm: 4px; --theme-radius-md: 8px; --theme-radius-lg: 12px; --theme-shadow-sm / --theme-shadow-md / --theme-shadow-lg --theme-btn-primary-bg / --theme-btn-primary-text / --theme-btn-primary-hover /* + backwards-compat aliassen: --brinxx-pink, --brinxx-primary, etc. */}Tenant overrides (bijv. src/themes/brinxx/override.css):
:root { --theme-accent: #e91e63; /* Brinxx Magenta */ --theme-accent-dark: #c2185b; --theme-topbar-bg: #e91e63; --theme-nav-bg: #2c3e50;}Bestaande Backend APLT Routes
Section titled “Bestaande Backend APLT Routes”Admin routes (al werkend):
| Route | Functie |
|---|---|
/admin/aplt/invoices | CRUD facturen, PDF generatie, nummering F-YYYY-#### |
/admin/aplt/invoices/pdf | PDF download (pdfkit, A4, on-the-fly) |
/admin/aplt/invoices/eml | E-mail als .eml met PDF bijlage |
/admin/aplt/quotations | CRUD offertes, nummering Q-YYYY-#### |
/admin/aplt/quotations/pdf | PDF met productafbeeldingen |
/admin/aplt/quotations/confirm | Offerte → Order conversie |
/admin/aplt/quotations/eml | E-mail als .eml |
/admin/aplt/orders | CRUD orders, nummering O-YYYY-#### |
/admin/aplt/orders/status | Status workflow: pending → confirmed → shipped → delivered |
/admin/aplt/credit-notes | Credit notes (vol/partieel), nummering C-YYYY-#### |
/admin/aplt/payments | Betalingen registreren + alloceren, nummering B-YYYY-#### |
/admin/aplt/reports | Rapportages: aged receivables, revenue, BTW, dashboard KPI |
/admin/aplt/document-chain | Volledige documentketen traversal |
Store routes (bestaand, GEEN auth):
| Route | Functie |
|---|---|
/store/aplt/quotations | GET/POST/PUT — open voor n8n |
/store/aplt/quotations/lines | GET/POST/PUT/DELETE — open voor n8n |
/store/aplt/products | GET — productcatalogus |
/store/aplt/categories | GET — categorieën |
Database tabellen (al aanwezig):
aplt_quotation_headers / aplt_quotation_linesaplt_order_headers / aplt_order_linesaplt_invoice_headers / aplt_invoice_lines / aplt_invoice_vat_summaryaplt_payments / aplt_payment_allocationsaplt_document_relations (source → target, relation_type)aplt_audit_logaplt_number_sequencesaplt_customers / aplt_discount_groups / aplt_payment_termsaplt_cms_settings (bedrijfsinfo per brand_slug)aplt_settings (verzendkosten, franco-grens)Storefront Tech Stack
Section titled “Storefront Tech Stack”| Package | Versie | Doel |
|---|---|---|
| Next.js | ^16.1.6 | Framework |
| React | 19.0.0-rc | UI library |
| Tailwind CSS | ^3.0.23 | Styling |
| @medusajs/js-sdk | latest | Medusa client |
| @medusajs/ui | latest | UI componenten |
| @magiverse/i18n | file:./packages/magiverse-i18n | i18n (lokaal pakket, al aanwezig) |
| @headlessui/react | ^2.2.0 | Accessible UI primitives |
| @stripe/react-stripe-js | ^5.3.0 | Betalingen |
| pg | ^8.11.3 | Direct database queries |
| meilisearch | ^0.37.0 | Zoekfunctie |
Architectuur Overzicht
Section titled “Architectuur Overzicht”Nieuwe Bestanden (Storefront)
Section titled “Nieuwe Bestanden (Storefront)”src/app/[countryCode]/(main)/account/@dashboard/├── invoices/│ └── page.tsx ← NIEUW├── quotes/│ └── page.tsx ← NIEUW├── wishlist/│ └── page.tsx ← NIEUW└── orders/ └── details/ └── [id]/ └── return/ └── page.tsx ← NIEUW
src/modules/account/components/├── invoice-list/│ └── index.tsx ← NIEUW├── invoice-card/│ └── index.tsx ← NIEUW├── quote-list/│ └── index.tsx ← NIEUW├── quote-card/│ └── index.tsx ← NIEUW├── return-form/│ └── index.tsx ← NIEUW├── wishlist/│ └── index.tsx ← NIEUW├── two-factor/│ ├── index.tsx ← NIEUW (2FA settings)│ ├── otp-input.tsx ← NIEUW (OTP invoer)│ └── recovery-codes.tsx ← NIEUW (herstelcodes)├── dashboard-overview/│ └── index.tsx ← NIEUW (vervangt overview)├── status-badge/│ └── index.tsx ← NIEUW (herbruikbaar)├── order-timeline/│ └── index.tsx ← NIEUW (visuele tijdlijn)└── notification-preferences/ └── index.tsx ← NIEUWNieuwe Backend Routes (magic_development)
Section titled “Nieuwe Backend Routes (magic_development)”src/api/store/aplt/├── invoices/│ └── route.ts ← NIEUW (GET, JWT auth)├── invoices/│ └── pdf/│ └── route.ts ← NIEUW (GET, PDF stream)├── quotes/│ └── route.ts ← NIEUW (GET, JWT auth)├── quotes/│ └── [id]/│ ├── accept/│ │ └── route.ts ← NIEUW (POST)│ └── reject/│ └── route.ts ← NIEUW (POST)└── returns/ └── route.ts ← NIEUW (POST, met foto upload)
src/api/store/├── auth/│ └── otp/│ └── route.ts ← NIEUW (POST verify, POST resend)└── customer/ └── 2fa/ └── route.ts ← NIEUW (GET status, POST enable/disable)Data Flow Diagram
Section titled “Data Flow Diagram”┌─────────────────────────────────────────────────────────────────┐│ STOREFRONT (Next.js 16) ││ ││ ┌───────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────┐ ││ │ Facturen │ │ Offertes │ │ Retouren │ │ Wishlist │ ││ │ Page │ │ Page │ │ Form │ │ Page │ ││ └─────┬─────┘ └─────┬─────┘ └────┬─────┘ └──────┬───────┘ ││ │ │ │ │ ││ ┌─────┴──────────────┴──────────────┴───────────────┴────────┐ ││ │ Server Actions / API calls │ ││ │ (JWT via _medusa_jwt cookie) │ ││ └─────────────────────────┬───────────────────────────────────┘ │└────────────────────────────┼─────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────────┐│ BACKEND (Medusa v2.13.1) ││ ││ ┌──────────────────────────────────────────────────────────┐ ││ │ NIEUWE Store Routes (JWT auth) │ ││ │ │ ││ │ GET /store/aplt/invoices → klant-specifiek │ ││ │ GET /store/aplt/invoices/pdf → PDF stream │ ││ │ GET /store/aplt/quotes → klant-specifiek │ ││ │ POST /store/aplt/quotes/:id/accept │ ││ │ POST /store/aplt/quotes/:id/reject │ ││ │ POST /store/aplt/returns → retourverzoek │ ││ │ POST /store/auth/otp → OTP verificatie │ ││ │ GET /store/customer/2fa → 2FA status │ ││ └──────────────────────┬───────────────────────────────────┘ ││ │ ││ ┌──────────────────────┴───────────────────────────────────┐ ││ │ PostgreSQL (APLT Database) │ ││ │ │ ││ │ aplt_invoice_headers / aplt_invoice_lines │ ││ │ aplt_quotation_headers / aplt_quotation_lines │ ││ │ aplt_order_headers / aplt_order_lines │ ││ │ aplt_customers (email match met Medusa customer) │ ││ └──────────────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────────────┘Fase 1 — Huisstijl & Design System (3-4 dagen)
Section titled “Fase 1 — Huisstijl & Design System (3-4 dagen)”Alle bestaande account-pagina’s restylen naar de Magic eVerse design language, zodat het klantportaal visueel consistent is met de rest van de storefront.
-
Account sidebar navigatie restylen
Huidige
account-nav/index.tsxheeft geen iconen en geen visuele actieve state.Wijzigingen:
- Lucide React iconen toevoegen per menu-item (User, Package, MapPin, FileText, Heart, LogOut)
- Actieve state indicator: linkerborder accent kleur (
border-l-2 border-[var(--theme-accent)]) - Hover effect met
bg-[var(--theme-light-gray)]entransition-colors - Nieuwe menu-items toevoegen: Facturen, Offertes, Verlanglijst
- Mobile: sidebar collapst naar horizontale bottom-nav met iconen (geen labels)
┌────────────────────────────────────────────────┐│ DESKTOP SIDEBAR │ MOBILE BOTTOM-NAV ││ │ ││ ┌─────────────────────┐ │ ┌─┬─┬─┬─┬─┬─┐ ││ │ ● Overzicht │ │ │🏠│📦│📄│💰│❤│⚙│ ││ │ Profiel │ │ └─┴─┴─┴─┴─┴─┘ ││ │ Adressen │ │ ││ │ Bestellingen │ │ ││ │ Facturen NIEUW│ │ ││ │ Offertes NIEUW│ │ ││ │ Verlanglijst NIEUW│ │ ││ │ │ │ ││ │ ───────────────── │ │ ││ │ Uitloggen │ │ ││ └─────────────────────┘ │ │└────────────────────────────────────────────────┘Bestanden:
src/modules/account/components/account-nav/index.tsx— restylensrc/modules/account/templates/account-layout.tsx— responsive grid aanpassen
-
Cards en containers restylen
Alle content-blokken krijgen consistente styling:
bg-white rounded-lg shadow-sm border border-[var(--theme-border)]- Padding:
p-6(desktop),p-4(mobile) - Headers in cards:
text-lg font-semibold text-[var(--theme-dark)] - Subtekst:
text-sm text-[var(--theme-gray)]
Bestanden:
src/modules/account/components/account-info/index.tsxsrc/modules/account/components/overview/index.tsxsrc/modules/account/components/order-card/index.tsxsrc/modules/account/components/address-book/index.tsx- Alle profile-* componenten
-
Loading skeletons implementeren
Vervang de huidige spinner (
loading.tsx) door skeleton loaders:// Skeleton component voorbeeld<div className="animate-pulse"><div className="h-4 bg-gray-200 rounded w-3/4 mb-4" /><div className="h-4 bg-gray-200 rounded w-1/2 mb-4" /><div className="h-32 bg-gray-200 rounded mb-4" /></div>Bestanden:
src/app/[countryCode]/(main)/account/loading.tsx— skeleton layoutsrc/app/[countryCode]/(main)/account/@dashboard/loading.tsx— dashboard skeleton- Nieuwe loading.tsx per sub-route (orders, invoices, etc.)
-
Status-badge component
Herbruikbaar component voor order/factuur/offerte statussen:
Status Kleur CSS Wachtend / Draft Oranje bg-amber-100 text-amber-800Bevestigd / Open Blauw bg-blue-100 text-blue-800Verzonden Indigo bg-indigo-100 text-indigo-800Afgeleverd / Betaald Groen bg-green-100 text-green-800Geannuleerd / Vervallen Rood bg-red-100 text-red-800Nieuw bestand:
src/modules/account/components/status-badge/index.tsx -
Inter font verificatie
Controleer dat Inter font correct geladen wordt via
next/font/googlein de root layout. Tailwind config moetfontFamily.sansoverschrijven.Bestanden:
src/app/layout.tsx,tailwind.config.ts -
Tenant-theming verificatie
Controleer dat
NEXT_PUBLIC_THEMEcorrect werkt voor alle 7 tenants. Elke tenant krijgt eigen kleuraccent zonder codewijziging — dit is al opgezet viasrc/themes/index.tsmaar moet getest worden met de nieuwe account componenten.
Acceptatiecriteria Fase 1
Section titled “Acceptatiecriteria Fase 1”┌────────────────────────────────────────────────────────┐│ CHECKLIST FASE 1 │├────────────────────────────────────────────────────────┤│ ││ [ ] Sidebar met iconen en actieve state indicator ││ [ ] Mobile bottom-nav met iconen ││ [ ] Alle cards met consistente shadow/border/radius ││ [ ] Loading skeletons ipv spinners ││ [ ] Status-badge component herbruikbaar ││ [ ] Inter font correct geladen ││ [ ] Tenant theming werkt op account pagina's ││ [ ] Responsive op mobile (375px+), tablet, desktop ││ [ ] Geen visuele regressie op bestaande pagina's ││ │└────────────────────────────────────────────────────────┘Fase 2 — Authenticatie & 2FA (4-5 dagen)
Section titled “Fase 2 — Authenticatie & 2FA (4-5 dagen)”Login flow verbeteren met “onthoud mij”, wachtwoord vergeten, e-mail verificatie, en Two-Factor Authentication via OTP (e-mail of telefoon).
-
“Onthoud mij” optie
Checkbox op login formulier. Wanneer aangevinkt: JWT cookie levensduur van 7 → 30 dagen.
Wijzigingen:
src/modules/account/components/login/index.tsx— checkbox toevoegensrc/lib/data/cookies.ts—setAuthToken()aanpassen:maxAgeparameter meegevensrc/lib/data/customer.ts—login()action: “remember me” waarde doorgeven
-
Wachtwoord vergeten — reset flow
Nieuwe pagina + backend flow:
- Klant voert e-mail in → backend stuurt reset link met beveiligde token
- Klant klikt link → pagina met nieuw wachtwoord invoeren
- Token geldig 15 minuten, eenmalig gebruik
Nieuwe bestanden:
src/app/[countryCode]/(main)/account/forgot-password/page.tsxsrc/app/[countryCode]/(main)/account/reset-password/page.tsx- Backend: Medusa native reset password flow via
sdk.auth.resetPassword()
-
E-mail verificatie bij registratie
Flow:
- Klant registreert → e-mail met verificatielink
- Account is “unverified” tot link geklikt
- Unverified accounts kunnen inloggen maar zien een banner: “Verifieer je e-mail”
Wijzigingen:
- Backend:
@nicogorga/medusa-auth-emailpass-verifiedinstalleren en configureren src/modules/account/components/register/index.tsx— success state met “controleer je e-mail” berichtsrc/app/[countryCode]/(main)/account/verify-email/page.tsx— NIEUW, verificatie landing
-
Two-Factor Authentication (2FA) via OTP
Eigen OTP Implementatie (Optie B):
Nieuwe database tabel:
CREATE TABLE aplt_customer_2fa (id SERIAL PRIMARY KEY,customer_email VARCHAR(255) NOT NULL UNIQUE,is_enabled BOOLEAN DEFAULT FALSE,otp_secret VARCHAR(64), -- Random secret voor OTP generatierecovery_codes TEXT, -- JSON array van 8 gehashte codescreated_at TIMESTAMP DEFAULT NOW(),updated_at TIMESTAMP DEFAULT NOW());CREATE TABLE aplt_otp_codes (id SERIAL PRIMARY KEY,customer_email VARCHAR(255) NOT NULL,code VARCHAR(6) NOT NULL,expires_at TIMESTAMP NOT NULL, -- +10 minutenused BOOLEAN DEFAULT FALSE,created_at TIMESTAMP DEFAULT NOW());Login flow met 2FA:
┌──────────────┐ ┌───────────────┐ ┌──────────────┐│ E-mail + │ │ 2FA Check │ │ OTP Code ││ Wachtwoord │────▶│ Heeft klant │────▶│ Invoeren ││ Formulier │ │ 2FA aan? │ │ (6 cijfers) │└──────────────┘ └───────┬───────┘ └──────┬───────┘│ │NEE │ │ CORRECT▼ ▼┌──────────────┐ ┌──────────────┐│ Direct │ │ JWT Token ││ Ingelogd │ │ Uitgegeven │└──────────────┘ └──────────────┘│FOUT │▼┌──────────────┐│ Herstelcode ││ Optie │└──────────────┘Backend routes:
POST /store/auth/otp— Verifieer OTP code- Input:
{ email, code }of{ email, recovery_code } - Genereert random 6-cijferige code, slaat op in
aplt_otp_codes, stuurt via SMTP - Code geldig 10 minuten, max 3 pogingen per 15 minuten
- Input:
GET /store/customer/2fa— 2FA status ophalen (JWT auth)POST /store/customer/2fa— 2FA in-/uitschakelen (JWT auth)- Enable: genereert 8 herstelcodes, retourneert ze eenmalig
- Disable: vereist wachtwoord bevestiging
Frontend componenten:
src/modules/account/components/two-factor/index.tsx— 2FA settings in profielsrc/modules/account/components/two-factor/otp-input.tsx— 6-cijfer invoerveld (auto-focus, paste support)src/modules/account/components/two-factor/recovery-codes.tsx— Codes tonen + download als .txt
Wijzigingen login flow:
src/modules/account/components/login/index.tsx— Na succesvolle wachtwoord check: als 2FA enabled, toon OTP invoerveldsrc/lib/data/customer.ts—login()splitsen in twee stappen:- Wachtwoord verificatie → tijdelijk token
- OTP verificatie → definitief JWT token
-
Passkey (Fase 2 — later)
- Na eerste login een passkey koppelen (Touch ID, Face ID, Windows Hello)
- Volledig passwordless voor terugkerende klanten
- Niet in scope van dit ticket — apart ticket aanmaken
Acceptatiecriteria Fase 2
Section titled “Acceptatiecriteria Fase 2”┌────────────────────────────────────────────────────────┐│ CHECKLIST FASE 2 │├────────────────────────────────────────────────────────┤│ ││ [ ] "Onthoud mij" checkbox werkt (30 dagen cookie) ││ [~] Wachtwoord vergeten flow (admin: ✅, storefront: TODO) ││ [ ] E-mail verificatie bij registratie ││ [ ] 2FA in-/uitschakelen via profielpagina ││ [ ] OTP code via e-mail ontvangen en invoeren ││ [ ] Herstelcodes genereren en downloaden ││ [ ] Herstelcode als backup voor OTP werkt ││ [ ] Max 3 OTP pogingen per 15 minuten (rate limit) ││ [ ] Admin kan zien welke klanten 2FA hebben ││ [ ] Login flow werkt correct met EN zonder 2FA ││ │└────────────────────────────────────────────────────────┘Fase 3 — Orders & Ordergeschiedenis (3-4 dagen)
Section titled “Fase 3 — Orders & Ordergeschiedenis (3-4 dagen)”Orders overzicht en detail pagina’s uitbreiden met filters, zoeken, status-badges, tijdlijn, track & trace, retour en opnieuw bestellen.
-
Orders overzichtspagina verbeteren
Huidige
order-overview/index.tsxtoont een simpele lijst. Uitbreiden met:Feature Implementatie Status filter tabs alle / open / verzonden / afgeleverd / geannuleerd— via URL search paramsZoekbalk Op ordernummer of productnaam — client-side filter of server-side query Sortering Datum nieuw → oud (default), status — via dropdown Paginering 20 per pagina, prev/next knoppen — Medusa SDK offset+limitStatus-badges Hergebruik status-badgecomponent uit Fase 1Bestanden:
src/modules/account/components/order-overview/index.tsx— restylen + featuressrc/modules/account/components/order-card/index.tsx— restylen met badgesrc/app/[countryCode]/(main)/account/@dashboard/orders/page.tsx— search params handling
-
Order detail pagina uitbreiden
Huidige detail pagina toont basisinfo. Uitbreiden met:
┌─────────────────────────────────────────────────────────┐│ Order #O-2025-0042 ● Verzonden│├─────────────────────────────────────────────────────────┤│ ││ ┌───────────────────────────────────────────────────┐ ││ │ PRODUCTEN │ ││ │ ┌────┐ │ ││ │ │ 📷 │ Blauwe Pen Deluxe ×100 €245,00 │ ││ │ └────┘ Variant: Blauw/Zilver │ ││ │ ┌────┐ │ ││ │ │ 📷 │ Notitieboek A5 ×50 €187,50 │ ││ │ └────┘ Variant: Hardcover │ ││ └───────────────────────────────────────────────────┘ ││ ││ ┌─────────────────────┐ ┌─────────────────────────┐ ││ │ BEZORGADRES │ │ BETALING │ ││ │ Bedrijf BV │ │ Bankoverschrijving │ ││ │ Straat 1 │ │ │ ││ │ 1234 AB Stad │ │ Subtotaal: €432,50 │ ││ │ │ │ Verzending: €12,50 │ ││ │ LEVERDATUM │ │ BTW 21%: €93,45 │ ││ │ 15 maart 2026 │ │ ───────────────────── │ ││ │ │ │ Totaal: €538,45 │ ││ └─────────────────────┘ └─────────────────────────┘ ││ ││ ┌───────────────────────────────────────────────────┐ ││ │ TIJDLIJN │ ││ │ ● Besteld 3 mrt 2026, 14:30 │ ││ │ ● Betaald 3 mrt 2026, 14:31 │ ││ │ ● Ingepakt 4 mrt 2026, 09:15 │ ││ │ ● Verzonden 4 mrt 2026, 16:00 📦 Track & Trace│ ││ │ ○ Afgeleverd (verwacht 6 mrt) │ ││ └───────────────────────────────────────────────────┘ ││ ││ ┌─────────────────┐ ┌─────────────────────────────┐ ││ │ 🔄 Retour │ │ 🛒 Opnieuw bestellen │ ││ │ aanvragen │ │ │ ││ └─────────────────┘ └─────────────────────────────┘ │└─────────────────────────────────────────────────────────┘Nieuwe gegevens:
- Geschatte leverdatum: uit
aplt_order_headers.expected_delivery_date - Track & trace link: uit order metadata (
tracking_url) - Tijdlijn: afleiden uit order status + timestamps in
aplt_audit_log - Opnieuw bestellen: alle items toevoegen aan cart via
addToCart()server action
Bestanden:
src/app/[countryCode]/(main)/account/@dashboard/orders/details/[id]/page.tsx— uitbreidensrc/modules/account/components/order-timeline/index.tsx— NIEUW
- Geschatte leverdatum: uit
-
Opnieuw bestellen functionaliteit
“Opnieuw bestellen” knop voegt alle orderregels toe aan de huidige cart:
- Loop door order items
- Roep
addToCart(variantId, quantity)aan per item - Redirect naar cart pagina
- Error handling als product niet meer beschikbaar is
Wijzigingen:
src/lib/data/cart.ts— eventueel bulkaddToCarttoevoegen- Order detail pagina — knop + server action
Acceptatiecriteria Fase 3
Section titled “Acceptatiecriteria Fase 3”┌────────────────────────────────────────────────────────┐│ CHECKLIST FASE 3 │├────────────────────────────────────────────────────────┤│ ││ [ ] Order filter tabs werken (alle/open/verzonden/etc) ││ [ ] Zoekbalk op ordernummer en productnaam ││ [ ] Sortering op datum en status ││ [ ] Paginering (20 per pagina) ││ [ ] Status-badges met kleurcodering ││ [ ] Order detail: producten met afbeelding ││ [ ] Order detail: subtotaal, verzending, BTW, totaal ││ [ ] Order detail: bezorgadres en betaalmethode ││ [ ] Order detail: geschatte leverdatum ││ [ ] Order detail: track & trace link (indien aanwezig) ││ [ ] Order detail: visuele tijdlijn ││ [ ] "Opnieuw bestellen" voegt items toe aan cart ││ [ ] "Retour aanvragen" knop aanwezig (link naar Fase 4) ││ │└────────────────────────────────────────────────────────┘Fase 4 — Facturen, Offertes & Retouren (5-6 dagen)
Section titled “Fase 4 — Facturen, Offertes & Retouren (5-6 dagen)”4A. Facturen (/account/invoices)
Section titled “4A. Facturen (/account/invoices)”-
Backend: GET /store/aplt/invoices (NIEUW)
Nieuwe route met JWT klant-autorisatie:
src/api/store/aplt/invoices/route.ts export const AUTHENTICATE = true // Medusa JWT authexport async function GET(req, res) {// 1. Haal klant e-mail uit JWT token (req.auth_context.actor_id → customer lookup)// 2. Zoek aplt_customers record op basis van e-mail// 3. Query aplt_invoice_headers WHERE customer_id = klant.id// 4. Filter op optionele query params: ?status=open&year=2025// 5. Return gefilterde facturen met lines} -
Backend: GET /store/aplt/invoices/pdf (NIEUW)
Hergebruik de bestaande PDF generatie logica uit
/admin/aplt/invoices/pdf/route.ts:src/api/store/aplt/invoices/pdf/route.ts export const AUTHENTICATE = trueexport async function GET(req, res) {// 1. Haal klant e-mail uit JWT// 2. Verifieer dat factuur behoort tot deze klant// 3. Genereer PDF (hergebruik bestaande pdfkit logica)// 4. Stream als attachment} -
Frontend: Facturen pagina
┌─────────────────────────────────────────────────────────┐│ Facturen │├─────────────────────────────────────────────────────────┤│ ││ Filter: [Alle ▼] Jaar: [2025 ▼] 🔍 Zoek... ││ ││ ┌───────────────────────────────────────────────────┐ ││ │ F-2025-0042 │ 15 feb 2025 │ €538,45 │ ● Open │ ││ │ │ │ │ 📥 PDF │ ││ ├───────────────────────────────────────────────────┤ ││ │ F-2025-0038 │ 2 feb 2025 │ €1.250 │ ●Betaald│ ││ │ │ │ │ 📥 PDF │ ││ ├───────────────────────────────────────────────────┤ ││ │ F-2024-0195 │ 18 dec 2024 │ €890,00 │●Vervall│ ││ │ │ │ │ 📥 PDF │ ││ └───────────────────────────────────────────────────┘ ││ ││ [📦 Exporteer geselecteerde als ZIP] ││ ││ Pagina 1 van 3 [◀ Vorige] [Volgende ▶] │└─────────────────────────────────────────────────────────┘Features:
- Lijst facturen met nummer, datum, bedrag, status
- Status filter: alle, open, betaald, vervallen
- Jaar filter
- PDF download per factuur (direct stream, geen pagina-refresh)
- Meerdere selecteren + exporteer als ZIP (client-side via JSZip of backend endpoint)
Nieuwe bestanden:
src/app/[countryCode]/(main)/account/@dashboard/invoices/page.tsxsrc/modules/account/components/invoice-list/index.tsxsrc/modules/account/components/invoice-card/index.tsxsrc/lib/data/invoices.ts— server actions voor factuur data
4B. Offertes (/account/quotes)
Section titled “4B. Offertes (/account/quotes)”-
Backend: GET /store/aplt/quotes (NIEUW)
// Klant-specifieke offertes ophalen// Filter op status: open, accepted, expired, rejected// Include lines voor preview -
Backend: POST /store/aplt/quotes/[id]/accept (NIEUW)
// 1. Verifieer offerte behoort tot klant// 2. Controleer vervaldatum niet verstreken// 3. Hergebruik bestaande /admin/aplt/quotations/confirm logica:// - Kopieer quotation lines naar aplt_order_lines// - Maak aplt_document_relations aan// - Update quotation status naar 'accepted'// 4. Return order_id + order_number -
Backend: POST /store/aplt/quotes/[id]/reject (NIEUW)
// 1. Verifieer offerte behoort tot klant// 2. Update status naar 'rejected'// 3. Sla afwijsreden op in metadata/notes// 4. Log in aplt_audit_log -
Frontend: Offertes pagina
┌─────────────────────────────────────────────────────────┐│ Offertes │├─────────────────────────────────────────────────────────┤│ ││ ⚠️ Offerte Q-2025-0117 verloopt over 2 dagen! ││ ││ ┌───────────────────────────────────────────────────┐ ││ │ Q-2025-0117 │ 1 mrt 2025 │ €2.450 │ ● Open │ ││ │ Geldig tot: 6 mrt 2025 │ ││ │ [✅ Accepteren] [❌ Afwijzen] [📥 PDF] │ ││ ├───────────────────────────────────────────────────┤ ││ │ Q-2025-0098 │ 15 feb 2025 │ €890 │●Geaccept. │ ││ │ Omgezet naar order O-2025-0043 │ ││ │ [📥 PDF] │ ││ └───────────────────────────────────────────────────┘ │└─────────────────────────────────────────────────────────┘Features:
- Banner bij offertes die binnen 3 dagen verlopen
- Accepteren → bevestigingsdialoog → conversie naar order
- Afwijzen → reden invoeren (verplicht) → bevestiging
- PDF download
- Vervaldatum duidelijk zichtbaar
- Link naar resulterende order bij geaccepteerde offertes
Nieuwe bestanden:
src/app/[countryCode]/(main)/account/@dashboard/quotes/page.tsxsrc/modules/account/components/quote-list/index.tsxsrc/modules/account/components/quote-card/index.tsxsrc/lib/data/quotes.ts— server actions
4C. Retourverzoeken
Section titled “4C. Retourverzoeken”-
Frontend: Retourformulier
Nieuw formulier bereikbaar via order detail pagina:
┌─────────────────────────────────────────────────────────┐│ Retour aanvragen — Order #O-2025-0042 │├─────────────────────────────────────────────────────────┤│ ││ Selecteer producten om te retourneren: ││ ││ [✓] Blauwe Pen Deluxe ×100 ││ Reden: [Beschadigd ▼] ││ Aantal: [50] ││ ││ [ ] Notitieboek A5 ×50 ││ ││ Foto's (optioneel, max 3, max 5MB per stuk): ││ [📷 Upload foto] [📷 Upload foto] [📷 Upload foto] ││ ││ Toelichting: [________________________] ││ ││ [📤 Retourverzoek indienen] │└─────────────────────────────────────────────────────────┘Retourredenen:
- Beschadigd ontvangen
- Verkeerd product geleverd
- Past niet / voldoet niet aan verwachting
- Defect / niet werkend
- Anders (vrij tekstveld)
Backend: Medusa native returns API (
POST /store/orders/:id/returnsofsdk.store.return.create())Foto upload: Via FormData naar een nieuwe
/store/aplt/returnsroute die bestanden opslaat in/mnt/data/return_photos/(of S3-compatible storage)Nieuwe bestanden:
src/app/[countryCode]/(main)/account/@dashboard/orders/details/[id]/return/page.tsxsrc/modules/account/components/return-form/index.tsxsrc/lib/data/returns.ts— server actions
Acceptatiecriteria Fase 4
Section titled “Acceptatiecriteria Fase 4”┌────────────────────────────────────────────────────────┐│ CHECKLIST FASE 4 │├────────────────────────────────────────────────────────┤│ ││ FACTUREN: ││ [ ] Store route /store/aplt/invoices werkt met JWT ││ [ ] Facturen gefilterd op ingelogde klant ││ [ ] PDF download werkt vanuit portaal ││ [ ] Filter op status en jaar ││ [ ] ZIP export van meerdere facturen ││ ││ OFFERTES: ││ [ ] Store route /store/aplt/quotes werkt met JWT ││ [ ] Offertes gefilterd op ingelogde klant ││ [ ] Accepteren converteert naar order ││ [ ] Afwijzen met reden werkt ││ [ ] Banner bij bijna-verlopen offertes ││ [ ] PDF download werkt ││ ││ RETOUREN: ││ [ ] Retourformulier met product selectie ││ [ ] Retourredenen dropdown ││ [ ] Foto upload (max 3, max 5MB) ││ [ ] Bevestigingsscherm na indienen ││ [ ] Retourverzoek zichtbaar in Medusa admin ││ │└────────────────────────────────────────────────────────┘Fase 5 — Profiel & Dashboard Uitbreiding (2-3 dagen)
Section titled “Fase 5 — Profiel & Dashboard Uitbreiding (2-3 dagen)”5A. Profielpagina uitbreiden
Section titled “5A. Profielpagina uitbreiden”-
Inline bewerken
Huidige profiel componenten (
profile-name,profile-email,profile-phone,profile-billing-address) gebruiken alaccount-infomet een edit toggle. Restylen zodat de edit-state inline is (geen apart formulier/modal). -
Profielfoto upload (optioneel)
- Upload naar
/uploads/avatars/{customer_id}.jpg - Opslaan in customer metadata:
{ avatar_url: "/uploads/avatars/..." } - Max 2MB, alleen JPG/PNG
- Circulaire preview met fallback initialen
- Upload naar
-
Taalvoorkeur instellen
- Dropdown: NL / EN / DE
- Opslaan in customer metadata:
{ preferred_language: "nl" } - Gebruikt
@magiverse/i18n(al aanwezig als lokaal pakket) - Bij laden: check customer metadata → cookie → Accept-Language header
-
E-mail notificatievoorkeuren
Checkboxes voor:
- Orderupdates (default: aan)
- Offerte notificaties (default: aan)
- Nieuwsbrief (default: uit)
Opslaan in customer metadata:
{ notifications: { orders: true, quotes: true, newsletter: false } } -
2FA sectie in profiel
Verwijzing naar componenten uit Fase 2:
- Status indicator (aan/uit)
- In-/uitschakelen toggle
- Herstelcodes downloaden knop
- Link naar volledige 2FA instellingen
-
Account verwijderen (GDPR)
- “Account verwijderen” knop onderaan profielpagina
- Bevestigingsflow: wachtwoord invoeren + e-mail verificatie
- Soft-delete: markeer account als
deleted, anonimiseer persoonsgegevens na 30 dagen - E-mail bevestiging van verwijdering
5B. Dashboard Overview uitbreiden
Section titled “5B. Dashboard Overview uitbreiden”-
Welkomstbanner
┌─────────────────────────────────────────────────────────┐│ Welkom terug, Jan! 👋 ││ Hier is een overzicht van je account. │└─────────────────────────────────────────────────────────┘ -
Statistieken cards
┌──────────────┐ ┌──────────────┐ ┌──────────────┐│ 📦 12 │ │ 📋 2 │ │ 💰 €1.250 ││ Bestellingen│ │ Open │ │ Te betalen ││ │ │ Offertes │ │ Facturen │└──────────────┘ └──────────────┘ └──────────────┘Data ophalen via de nieuwe store routes (parallel server-side fetch).
-
Recente orders (laatste 3)
Compacte order cards met status-badge, datum, bedrag.
-
Snelkoppelingen
[🛒 Nieuwe bestelling] [📋 Offerte aanvragen] [📄 Facturen] [👤 Profiel] -
Waarschuwingsbanners
- Offerte bijna verlopen: “Je offerte Q-2025-0117 verloopt over 2 dagen”
- Factuur vervallen: “Je hebt 1 openstaande factuur”
- E-mail niet geverifieerd: “Verifieer je e-mailadres”
Acceptatiecriteria Fase 5
Section titled “Acceptatiecriteria Fase 5”┌────────────────────────────────────────────────────────┐│ CHECKLIST FASE 5 │├────────────────────────────────────────────────────────┤│ ││ [ ] Profiel: inline bewerken werkt ││ [ ] Profiel: taalvoorkeur opslaan en laden ││ [ ] Profiel: notificatievoorkeuren ││ [ ] Profiel: 2FA sectie met status indicator ││ [ ] Profiel: account verwijderen flow (GDPR) ││ [ ] Dashboard: welkomstbanner met naam ││ [ ] Dashboard: 3 statistieken cards ││ [ ] Dashboard: recente orders met status ││ [ ] Dashboard: snelkoppeling knoppen ││ [ ] Dashboard: waarschuwingsbanners ││ │└────────────────────────────────────────────────────────┘Fase 6 — Multi-language (3-4 dagen)
Section titled “Fase 6 — Multi-language (3-4 dagen)”-
Account vertalingen toevoegen
Nieuwe vertaalsleutels voor alle account-pagina’s:
{"account": {"nav": {"overview": "Overzicht","profile": "Profiel","addresses": "Adressen","orders": "Bestellingen","invoices": "Facturen","quotes": "Offertes","wishlist": "Verlanglijst","logout": "Uitloggen"},"dashboard": {"welcome": "Welkom terug, {name}!","orders_count": "Bestellingen","open_quotes": "Open offertes","outstanding_invoices": "Te betalen facturen"},"orders": {"title": "Bestellingen","search_placeholder": "Zoek op ordernummer of product...","filter_all": "Alle","filter_open": "Open","filter_shipped": "Verzonden","filter_delivered": "Afgeleverd","filter_cancelled": "Geannuleerd","reorder": "Opnieuw bestellen","request_return": "Retour aanvragen"},"invoices": {"title": "Facturen","download_pdf": "Download PDF","export_zip": "Exporteer als ZIP","status_open": "Open","status_paid": "Betaald","status_overdue": "Vervallen"},"quotes": {"title": "Offertes","accept": "Accepteren","reject": "Afwijzen","expires_in": "Verloopt over {days} dagen","expired": "Verlopen","converted_to_order": "Omgezet naar order {number}"},"returns": {"title": "Retour aanvragen","select_products": "Selecteer producten om te retourneren","reason": "Reden","reason_damaged": "Beschadigd ontvangen","reason_wrong": "Verkeerd product geleverd","reason_not_as_expected": "Voldoet niet aan verwachting","reason_defective": "Defect / niet werkend","reason_other": "Anders","upload_photos": "Foto's uploaden","submit": "Retourverzoek indienen"},"profile": {"title": "Profiel","language_preference": "Taalvoorkeur","notifications": "E-mail notificaties","delete_account": "Account verwijderen","two_factor": "Twee-factor authenticatie"},"auth": {"login": "Inloggen","register": "Registreren","remember_me": "Onthoud mij","forgot_password": "Wachtwoord vergeten?","otp_title": "Verificatiecode invoeren","otp_description": "Er is een code naar je e-mail gestuurd","use_recovery_code": "Gebruik een herstelcode"}}}Vertalingen in NL, EN, DE toevoegen aan de
@magiverse/i18ntranslation files. -
next-intl evaluatie
-
Taalswitch in header
- Vlag-icoontje in storefront header (al aanwezig via
react-country-flagdependency) - Opgeslagen in cookie (
magiverse_language) en customer metadata - Taaldetectie volgorde: customer metadata → cookie → browser Accept-Language →
nldefault
- Vlag-icoontje in storefront header (al aanwezig via
-
Tolgee evaluatie (voor productinhoud)
Zie: i18n Integration Plan voor de volledige Tolgee strategie.
Fase 7 — Wishlist & E-mail Templates (4 dagen)
Section titled “Fase 7 — Wishlist & E-mail Templates (4 dagen)”7A. Wishlist / Verlanglijst
Section titled “7A. Wishlist / Verlanglijst”-
Plugin installatie
medusa-plugin-wishlist(RSC-Labs, MIT, Medusa 2.0+)Backend installatie in
magic_development:Terminal window cd /mnt/data/magic_omniverse/magic_commerce/magic_development/backendnpm install medusa-plugin-wishlistConfiguratie in
medusa-config.ts:plugins: [// ... bestaande plugins{ resolve: "medusa-plugin-wishlist" }] -
Hart-icoontje op productpagina
- Toggle hart-icoon (leeg/gevuld) op elke product card en product detail pagina
- Unauthenticated: redirect naar login
- Authenticated: toggle via wishlist API
Bestanden om aan te passen:
src/modules/products/components/product-card/— hart-icoon toevoegensrc/modules/products/templates/product-info/— hart-icoon toevoegen
-
Verlanglijst pagina
┌─────────────────────────────────────────────────────────┐│ Verlanglijst (4 items) │├─────────────────────────────────────────────────────────┤│ ││ ┌────┐ Blauwe Pen Deluxe €2,45/stuk [🗑️] ││ │ 📷 │ Min. 100 stuks ││ └────┘ ││ ┌────┐ Notitieboek A5 Hardcover €3,75/stuk [🗑️] ││ │ 📷 │ Min. 50 stuks ││ └────┘ ││ ││ [🛒 Alles toevoegen aan winkelwagen] ││ [📋 Omzetten naar offerte-aanvraag] ← B2B feature ││ [🔗 Deel verlanglijst] │└─────────────────────────────────────────────────────────┘Features:
- Product verwijderen van verlanglijst
- “Voeg alles toe aan cart” knop
- B2B: “Omzetten naar offerte-aanvraag” — maakt een quotation aan via
/store/aplt/quotations - Deelbare link via JWT-token (publieke toegang zonder login)
Nieuwe bestanden:
src/app/[countryCode]/(main)/account/@dashboard/wishlist/page.tsxsrc/modules/account/components/wishlist/index.tsxsrc/lib/data/wishlist.ts— server actions
7B. E-mail Templates
Section titled “7B. E-mail Templates”-
React Email + Resend setup
Terminal window npm install @react-email/components resendE-mail templates in tenant-huisstijl met dezelfde
--theme-*variabelen (inline CSS voor e-mail compatibility). -
Templates aanmaken/restylen
E-mail Trigger Template Orderbevestiging Order aangemaakt emails/order-confirmation.tsxVerzendbevestiging Order status → shipped emails/shipping-confirmation.tsxFactuur beschikbaar Factuur aangemaakt emails/invoice-available.tsxOfferte bijna verlopen Cron: 3 dagen voor vervaldatum emails/quote-expiring.tsxRetourverzoek ontvangen Retour ingediend emails/return-received.tsx2FA OTP code Login met 2FA emails/otp-code.tsxWachtwoord gewijzigd Wachtwoord update emails/password-changed.tsxWelkom / E-mail verificatie Registratie emails/welcome-verify.tsxLocatie:
src/emails/in de backend of storefront (afhankelijk van waar de e-mail wordt verstuurd) -
Template structuur
Elke e-mail template:
- Logo bovenaan (tenant-specifiek via
NEXT_PUBLIC_THEME) - Accent kleur als header bar
- Content in clean cards
- Footer met bedrijfsgegevens + afmeldlink
- Responsive (mobile-first)
- Logo bovenaan (tenant-specifiek via
Fase 8 — Testing & Uitrol (2-3 dagen)
Section titled “Fase 8 — Testing & Uitrol (2-3 dagen)”-
Testen op beta.brinxx.nl
- Alle flows handmatig doorlopen op de beta omgeving
- Mobile testing (iOS Safari, Android Chrome)
- Cross-browser (Chrome, Firefox, Safari, Edge)
- 2FA flow met echte e-mail
-
Performance check
- Lighthouse score > 80 op account pagina’s
- Geen onnodige re-renders (React DevTools profiler)
- PDF download < 3 seconden
-
Security review
- JWT autorisatie op alle nieuwe store routes
- Klant kan ALLEEN eigen data zien (facturen, offertes, orders)
- OTP brute-force bescherming (rate limiting)
- CSRF bescherming op state-changing endpoints
- File upload validatie (type, grootte)
-
Distributie naar alle tenants
Na goedkeuring op beta.brinxx.nl:
Terminal window # Gebruik bestaande tenant-sync workflow# Zie: /plans/brinxx-sync-plan voor het sync procesVolgorde:
- magic_development (template)
- magic_brinxx (beta → productie)
- magic_default, magic_demo (test tenants)
- magic_jodasign, magic_logohorloge, magic_bovisales, magic_desluis (productie tenants)
-
Post-deploy verificatie
Per tenant controleren:
- Login + 2FA flow
- Dashboard overview met data
- Facturen/offertes laden correct
- PDF download werkt
- Taalswitch werkt
- Mobile responsive OK
Benodigde Plugins & Packages
Section titled “Benodigde Plugins & Packages”| Feature | Package | Medusa vereiste | Licentie | Status |
|---|---|---|---|---|
| i18n (UI) | @magiverse/i18n | - | Intern | Al aanwezig in storefront |
| 2FA / OTP | Eigen implementatie via SMTP | - | - | Te bouwen |
| 2FA / OTP (alternatief) | @perseidesjs/auth-otp | >= 2.3.0 | Commercieel | Evalueren kosten |
| E-mail verificatie | @nicogorga/medusa-auth-emailpass-verified | >= 2.10.3 | MIT | Te installeren |
| Passkey (fase 2) | @tsc_tech/medusa-plugin-auth-passkey | >= 2.4.0 | MIT | Later ticket |
| Wishlist | medusa-plugin-wishlist (RSC-Labs) | 2.0+ | MIT | Te installeren |
| E-mail templates | @react-email/components + Resend | - | MIT | Te installeren |
| Iconen | lucide-react | - | MIT | Te installeren |
| PDF (backend) | pdfkit | - | MIT | Al aanwezig |
| ZIP export | jszip | - | MIT | Al aanwezig in backend |
Fasering Overzicht
Section titled “Fasering Overzicht”┌─────────────────────────────────────────────────────────────────┐│ FASE │ INHOUD │ GESCHATTE DUUR │├──────────┼─────────────────────────────────────┼────────────────┤│ Fase 1 │ Huisstijl & Design System │ 3-4 dagen ││ Fase 2 │ Authenticatie & 2FA │ 4-5 dagen ││ Fase 3 │ Orders & Ordergeschiedenis │ 3-4 dagen ││ Fase 4 │ Facturen, Offertes & Retouren │ 5-6 dagen ││ Fase 5 │ Profiel & Dashboard uitbreiding │ 2-3 dagen ││ Fase 6 │ Multi-language (account pagina's) │ 3-4 dagen ││ Fase 7 │ Wishlist + E-mail templates │ 4 dagen ││ Fase 8 │ Testing & uitrol alle tenants │ 2-3 dagen │├──────────┼─────────────────────────────────────┼────────────────┤│ TOTAAL │ │ 26-33 dagen │└──────────┼─────────────────────────────────────┴────────────────┘
Afhankelijkheden: Fase 1 ──────────▶ Fase 3 (styling nodig voor orders) Fase 1 ──────────▶ Fase 4 (styling nodig voor facturen/offertes) Fase 1 ──────────▶ Fase 5 (styling nodig voor dashboard) Fase 2 ──────────▶ Fase 5 (2FA componenten in profiel) Fase 4 ──────────▶ Fase 5 (factuur/offerte data voor dashboard) Fase 1-7 ────────▶ Fase 8 (alles moet klaar zijn voor testing) Fase 6 kan parallel met Fase 3-5 (onafhankelijke i18n laag)Risico’s & Mitigaties
Section titled “Risico’s & Mitigaties”| Risico | Impact | Mitigatie |
|---|---|---|
| @perseidesjs/auth-otp is te duur | Vertraging 2FA | Eigen OTP via SMTP bouwen (Optie B, aanbevolen) |
| APLT store routes bestaan nog niet | Fase 4 blokkeert | Backend routes als eerste oppakken in Fase 4 |
| Klant-matching via e-mail faalt | Klant ziet geen data | Validatie toevoegen: als aplt_customers geen match heeft, toon “Neem contact op” bericht |
| Multi-tenant theming breekt | Visuele bugs per tenant | Theme testen op minimaal 3 tenants (brinxx, default, jodasign) in elke fase |
| PDF generatie traag voor klant | Slechte UX | Loading state tonen, PDF async genereren als het > 3s duurt |
| File upload kwetsbaarheden | Beveiligingsrisico | Strikte validatie: alleen JPG/PNG, max 5MB, virus scan overwegen |
| 2FA lock-out | Klant kan niet inloggen | Herstelcodes (8 stuks) + admin override mogelijkheid |
| Medusa v2.13.1 breaking changes | Plugin incompatibiliteit | Plugins testen in development vóór installatie op tenants |
Aandachtspunten
Section titled “Aandachtspunten”Gerelateerde Documentatie
Section titled “Gerelateerde Documentatie”- i18n Integration Plan — Multi-language strategie (Tolgee + @magiverse/i18n)
- Brinxx Code Sync Plan — Tenant distributie workflow
- Platform Audit — Overzicht platform status
- Development Workflow — Ontwikkel- en testproces
- Deployment — Container rebuild procedures
Aangemaakt door: Wayne | Toegewezen aan: Michiel | Akkoord Wayne vereist voor start ontwikkeling
Plan opgesteld: 4 maart 2026 | Geschatte doorlooptijd: 26-33 werkdagen