Files
encoach_frontend_new_v3/docs/ODOO_MIGRATION_FRONTEND_SRS.md
Yamen Ahmad 88a385ed07 feat: initial frontend codebase — EnCoach v3
React 18 + TypeScript + Vite 5 + Tailwind CSS + shadcn/ui frontend:
- Multi-role auth: student, teacher, admin, corporate, agent, developer
- Student portal: dashboard, courses, adaptive learning, exams, placement
- Teacher portal: courses, assignments, grading, attendance, AI workbench
- Admin portal: 60+ management pages (LMS, exams, users, entities, AI)
- AI-powered features: study coach, generation page, gap analysis, TTS
- Exam system: session, auto-save, results, grading queue
- Full IELTS workflow: reading/listening/writing/speaking modules

Made-with: Cursor
2026-04-11 15:47:32 +04:00

37 KiB

EnCoach Frontend API Migration SRS

SUPERSEDED -- This document has been replaced by ENCOACH_UNIFIED_SRS.md (v2.0). The migration is complete. The old ielts-ui Next.js frontend has been replaced by encoach_frontend_new_v2 (React 18 + Vite + TypeScript), deployed at http://5.189.151.117:3000.

ielts-ui Migration Guide: Next.js API Routes to Odoo 19

Version: 1.0 Date: March 11, 2026 Status: Active SUPERSEDED Audience: Frontend developer(s) maintaining ielts-ui Companion document: ODOO_MIGRATION_SRS.md (backend Odoo specification)


Table of Contents

  1. Migration Overview
  2. Authentication Migration
  3. API Base URL Change
  4. Endpoint-by-Endpoint Migration Map
  5. SSR Migration Strategy
  6. Files to Delete
  7. Migration Checklist

1. Migration Overview

1.1 What Is Changing

The ielts-ui Next.js application currently serves two roles:

  1. Browser UI -- React pages, components, Zustand stores, hooks
  2. BFF (Backend-for-Frontend) -- 108 API route files in src/pages/api/ that query MongoDB directly, manage iron-session cookies, and proxy AI requests

After migration, ielts-ui serves only the Browser UI. All backend logic moves to Odoo 19. The src/pages/api/ directory and all server-side database utilities are eliminated entirely.

1.2 Current Architecture (what the frontend sees)

