28 Commits

Author SHA1 Message Date
c69451fba2 [verified] add upload size and MIME guards
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
(cherry picked from commit f5e05376f637f55b73e474cac8199529682ca398)
2026-06-08 01:18:39 +00:00
0b1496fff5 feat(docling): detect response regions with OpenCV 2026-06-07 19:57:22 +01:00
CC Worker
9c1aee28e2 feat(exam): persist S4-9 region kinds + Part geometry; keep metadata out of graph
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
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>
2026-06-06 21:14:20 +00:00
CC Worker
93972a62f7 fix: revert explicit apikey header (caused Kong duplicate-apikey 401)
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
The previous commit added apikey to _create_base_client headers, but supabase-py
already sets apikey from the key arg → two apikey headers → Kong rejected every
as-user call with 401 'Duplicate API key found' (exam API 502'd on auth). Revert
to Authorization-only; fix the two header unit tests to assert the real contract
(apikey via the key arg; options.headers carries only the user Authorization).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:30:36 +00:00
CC Worker
f3da9f3b59 fix: explicit apikey header + resilient dev-stack seed-count baselines
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
- client.py: set apikey explicitly in _create_base_client headers (Kong needs it
  on every request; for per-user clients apikey stays anon while Authorization
  carries the user JWT). Fixes the 2 stale header unit tests that asserted apikey
  in options.headers, and is robust against supabase-py default-header changes.
- test_dev_stack: exact == seed counts → >= baselines. The greenfield seed sets a
  floor; additive exam-marker fixtures (S4-4 cohort) legitimately push live .94
  counts above the old snapshot. >= still catches a broken/missing seed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:25:39 +00:00
CC Worker
77bb0766ff feat(exam): Neo4j projection on template save + neo4j-sync (S4-7)
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>
2026-06-06 19:02:18 +00:00
CC Worker
98be55ab57 fix(storage): de-double braces in storage.py (set-of-dict crash)
Pre-existing bug (E7): the whole file had doubled braces, so every dict literal
was a set containing a dict -> 'unhashable type: dict' at runtime, and log
f-strings printed literal {braces}. This broke StorageManager.upload_file /
list_bucket_contents / create_bucket / bucket-init for ALL callers (incl.
files.py uploads), not just exam scans. Mechanical de-double; no logic change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 18:46:50 +00:00
CC Worker
c690caa26d feat(exams): cc.public.exams Neo4j graph init + node schemas
- modules/database/schemas/nodes/exams/exam_nodes.py: neontology node classes for
  ExamBoard/Specification/SpecPoint/ExamPaper/Question/Part/Region (uuid_string joins
  to Supabase exam_questions.id / exam_response_areas.id / eb_exams.exam_code).
- run/initialization/init_exam_graph.py: idempotent init — creates the shared public
  cc.public.exams database, 10 uniqueness constraints, and seeds AQA + AQA-PHYS-8463
  (GCSE Physics) with its 8 top-level topic SpecPoints.

Applied + verified on dev Neo4j (192.168.0.209, enterprise): db online, 10 constraints,
AQA-[:PUBLISHES]->AQA-PHYS-8463-[:HAS_SPEC_POINT]->8 points. Full sub-point catalogue is
a later data task. spec_code AQA-PHYS-8463 must match the eb_exams seed (S4-3).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 16:14:56 +00:00
CC Worker
4b296cff74 fix: include school_id in bootstrap profile select query
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
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>
2026-06-03 07:26:30 +00:00
f203f376e9 fix(supabase): remove duplicate apikey header in _create_base_client
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
supabase-py injects apikey internally via create_client(url, key). Manually
setting headers['apikey'] caused PostgREST to log "Duplicate API key found /
JSON could not be generated" on every bootstrap request.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 21:37:10 +00:00
39ad1818ae Merge branch agent/p0-correctness-security
Some checks failed
api-ci-deploy / test-build-deploy (push) Has been cancelled
# Conflicts:
#	modules/database/supabase/utils/client.py
2026-05-28 19:17:22 +01:00
88a3193e01 Keep platform bootstrap permissions additive 2026-05-28 15:10:54 +01:00
4f6634e088 Implement Supabase-first me bootstrap 2026-05-28 14:14:35 +01:00
54760083b5 fix: tighten API P0 auth and route handling 2026-05-28 12:42:42 +01:00
d5bda761d6 fix: enable per-user RLS via SupabaseAnonClient.for_user() and StorageUser(access_token=) 2026-05-27 21:51:58 +01:00
ef75f08392 fix(redis): connect during health checks 2026-05-27 16:50:25 +01:00
035ea17844 fix: prevent platform admin from being auto-enrolled in default school
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>
2026-05-27 04:16:22 +01:00
abf8d05ca1 feat(phase-b): Supabase-first timetable, classes, enrollment, and student views
- timetable_builder_router: Supabase-primary slot write (POST /timetable/slots),
  week_cycle support, GET /slots reads from Supabase, materialize-periods endpoint,
  rebuild-neo4j endpoint, sync-lessons endpoint (Track B: TaughtLesson Neo4j nodes),
  _sync_teacher_timetables_to_neo4j and _sync_taught_lessons_to_neo4j helpers
- classes_router: GET /{class_id} enriched with profiles + enrollment_requests,
  GET /school/students for admin search, PATCH /enrollment-requests/{id} approve/reject
- taught_lessons_router: GET /student/lessons student week view with enrichment
- school_router: academic_periods sync, day-type management
- platform_admin_router + platform_admin: POST /admin/reset and /admin/seed endpoints
- invitations_router: teacher invite scaffolding
- reset_environment + seed_environment: idempotent dev environment scripts
- graph_tree_router: Supabase-first institute resolution
- provisioning_service: neo4j_private_db_name column support
- main.py + run/routers.py: register new routers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 02:55:44 +01:00
fe3d7a12c8 feat(phase-b): school/timetable API routers + graph nav tree
New routers (all previously untracked):
- graph_tree_router: /graph/tree, /graph/node/children, /graph/calendar/academic
  Supabase-driven tree builder; institute DB resolved by teacher email scan
- school_router: /school/status (role + calendar flags), /school/info PATCH
  Self-heals profiles.school_id from institute_memberships if null
- timetable_builder_router: /timetable/setup (AcademicYear/Term/Week + SchoolTimetable),
  /timetable/slots (read/write TimetableSlot nodes), /timetable/init (TeacherTimetable)
- user_init_router: /user/init (provision user node in institute DB)

routers.py: register all new routers with correct prefixes
users.py: add JournalNode and PlannerNode schema classes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 01:24:44 +01:00
84f7fa9de1 fix: cache Neo4j driver failure state to avoid 60s retry on every request
get_global_driver() now sets _driver_unavailable=True when the initial
connection fails, so subsequent calls fail immediately instead of
spending 60s retrying each time. Added reset_global_driver() to allow
manual reconnection after Neo4j comes back up.

Also fixes APP_BOLT_URL in .env: was bolt://bolt.classroomcopilot.ai
(public IP, port not exposed), now bolt://192.168.0.209:7687 (LAN).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 17:26:21 +00:00
36ae76143f Phase 3B: Implement pluggable LLM client for summary generation
- Create llm_client.py with 5 provider implementations (Anthropic, OpenAI, Ollama, OpenRouter, Google)
- Add build_prompt() helper to construct system/user prompts from templates
- Wire up POST /transcribe/sessions/{id}/summaries endpoint to call LLM client
- Return generated content + token counts (input_tokens, output_tokens)
- API keys passed per-request, never stored or logged
- Uses prompt templates from prompts.py based on summary_type
2026-05-20 22:20:19 +00:00
b47c7c252d feat(transcription): add Supabase schema and API endpoints for CIS 2026-05-20 21:03:00 +00:00
Classroom Copilot Dev
2d2c88706e fix: update Supabase env vars with new keys and local URL
- Updated ANON_KEY and SERVICE_ROLE_KEY from supabase container
- Changed SUPABASE_URL to local dev instance (192.168.0.155:8000)
- Synced .env.local with .env for consistency
2026-02-23 03:38:41 +00:00
14030170e7 timing 2025-11-19 20:13:35 +00:00
92dc4ff1ef docker redis checks 2025-11-19 19:34:13 +00:00
3758c7572a latest 2025-11-14 14:47:19 +00:00
2a85845835 Environment methods 2025-08-23 19:01:36 +01:00
e0c489f625 Initial commit 2025-07-11 13:52:19 +00:00