Files
encoach_backend_new_v2/docs/WORK_REPORT.md
Yamen Ahmad 6712d1d551 docs: add WORK_REPORT.md and USER_MANUAL.md
- 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
2026-04-19 14:41:19 +04:00

330 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](#executive-summary)
- [What shipped — by phase](#what-shipped--by-phase)
- [Phase 0 — Platform safety & operations](#phase-0--platform-safety--operations)
- [Phase 1 — Exam correctness & data provenance](#phase-1--exam-correctness--data-provenance)
- [Phase 2 — Performance & observability](#phase-2--performance--observability)
- [Phase 3 — Human-in-the-loop, compliance, i18n, a11y, CI](#phase-3--human-in-the-loop-compliance-i18n-a11y-ci)
- [Branding update](#branding-update)
- [Repository migration](#repository-migration)
- [Commits landed in this sprint](#commits-landed-in-this-sprint)
- [Verification results](#verification-results)
- [Known gaps & deferred items](#known-gaps--deferred-items)
- [Operator checklist for production](#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.
1. **Merged duplicate exam models.** `encoach_scoring` is now the single home
for `encoach.student.attempt` and `encoach.student.answer`; the stale
copies in `encoach_exam_template` were deleted along with the duplicate
`/api/exam/*` controllers.
2. **Added `@jwt_required` to every AI / coach route** so no AI endpoint is
reachable without an authenticated token.
3. **Added health endpoints**
- `GET /api/health` — liveness.
- `GET /api/health/ready` — readiness (DB ping + LLM reachability).
4. **Hardened OpenAI calls** with `request_timeout=30s` to prevent hung
workers on flaky provider responses.
5. **Gated `seed_demo_data.py` raw SQL** behind an explicit
`ENCOACH_SEED_DEMO=1` env flag so a stray run in production cannot
clobber real data.
6. **Fixed `docker-compose.yml`** and shipped `odoo-docker.conf` so the
container-local run works out of the box.
7. **Published `/logo.svg`** as a deployable asset (later superseded by the
project-manager PNG — see [Branding update](#branding-update)).
8. **Promoted a canonical `cefr_mapper`** to `encoach_ai.services.cefr_mapper`
(no more two copies drifting).
9. **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*.
1. **QualityChecker + IeltsValidator wired into exam submit.** Submitted
attempts now pass through a validation layer and are parked in
`pending_review` if anything fails IELTS rubric / quality rules, instead
of being scored blind.
2. **Populated RAG metadata** on every `encoach.vector.embedding` record:
`course_id`, `subject_id`, `entity_id`, and taxonomy tags. Queries can
now be scoped per tenant / per skill.
3. **Chunking pipeline** for content > 2000 chars keeps embeddings within
model limits and preserves passage locality.
4. **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.
5. **Schema validation of LLM output** before DB insert (jsonschema-style).
Malformed JSON no longer reaches storage.
6. **Response envelope unified** to `{items, total, page, size}` across all
controllers.
7. **Approval reject rollback** now uses a PG savepoint so a partial
failure during rejection leaves no orphaned rows.
8. **Ticket notifications** fire on status and assignee change.
9. **`new_project/` retired.** `backend/` is declared canonical;
`new_project/DEPRECATED.md` carries the redirect notice.
### Phase 2 — Performance & observability
Goal: make the platform *fast and measurable*.
1. **Reports use SQL `read_group`** instead of Python loops. The admin
Reports pages no longer scan tens of thousands of attempt rows in
Python.
2. **`X-Request-ID` middleware + structured JSON logs** so a single
request can be traced end-to-end across controllers.
3. **Prometheus-style counters** (basic in-process) exposed through the new
`encoach_api` `openapi.py` controller, which also exports a live
OpenAPI spec by scanning `@http.route` decorators at runtime.
4. **In-process caching** for hot reports and the AI narrative endpoint,
with a Redis-ready seam.
5. **Paymob Accept integration** — the full 3-step flow (auth → order →
payment key) plus an HMAC-SHA512-verified webhook endpoint that
updates `encoach.paymob.order` atomically. Credentials come from
`ir.config_parameter`.
6. **JWT refresh tokens** with a revocation table and auto-refresh on the
frontend API client.
7. **Composite DB indexes** on the hottest report / ticket / attempt paths.
8. **React.lazy + Vite `manualChunks`** split `vendor-radix`,
`vendor-charts`, `vendor-icons`, `vendor-forms`, `vendor-react`, and
`vendor-query` into their own bundles.
9. **Fixed all 181 TypeScript errors.** `npx tsc --noEmit -p
tsconfig.app.json` now passes cleanly.
### Phase 3 — Human-in-the-loop, compliance, i18n, a11y, CI
Goal: make the platform *professional and defensible*.
1. **i18n.** `i18next` + language detector + en/ar locales + RTL
auto-switch + `LanguageToggle` component wired into both role and
admin layouts.
2. **GDPR compliance.** `/api/gdpr/export` returns a JSON snapshot of the
caller's personal data. `/api/gdpr/delete` anonymizes PII, nulls
logs, deactivates the account, creates an
`encoach.gdpr.erasure.request` tombstone, and refuses admin
self-erasure. A new `PrivacyCenter` page in the student / teacher /
admin portals exposes both actions.
3. **Human-in-the-loop exam review.** `pending_review → publish`
workflow, backed by a new `review_workflow.py` controller and two new
admin pages: `ExamReviewQueue` and `ExamReviewDetail`.
4. **AI prompt management.** New `encoach.ai.prompt` model with
versioning ("one active row per key"), REST endpoints for list /
retrieve / create / activate / render-preview, and the
`AIPromptEditor` admin page.
5. **Student AI feedback loop.** `encoach.ai.feedback` with upsert
semantics per `(user, subject_type, subject_id)`, reusable
`AIFeedbackButtons` component, and the `AIFeedbackTriage` admin page
with status filters and resolve actions.
6. **Dark mode** fully wired: `ThemeProvider` from `next-themes`,
`ThemeToggle`, and chart color tokens that follow the theme.
7. **Accessibility.** `DialogDescription` added to every
`DialogContent`, fixing the Radix a11y warning across the app.
8. **CI scaffolding.** `.github/workflows/ci.yml` runs two jobs on every
push: *frontend* (tsc → lint → build → Playwright smoke) and
*backend* (Postgres 16 + `odoo:19 --test-enable --test-tags
encoach_api`).
9. **Onboarding consolidated.** Single root `README.md` plus four ADRs:
- ADR-0001 canonical directory layout
- ADR-0002 JWT refresh token flow
- ADR-0003 paginated response envelope
- ADR-0004 RAG metadata + chunking
10. **Dead code removed.** `ExamPage` marketing, `Index`, `ProfilePage`
import, 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-auto` so the wordmark and tagline are
legible.
- **Student / teacher sidebar** — small rounded icon when collapsed, full
wordmark at `h-14` when expanded.
- **Admin sidebar** — same collapsed / expanded behavior.
- **`og:image` meta** (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:
1. Added the new repo as the `origin` remote.
2. Pushed the current `v4` tip as `main` (default branch).
3. Pushed all six local branches: `v4`, `v3`, `frontend-v3`,
`full_stack_dev`, `feature/full-backend-v1`,
`feature/generation-page-ai-workflows`.
4. Pushed all tags (none existed locally).
5. Rebound `v4` upstream to `origin/v4`.
6. **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.rule` entity isolation + drop blanket `sudo()`.** Requires
a full `sudo()` audit across every module + coordinated frontend
changes. Deferred to a follow-up ticket.
- **AIFeedbackButtons inside `AiStudyCoach`.** The coach's response
currently lacks the `ai_log_id` that 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`, and
`payment.paymob.iframe_id` must be set in `ir.config_parameter`
before 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:
1. **Set Paymob credentials** in `ir.config_parameter`:
- `payment.paymob.api_key`
- `payment.paymob.integration_id`
- `payment.paymob.hmac_secret`
- `payment.paymob.iframe_id`
2. **Set the OpenAI key** in `ir.config_parameter` as `openai.api_key`
(or the matching env var on the container).
3. **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).
4. **Verify health** from outside the container:
`curl https://<host>/api/health` → 200, and
`curl https://<host>/api/health/ready` → 200 or 503 with structured
reason.
5. **Pin the default-branch protection** on
`git.albousalh.com/yamen/full_encoach_platform` (`main`).
6. **Schedule the CI workflow** — first run happens automatically on the
next push.
7. **Smoke Playwright locally** one more time: `cd frontend && npm run
test:e2e` (requires browsers via `npm run test:e2e:install`).