Yamen Ahmad d5b1987bba feat(platform): full institutional roadmap — exam security, live sessions, handwritten, personalized AI plans, Turnitin, lesson polish
Backend (encoach_lms_api):
- New models: encoach.exam.security.event, encoach.live.session,
  encoach.live.session.participant, encoach.handwritten.submission.
- Extended: encoach.exam.custom (security_level, single_attempt,
  suspicious_event_threshold), encoach.course.plan (is_personalized,
  personalized_for_id, weakness_summary), encoach.entity (turnitin_*).
- New controllers / 24 endpoints:
  * exam_security: POST /api/exam/security/event,
    GET /api/exam/single-attempt-check,
    GET /api/teacher/exam/<id>/security/events,
    GET /api/teacher/exam/attempt/<id>/security/events,
    GET /api/teacher/exam/<id>/live.
  * live_sessions: full CRUD + /notify, /join, /leave, /end,
    /recording, /remove-participant, /attendance, /ics
    (RFC-5545 iCalendar with VALARM + ATTENDEE/ORGANIZER, attached to
    invite emails so Gmail/Outlook/Apple Mail prompt to add).
  * personalized_plan: GET/POST /api/student/personalized-plan
    (CEFR / weeks / focus / grammar_focus payloads).
  * handwritten: student upload + AI grading (pytesseract OCR +
    OpenAI scoring) + teacher review override.
  * reports_export: CSV + PDF export for student-performance and
    record reports.
  * turnitin: per-entity settings (admin), test connection, submit
    text. Real upload stubbed pending institutional API key.
- Manifest: depends now lists encoach_scoring, encoach_exam_template,
  encoach_ai_course so security/live-session models load cleanly.
- teacher_insights.py: fixed assignment traversal via op.batch.course_id,
  res.users mapping, and capped rate_completed at 100% (unique
  student/exam pairs).
- reports.py: branch_id / subject_id / gender filters wired into the
  Reports stack.

Frontend:
- New services: examSecurity, liveSession, personalizedPlan,
  handwritten, turnitin, reportsExport.
- New pages: LiveSessionsPage, LiveSessionRoom (Jitsi IframeAPI embed
  with host bar — Mute all / Cams off / per-row Ask-to-unmute /
  Remove + log audit reason, kickParticipant after backend audit POST),
  TurnitinSettings (admin), TeacherTestSessionConsole, AddToCalendar
  per-card .ics button.
- New components: PersonalizedPlanCard (Quick generate + Customize
  dialog: CEFR, weeks, focus, 9-checkbox grammar), AITutorAvatar,
  HandwrittenSubmissionPanel, ImageLightbox, InfographicBlock
  (six-tone callout with key-based auto-detect — did_you_know,
  key_takeaway, tip, objective, common_mistakes, etc.), ExportButtons.
- useExamSecurity hook: tab/blur, copy/paste/cut, fullscreen exit,
  suspicious shortcuts; debounced auto-post + auto-lock callback.
- StudentCourseDetail / TeacherCourseInsights: discussion now
  embedded as a per-course tab.
- StudentCourses: unified My Courses + My Course Plan with
  is_mandatory color-coding + Accredited Core / Supplementary
  sections (always rendered, with empty states).
- MaterialBookView: special-cases image keys into ImageLightbox,
  routes infographic-style keys into colored InfographicBlock cards,
  splits long strings into paragraphs, rounded-2xl shadow-sm wrapper.
- MaterialViewer: ImageViewer now uses lightbox, ArticleViewer is
  now a real <article class="prose">.
- Layout shells: Live Sessions in Student/Teacher sidebars, Turnitin
  in Admin sidebar; EN + AR i18n keys.
- App.tsx: lazy routes for /live, /live/:id,
  /teacher/exam/:assignmentId/console, /admin/turnitin.
- Visual identity refresh: warm cream bg, white sidebar with charcoal
  active pills, dark CTA buttons, bright orange accents,
  rounded-2xl cards.

