Yamen Ahmad a554ef5d42
Some checks failed
CI / Frontend — lint + build + e2e (pull_request) Has been cancelled
CI / Backend — Odoo HttpCase (pull_request) Has been cancelled
fix(qa): approval queue, rubric UX, structure enforcement, upload/publish limits
Addresses the QA notes on the end-to-end approval flow. Highlights:

Backend
- encoach_ai/generation_submit: create encoach.approval.request on submit so
  submitted exams actually reach the approver queue (previously only the
  workflow id was stored on the exam, leaving approvers with an empty inbox).
  Initial exam status flips to pending_approval instead of draft.
- encoach_exam_template/approval_workflows:
  * /api/approval-users filters out students (user_type='student',
    op_student_id set, share=True) so the approver dropdown only lists staff.
  * _ser_request enriches requests with target_name / target_status and the
    current stage approver for UI badges.
  * list_requests supports mine=1 / requester=1 so approvers only see queue
    items awaiting their action.
  * approve_request / reject_request now transition the underlying
    encoach.exam.custom to published / rejected on final approval.
- encoach.exam.custom.status: add pending_approval and rejected states to
  match the approval workflow transitions.

Frontend UX
- GenerationPage: rubric field shows "Auto-graded — no rubric" for Listening
  and Reading (rubrics only apply to Writing / Speaking). Divider dropdowns
  now carry explicit help text explaining None / Line / Space / Page Break
  and where to write prompts. Selecting an official exam structure
  auto-populates the required tasks/sections/parts, the delete button is
  hidden for essential tasks, and submit is blocked if the user dropped
  below the structure's required count.
- RubricsPage: "Add Criterion" is now a dropdown with IELTS-specific
  presets (Task Achievement, Coherence & Cohesion, Fluency & Coherence, …)
  keyed off the selected skill, plus a "Custom (blank row)" fallback.
- AdminCourses: added tooltips and helper copy clarifying Difficulty vs
  CEFR Level in the Create Course dialog.
- CustomExamCreate: validate the whole form before Save/Publish, surface
  backend error messages (413/504/401) instead of a generic toast, read the
  exam id from the correct response field, and avoid marking Publish as
  failed when only the optional Save-as-Template step errors.
- ResourceManager / TeacherLibrary: upload toast now shows a concrete
  reason (HTTP 413 / 504 / 401) instead of a generic "Upload failed".

Config (504 / 413 / resource upload fixes)
- odoo.conf + odoo-docker.conf: raise limit_time_cpu to 600s,
  limit_time_real to 900s, limit_request to 128 MB, and memory caps so
  /api/exam/generation/submit and multipart resource uploads stop hitting
  504 / 413 during QA.
- frontend/Dockerfile (nginx): add client_max_body_size 128m, bump
  proxy_read_timeout / proxy_send_timeout to 900s, and disable request
  buffering so large AI/resource payloads stream through the proxy.

Made-with: Cursor
2026-04-20 17:14:39 +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 375 MiB
Languages
Python 70.8%
HTML 22.1%
JavaScript 3.9%
SCSS 2.1%
CSS 1.1%