Awareness

Technische Documentatie

Architectuur, database, plugin-systeem, API-structuur en frontend — voor ontwikkelaars en systeembeheerders.

Stack

LaagTechnologieVersie
BackendFastAPI (Python)0.115+
Database driverasyncpg—
DatabasePostgreSQL15+
FrontendReact 18 + TypeScript + Vite18.x / 5.x
UI libraryTailwind CSS + shadcn/ui3.x
GrafiekenRecharts2.15.0
State managementZustand (persist)—
AuthPyJWT + JWT-claims—
Reverse proxyTraefik v33.x
ContainersDocker Compose v2—

Architectuurdiagram

  Browser (React SPA — TypeScript + Vite + Tailwind)
       │  HTTPS
       ▼
  Traefik v3 (SSL wildcard *.uw-domein.nl)
       │
       ├──/          → Frontend container (Nginx, React bundle)
       └──/api/      → Backend container (FastAPI + asyncpg)
                               │
                               ▼
                     PostgreSQL 15
                      ├── public
                      │     ├── tenants
                      │     ├── superadmin_users
                      │     └── magic_link_tokens
                      ├── tenant_001
                      │     ├── users
                      │     ├── campaigns
                      │     ├── training_templates
                      │     └── ... (alle tenant-tabellen)
                      └── tenant_002
                            └── ...

  Plugins (gemount als volume):
  /plugins/
    ├── phishing_awareness/
    │     ├── manifest.json
    │     ├── backend/router.py    → geladen door FastAPI bij opstart
    │     └── frontend/index.tsx  → geladen door React router
    └── <eigen-plugin>/

Database — Schema-per-tenant

Elke tenant krijgt een eigen PostgreSQL-schema. Het public schema bevat alleen platformbrede gegevens.

Public schema (platformbreed)

TabelInhoud
tenantsTenant-registraties (naam, subdomein, branding, module-flags)
superadmin_usersSuperadmin accounts (cross-tenant beheer)
magic_link_tokensEenmalige inlog-tokens (15 min geldig)

Tenant-schema (per organisatie)

CategorieTabellen
Gebruikersusers, user_profiles, invitation_tokens, audit_log
Organisatiedepartments, department_managers, groups, delegations
Campagnescampaigns, campaign_tags, campaign_notes, campaign_reminders, campaign_group_assignments, campaign_department_assignments
Trainingentraining_templates, training_template_versions, training_progress, training_progress_save
Gamificationuser_streaks, user_levels, badges, user_badges, challenges, user_challenges
Risicohuman_risk_scores, hrs_events
Notificatiesnotifications
Rapportagesreport_history, scheduled_report_configs
Integratieswebhooks, api_keys, plugin_settings
Instellingentenant_settings
Migraties
Migraties worden uitgevoerd via psql direct — Alembic wordt niet gebruikt vanwege incompatibiliteit met asyncpg en raw SQL in de initialisatiescripts. Migratiescripts staan genummerd in migrations/ en worden in volgorde uitgevoerd.

Plugin-systeem — technisch

Bij opstart scant de backend /plugins/ en laadt elke folder met een geldige manifest.json. De FastAPI router en het React component worden dynamisch geregistreerd.

json
{
  "id": "phishing_awareness",
  "name": "Phishing Awareness",
  "version": "1.0.0",
  "description": "Basistraining over phishing-herkenning",
  "author": "secctl.io",
  "min_platform_version": "0.3.0",
  "required_roles": ["medewerker"],
  "backend_router": "backend/router.py",
  "frontend_entry": "frontend/index.tsx"
}

Backend: router.py exporteert een FastAPI APIRouter. De backend monteert deze onder /api/plugins/<plugin-id>/.

Frontend: index.tsx exporteert een React component. De router registreert het op /plugins/<plugin-id> in de SPA.

Plugin-isolatie
Elke plugin draait achter een error boundary. Een crash in een plugin haalt de backend of andere plugins niet neer. Plugin-data staat in de tenant-tabellen (plugin_settings) — niet in eigen tabellen per plugin.

