Builds the §24 product on top of the LangGraph runtime from §22:
Phase A (Sources / RAG)
- encoach.course.plan.source model (file | url | text)
- SourceIndexer extracts PDF (pypdf), DOCX (python-docx), HTML, plain
text and embeds chunks via the existing pgvector pipeline scoped to
plan_id, so resources.search only returns the plan's own corpus
- Endpoints: list/create/upload/reindex/delete + plan-scoped retrieval
Phase B (Deliverables)
- services.deliverables.compute_deliverables walks the plan, derives
{planned, generated, ready} per week from material + media state
- GET /api/ai/course-plan/<id>/deliverables drives the new wizard
preview step and the live progress strip on the detail page
Phase C (Multi-modal media)
- encoach.course.plan.media model + MediaService:
audio: AWS Polly (default) or ElevenLabs
image: OpenAI DALL-E 3, capped per plan via system parameter
video: local ffmpeg subprocess (image + audio -> MP4 1280x720)
- Three new agent tools (media.synthesize_audio / generate_image /
compose_video), wired into course_week_materials and a new
course_media_director agent
- Endpoints per material + week-level batch generator
Phase D (Assignments)
- encoach.course.plan.assignment supports mode='batch' (op.batch) or
mode='students' (res.users), with due_date + message + state
- REST endpoints to list / create / delete assignments
Phase E (Student view)
- /api/student/course-plans + /api/student/course-plans/<id>
enforce visibility via assignment.expand_user_ids()
- New /student/course-plans list + read-only drilldown rendering
audio/image/video tiles from /web/content/<attachment_id>
Cross-cutting
- encoach.ai.tool.category: + media (so the new tools register)
- encoach.embedding gains a plan_id filter for plan-scoped RAG
- Wizard adds Sources + Multimedia steps; AdminCoursePlanDetail
rewritten with DeliverablesStrip + SourcesCard + AssignmentsCard +
per-material MediaDrawer
- ~280 new EN + AR i18n keys (full RTL coverage)
- smoke_course_plan.py exercises every phase via odoo-bin shell;
last run: PASS A/B/D/E + DALL-E 3 image (753 KB), Polly audio
fails cleanly when AWS creds aren't configured (expected)
Documentation: §24 added to docs/PROJECT_SUMMARY.md with phase-by-phase
artefact list, endpoints, smoke test, ops notes, and gotchas.
Made-with: Cursor
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) andfrontend/(all client code). The legacynew_project/directory is deprecated — seenew_project/DEPRECATED.md.
1. Quickstart
Docker (recommended)
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[] }(seeencoach_api.controllers.base.paginated_envelope). - CEFR mapping — only
encoach_ai.services.cefr_mapperis canonical. Do not reintroduce localband_to_cefrcopies. - JWT tokens — short-lived access tokens (1h) + revocable refresh tokens
(7d). Only
accesstokens are accepted as Bearer credentials; refresh tokens must go through/api/auth/refresh. Seedocs/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 pagination —
PaginatedResponse<T>exposes bothitemsanddata. Read fromitemsin new code. - Frontend theming — tokens live in
frontend/src/index.css(:rootand.dark). Always usehsl(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
- Branch from
main— never push direct. Branch protection enforces it. - Run
npx tsc --noEmit -p tsconfig.app.json(frontend) and the module smoke tests before opening a PR. - Every architectural decision should be captured as an ADR under
docs/adr/. Copy0000-template.mdto start one. - Open the PR against
mainand request review from devops (Talal).