Backend follow-on to migration 73:
- schemas: ResponseAreaPayload.kind extended to response|context|question_number|
mark_area|reference|furniture + context_type; QuestionPayload gains bounds+page.
- PUT serialization persists Part bounds/page and region context_type.
- Neo4j projection only emits Region nodes for response/context regions; the
metadata kinds (question_number/mark_area/reference/furniture) are physical-layer
only and stay out of cc.public.exams.
- Unit test: new kinds + Part geometry + context_type round-trip.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
modules/database/services/exam_projection.py projects a saved template into
cc.public.exams: ExamPaper -> Question/Part -> Region + Part-[:ASSESSES]->
SpecPoint, joined by shared UUIDs (exam_questions.id, exam_response_areas.id,
exam_code, spec_code). Full re-sync per exam_code (idempotent). Reads via
service role + writes via system Neo4j driver (R3.5.1 documented graph-writer).
Wiring (R3.5.4/R5.3):
- PUT /templates/{id} enqueues project_template_safe via BackgroundTasks
(swallows failures so a graph hiccup never fails the canvas save).
- POST /templates/{id}/neo4j-sync — manual trigger, as-user auth + owner check,
runs synchronously and returns projection counts.
Unit tests: projection scheduled on PUT; neo4j-sync owner/403/404.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The _get_profile select list omitted school_id, causing
/me/bootstrap to always return null for that field even after
the column was populated.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Two root causes fixed:
1. seed_environment.py: KevlarAI website was 'https://kevlarai.com' (real
domain) instead of 'https://kevlarai.test'. Also, seed step 8 now patches
kcar's auth user_metadata to set user_type='platform_admin' on every
reset+seed, so the fix is self-healing and doesn't require manual DB edits.
2. provisioning_service.py: user_type_map now maps 'platform_admin' to
('superadmin', 'superadmin'), so _ensure_membership() is never called for
platform admin accounts and they are never silently enrolled in the
default institute.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>