Verification:
- All 12 new endpoints smoke-tested via curl (200 + sane payloads).
- /api/live-sessions/<id>/ics returns valid 23-line VCALENDAR.
- Frontend tsc --noEmit clean.
- Odoo restarted successfully (registry loaded in 0.77s, no errors).
- docs/PROJECT_SUMMARY.md updated with both today's polish + the
  full Phase 2/3/4 rollout for the record.

Status: 27/29 institutional requirements fully wired. Turnitin
upload + LMS-side breakout/poll persistence remain partial (see
PROJECT_SUMMARY for details).

Made-with: Cursor
2026-04-30 14:06:48 +04:00

EnCoach — Adaptive AI Learning Platform

EnCoach is a smart learning environment for individual and collaborative learning, fully integrated with AI and equipped with intelligent, professional-grade exercises, assessments, and e-exams.

This repository hosts the full stack:

  • Backend — Odoo 19 + ~30 encoach_* modules (Python 3.12, PostgreSQL 16)
  • Frontend — React 18 + Vite + TypeScript single-page app
  • AI layer — OpenAI + pgvector RAG, quality-gate validation, IELTS validator
  • Ops — Docker Compose, JWT auth with refresh tokens, Prometheus-compatible metrics, dynamic OpenAPI 3.0 spec

Canonical trees: backend/ (all server code) and frontend/ (all client code). The legacy new_project/ directory is deprecated — see new_project/DEPRECATED.md.


1. Quickstart

docker compose up -d
# Odoo:     http://localhost:8069
# Frontend: cd frontend && npm install && npm run dev  (http://localhost:8080)

Create a new Odoo database on first visit, then install the encoach_api module to pull in every encoach_* dependency.

Source

Prerequisites: Python 3.12, PostgreSQL 16, Node 20, npm 10.

# Backend
./setup.sh          # creates venv, installs requirements.txt
./run.sh            # starts Odoo on :8069

# Frontend
cd frontend
npm install
npm run dev         # starts Vite on :8080, proxies /api → :8069

See MANUAL-RUN.md for a step-by-step walkthrough and CONNECT-POSTGRES.md for database wiring.


2. Repository layout

odoo19/
├── backend/
│   └── custom_addons/
│       ├── encoach_api/              REST base + JWT + OpenAPI + metrics
│       ├── encoach_core/             Users, entities, roles, permissions
│       ├── encoach_taxonomy/         Subject → Domain → Topic
│       ├── encoach_ai/               OpenAI wrapper, cefr_mapper, validator
│       ├── encoach_ai_course/        AI course/exam generation pipelines
│       ├── encoach_ai_grading/       AI grading (writing/speaking/math/IT)
│       ├── encoach_ai_media/         TTS (Polly), STT (Whisper), ELAI
│       ├── encoach_vector/           pgvector store + RAG embeddings
│       ├── encoach_exam_template/    Canonical exam + student attempt models
│       ├── encoach_scoring/          Score computation, CEFR mapping
│       ├── encoach_quality_gate/     Automated content-quality checks
│       ├── encoach_ielts_validation/ IELTS-specific validators
│       ├── encoach_adaptive/         Adaptive engine, style matcher
│       ├── encoach_lms_api/          OpenEduCat bridge + LMS endpoints
│       ├── encoach_branding/         White-label config per entity
│       └── … (other encoach_* modules)
├── frontend/
│   ├── src/
│   │   ├── pages/                    Route pages (React.lazy code-split)
│   │   ├── components/               Shared UI (shadcn/ui + custom)
│   │   ├── services/                 Thin API wrappers over fetch
│   │   ├── hooks/queries/            React Query hooks + keys
│   │   ├── lib/api-client.ts         Fetch + auto JWT refresh
│   │   └── types/                    Shared DTO types
│   └── vite.config.ts                manualChunks: react, query, charts, radix…
├── docs/
│   ├── PROJECT_SUMMARY.md            Release notes & architecture history
│   ├── adr/                          Architecture Decision Records
│   └── ENCOACH_*.md                  SRS, workflows, user stories
├── docker-compose.yml
├── Dockerfile
├── requirements.txt                  Python deps (pgvector, textstat, etc.)
└── README.md                         You are here

