Commit Graph

171 Commits

Author SHA1 Message Date
RaymondVerhoef
85452f66a7 feat(r42): improve KB grounding accuracy and add clear-history
R42 was missing knowledge-graph information (e.g. pension questions)
because retrieval and context-building dropped relevant facts:

- retrieval: exact-token TF-IDF could not match Dutch compound words,
  so a "pensioen" query scored 0 against "pensioenregeling" /
  "partnerpensioen" and never retrieved them. Add a compound-word
  fallback (shared >=6-char stem or containment, 0.4x weight) alongside
  exact matching.
- rag: deep article content was only injected for verbatim-mentioned
  topics; retrieved topics contributed just a 200-char description.
  Inject ~1000 chars of content for up to 5 topics (mentions first,
  then top-ranked retrieved) and widen the description snippet to 320.
- prompts: add a NAUWKEURIGHEID block (use all relevant facts, call
  lookup_topic before giving up) and relax the 4-sentence cap for
  detail/list answers so complete facts aren't summarised away.

Also add a clear-history control: a trash button in the chat header
(confirm dialog) wipes chat🧵{userId} and reseeds the greeting
via clearThread() in useChat.

Tests: compound-word matching + rag deep-content injection. Spec updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:25:08 +02:00
e73700763d Merge pull request 'Fix #32: gestringifieerde arrays in onboarding-overview output normaliseren' (#33) from fix/issue-32-onboarding-schema into main
All checks were successful
On Push to Main / test (push) Successful in 35s
On Push to Main / publish (push) Successful in 1m12s
On Push to Main / deploy-dev (push) Successful in 3m15s
Reviewed-on: #33
2026-07-13 07:46:53 +00:00
RaymondVerhoef
182fb2357f fix: coerce stringified arrays in onboarding overview output (#32)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 41s
On Pull Request to Main / publish (pull_request) Successful in 1m15s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m17s
Opening an onboarding theme could fail with "LLM output failed schema
validation": the fast-tier model occasionally emits the key_points and
topics_covered tool fields as JSON-encoded strings instead of real
arrays. Same failure class the quiz schema already guards against with
z.preprocess.

- onboardingOverviewSchema: parse "[...]" strings back to arrays before
  validation; split a bullet/newline string of key points as a fallback;
  keep the first 5 key points on overage instead of failing the user.
  Genuinely bad output (too few points, non-JSON strings, wrong types)
  still fails validation.
- emit_onboarding_overview tool: descriptions now state the fields must
  be JSON arrays, never strings (prompt-side nudge).
- 5 regression tests reproducing the exact #32 payload shapes
  (npm test 139/139).

Closes #32

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 09:38:46 +02:00
b1d3686d35 Merge pull request 'Onboarding-track: 5-daagse thema-introductie vanuit de "New here?"-kaart (#30)' (#31) from feat/onboarding-track into main
All checks were successful
On Push to Main / test (push) Successful in 34s
On Push to Main / publish (push) Successful in 1m11s
On Push to Main / deploy-dev (push) Successful in 3m19s
Reviewed-on: #31
2026-07-13 07:20:00 +00:00
RaymondVerhoef
b1330ebe3e ci: validate the production Caddyfile inside the built image (#26)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 41s
On Pull Request to Main / publish (pull_request) Successful in 1m10s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m15s
The caddy-validate step added for #26 (and merged to main via #29) used a
`-v "$PWD":/workspace` bind mount, which does not propagate to the sibling
Docker daemon in the Gitea act runner — the container saw an empty dir and
every PR failed with "open Caddyfile: no such file or directory".

Validate instead inside the freshly built image, where the production
Caddyfile lives at /etc/caddy/Caddyfile: no bind mount, and it checks the
exact file that ships. Caddyfile.test keeps being covered by the homepage
smoke test (its container must serve 200).

Closes #26

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 09:13:12 +02:00
RaymondVerhoef
5214c9db3b feat: 5-day theme-level onboarding track from the "New here?" card (#30)
Some checks failed
On Pull Request to Main / test (pull_request) Failing after 24s
On Pull Request to Main / publish (pull_request) Has been skipped
On Pull Request to Main / deploy-dev (pull_request) Has been skipped
A self-paced onboarding track that introduces a new employee to every KB
theme in breadth (not depth), so they grasp how Respellion works day to
day and week to week. Offered as a CTA inside the Dashboard "New here?"
explainer card; always available regardless of enrollment.

Design:
- Theme is the trackable unit; the 5 "days" are a read-time presentation
  grouping, so re-chunking never loses progress. Completion is stored per
  theme in onboarding_completions.
- Per-theme overview generated lazily on first open (fast-tier
  emit_onboarding_overview tool), cached in onboarding_overviews keyed by
  theme + a topics_fingerprint that triggers regeneration when the theme's
  topic set changes.
- Reachable via /onboarding-track using the existing skipEnrollmentGate
  prop, decoupled from the 26-week curriculum (distinct from /onboarding,
  the enrollment page).

Backend:
- pb_migrations/1781200000_created_onboarding.js: two collections with
  authenticated-only rules and unique indexes; TEXT team_member_id (no
  relation) per the post-#18/#27 convention. Mirrored in
  scripts/setup-pb-collections.mjs.
- src/lib/onboardingService.js: pure helpers (orderThemes,
  distributeThemesIntoDays, computeTopicsFingerprint,
  computeOnboardingProgress, buildOnboardingPlan) + generation + I/O.
- db.js onboarding helpers use pb.filter() bindings (theme is free text).
- LLM tool + Zod schema + registry + simulation stub.

Frontend:
- src/pages/OnboardingTrack.jsx (day list, per-theme overview, completion
  banner, progress ring/day bar).
- Dashboard "New here?" card CTA + X/5-days progress chip (hidden when the
  KB has no themes).

Docs: data-model, generation-spec (§D), frontend-spec updated.

Verified: 22 new unit tests (npm test 134/134), eslint clean on changed
files, npm run build OK, PocketBase v0.30.4 boot applies the migration
(collections + unique indexes + authed rules confirmed), and a backend
contract check (upsert idempotency, unique-index guard, special-char
theme filtering).

Closes #30

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 09:08:38 +02:00
48715df147 Merge pull request 'Fix #27: TeamManager-rosterbeheer, role-escalatie gedicht, escalate-only resync' (#29) from fix/issue-27-teammanager-admin-rules into main
Some checks failed
On Push to Main / test (push) Failing after 25s
On Push to Main / publish (push) Has been skipped
On Push to Main / deploy-dev (push) Has been skipped
Reviewed-on: #29
2026-07-12 19:04:43 +00:00
85204938df Merge pull request 'CI: caddy validate van beide Caddyfiles in de test-job' (#28) from fix/issue-26-ci-caddy-validate into main
Some checks failed
On Push to Main / publish (push) Has been cancelled
On Push to Main / deploy-dev (push) Has been cancelled
On Push to Main / test (push) Has been cancelled
Reviewed-on: #28
2026-07-12 19:04:29 +00:00
RaymondVerhoef
cbce4555ff fix: TeamManager admin rules, close role self-escalation, escalate-only resync (#27)
Some checks failed
On Pull Request to Main / test (pull_request) Failing after 24s
On Pull Request to Main / publish (pull_request) Has been skipped
On Pull Request to Main / deploy-dev (pull_request) Has been skipped
TeamManager could not manage the roster: updateRule allowed self-update
only and deleteRule was superuser-only. The same self-update rule also
left a privilege escalation open — it did not restrict fields, so any
authenticated user could PATCH their own role to "admin".

- team_members rules (migration 1781000003 + base migration + setup
  script mirror):
    update: (@request.auth.id = id && @request.body.role:isset = false)
            || @request.auth.role = "admin"
    delete: @request.auth.role = "admin"
  Self-service onboarding keeps working (it never touches role); the
  role field is admin-only; deletion is admin-only.
- pb_hooks/team_members.pb.js: the ENTRA_ADMIN_EMAILS resync is now
  escalate-only — it guarantees admin for allow-list members on every
  login but no longer demotes, otherwise every TeamManager promotion
  would revert on the member's next sign-in (ADR-004 amended).
- TeamManager.jsx: info text updated to the new behaviour.

Verified with a two-identity mock-OIDC matrix (11/11): allow-list vs
regular login, self-escalation blocked while onboarding self-update
still works, cross-user update/delete blocked, admin promote/demote/
delete work, promotion survives the member's next login, allow-list
admin stays admin. Regression: #22 matrix 9/9, #24 matrix 8/8, #18
harness 15/15, npm test 112/112, eslint clean.

Closes #27

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 21:01:28 +02:00
RaymondVerhoef
6bf8bad5fb ci: validate both Caddyfiles in the test job (#26)
Some checks failed
On Pull Request to Main / test (pull_request) Failing after 26s
On Pull Request to Main / publish (pull_request) Has been skipped
On Pull Request to Main / deploy-dev (pull_request) Has been skipped
The test image swaps in Caddyfile.test, so the production Caddyfile was
never exercised by CI: the parse error from issue #20 sailed through
every check and only surfaced when the deploy gate failed — after the
broken container had already replaced the healthy one. Running
`caddy validate` (same caddy:2-alpine base as the Dockerfile) on both
files up front fails the PR check in seconds instead.

Touches the frozen .github/workflows/ per explicit product-owner
approval in #26.

Closes #26

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 20:55:35 +02:00
RaymondVerhoef
54137122a7 fix: read Entra claims from id_token + UPN e-mail fallback (#24)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 38s
On Pull Request to Main / publish (pull_request) Successful in 1m10s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m7s
First Microsoft logins failed with 400 "email: Cannot be blank": Graph's
/oidc/userinfo endpoint omits the email claim for accounts without a
mail attribute, and team_members requires an e-mail (it also drives the
ENTRA_ADMIN_EMAILS role mapping). Reproduced against a mock Entra with
PocketBase v0.30.4; the user-supplied response body matched the
missing-email fingerprint exactly.

- provider config (reconciler + migration fast-path): userInfoURL is now
  empty, so PocketBase reads the claims from the Entra id_token, which
  always carries preferred_username (UPN) and email when available. The
  #18 reconciler flips the already-deployed Labs provider automatically
  on the next boot — no migration needed.
- pb_hooks/entra_oidc.pb.js: onRecordAuthWithOAuth2Request hook falls
  back to the lowercased UPN when the email claim is absent. Guest UPNs
  (ext_user#EXT#@tenant...) are excluded explicitly — "#" is RFC-valid
  in an e-mail local part, so both a naive regex AND PocketBase's own
  validation would accept them (caught by test V5). The hook also logs
  every failed OAuth2 attempt with the underlying error to the container
  log, which PocketBase otherwise only writes to its internal logs db.

Verified with a switchable mock-Entra matrix (8/8): no-email→UPN e-mail
+ allow-list role, email claim wins when present, no duplicate on
re-login, guest UPN yields a clean validation error, anonymous REST
create stays rejected, both log lines present. Regression: issue-22
matrix 9/9 (baseline pinned to 1a1351d now that #23 is merged), DoD
harness 15/15, npm test 112/112.

Closes #24

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 19:26:25 +02:00
8decdd454f Merge pull request 'Fix #22: OAuth2 sign-up toegestaan via @request.context-rule (eerste Microsoft-login werkt weer)' (#23) from fix/issue-22-oauth2-signup-rule into main
All checks were successful
On Push to Main / test (push) Successful in 33s
On Push to Main / publish (push) Successful in 1m4s
On Push to Main / deploy-dev (push) Successful in 3m3s
Reviewed-on: #23
2026-07-12 15:11:24 +00:00
RaymondVerhoef
897b46d4a1 fix: allow OAuth2 sign-up on team_members via @request.context rule (#22)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 39s
On Pull Request to Main / publish (pull_request) Successful in 1m9s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m9s
Every first Microsoft login failed with 403 "Only superusers can perform
this action": PocketBase applies the collection createRule to the
automatic record creation during OAuth2 sign-up, and team_members was
created with createRule null (superuser-only) on the wrong assumption
that the OAuth2 flow bypasses it. Since the pre-Azure records were
deliberately dropped, every user was a first login and nobody could get
in. Reproduced locally against a mock OIDC provider (PocketBase v0.30.4).

createRule becomes '@request.context = "oauth2"': record creation is
allowed exclusively from within the OAuth2 flow. Anonymous REST creates
(which could otherwise pre-seed rogue admin profiles) remain rejected —
covered by an explicit test.

- pb_migrations/1781000002_allow_oauth2_signup.js: applies the rule on
  already-migrated environments (Labs); idempotent, guarded, with down
- pb_migrations/1781000000_team_members_to_auth.js: same rule for fresh
  environments (filename unchanged — ledger-safe)
- scripts/setup-pb-collections.mjs: fallback entry mirrored
- docs/auth-spec.md: ADR 009 + files table

Verified with a mock-OIDC matrix (9/9): baseline reproduces the 403 on
the old rule; upgrade path heals (first login 200, role/enrollment/name
defaults, second login no duplicate, anonymous create still rejected);
fresh chain + admin allow-list mapping OK. DoD harness regression 15/15,
npm test 112/112.

Closes #22

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 15:15:54 +02:00
RaymondVerhoef
80f738ddcb fix: valid Caddyfile handle_errors + frontend health-gate in deploys (#20)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 39s
On Pull Request to Main / publish (pull_request) Successful in 1m7s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m6s
The learning-platform (Caddy) container crash-looped since this morning's
89d3395: `Content-Type application/json` is not a valid subdirective of
`respond` — a Caddyfile parse error aborts Caddy at startup, taking the
whole app offline for authenticated users while every CI run stayed green.
Verified with caddy v2.10.0: "unrecognized subdirective 'Content-Type',
at Caddyfile:53"; the fixed file validates clean.

CI was blind to this twice over: test.yml swaps the real Caddyfile for
Caddyfile.test in the test image, and the deploy health-gate from #18
only covers PocketBase.

- Caddyfile: set Content-Type via a `header @api` directive before the
  `respond`; behaviour of the JSON error response is unchanged
- infra/*/site/deploy-playbook.yml: frontend health-gate (docker exec
  wget --spider on the container) with log dump + abort on failure, and
  an always-on post-deploy smoke report (compose ps, proxy health,
  team_members auth-methods, PocketBase log tail) for visibility behind
  the auth perimeter

Closes #20

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 14:20:15 +02:00
1a1351ddcb Merge pull request 'Fix #18: migratie-ledger-sync + deploy-proof Azure SSO' (#19) from fix/issue-18-migration-ledger-sso into main
All checks were successful
On Push to Main / test (push) Successful in 32s
On Push to Main / publish (push) Successful in 1m8s
On Push to Main / deploy-dev (push) Successful in 3m0s
Reviewed-on: #19
2026-07-11 11:54:37 +00:00
RaymondVerhoef
d79e69aad2 fix: heal migration-ledger mismatch and make Azure SSO deploy-proof (#18)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 39s
On Pull Request to Main / publish (pull_request) Successful in 1m9s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m1s
PocketBase on Labs crash-looped since the SSO deploy (PR #17): mounting
--migrationsDir for the first time replayed the entire migration history
against a database that was provisioned out-of-band (empty _migrations
ledger) and died on 1778948471_created_content.js. On top of that the
team_members->auth migration had its own crash paths and trapped OAuth2
config inside a one-shot, env-dependent migration.

- pb_migrations/1000000000_baseline_ledger_sync.js: detects an
  out-of-band provisioned DB (schema exists, ledger empty) and marks the
  79 historical migrations as applied; no-op on fresh or already-synced DBs
- pb_migrations/1781000000_team_members_to_auth.js: idempotency guard,
  relation->text conversion WITH data preservation (PocketBase diffs
  fields by id, so the column is backed up and restored via SQL), unique
  index rebuild, no silent catches, env only as fast-path
- pb_hooks/entra_oidc.pb.js + pb_hooks/utils.js: reconcile the Entra OIDC
  provider from ENTRA_* env on every bootstrap + cron tick
  (compare-before-save, warn-once); heals environments that migrated
  without secrets and supports secret rotation without re-apply
- pb_hooks/team_members.pb.js: require() pattern — JSVM runs callbacks as
  isolated programs, top-level helpers are not in scope (adopts Leroy's
  fix from the fix-sso branch)
- infra/*/site/deploy-playbook.yml: health-gate after compose up — the
  deploy fails loudly with container logs when PocketBase does not become
  healthy (runs #83-#88 were green while PB crash-looped)
- docker-compose.yml: .env.local is optional again
- docs/auth-spec.md + AI_AGENT.md: ledger/reconciler documentation, ADRs
  006-008, never-rename-applied-migrations warning

Verified locally against PocketBase v0.30.4 with a 7-scenario DoD matrix
(fresh DB +/- env, out-of-band DB with data incl. data preservation,
populated-ledger upgrade, late-secrets healing, re-run guard, hook
provisioning): 15/15 pass. npm test 112/112.

Closes #18

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:14:09 +02:00
RaymondVerhoef
89d3395a62 feat: enhance OIDC configuration for Azure login and improve error handling in API responses
All checks were successful
On Push to Main / test (push) Successful in 56s
On Push to Main / publish (push) Successful in 1m24s
On Push to Main / deploy-dev (push) Successful in 2m58s
2026-07-11 10:19:54 +02:00
RaymondVerhoef
d5191073f0 feat: migrate team_members to OIDC-based auth collection and update docker-compose environment configuration
All checks were successful
On Push to Main / test (push) Successful in 57s
On Push to Main / publish (push) Successful in 1m16s
On Push to Main / deploy-dev (push) Successful in 3m0s
2026-06-25 18:05:39 +02:00
fab7a12f7b Merge pull request 'fix/issue-16-azure-login' (#17) from fix/issue-16-azure-login into main
All checks were successful
On Push to Main / test (push) Successful in 30s
On Push to Main / publish (push) Successful in 1m15s
On Push to Main / deploy-dev (push) Successful in 2m54s
Reviewed-on: #17
2026-06-24 14:00:40 +00:00
RaymondVerhoef
fe99381cb7 ci: pass Entra (Azure) secrets to deploy playbooks (#16)
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 55s
On Pull Request to Main / publish (pull_request) Successful in 1m16s
On Pull Request to Main / deploy-dev (pull_request) Successful in 3m2s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 15:57:33 +02:00
RaymondVerhoef
3af105bccd feat: Azure (Entra ID) login as user login (#16)
Replaces the client-side PIN login with real authentication against Azure
Entra ID via PocketBase's built-in OAuth2 (OIDC) flow. Every Azure user is
auto-provisioned as a team_member on first login.

- pb_migrations: team_members becomes a PocketBase auth collection (OIDC
  provider configured from env); all collections require @request.auth.id
- pb_hooks: provisioning of role (ENTRA_ADMIN_EMAILS allow-list) and
  enrollment_status, with admin-role re-sync on every login
- frontend: "Sign in with Microsoft" login, pb.authStore-based session,
  TeamManager manages roster/roles (no PIN/manual create)
- infra: Entra env wiring + pb_hooks mount for dev (Labs) and prod
- src/lib/azureAuth.js + tests for the canonical role/allow-list logic
- docs/auth-spec.md

Knowledge base, generated tests and micro-learnings are left untouched.
Existing PIN users are dropped (no migration required, per sign-off).

Closes #16

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 11:41:08 +02:00
5f34a6f825 Merge pull request 'Bescherm excluded en locked topics tegen AI-deletion/merge' (#15) from fix/protect-excluded-locked-topics into main
All checks were successful
On Push to Main / test (push) Successful in 36s
On Push to Main / publish (push) Successful in 1m19s
On Push to Main / deploy-dev (push) Successful in 1m45s
Reviewed-on: #15
2026-06-04 06:29:33 +00:00
RaymondVerhoef
9395ea11fe fix: bescherm excluded en locked topics tegen AI-deletion/merge
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 46s
On Pull Request to Main / publish (pull_request) Successful in 1m26s
On Pull Request to Main / deploy-dev (pull_request) Successful in 1m49s
Topics met learning_relevance="exclude" of relevance_locked=true werden
door de Full Analysis stilletjes verwijderd: het model zag exclude als
"irrelevant" en stelde ze voor in actions.deletions / actions.merges,
en analyzeGraph paste die zonder filter toe. Het locked-vlaggetje werd
in full-scope payload niet eens meegestuurd, dus zelfs een nieuwe prompt
kon niet helpen.

Defense-in-depth fixes:

1. Pure graphGuard.filterAiActions strips elke deletion/merge waarvan de
   target excluded of locked is, vóór bulkSave. Merges waarin een
   protected topic juist de keepId is (canonical survivor) blijven door.

2. SYSTEM_PROMPTS.full krijgt een expliciete "PROTECTED TOPICS" sectie
   die exclude en locked topics als nooit-te-verwijderen markeert.

3. relevance_locked wordt nu ook in de full-scope compactTopics payload
   meegestuurd, zodat het model de vlag überhaupt ziet.

4. UI-feedback: GraphControls toont een ShieldCheck banner met aantal
   geblokkeerde acties na de analyze, en het excluded-aantal naast de
   "Show Excluded Nodes" toggle (visible/hidden).

5. 13 nieuwe Vitest cases dekken protected detection en alle drop/keep
   paden van filterAiActions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-04 08:22:12 +02:00
e310b6d85b Merge pull request 'Knowledge graph table view met sort, group en bulk edit' (#11) from fix/issue-10-knowledge-graph-bulk-changes into main
All checks were successful
On Push to Main / test (push) Successful in 44s
On Push to Main / publish (push) Successful in 1m21s
On Push to Main / deploy-dev (push) Successful in 1m46s
Reviewed-on: #11
2026-06-03 20:09:07 +00:00
2b2921f6ed Merge pull request 'fix: stop warning about merged themes in curriculum schedule' (#13) from fix/issue-12-curriculum-merge-warning into main
Some checks failed
On Push to Main / test (push) Has been cancelled
On Push to Main / publish (push) Has been cancelled
On Push to Main / deploy-dev (push) Has been cancelled
Reviewed-on: #13
2026-06-03 20:08:57 +00:00
RaymondVerhoef
2274de4de7 fix: stop warning about merged themes in curriculum schedule
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 44s
On Pull Request to Main / publish (pull_request) Successful in 1m22s
On Pull Request to Main / deploy-dev (pull_request) Successful in 1m40s
When the KB has more than 26 themes the curriculum AI is required to
merge — so theme labels not appearing as week names are expected, not
warnings. The previous validation surfaced this as a console.warn that
read like an error in the learning station console.

- validateSchedule now only flags missing theme labels when themes_kb <= 26
- adds a real coverage check: warns when learning topics are absent from
  every week (the actual signal we care about)
- adds vitest coverage for both behaviours

Closes #12

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 22:05:34 +02:00
RaymondVerhoef
eb08c4ad96 feat: knowledge graph table view met sort, group en bulk edit
All checks were successful
On Pull Request to Main / test (pull_request) Successful in 48s
On Pull Request to Main / publish (pull_request) Successful in 1m20s
On Pull Request to Main / deploy-dev (pull_request) Successful in 1m52s
Voegt een Graph/Table toggle toe aan de admin Knowledge Graph. De tabel
ondersteunt sorteren per kolom, groeperen op type/relevance/theme/difficulty,
filteren op label, multi-select en bulk-wijzigen van type, learning_relevance
en relevance_locked.

Closes #10

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-03 17:08:51 +02:00
RaymondVerhoef
218f6e7d64 feat: theme-grouped pickers, theme-session content panel, theme/topic naming
All checks were successful
On Push to Main / test (push) Successful in 42s
On Push to Main / publish (push) Successful in 1m17s
On Push to Main / deploy-dev (push) Successful in 1m56s
- Admin Topic Quizzes (was Quizzes): topics are now grouped under
  collapsible theme headers with per-theme counts. Topics without a
  theme fall into a "No theme" bucket rendered last.
- /topic-test picker: eligible topics grouped by theme so learners can
  scan a curriculum theme and drill its topics on demand.
- Fix admin Theme Content panel (was Learning Content): it was empty
  because content moved to the theme_sessions collection in an earlier
  refactor while the panel still queried the legacy per-topic content
  table. Rewrites ContentManager to read db.getAllThemeSessions and
  render the emit_theme_session schema (title, intro, topic sections,
  connections, key takeaways). Adds db.getAllThemeSessions and
  db.deleteThemeSession.
- Disambiguate theme vs topic across the app: the weekly curriculum
  test is now "Theme Test" (nav, page heading, Dashboard card, button,
  explainer); the on-demand bank test stays "Topic Test". Admin nav
  also clarified to "Theme Content" / "Topic Quizzes".

No schema changes. 85/85 tests still pass, build green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 16:37:50 +02:00
RaymondVerhoef
43a71e2110 feat: on-demand topic tests with shared question bank
All checks were successful
On Push to Main / test (push) Successful in 1m1s
On Push to Main / publish (push) Successful in 1m22s
On Push to Main / deploy-dev (push) Successful in 2m18s
Adds a /topic-test route where learners can take a 5-question test on any
eligible topic at any time. Questions come from a shared, admin-curated
question_bank — no LLM calls on the user path. Points feed the existing
leaderboard with a 10pt/topic/week cap (per ISO week) so the bank can't be
farmed, and repeats from a thin bank yield 0 points.

- New PB collections: question_bank, on_demand_attempts (+ migrations and
  setup-pb-collections.mjs entries).
- db.js: un-deprecates getQuizBank/setQuizBank against question_bank so the
  existing admin TestManager panel becomes functional again; adds
  saveOnDemandAttempt, getOnDemandPointsThisWeek, getUserSeenQuestionIds,
  getAllOnDemandAttempts, isoWeekKey.
- testService.js: getEligibleTopicsForOnDemand, startOnDemandTest (unseen-
  first draw), finishOnDemandTest (cap enforcement + leaderboard upsert).
- New TopicTest page, route, and nav entry; weekly test flow untouched.
- Leaderboard folds on-demand 100%s into perfect-score count and merges
  on-demand attempts into the recent activity feed.
- Spec: docs/on-demand-tests-spec.md with ADRs and extension points.
- Tests: 5 new vitest cases covering eligibility, draw fallback, scoring,
  partial cap, and exhausted cap (85/85 total).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 15:06:43 +02:00
RaymondVerhoef
d1a1cc913c Make Dashboard explainer always accessible via help icon
All checks were successful
On Push to Main / test (push) Successful in 44s
On Push to Main / publish (push) Successful in 1m26s
On Push to Main / deploy-dev (push) Successful in 1m54s
Adds a HelpCircle toggle button in the Dashboard header so users can
re-open the platform explainer after dismissing it. The per-user
dismissed state is preserved as the initial-open default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 14:43:20 +02:00
RaymondVerhoef
8160242be5 feat: update loading message duration and add caching information; increase timeout for theme session generation
All checks were successful
On Push to Main / test (push) Successful in 43s
On Push to Main / publish (push) Successful in 1m25s
On Push to Main / deploy-dev (push) Successful in 1m56s
2026-05-28 12:03:55 +02:00
RaymondVerhoef
d38c75beb1 feat: theme-level weekly sessions and theme-grouped knowledge library
All checks were successful
On Push to Main / test (push) Successful in 46s
On Push to Main / publish (push) Successful in 1m28s
On Push to Main / deploy-dev (push) Successful in 2m9s
- New theme_sessions + theme_session_completions PocketBase collections
- Generate a detailed per-week theme summary covering every topic in the
  week's curriculum slot via EMIT_THEME_SESSION_TOOL; cache per
  (curriculum_version, week_number)
- Replace Leren.jsx "This Week's Topic" card with "This Week's Theme
  Session" that opens the new ThemeSessionView; per-topic micro-learnings
  remain reachable as optional practice from inside the session
- Group the Knowledge Library by topic.theme, pin the current week's
  theme on top, and badge topics already covered by the active session
- Mark week complete when the user finishes reading the theme session

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 10:44:10 +02:00
RaymondVerhoef
6a1f5556a9 Add dismissible platform explainer to Dashboard
All checks were successful
On Push to Main / test (push) Successful in 39s
On Push to Main / publish (push) Successful in 1m8s
On Push to Main / deploy-dev (push) Successful in 1m38s
Introduces a per-user, dismissible "How Respellion works" card on the
Dashboard so new users understand the learn/test/leaderboard loop and
where to find R42 and the main navigation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 22:24:44 +02:00
RaymondVerhoef
ad5be01b70 feat: enhance ConceptExplainer to handle content extraction and display; add normalization for PocketBase records
All checks were successful
On Push to Main / test (push) Successful in 39s
On Push to Main / publish (push) Successful in 1m8s
On Push to Main / deploy-dev (push) Successful in 1m34s
2026-05-27 21:18:17 +02:00
RaymondVerhoef
ce276f0296 feat: enhance KnowledgeGraph with edge styles, node navigation, and AI analysis scopes; update GraphControls and NodeDetailPanel for improved relation management 2026-05-27 21:09:05 +02:00
RaymondVerhoef
47a738fde3 feat: migrate graph snapshot handling to localStorage for improved persistence
All checks were successful
On Push to Main / test (push) Successful in 39s
On Push to Main / publish (push) Successful in 1m7s
On Push to Main / deploy-dev (push) Successful in 1m36s
2026-05-27 20:27:16 +02:00
RaymondVerhoef
9fb22b8090 feat: update getQuizResult to handle no records gracefully by using getList 2026-05-27 20:27:08 +02:00
RaymondVerhoef
6309ae716b feat: implement snapshot restore functionality and enhance graph state management
All checks were successful
On Push to Main / test (push) Successful in 40s
On Push to Main / publish (push) Successful in 1m10s
On Push to Main / deploy-dev (push) Successful in 1m35s
2026-05-27 17:43:18 +02:00
RaymondVerhoef
6ea8860b96 feat: refactor KnowledgeGraph component and add NodeDetailPanel for enhanced node management
Some checks failed
On Push to Main / test (push) Successful in 47s
On Push to Main / publish (push) Failing after 31m8s
On Push to Main / deploy-dev (push) Has been cancelled
2026-05-27 15:18:01 +02:00
RaymondVerhoef
7b6a5b4bf0 feat: add GraphControls component and useGraphData hook for knowledge graph management 2026-05-27 15:05:26 +02:00
RaymondVerhoef
3aa32c383e feat: implement quiz results tracking and caching for user tests
All checks were successful
On Push to Main / test (push) Successful in 47s
On Push to Main / publish (push) Successful in 1m27s
On Push to Main / deploy-dev (push) Successful in 2m7s
2026-05-27 10:05:56 +02:00
RaymondVerhoef
07af2783dc Add comprehensive documentation for key organizational aspects
All checks were successful
On Push to Main / test (push) Successful in 1m33s
On Push to Main / publish (push) Successful in 1m31s
On Push to Main / deploy-dev (push) Successful in 2m3s
- Introduced "Pension Scheme & Benefits" detailing secondary employment benefits and pension specifics.
- Created "Roles & Accountabilities" outlining the Holacracy role structure and responsibilities within Respellion.
- Added "Security" section covering GDPR compliance and workplace safety protocols.
- Established "Spending and Contracting" policy detailing expense categories and submission processes.
- Documented "Who We Are" to define Respellion's identity, services, and operational model under Holacracy and ISO 9001.
2026-05-27 08:24:56 +02:00
RaymondVerhoef
7066f881f9 feat: implement onboarding process and enrollment status tracking for users 2026-05-26 21:33:20 +02:00
RaymondVerhoef
febc9dc7f2 Merge branch 'main' of https://git.labs.respellion.tech/rve/learning-platform
All checks were successful
On Push to Main / test (push) Successful in 41s
On Push to Main / publish (push) Successful in 1m12s
On Push to Main / deploy-dev (push) Successful in 1m39s
2026-05-26 14:23:15 +02:00
RaymondVerhoef
46d2735237 Merge branch 'main' of https://git.labs.respellion.tech/rve/learning-platform
Some checks failed
On Push to Main / test (push) Successful in 41s
On Push to Main / deploy-dev (push) Has been cancelled
On Push to Main / publish (push) Has been cancelled
2026-05-26 14:22:08 +02:00
RaymondVerhoef
daec9cf5b5 Add hot update files for layout and webpack with source maps
- Created new hot update JSON and JS files for app layout and webpack.
- Included eval-source-map for development purposes in the layout hot update.
- Added full hash retrieval function in the webpack hot update.
2026-05-26 14:22:01 +02:00
RaymondVerhoef
9b3d7fde8c fix: end micro-learning sessions explicitly and route to test
Every micro-learning format used to call onComplete implicitly — scroll
to the bottom of the explainer, flip the last flashcard, or pick any
scenario option — which yanked users out of the content before they
were done with it.

Replace the implicit triggers with a Finish session button on each
format. The scenario quiz exposes the button only after an option is
chosen so explanations still get read; the flashcard set exposes a
viewed-cards counter next to it.

The topic-reviewed landing screen now offers Back to Station, Try
another format, and Go to test, so finishing a session leads somewhere
useful instead of dead-ending. Drop the unreachable completion box that
the container was rendering underneath the parent's success screen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 14:20:41 +02:00
RaymondVerhoef
84e7468841 feat: drop reflection_prompt type and flag cached micro-learnings
Remove the reflection_prompt micro-learning format end-to-end: type
config, tool definition, container case, selector tile, and the
ReflectionPrompt component file. The format wasn't pulling its weight as
a learning surface.

Add a Beschikbaar badge to selector tiles whose topic already has a
published micro-learning of that type, so users know which formats open
instantly instead of triggering a fresh generation. Cached records are
fetched once per topic via the new getExistingTypesForTopic helper, and
re-fetched after a generation returns so newly-created formats light up
without a manual refresh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 13:41:20 +02:00
RaymondVerhoef
9ea5d5444d fix: generate weekly quiz in a single batch LLM call
The weekly quiz path made up to six sequential LLM calls (one per topic)
with three retries each, blowing past the 30s budget. Worse, the
quiz_banks collection has been dropped, so getQuizBank/setQuizBank are
no-ops and every generated batch was thrown away — the assembled quiz
ended up empty and surfaced as "Could not assemble enough questions."

Replace the per-topic loop with a single batched call on the fast tier
that emits all five questions in one round-trip, using the review topics
as prompt context instead of separate calls.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 13:22:44 +02:00
RaymondVerhoef
a653812cd8 feat: implement micro-learning generation service and UI components for interactive topic-based learning
All checks were successful
On Push to Main / test (push) Successful in 32s
On Push to Main / publish (push) Successful in 59s
On Push to Main / deploy-dev (push) Successful in 1m33s
2026-05-25 22:17:26 +02:00