Frontend - i18n: install tailwindcss-rtl, Cairo font, RTL-aware direction in index.css. - Language toggle: localize aria-label / menu label, persist choice, update document dir synchronously. - Sidebar: add `side` prop so the drawer pins to the right in RTL; wire up AdminLmsLayout, RoleLayout (student/teacher) and AppSidebar to pass side = i18n.dir() === 'rtl' ? 'right' : 'left'. - AdminLmsLayout: convert every nav item from hard-coded title to titleKey, translate group labels (incl. the collapsible Training), breadcrumbs, user menu (Profile / Settings / Logout), help button and toggle aria labels; replace physical mr-/right- utilities with logical me-/end-. - AI components (AiTipBanner, AiInsightsPanel, AiAlertBanner, AiSearchBar, AiAssistantDrawer): apply dir="auto" at the container level, localize titles, loading / error / empty states. - Dashboards (admin / student / teacher): wrap numeric values in <bdi>, localize dates via ar-EG, fix flex direction for KPI and assignment cards. - UI primitives (breadcrumb, calendar, carousel, dropdown-menu, menubar, context-menu, pagination, sidebar): flip chevrons in RTL via a scoped CSS rule, swap pl-/pr-/ml-/mr- for ps-/pe-/ms-/me-. - Add logical-direction helpers and bidirectional isolation classes. Locales - Expand en.ts and ar.ts with full `nav`, `sidebarGroup`, `breadcrumb`, `userMenu`, `chrome`, `ai`, and dashboard key sets; keep key parity. API client - `api-client.ts` reads the active language from localStorage/i18n and sends `Accept-Language` on every request so the backend can localize AI output. Backend (encoach_ai) - openai_service: add _LANGUAGE_NAMES, normalize_language, language-aware system prompt injection for every OpenAI call. - coach_service + controllers (coach_controller, ai_controller): thread the requested language from headers / user locale down to OpenAIService. - ai_feedback: fix latent registry error by pointing course_id at op.course instead of the non-existent encoach.course. Other - .gitignore: ignore runtime odoo logs and local caches. 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).