Browser (React)
  │
  ├── axios/SWR/fetch calls to /api/* (same origin)
  │
  └── Next.js API Routes (src/pages/api/)
        ├── iron-session cookie auth
        ├── MongoDB queries (via src/utils/*.be.ts)
        └── Proxy to AI backend (via BACKEND_URL)

1.3 Target Architecture (what the frontend sees)

Browser (React)
  │
  ├── axios/SWR/fetch calls to ODOO_URL/api/* (cross-origin)
  │     └── Authorization: Bearer <JWT>
  │
  └── Odoo 19 (separate service)
        ├── JWT auth
        ├── PostgreSQL (replaces MongoDB)
        └── All AI/ML handled internally by Odoo

1.4 What Does NOT Change

  • All React page components, layouts, and UI rendering
  • Zustand stores (src/stores/exam/, src/stores/preferencesStore.ts, etc.)
  • All components in src/components/ (they still call the same API shapes -- only the base URL and auth mechanism change)
  • Styling (Tailwind, DaisyUI)
  • TypeScript interfaces in src/interfaces/
  • Client-side routing
  • Strapi CMS and the landing page

1.5 Guiding Principle

Odoo's REST API is designed to return the same JSON shapes the frontend currently expects. If the frontend calls GET /api/users/list and expects { users: [...], total: N }, Odoo's GET /api/users/list returns the same shape. The migration is primarily a transport change (base URL + auth header), not a data format change.


2. Authentication Migration

This is the most significant structural change.

2.1 Current Auth Pattern

Aspect Current Implementation
Identity provider Firebase Auth (signInWithEmailAndPassword)
Session iron-session (encrypted httpOnly cookie named eCrop/ielts)
Client auth Automatic -- browser sends cookie on same-origin requests
SSR auth withIronSessionSsr + getServerSideProps reads req.session.user
User hook useUser() calls GET /api/user via SWR; cookie sent automatically
Config src/lib/session.ts (SECRET_COOKIE_PASSWORD, cookieName)

2.2 Target Auth Pattern

Aspect Target Implementation
Identity provider Odoo 19 native auth (res.users)
Session JWT token issued by Odoo
Client auth Authorization: Bearer <token> header on every request
SSR auth JWT stored in httpOnly cookie; getServerSideProps reads cookie and calls Odoo
User hook useUser() calls GET ODOO_URL/api/user with JWT header
Config NEXT_PUBLIC_API_URL env var

2.3 New Auth Infrastructure

Create a new file src/lib/api.ts:

import axios from "axios";

const api = axios.create({
  baseURL: process.env.NEXT_PUBLIC_API_URL,
  withCredentials: true,
});

api.interceptors.request.use((config) => {
  const token = getToken();
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      clearToken();
      if (typeof window !== "undefined") {
        window.location.href = "/login";
      }
    }
    return Promise.reject(error);
  }
);

export default api;

JWT storage helpers (also in src/lib/api.ts or a separate src/lib/auth.ts):

import Cookies from "js-cookie";

const TOKEN_KEY = "encoach_token";

export function setToken(token: string) {
  Cookies.set(TOKEN_KEY, token, { secure: true, sameSite: "lax" });
}

export function getToken(): string | undefined {
  return Cookies.get(TOKEN_KEY);
}

export function clearToken() {
  Cookies.remove(TOKEN_KEY);
}

Note: Using a cookie for JWT storage (rather than localStorage) is recommended because getServerSideProps can read cookies from the request headers, enabling SSR auth. The cookie is NOT httpOnly in this approach (so JS can read it for the axios interceptor). If httpOnly is required, use a thin proxy or Next.js middleware to inject the header.

2.4 Files That Change for Auth

File Current Target
src/pages/login.tsx axios.post("/api/login", { email, password }) api.post("/api/login", { email, password }) -- store JWT from response
src/pages/register.tsx fetch to /api/register (SSR) + code lookup api.post("/api/register", payload) -- store JWT from response
src/pages/official-exam.tsx axios.post("/api/logout") api.post("/api/logout") + clearToken()
src/components/Sidebar.tsx axios.post("/api/logout") api.post("/api/logout") + clearToken()
src/components/MobileMenu.tsx axios.post("/api/logout") api.post("/api/logout") + clearToken()
src/utils/email.ts axios.post("/api/reset/sendVerification") api.post("/api/reset/sendVerification")
src/hooks/useUser.tsx SWR fetcher uses axios.get("/api/user") SWR fetcher uses api.get("/api/user")
src/lib/session.ts iron-session config DELETE -- replaced by src/lib/api.ts

2.5 Login Flow Change

Current:

  1. User submits email + password
  2. POST /api/login (same origin)
  3. API route calls Firebase Auth, looks up user in MongoDB, saves to iron-session
  4. Response: user JSON + Set-Cookie header
  5. mutateUser(response.data) updates SWR cache

Target:

  1. User submits email + password
  2. POST ODOO_URL/api/login (cross-origin)
  3. Odoo validates credentials, returns { user: {...}, token: "jwt..." }
  4. Frontend stores JWT via setToken(response.data.token)
  5. mutateUser(response.data.user) updates SWR cache

Login page change (src/pages/login.tsx):

// BEFORE
const response = await axios.post("/api/login", { email, password });
mutateUser(response.data);

// AFTER
import api, { setToken } from "@/lib/api";
const response = await api.post("/api/login", { email, password });
setToken(response.data.token);
mutateUser(response.data.user);

2.6 Logout Flow Change

Current: POST /api/logout destroys iron-session.

Target: POST ODOO_URL/api/logout (optional server-side invalidation) + clearToken() client-side.

// BEFORE
await axios.post("/api/logout");
mutateUser(null);
router.push("/login");

// AFTER
import api, { clearToken } from "@/lib/api";
await api.post("/api/logout").catch(() => {});
clearToken();
mutateUser(null);
router.push("/login");

3. API Base URL Change

3.1 Environment Variable

Add to .env.local:

NEXT_PUBLIC_API_URL=https://api.encoach.com

Development:

NEXT_PUBLIC_API_URL=http://localhost:8069

3.2 Shared Axios Instance

Replace all direct axios imports with the shared api instance from src/lib/api.ts (defined in Section 2.3).

Search and replace pattern across the codebase:

// BEFORE (scattered across ~40 files)
import axios from "axios";
axios.get("/api/...");
axios.post("/api/...");
axios.patch("/api/...");
axios.delete("/api/...");

// AFTER
import api from "@/lib/api";
api.get("/api/...");
api.post("/api/...");
api.patch("/api/...");
api.delete("/api/...");

The /api/... path stays the same -- the baseURL on the axios instance prepends the Odoo host.

3.3 SWR Fetcher Update

Update src/hooks/useUser.tsx:

// BEFORE
const fetcher = (url: string) => axios.get(url).then((res) => res.data);

// AFTER
import api from "@/lib/api";
const fetcher = (url: string) => api.get(url).then((res) => res.data);

3.4 fetch() Calls

A few files use fetch() instead of axios (primarily src/components/ExamEditor/ImportExam/WordUploader.tsx). These also need the base URL and auth header:

// BEFORE
const res = await fetch(`/api/exam/${module}/import/`, { method: "POST", body: formData });

// AFTER
import { getToken } from "@/lib/api";
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/exam/${module}/import/`, {
  method: "POST",
  body: formData,
  headers: { Authorization: `Bearer ${getToken()}` },
});

Note: fetch() calls to blob URLs (e.g., fetch(blobUrl) for audio/video previews) do NOT change. Only calls to /api/* endpoints change.


4. Endpoint-by-Endpoint Migration Map

For each API call the frontend makes, this section specifies the current URL, new Odoo URL, HTTP method, and every file that makes the call.

Convention: Where the Odoo URL is the same path as the current URL (just different host), only the base URL changes. These are marked "Path unchanged." Where the Odoo URL differs, the new path is shown.

4.1 Auth

# Method Current URL Odoo URL Files
1 POST /api/login Path unchanged src/pages/login.tsx
2 POST /api/logout Path unchanged src/pages/official-exam.tsx, src/components/Sidebar.tsx, src/components/MobileMenu.tsx
3 POST /api/reset Path unchanged src/pages/login.tsx
4 POST /api/reset/sendVerification Path unchanged src/utils/email.ts

Response change for login: Odoo returns { user: {...}, token: "jwt..." } instead of just the user object. Frontend must extract and store the token.

4.2 User

# Method Current URL Odoo URL Files
5 GET /api/user Path unchanged src/hooks/useUser.tsx (SWR)
6 DELETE /api/user Path unchanged (called from useUser context)
7 POST /api/users/update PATCH /api/users/update src/pages/profile.tsx, src/components/UserCard.tsx
8 GET /api/users/list Path unchanged src/utils/groups.ts
9 GET /api/users/{id} Path unchanged src/utils/groups.ts
10 POST /api/users/controller Path unchanged src/components/Imports/StudentClassroomTransfer.tsx
11 GET /api/users/balance Path unchanged src/hooks/useUserBalance.tsx (if used)

Note on #7: The current frontend uses POST for user updates. Odoo convention is PATCH. Either Odoo can accept both, or the frontend changes the method.

4.3 Registration / Codes

# Method Current URL Odoo URL Files
12 POST /api/register Path unchanged src/pages/register.tsx (SSR currently; move to client-side)
13 GET /api/code/{code} Path unchanged src/pages/register.tsx

Note on #12: Registration is currently handled in getServerSideProps. With Odoo, move registration to a client-side form submission. The register page should call api.post("/api/register", payload) and store the returned JWT.

4.4 Exams

# Method Current URL Odoo URL Files
14 GET /api/exam Path unchanged src/hooks/useExams.tsx
15 GET /api/exam/{module}?{params} Path unchanged src/utils/exams.ts (getExam)
16 GET /api/exam/{module}/{id} Path unchanged src/utils/exams.ts (getExamById)
17 POST /api/exam/{module} Path unchanged src/components/ExamEditor/SettingsEditor/reading/index.tsx, writing/index.tsx, listening/index.tsx, speaking/index.tsx, level.tsx
18 PATCH /api/exam/{module}/{id} Path unchanged src/pages/(admin)/Lists/ExamList.tsx, src/pages/approval-workflows/[id]/index.tsx
19 DELETE /api/exam/{module}/{id} Path unchanged src/pages/(admin)/Lists/ExamList.tsx
20 GET /api/exam/avatars Path unchanged src/pages/generation.tsx
21 GET/POST /api/exam/generate/{module}/{sectionId} Path unchanged src/components/ExamEditor/SettingsEditor/Shared/Generate.ts
22 POST /api/exam/media/speaking Path unchanged src/components/ExamEditor/SettingsEditor/Shared/generateVideos.ts
23 POST /api/exam/media/listening Path unchanged src/components/ExamEditor/SettingsEditor/listening/components.tsx
24 POST /api/exam/media/instructions Path unchanged src/components/ExamEditor/Standalone/ListeningInstructions/index.tsx
25 POST /api/exam/{module}/import/ Path unchanged src/components/ExamEditor/ImportExam/WordUploader.tsx (uses fetch)

4.5 Evaluation / Grading

# Method Current URL Odoo URL Files
26 POST /api/evaluate/writing Path unchanged src/utils/evaluation.ts
27 POST /api/evaluate/speaking Path unchanged src/utils/evaluation.ts
28 POST /api/evaluate/interactiveSpeaking Path unchanged src/utils/evaluation.ts
29 GET /api/evaluate/status?... Path unchanged src/utils/evaluation.ts (polling)
30 GET /api/evaluate/fetchSolutions?... Path unchanged src/utils/evaluation.ts
31 POST /api/grading Path unchanged src/pages/api/grading/index.ts (if called by frontend)
32 POST /api/grading/multiple Path unchanged (if called by frontend)

4.6 Storage

# Method Current URL Odoo URL Files
33 POST /api/storage Path unchanged src/components/ExamEditor/SettingsEditor/writing/index.tsx, speaking/index.tsx, listening/index.tsx, level.tsx
34 POST /api/storage/delete DELETE /api/storage/{id} (or keep POST) src/utils/evaluation.ts

Note: Odoo will use ir.attachment for file storage. The response must return a publicly accessible URL for the uploaded file, matching the current behavior.

4.7 Speaking Audio

# Method Current URL Odoo URL Files
35 POST /api/speaking Path unchanged src/components/Solutions/Speaking.tsx, src/components/Solutions/InteractiveSpeaking.tsx

4.8 Sessions

# Method Current URL Odoo URL Files
36 POST /api/sessions Path unchanged src/stores/exam/index.ts (Zustand saveSession)
37 DELETE /api/sessions/{id} Path unchanged src/components/Medium/SessionCard.tsx

4.9 Stats

# Method Current URL Odoo URL Files
38 POST /api/stats Path unchanged src/stores/exam/index.ts (Zustand saveStats)
39 GET /api/stats/{id} Path unchanged src/pages/training/[id]/index.tsx
40 POST /api/statistical Path unchanged src/pages/statistical.tsx

4.10 Training

# Method Current URL Odoo URL Files
41 POST /api/training Path unchanged src/pages/training/index.tsx
42 GET /api/training/{id} Path unchanged src/pages/training/[id]/index.tsx
43 GET /api/training/walkthrough Path unchanged src/pages/training/[id]/index.tsx

4.11 Groups

# Method Current URL Odoo URL Files
44 GET /api/groups?participant={userId} Path unchanged src/utils/groups.ts
45 POST /api/groups Path unchanged src/pages/classrooms/create.tsx
46 PATCH /api/groups/{id} Path unchanged src/pages/classrooms/[id].tsx
47 DELETE /api/groups/{id} Path unchanged src/pages/classrooms/[id].tsx

4.12 Entities

# Method Current URL Odoo URL Files
48 POST /api/entities Path unchanged src/pages/entities/create.tsx
49 PATCH /api/entities/{id} Path unchanged src/pages/entities/[id]/index.tsx
50 DELETE /api/entities/{id} Path unchanged src/pages/entities/[id]/index.tsx
51 PATCH /api/entities/{id}/users Path unchanged src/pages/entities/[id]/index.tsx

4.13 Roles

# Method Current URL Odoo URL Files
52 POST /api/roles Path unchanged src/pages/entities/[id]/roles/index.tsx
53 PATCH /api/roles/{id} Path unchanged src/pages/entities/[id]/roles/[role].tsx
54 DELETE /api/roles/{id} Path unchanged src/pages/entities/[id]/roles/[role].tsx
55 POST /api/roles/{id}/users Path unchanged src/pages/entities/[id]/index.tsx

4.14 Permissions

# Method Current URL Odoo URL Files
56 PATCH /api/permissions/{id} Path unchanged src/pages/permissions/[id].tsx

4.15 Payments

# Method Current URL Odoo URL Files
57 POST /api/payments Path unchanged src/pages/payment-record.tsx
58 PATCH /api/payments/{id} Path unchanged src/pages/payment-record.tsx
59 DELETE /api/payments/{id} Path unchanged src/pages/payment-record.tsx
60 GET/POST/DELETE /api/payments/files/{type}/{paymentId} Path unchanged src/components/PaymentAssetManager.tsx
61 POST /api/paymob Path unchanged src/components/PaymobPayment.tsx

Bug fix opportunity: In src/pages/payment-record.tsx, the PATCH call uses api/payments/${id} without a leading /. When switching to the shared axios instance with a baseURL, this will work correctly. But verify during testing.

4.16 Assignments

# Method Current URL Odoo URL Files
62 POST /api/assignments Path unchanged src/pages/assignments/creator/index.tsx
63 PATCH /api/assignments/{id} Path unchanged src/pages/assignments/creator/[id].tsx, src/pages/assignments/[id].tsx
64 DELETE /api/assignments/{id} Path unchanged src/pages/assignments/creator/[id].tsx, src/pages/assignments/[id].tsx
65 POST /api/assignments/{id}/start Path unchanged src/pages/assignments/creator/[id].tsx, src/pages/assignments/[id].tsx

4.17 Invites

# Method Current URL Odoo URL Files
66 GET /api/invites/{decision}/{id} POST /api/invites/{decision}/{id} src/components/Medium/InviteCard.tsx, src/components/Medium/InviteWithUserCard.tsx

Note: Currently uses GET for accept/decline actions (side-effectful GET). Odoo should accept POST. Consider updating the frontend to use POST -- it's a more correct HTTP method for state-changing operations.

4.18 Approval Workflows

# Method Current URL Odoo URL Files
67 POST /api/approval-workflows/create Path unchanged src/pages/approval-workflows/create.tsx
68 PUT /api/approval-workflows/{id} Path unchanged src/pages/approval-workflows/[id]/index.tsx
69 PUT /api/approval-workflows/{id}/edit Path unchanged src/pages/approval-workflows/[id]/edit.tsx
70 DELETE /api/approval-workflows/{id} Path unchanged src/pages/approval-workflows/index.tsx

4.19 Transcription

# Method Current URL Odoo URL Files
71 POST /api/transcribe Path unchanged (called from evaluation utils if needed)

4.20 Batch Users

# Method Current URL Odoo URL Files
72 POST /api/batch_users Path unchanged (admin import page)

4.21 Make User (Admin)

# Method Current URL Odoo URL Files
73 POST /api/make_user Path unchanged (admin user creation)

5. SSR Migration Strategy

5.1 Current SSR Auth Pattern

~35 pages use this pattern:

import { withIronSessionSsr } from "iron-session/next";
import { sessionOptions } from "@/lib/session";

export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
  const user = await requestUser(req, res);
  if (!user || !user.isVerified) return redirect("/login");
  return { props: { user } };
}, sessionOptions);

Store the JWT in a regular cookie (set by js-cookie on login). In getServerSideProps, read the cookie from the request and call Odoo to validate.

New helper src/lib/ssr-auth.ts:

import type { GetServerSidePropsContext, GetServerSidePropsResult } from "next";

const API_URL = process.env.NEXT_PUBLIC_API_URL;
const TOKEN_COOKIE = "encoach_token";

export function withAuth<P extends Record<string, unknown>>(
  handler: (ctx: GetServerSidePropsContext, user: User) => Promise<GetServerSidePropsResult<P>>
) {
  return async (ctx: GetServerSidePropsContext): Promise<GetServerSidePropsResult<P>> => {
    const token = ctx.req.cookies[TOKEN_COOKIE];
    if (!token) {
      return { redirect: { destination: "/login", permanent: false } };
    }

    try {
      const res = await fetch(`${API_URL}/api/user`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      if (!res.ok) throw new Error("Unauthorized");
      const user = await res.json();
      if (!user.isVerified) {
        return { redirect: { destination: "/login", permanent: false } };
      }
      return handler(ctx, user);
    } catch {
      return { redirect: { destination: "/login", permanent: false } };
    }
  };
}

Page migration example:

// BEFORE
export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
  const user = await requestUser(req, res);
  if (!user) return redirect("/login");
  // ... fetch additional data using user ...
  return { props: { user, someData } };
}, sessionOptions);

// AFTER
export const getServerSideProps = withAuth(async (ctx, user) => {
  // ... fetch additional data using user ...
  return { props: { user, someData } };
});

5.3 Alternative: Client-Only Auth (Option B)

Remove all getServerSideProps auth checks. Every page uses useUser({ redirectTo: "/login" }) to protect itself.

Pros: Simpler; no SSR auth at all. Cons: Brief flash of unauthenticated content; pages that fetch data server-side need to move data fetching to client-side.

5.4 Pages Requiring SSR Migration

Every page below currently uses withIronSessionSsr and needs to switch to withAuth (Option A) or remove SSR auth (Option B):

Page SSR Data Fetching
src/pages/index.tsx User only (redirects to dashboard)
src/pages/login.tsx Reverse guard (redirect if already logged in)
src/pages/dashboard/index.tsx User only
src/pages/dashboard/teacher.tsx User + groups + assignments + stats
src/pages/dashboard/student.tsx User + assignments + stats
src/pages/dashboard/corporate.tsx User + entity data
src/pages/dashboard/mastercorporate.tsx User + multi-entity data
src/pages/dashboard/admin.tsx User + platform stats
src/pages/dashboard/developer.tsx User
src/pages/users/index.tsx User + user list
src/pages/users/performance.tsx User + performance data
src/pages/training/index.tsx User
src/pages/training/[id]/index.tsx User + training data
src/pages/tickets.tsx User + tickets
src/pages/stats.tsx User + stats
src/pages/statistical.tsx User
src/pages/settings.tsx User
src/pages/record.tsx User
src/pages/profile.tsx User
src/pages/popout.tsx User (session-based)
src/pages/permissions/index.tsx User + permissions
src/pages/permissions/[id].tsx User + permission detail
src/pages/payment.tsx User
src/pages/payment-record.tsx User + payments
src/pages/official-exam.tsx User
src/pages/generation.tsx User
src/pages/exercises.tsx User + exam data
src/pages/exam.tsx User + exam + session data
src/pages/entities/index.tsx User + entities
src/pages/entities/create.tsx User
src/pages/entities/[id]/index.tsx User + entity detail
src/pages/entities/[id]/roles/index.tsx User + roles
src/pages/entities/[id]/roles/[role].tsx User + role detail
src/pages/classrooms/*.tsx User + groups
src/pages/assignments/*.tsx User + assignments
src/pages/approval-workflows/*.tsx User + workflows

For pages that only need user auth (no server-side data): Replace getServerSideProps with client-side useUser({ redirectTo: "/login" }).

For pages that fetch additional data server-side: Use withAuth and make the data-fetching calls to Odoo using the JWT token from the cookie.


6. Files to Delete

After migration, the following files are no longer needed. They represent the BFF layer being replaced by Odoo.

6.1 API Route Files (108 files)

Delete the entire src/pages/api/ directory:

Auth & User:

  • src/pages/api/login.ts
  • src/pages/api/logout.ts
  • src/pages/api/register.ts
  • src/pages/api/user.ts
  • src/pages/api/make_user.ts
  • src/pages/api/batch_users.ts
  • src/pages/api/reset/index.ts
  • src/pages/api/reset/confirm.ts
  • src/pages/api/reset/sendVerification.ts
  • src/pages/api/reset/verify.ts
  • src/pages/api/users/update.ts
  • src/pages/api/users/search.ts
  • src/pages/api/users/list.ts
  • src/pages/api/users/controller.ts
  • src/pages/api/users/balance.ts
  • src/pages/api/users/agents/index.ts
  • src/pages/api/users/agents/[code].ts
  • src/pages/api/users/[id].ts

Exams:

  • src/pages/api/exam/index.ts
  • src/pages/api/exam/upload.ts
  • src/pages/api/exam/avatars.ts
  • src/pages/api/exam/generate/[...module].ts
  • src/pages/api/exam/media/[...module].ts
  • src/pages/api/exam/media/poll.ts
  • src/pages/api/exam/media/instructions.ts
  • src/pages/api/exam/[module]/index.ts
  • src/pages/api/exam/[module]/import.ts
  • src/pages/api/exam/[module]/[id].ts

Evaluation:

  • src/pages/api/evaluate/writing.ts
  • src/pages/api/evaluate/speaking.ts
  • src/pages/api/evaluate/interactiveSpeaking.ts
  • src/pages/api/evaluate/status.ts
  • src/pages/api/evaluate/fetchSolutions.ts

Grading:

  • src/pages/api/grading/index.ts
  • src/pages/api/grading/multiple.ts

Stats & Sessions:

  • src/pages/api/stats/index.ts
  • src/pages/api/stats/update.ts
  • src/pages/api/stats/disabled.ts
  • src/pages/api/stats/user/[user].ts
  • src/pages/api/stats/session/[session].ts
  • src/pages/api/stats/[id]/index.ts
  • src/pages/api/stats/[id]/[export]/pdf.tsx
  • src/pages/api/statistical.ts
  • src/pages/api/sessions/index.ts
  • src/pages/api/sessions/[id].ts

Training:

  • src/pages/api/training/index.ts
  • src/pages/api/training/[id].ts
  • src/pages/api/training/user/[user].ts
  • src/pages/api/training/walkthrough/index.ts

Entities & Groups:

  • src/pages/api/entities/index.ts
  • src/pages/api/entities/users.ts
  • src/pages/api/entities/groups.ts
  • src/pages/api/entities/[id]/index.ts
  • src/pages/api/entities/[id]/users.ts
  • src/pages/api/groups/index.ts
  • src/pages/api/groups/controller.ts
  • src/pages/api/groups/[id].ts

Roles & Permissions:

  • src/pages/api/roles/index.ts
  • src/pages/api/roles/[id]/index.ts
  • src/pages/api/roles/[id]/users.ts
  • src/pages/api/permissions/index.ts
  • src/pages/api/permissions/bootstrap.ts
  • src/pages/api/permissions/[id].ts

Invites & Codes:

  • src/pages/api/invites/index.ts
  • src/pages/api/invites/[id].ts
  • src/pages/api/invites/accept/[id].ts
  • src/pages/api/invites/decline/[id].ts
  • src/pages/api/code/index.ts
  • src/pages/api/code/entities.ts
  • src/pages/api/code/[id].ts

Payments:

  • src/pages/api/stripe.ts
  • src/pages/api/paypal/index.ts
  • src/pages/api/paypal/approve.ts
  • src/pages/api/paypal/raas.ts
  • src/pages/api/paymob/index.ts
  • src/pages/api/paymob/webhook.ts
  • src/pages/api/payments/index.ts
  • src/pages/api/payments/[id].ts
  • src/pages/api/payments/assigned.ts
  • src/pages/api/payments/paypal.ts
  • src/pages/api/payments/files/[type]/[paymentId].ts
  • src/pages/api/packages/index.ts
  • src/pages/api/packages/[id].ts
  • src/pages/api/discounts/index.ts
  • src/pages/api/discounts/[id].ts

Assignments:

  • src/pages/api/assignments/index.ts
  • src/pages/api/assignments/corporate/index.ts
  • src/pages/api/assignments/corporate/[id].ts
  • src/pages/api/assignments/[id]/index.ts
  • src/pages/api/assignments/[id]/start.ts
  • src/pages/api/assignments/[id]/release.ts
  • src/pages/api/assignments/[id]/archive.tsx
  • src/pages/api/assignments/[id]/unarchive.tsx
  • src/pages/api/assignments/[id]/[export]/pdf.tsx
  • src/pages/api/assignments/[id]/[export]/excel.ts

Approval Workflows:

  • src/pages/api/approval-workflows/index.ts
  • src/pages/api/approval-workflows/create.ts
  • src/pages/api/approval-workflows/[id]/index.ts
  • src/pages/api/approval-workflows/[id]/edit.ts

Other:

  • src/pages/api/storage/index.ts
  • src/pages/api/storage/insert.ts
  • src/pages/api/storage/delete.ts
  • src/pages/api/speaking.ts
  • src/pages/api/transcribe/index.ts
  • src/pages/api/tickets/index.ts
  • src/pages/api/tickets/[id].ts
  • src/pages/api/tickets/assignedToUser/index.ts
  • src/pages/api/hello.ts

6.2 Backend Utility Files (14 files)

These files contain MongoDB query logic used by API routes. Delete all:

  • src/utils/approval.workflows.be.ts
  • src/utils/assignments.be.ts
  • src/utils/codes.be.ts
  • src/utils/disabled.be.ts
  • src/utils/entities.be.ts
  • src/utils/exams.be.ts
  • src/utils/grading.be.ts
  • src/utils/groups.be.ts
  • src/utils/invites.be.ts
  • src/utils/permissions.be.ts
  • src/utils/roles.be.ts
  • src/utils/sessions.be.ts
  • src/utils/stats.be.ts
  • src/utils/users.be.ts

6.3 Library Files (3 files)

  • src/lib/session.ts -- iron-session config (replaced by src/lib/api.ts)
  • src/lib/mongodb.ts -- MongoDB connection (no longer needed)
  • src/lib/createWorkflowsOnExamCreation.ts -- server-side workflow logic (moved to Odoo)

Keep:

  • src/lib/utils.ts -- general client-side utilities
  • src/lib/formidable-serverless.d.ts -- only needed if any remaining file upload logic stays; likely deletable

6.4 Firebase Files

If Odoo replaces Firebase Auth entirely, also remove:

  • src/firebase/ directory (Firebase client config)
  • src/constants/platform.json (Firebase service account -- server-side only)
  • src/constants/staging.json (Firebase service account -- server-side only)

6.5 Dependencies to Remove from package.json

iron-session
firebase
firebase-admin
mongodb
@beam-australia/react-env  (if no longer needed for client env)
bcrypt
formidable

6.6 Dependencies to Add

js-cookie              (JWT cookie storage)
@types/js-cookie       (TypeScript types)

7. Migration Checklist

A step-by-step checklist for the frontend developer. Complete in order.

Phase 1: Infrastructure Setup

  • 1.1 Add NEXT_PUBLIC_API_URL to .env.local (point to Odoo dev instance)
  • 1.2 Create src/lib/api.ts with shared axios instance, base URL, and JWT interceptor (Section 2.3)
  • 1.3 Create src/lib/auth.ts with setToken(), getToken(), clearToken() helpers
  • 1.4 Add js-cookie dependency: yarn add js-cookie @types/js-cookie
  • 1.5 Create src/lib/ssr-auth.ts with withAuth() helper for SSR (Section 5.2)

Phase 2: Auth Migration

  • 2.1 Update src/pages/login.tsx: use api.post(), store JWT, extract user from response
  • 2.2 Update src/pages/register.tsx: move registration to client-side, use api.post()
  • 2.3 Update logout calls in Sidebar.tsx, MobileMenu.tsx, official-exam.tsx: use api.post() + clearToken()
  • 2.4 Update src/hooks/useUser.tsx: use api instance for SWR fetcher
  • 2.5 Update src/utils/email.ts: use api instance
  • 2.6 Verify login/logout/register work end-to-end with Odoo

Phase 3: SSR Migration

  • 3.1 For each page in the SSR page list (Section 5.4), replace withIronSessionSsr with withAuth or client-side useUser({ redirectTo: "/login" })
  • 3.2 Update pages that fetch server-side data to call Odoo with the JWT token
  • 3.3 Verify all ~35 protected pages redirect correctly when not authenticated
  • 3.4 Verify the login page redirects correctly when already authenticated

Phase 4: API Call Migration (domain by domain)

For each domain, replace axios with api from @/lib/api:

  • 4.1 User endpoints (src/pages/profile.tsx, src/components/UserCard.tsx, src/utils/groups.ts, src/components/Imports/StudentClassroomTransfer.tsx)
  • 4.2 Exam endpoints (src/utils/exams.ts, src/hooks/useExams.tsx, src/pages/generation.tsx, all ExamEditor files, ExamList.tsx)
  • 4.3 Evaluation endpoints (src/utils/evaluation.ts)
  • 4.4 Storage endpoints (all ExamEditor/SettingsEditor files, src/utils/evaluation.ts)
  • 4.5 Speaking audio (src/components/Solutions/Speaking.tsx, InteractiveSpeaking.tsx)
  • 4.6 Sessions (src/stores/exam/index.ts, src/components/Medium/SessionCard.tsx)
  • 4.7 Stats (src/stores/exam/index.ts, src/pages/training/[id]/index.tsx, src/pages/statistical.tsx)
  • 4.8 Training (src/pages/training/index.tsx, src/pages/training/[id]/index.tsx)
  • 4.9 Groups (src/utils/groups.ts, src/pages/classrooms/create.tsx, src/pages/classrooms/[id].tsx)
  • 4.10 Entities (src/pages/entities/create.tsx, src/pages/entities/[id]/index.tsx)
  • 4.11 Roles (src/pages/entities/[id]/roles/index.tsx, [role].tsx)
  • 4.12 Permissions (src/pages/permissions/[id].tsx)
  • 4.13 Payments (src/pages/payment-record.tsx, src/components/PaymentAssetManager.tsx, src/components/PaymobPayment.tsx)
  • 4.14 Assignments (src/pages/assignments/creator/index.tsx, [id].tsx, src/pages/assignments/[id].tsx)
  • 4.15 Invites (src/components/Medium/InviteCard.tsx, InviteWithUserCard.tsx)
  • 4.16 Approval workflows (src/pages/approval-workflows/*.tsx)
  • 4.17 Codes (src/pages/register.tsx)
  • 4.18 Remaining: transcribe, batch_users, make_user, statistical
  • 4.19 Update WordUploader.tsx fetch() call with base URL and auth header

Phase 5: Cleanup

  • 5.1 Delete all 108 files in src/pages/api/
  • 5.2 Delete all 14 src/utils/*.be.ts files
  • 5.3 Delete src/lib/session.ts, src/lib/mongodb.ts, src/lib/createWorkflowsOnExamCreation.ts
  • 5.4 Delete src/firebase/ directory (if Firebase Auth fully removed)
  • 5.5 Delete src/constants/platform.json, src/constants/staging.json
  • 5.6 Remove unused dependencies from package.json: iron-session, firebase, firebase-admin, mongodb, bcrypt, formidable
  • 5.7 Run yarn install to update lockfile
  • 5.8 Run TypeScript compiler (yarn tsc --noEmit) and fix any remaining type errors
  • 5.9 Run linter (yarn lint) and fix issues

Phase 6: Testing

  • 6.1 Test login flow (email + password -> JWT stored -> user loaded)
  • 6.2 Test registration flow (individual and corporate)
  • 6.3 Test logout (token cleared, redirect to login)
  • 6.4 Test SSR protection (unauthenticated access to protected page -> redirect)
  • 6.5 Test exam taking flow (load exam, answer questions, submit, save stats)
  • 6.6 Test writing/speaking grading (submit, poll, receive result)
  • 6.7 Test entity/group/classroom management (CRUD operations)
  • 6.8 Test assignment lifecycle (create, start, release, archive)
  • 6.9 Test payment flows (Stripe, PayPal, Paymob)
  • 6.10 Test file uploads (exam media, profile pictures)
  • 6.11 Test training content generation
  • 6.12 Test ticket creation (from platform and landing page)
  • 6.13 Test admin user management (create, update, batch import)
  • 6.14 Cross-browser test (Chrome, Firefox, Safari)