- docs/WORK_REPORT.md: recap of the Phase 0/1/2/3 hardening sprint — what shipped per phase, branding update, repo migration to the new full_encoach_platform repo, per-commit file-churn, verification results (tsc, build, Playwright), known gaps, and an operator checklist for production promotion. - docs/USER_MANUAL.md: end-user guide for every role (Student, Teacher, Admin, Corporate, Agent, Developer). Walks through every portal URL, the AI coach / IELTS / adaptive flows, human-in-the-loop exam review, AI prompt editor, feedback triage, GDPR Privacy Center, language + theme toggles, and troubleshooting. Made-with: Cursor
17 KiB
EnCoach — Work Report
Period covered: Recent hardening & delivery sprint (Phases 0 → 3 of the
improvement roadmap).
Repository of record: https://git.albousalh.com/yamen/full_encoach_platform
Primary branch: main (= current v4 tip, commit 93c530ee).
This report summarizes what was built, fixed, and documented in the last few days. It's organized by phase so each block maps 1:1 to the roadmap items and the commits that shipped them.
Table of contents
- Executive summary
- What shipped — by phase
- Branding update
- Repository migration
- Commits landed in this sprint
- Verification results
- Known gaps & deferred items
- Operator checklist for production
Executive summary
| Area | Before | After |
|---|---|---|
| Duplicate exam models | Two student.attempt models in two modules |
Single canonical encoach.student.attempt in encoach_scoring |
| Auth on AI routes | Public in places | @jwt_required on every AI / coach endpoint |
| Health check | None | GET /api/health + GET /api/health/ready (DB + LLM probes) |
| LLM resilience | Hangs possible | request_timeout=30s on OpenAI calls |
| Exam submit | Straight to graded | QualityChecker + IeltsValidator → pending_review gate |
| RAG metadata | Missing entity/course/subject | Full provenance on every embedding + chunking for large passages |
| Question provenance | Anonymous | model, prompt_hash, log_id stamped on every encoach.question |
| LLM output validation | Raw JSON hope-for-the-best | Schema validation before DB insert |
| Response envelope | Inconsistent across controllers | {items,total,page,size} everywhere |
| Reports | Python loops over thousands of rows | SQL read_group aggregates |
| Payments | Mocked Paymob | Real Accept flow + HMAC-SHA512 webhook verification |
| JWT | Single access token only | Refresh tokens + revocation table |
| Frontend bundle | Monolithic | React.lazy + Vite manualChunks (radix/charts/icons/forms split) |
| TypeScript errors | 181 | 0 |
| i18n | Hard-coded English | i18next + en/ar locales + RTL auto-switch + LanguageToggle |
| Exam review | No human review step | pending_review → publish workflow + admin UI |
| AI prompts | Buried in Python constants | encoach.ai.prompt versioned templates + admin editor + render preview |
| Student feedback on AI | None | Thumbs up/down → encoach.ai.feedback + admin triage |
| GDPR | None | /api/gdpr/export + /api/gdpr/delete + Privacy Center page |
| Dark mode | Partial | Full ThemeProvider + toggle + chart tokens |
| Accessibility | Dialog warnings | DialogDescription on every DialogContent |
| CI | None | GitHub Actions: frontend (tsc, lint, build, Playwright) + backend Odoo |
| Documentation | Scattered | §21 Hardening Release in PROJECT_SUMMARY.md + 4 ADRs |
What shipped — by phase
Phase 0 — Platform safety & operations
Goal: make the platform safe to run before adding features.
- Merged duplicate exam models.
encoach_scoringis now the single home forencoach.student.attemptandencoach.student.answer; the stale copies inencoach_exam_templatewere deleted along with the duplicate/api/exam/*controllers. - Added
@jwt_requiredto every AI / coach route so no AI endpoint is reachable without an authenticated token. - Added health endpoints
GET /api/health— liveness.GET /api/health/ready— readiness (DB ping + LLM reachability).
- Hardened OpenAI calls with
request_timeout=30sto prevent hung workers on flaky provider responses. - Gated
seed_demo_data.pyraw SQL behind an explicitENCOACH_SEED_DEMO=1env flag so a stray run in production cannot clobber real data. - Fixed
docker-compose.ymland shippedodoo-docker.confso the container-local run works out of the box. - Published
/logo.svgas a deployable asset (later superseded by the project-manager PNG — see Branding update). - Promoted a canonical
cefr_mappertoencoach_ai.services.cefr_mapper(no more two copies drifting). - JWT cache TTL = 30s with an invalidation hook on user mutations so role/entity changes propagate within half a minute.
Phase 1 — Exam correctness & data provenance
Goal: make every AI-generated item trustworthy and traceable.
- QualityChecker + IeltsValidator wired into exam submit. Submitted
attempts now pass through a validation layer and are parked in
pending_reviewif anything fails IELTS rubric / quality rules, instead of being scored blind. - Populated RAG metadata on every
encoach.vector.embeddingrecord:course_id,subject_id,entity_id, and taxonomy tags. Queries can now be scoped per tenant / per skill. - Chunking pipeline for content > 2000 chars keeps embeddings within model limits and preserves passage locality.
- Provenance fields on
encoach.question:ai_model,prompt_hash,log_id— so any item can be traced back to the exact prompt + run that produced it. - Schema validation of LLM output before DB insert (jsonschema-style). Malformed JSON no longer reaches storage.
- Response envelope unified to
{items, total, page, size}across all controllers. - Approval reject rollback now uses a PG savepoint so a partial failure during rejection leaves no orphaned rows.
- Ticket notifications fire on status and assignee change.
new_project/retired.backend/is declared canonical;new_project/DEPRECATED.mdcarries the redirect notice.
Phase 2 — Performance & observability
Goal: make the platform fast and measurable.
- Reports use SQL
read_groupinstead of Python loops. The admin Reports pages no longer scan tens of thousands of attempt rows in Python. X-Request-IDmiddleware + structured JSON logs so a single request can be traced end-to-end across controllers.- Prometheus-style counters (basic in-process) exposed through the new
encoach_apiopenapi.pycontroller, which also exports a live OpenAPI spec by scanning@http.routedecorators at runtime. - In-process caching for hot reports and the AI narrative endpoint, with a Redis-ready seam.
- Paymob Accept integration — the full 3-step flow (auth → order →
payment key) plus an HMAC-SHA512-verified webhook endpoint that
updates
encoach.paymob.orderatomically. Credentials come fromir.config_parameter. - JWT refresh tokens with a revocation table and auto-refresh on the frontend API client.
- Composite DB indexes on the hottest report / ticket / attempt paths.
- React.lazy + Vite
manualChunkssplitvendor-radix,vendor-charts,vendor-icons,vendor-forms,vendor-react, andvendor-queryinto their own bundles. - Fixed all 181 TypeScript errors.
npx tsc --noEmit -p tsconfig.app.jsonnow passes cleanly.
Phase 3 — Human-in-the-loop, compliance, i18n, a11y, CI
Goal: make the platform professional and defensible.
- i18n.
i18next+ language detector + en/ar locales + RTL auto-switch +LanguageTogglecomponent wired into both role and admin layouts. - GDPR compliance.
/api/gdpr/exportreturns a JSON snapshot of the caller's personal data./api/gdpr/deleteanonymizes PII, nulls logs, deactivates the account, creates anencoach.gdpr.erasure.requesttombstone, and refuses admin self-erasure. A newPrivacyCenterpage in the student / teacher / admin portals exposes both actions. - Human-in-the-loop exam review.
pending_review → publishworkflow, backed by a newreview_workflow.pycontroller and two new admin pages:ExamReviewQueueandExamReviewDetail. - AI prompt management. New
encoach.ai.promptmodel with versioning ("one active row per key"), REST endpoints for list / retrieve / create / activate / render-preview, and theAIPromptEditoradmin page. - Student AI feedback loop.
encoach.ai.feedbackwith upsert semantics per(user, subject_type, subject_id), reusableAIFeedbackButtonscomponent, and theAIFeedbackTriageadmin page with status filters and resolve actions. - Dark mode fully wired:
ThemeProviderfromnext-themes,ThemeToggle, and chart color tokens that follow the theme. - Accessibility.
DialogDescriptionadded to everyDialogContent, fixing the Radix a11y warning across the app. - CI scaffolding.
.github/workflows/ci.ymlruns two jobs on every push: frontend (tsc → lint → build → Playwright smoke) and backend (Postgres 16 +odoo:19 --test-enable --test-tags encoach_api). - Onboarding consolidated. Single root
README.mdplus four ADRs:- ADR-0001 canonical directory layout
- ADR-0002 JWT refresh token flow
- ADR-0003 paginated response envelope
- ADR-0004 RAG metadata + chunking
- Dead code removed.
ExamPagemarketing,Index,ProfilePageimport, and other legacy routes excised.
Branding update
The project-manager-supplied EnCoach logo (icon + wordmark + tagline
"Unlock your potential with AI powered platform") now appears across:
- Login page — shown at
h-36 w-autoso the wordmark and tagline are legible. - Student / teacher sidebar — small rounded icon when collapsed, full
wordmark at
h-14when expanded. - Admin sidebar — same collapsed / expanded behavior.
og:imagemeta (social cards) — already pointed at/logo-icon.png, so it picks up the new asset automatically.
The duplicated inline <span>EnCoach</span> text was removed from every
sidebar since the wordmark is now baked into the image.
Commit: 47d09a3c chore(branding): adopt project-manager EnCoach logo across login and sidebars.
Repository migration
To consolidate the codebase into a single canonical repo for future work, the entire monorepo was migrated to:
https://git.albousalh.com/yamen/full_encoach_platform
Migration steps performed:
- Added the new repo as the
originremote. - Pushed the current
v4tip asmain(default branch). - Pushed all six local branches:
v4,v3,frontend-v3,full_stack_dev,feature/full-backend-v1,feature/generation-page-ai-workflows. - Pushed all tags (none existed locally).
- Rebound
v4upstream toorigin/v4. - Removed all seven prior remotes from
.git/config:backend-v3,frontend,frontend-v3,ip-origin,mirror-monorepo,origin-backend,origin-frontend.
The local checkout now has exactly one remote — origin → the new URL —
so any future git push / git pull goes there with no further config.
Commits landed in this sprint
93c530ee chore(ci,docs): GitHub Actions, ADRs, README overhaul, §21 Hardening Release
e70a2854 feat(frontend): Phase 2/3 hardening release
dcf5ea69 feat(backend): Phase 2/3 hardening release
47d09a3c chore(branding): adopt project-manager EnCoach logo across login and sidebars
c016a522 feat(reports): replace mock Reports pages with real backend aggregates
d940db07 fix(config): align Configuration pages with platform logic
7f23127e chore(remotes,docs): rename remotes to match source-of-truth doctrine
7737f6de docs(summary): declare encoach_backend_v4 + encoach_frontend_v4 as repos of record
File-churn totals for the four hardening commits:
| Commit | Files changed | Lines + | Lines − |
|---|---|---|---|
| branding (logo) | 4 | +42 | −18 |
| backend hardening | 70 | +4 221 | −716 |
| frontend hardening | 75 | +3 722 | −546 |
| CI + docs + ADRs | 10 | +740 | −96 |
Verification results
Ran before each commit and again after the final commit:
| Check | Result |
|---|---|
python -m compileall backend/custom_addons/encoach_* |
Pass, no syntax errors |
npx tsc --noEmit -p tsconfig.app.json |
Pass (0 errors, down from 181) |
npm run build |
Pass — 3.63 s, bundles split as expected |
python -m compileall seed_demo_data.py |
Pass |
Playwright smoke (test:e2e) |
2 / 2 tests pass (login renders, root→/login) |
Frontend bundle profile after manualChunks:
vendor-charts 422.80 kB │ gzip: 112.73 kB
vendor-radix 318.60 kB │ gzip: 99.50 kB
index (app shell) 219.02 kB │ gzip: 65.36 kB
vendor-forms 88.31 kB │ gzip: 24.40 kB
vendor-icons 53.77 kB │ gzip: 9.83 kB
vendor-query 41.17 kB │ gzip: 12.23 kB
vendor-react 23.33 kB │ gzip: 8.60 kB
Known gaps & deferred items
These were intentionally not addressed in this sprint to keep scope bounded. Each has a clear next owner / next step.
- P1.2 —
ir.ruleentity isolation + drop blanketsudo(). Requires a fullsudo()audit across every module + coordinated frontend changes. Deferred to a follow-up ticket. - AIFeedbackButtons inside
AiStudyCoach. The coach's response currently lacks theai_log_idthat the feedback model keys on. The reusable component ships, but wiring it into the coach is gated on a small service change. - Redis cache backend. The in-process cache ships; wiring it to Redis is a config + deployment-time step and was deferred.
- Paymob credentials.
payment.paymob.api_key,payment.paymob.integration_id,payment.paymob.hmac_secret, andpayment.paymob.iframe_idmust be set inir.config_parameterbefore checkout works. Left unset on purpose — no secrets in git. - Arabic translation coverage. Core UI (nav, auth, privacy, feedback, theme, common) is translated; deeper exam-builder strings still fall through to English.
Operator checklist for production
Before promoting to production, an operator should:
- Set Paymob credentials in
ir.config_parameter:payment.paymob.api_keypayment.paymob.integration_idpayment.paymob.hmac_secretpayment.paymob.iframe_id
- Set the OpenAI key in
ir.config_parameterasopenai.api_key(or the matching env var on the container). - Run migrations for the new modules / models:
encoach.ai.prompt,encoach.ai.feedback,encoach.gdpr.erasure.request,encoach.paymob.order,encoach.jwt.token(refresh revocation). - Verify health from outside the container:
curl https://<host>/api/health→ 200, andcurl https://<host>/api/health/ready→ 200 or 503 with structured reason. - Pin the default-branch protection on
git.albousalh.com/yamen/full_encoach_platform(main). - Schedule the CI workflow — first run happens automatically on the next push.
- Smoke Playwright locally one more time:
cd frontend && npm run test:e2e(requires browsers vianpm run test:e2e:install).