API-structuur

De backend is een FastAPI-applicatie met versioned routers onder /api/v1/. De volledige API-documentatie is beschikbaar via /docs (Swagger UI) en /redoc op uw omgeving.

RouterPrefixFunctie
auth.py/api/v1/authLogin, magic link, token refresh, wachtwoord
users.py/api/v1/usersGebruikersbeheer, import, sync, bulk-acties
departments.py/api/v1/departmentsAfdelingshiërarchie, stats, managers
campaigns.py/api/v1/campaignsCampagnes, toewijzingen, analytics, reminders
builder.py/api/v1/builderTraining Builder CRUD, versioning, publiceren
hrs.py/api/v1/hrsHuman Risk Score, overzicht, herberekening
gamification.py/api/v1/gamificationStreaks, XP-levels, badges, uitdagingen, leaderboard
reports.py/api/v1/reportsRapportgeneratie, geplande rapporten, geschiedenis
plugins.py/api/v1/pluginsPlugin-lijst, instellingen, statistieken
settings.py/api/v1/settingsWebhooks, API-keys, rol-permissies, delegaties
notifications.py/api/v1/notificationsIn-app notificaties CRUD
profile.py/api/v1/profileGebruikersprofiel GET/PUT (inclusief user_profiles)
admin_users.py/api/v1/adminCross-tenant gebruikersbeheer (superadmin only)
mfa.py/api/v1/mfaMulti-factor authenticatie en passkeys
sso.py/api/v1/ssoSSO/SAML-configuratie per tenant
azure_ad.py/api/v1/azure-adMicrosoft Azure AD SSO-login + Graph user-import

Frontend — React 18

bash
frontend/src/
├── views/              # pagina-componenten per module
│   ├── dashboard/
│   ├── campaigns/
│   ├── users/
│   ├── departments/
│   ├── gamification/
│   ├── reports/
│   ├── builder/
│   ├── hrs/
│   ├── plugins/
│   ├── settings/
│   ├── profile/
│   ├── admin/
│   └── auth/
├── components/
│   └── layout/         # Sidebar, Topbar (dark mode toggle, taalwissel)
├── stores/
│   ├── langStore.ts    # Zustand persist — taalvoorkeur (nl/en)
│   └── themeStore.ts   # Zustand persist — dark mode (system/light/dark)
├── i18n/
│   ├── translations.ts # NL + EN woordenboeken
│   └── index.ts        # translate(lang, key, vars?) functie
├── hooks/
│   └── useT.ts         # useT() hook — retourneert {t, lang}
└── router/
    └── index.tsx       # React Router v6 configuratie

i18n: Eigen vertalingssysteem zonder externe packages. useT() haalt taalvoorkeur op uit langStore en retourneert de vertaalfunctie t(key). Taalvoorkeur wordt gesynchroniseerd met het gebruikersprofiel in de database.

Authenticatie

JWT-tokens
  • Signed met HS256 en SECRET_KEY
  • Claims: sub (user_id), tenant_id, role
  • Tenant-isolatie op basis van JWT-claim — geen session-opslag op de server
  • Korte levensduur; verlenging via refresh flow
Magic links
  • Opgeslagen in public.magic_link_tokens
  • Eenmalig gebruik — token wordt direct na gebruik ongeldig
  • Geldigheid: 15 minuten
  • Volledig los van uitnodigingstokens (invitation_tokens)
Microsoft Azure AD / Entra ID SSO
Single sign-on via Azure AD is geïmplementeerd met de OAuth2 authorization-code flow (/api/v1/azure-ad/sso/authorize → /sso/callback). Na succesvolle login geeft de backend een eigen JWT uit. Gebruikersimport verloopt via de Microsoft Graph API.
Roadmap: generieke SAML SSO
Naast de Azure AD-koppeling is generieke SAML-ondersteuning voorbereid: de configuratie-endpoints (/api/v1/sso) en het datamodel zijn aanwezig. De SAML-loginflow zelf staat nog op de roadmap.