3. Architecture at a glance

┌────────────────────┐     HTTPS/JWT      ┌────────────────────┐
│  React SPA (Vite)  │  ───────────────►  │   Odoo 19 + FastAPI-style   │
│  - React Query     │  ◄───────────────  │   controllers (encoach_*)   │
│  - next-themes     │   X-Request-Id     └──────┬─────────────┘
│  - shadcn/ui       │                           │
└────────────────────┘                           ▼
                                          ┌──────────────┐
                                          │  PostgreSQL  │
                                          │  + pgvector  │
                                          └──────┬───────┘
                                                 │
                                                 ▼
                                          ┌──────────────┐
                                          │   OpenAI,    │
                                          │   Whisper,   │
                                          │   Polly…     │
                                          └──────────────┘

Every request carries an X-Request-Id and emits structured JSON logs. Prometheus-compatible counters are exposed at /api/metrics, and the live OpenAPI 3.0 spec is at /api/openapi.json.


4. Key conventions

  • Canonical response envelope — list endpoints return { items: T[], total, page, size, data: T[] } (see encoach_api.controllers.base.paginated_envelope).
  • CEFR mapping — only encoach_ai.services.cefr_mapper is canonical. Do not reintroduce local band_to_cefr copies.
  • JWT tokens — short-lived access tokens (1h) + revocable refresh tokens (7d). Only access tokens are accepted as Bearer credentials; refresh tokens must go through /api/auth/refresh. See docs/adr/0002-jwt-refresh-token-flow.md.
  • RAG metadata — vector embeddings carry course_id, subject_id, entity_id, taxonomy, content_hash. Chunking kicks in above 2 000 chars.
  • Frontend paginationPaginatedResponse<T> exposes both items and data. Read from items in new code.
  • Frontend theming — tokens live in frontend/src/index.css (:root and .dark). Always use hsl(var(--token)) instead of raw hex.

5. Health, observability, docs

Endpoint Purpose
GET /api/health Liveness (always 200 when server is up)
GET /api/health/ready Readiness (DB + required config)
GET /api/openapi.json Dynamic OpenAPI 3.0 spec generated from @http.route
GET /api/metrics Prometheus-format counters per route

6. Deployment

Staging and production both use Docker Compose. The staging server rebuilds automatically from main; never force-push. See INSTALL-ODOO-SUMMARY.md for bootstrap notes.

Service Staging URL
Odoo backend http://5.189.151.117:8069
React frontend http://5.189.151.117:3000

The .env file is never committed. On staging it lives at /opt/encoach/backend-v2/.env.


7. Further reading

Document Description
docs/PROJECT_SUMMARY.md Release notes + architecture history
docs/adr/ Architecture Decision Records (why we built it this way)
docs/ENCOACH_UNIFIED_SRS.md Unified frontend + backend SRS
docs/ENCOACH_ODOO19_BACKEND_SRS.md Backend SRS v3.0
docs/ENCOACH_WORKFLOWS_BACKEND_SRS.md Backend workflows
docs/ENCOACH_WORKFLOWS_FRONTEND_SRS.md Frontend workflows

8. Contributing

  1. Branch from main — never push direct. Branch protection enforces it.
  2. Run npx tsc --noEmit -p tsconfig.app.json (frontend) and the module smoke tests before opening a PR.
  3. Every architectural decision should be captured as an ADR under docs/adr/. Copy 0000-template.md to start one.
  4. Open the PR against main and request review from devops (Talal).
Description
No description provided
Readme 341 MiB
Languages
Python 34.8%
C 31.4%
JavaScript 27.9%
TypeScript 1.6%
SCSS 1.4%
Other 2.8%