# EnCoach Odoo 19 -- Developer Feedback

**Date:** March 11, 2026
**Status:** ALL ITEMS RESOLVED (March 13, 2026)
**Reference:** ODOO_MIGRATION_SRS_v2.md

---

## Overall Assessment

The delivery covers approximately **85% of the SRS v2 requirements**. All 15 custom modules are present, the core AI/ML services are well-implemented, data models match the specification, and 67-72 API endpoints are wired up with proper JWT authentication and security groups. The code quality is solid -- clean structure, proper error handling, and good separation of concerns.

The items below still need to be implemented to reach full SRS compliance.

---

## 1. Payment Integration (Critical -- Not Implemented)

**SRS Reference:** Section 7

All three payment services are currently stubs that return `"not yet implemented"`. The SRS requires full integration with:

### 1.1 Stripe

**Files:** `encoach_subscription/services/stripe_service.py`

Required functionality:
- Install and use the `stripe` Python SDK
- `create_checkout_session()` -- Create a Stripe Checkout Session using `stripe.checkout.Session.create()` with:
  - `line_items` from the selected `encoach.package`
  - `success_url` and `cancel_url` from the request
  - `client_reference_id` = user ID
  - `customer_email` = user email
  - Apply discount if `discount_code` is provided (validate against `encoach.discount`)
- Return `{ "sessionId": "cs_...", "url": "https://checkout.stripe.com/..." }`
- **Webhook endpoint** (`POST /api/stripe/webhook`):
  - Verify signature using `stripe.Webhook.construct_event()` with `STRIPE_WEBHOOK_SECRET`
  - Handle `checkout.session.completed` event:
    - Find user by `client_reference_id`
    - Extend `subscription_expiration` by the package's `duration_days`
    - Create `encoach.subscription.payment` record
    - For corporate users, propagate subscription to entity members

### 1.2 PayPal

**Files:** `encoach_subscription/services/paypal_service.py`

Required functionality:
- Use PayPal REST API (`httpx` or `requests`)
- Obtain access token from `PAYPAL_ACCESS_TOKEN_URL` using `client_id` + `client_secret`
- `create_order()` -- Create PayPal order via `POST /v2/checkout/orders`:
  - `intent: "CAPTURE"`
  - `purchase_units` with amount from package (minus discount)
  - Return `{ "orderId": "...", "approvalUrl": "https://paypal.com/..." }`
- `capture_order()` -- Capture approved order via `POST /v2/checkout/orders/{id}/capture`:
  - On success, extend subscription and create payment record
  - Return `{ "ok": true }`

### 1.3 Paymob

**Files:** `encoach_subscription/services/paymob_service.py`

Required functionality:
- Use Paymob API (`httpx` or `requests`)
- `create_intention()` -- Create payment intention:
  - Authenticate with `PAYMOB_API_KEY`
  - Create order, then payment key
  - Return `{ "intentionId": "...", "clientSecret": "..." }`
- `verify_transaction()` -- Verify webhook callback:
  - Validate HMAC using `PAYMOB_SECRET`
  - On success, extend subscription and create payment record
- **Webhook endpoint** (`POST /api/paymob/webhook`):
  - Verify transaction authenticity
  - Update subscription on success

### 1.4 Subscription Extension Logic

After any successful payment (all providers), the system must:
1. Calculate new expiration: `max(current_expiration, now()) + duration_days`
2. Update `user.subscription_expiration`
3. Create `encoach.subscription.payment` record with provider, amount, transaction ID
4. For corporate users: propagate the new expiration to all entity members

---

## 2. Missing API Endpoints

**SRS Reference:** Section 4

The following endpoints are specified in the SRS but not present in the delivery:

### 2.1 Exam Variants (add to `encoach_api/controllers/generation.py` or `exams.py`)

| Endpoint | Method | Description |
|----------|--------|-------------|
| `POST /api/exam/writing/<task>/attachment` | POST | Academic writing Task 1 with image upload (multipart form with `file` + `difficulty`). Must send image to GPT-4o vision API for prompt generation. |
| `GET /api/exam/level/` | GET | Return a pre-built level exam (no AI generation) |
| `GET /api/exam/level/utas` | GET | Return a UTAS-format level exam |
| `POST /api/exam/level/import/` | POST | Import level exam from uploaded file |
| `POST /api/exam/level/custom/` | POST | Generate custom level exam from JSON specification |
| `POST /api/exam/reading/import` | POST | Import reading exam from Word/Excel file |
| `POST /api/exam/listening/import` | POST | Import listening exam from file |

### 2.2 Entity/Role/Permission Management (new controller files needed)

| Endpoint | Method | Description |
|----------|--------|-------------|
| `GET /api/entities` | GET | List entities (with pagination) |
| `POST /api/entities` | POST | Create entity |
| `PATCH /api/entities/<id>` | PATCH | Update entity |
| `DELETE /api/entities/<id>` | DELETE | Delete entity |
| `GET /api/roles` | GET | List roles (filter by entityID) |
| `POST /api/roles` | POST | Create role |
| `PATCH /api/roles/<id>` | PATCH | Update role |
| `DELETE /api/roles/<id>` | DELETE | Delete role |
| `GET /api/permissions` | GET | List permissions |

### 2.3 Other Missing Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `GET /api/discounts` | GET | List discount codes |
| `POST /api/discounts` | POST | Create discount code |
| `PATCH /api/discounts/<id>` | PATCH | Update discount code |
| `DELETE /api/discounts/<id>` | DELETE | Delete discount code |
| `GET /api/approval-workflows` | GET | List approval workflows |
| `POST /api/approval-workflows` | POST | Create approval workflow |
| `PATCH /api/approval-workflows/<id>` | PATCH | Update approval workflow |
| `DELETE /api/approval-workflows/<id>` | DELETE | Delete approval workflow |

---

## 3. Evaluation Status Endpoint Path

**SRS Reference:** Section 4.2

**Current:** `GET /api/evaluate/status?sessionId=...&exerciseId=...` (query params)
**SRS specifies:** `GET /api/evaluate/<sessionId>/<exerciseId>` (path params)

The frontend SRS document (`ODOO_MIGRATION_FRONTEND_SRS.md`) references the path-param version. Please either:
- (A) Change the endpoint to use path params to match the SRS, OR
- (B) Confirm that query params are intentional so we can update the frontend SRS

---

## 4. Record-Level Security Rules (`ir.rule`)

**SRS Reference:** Section 5

The delivery has model-level ACL rules (`ir.model.access.csv`) for each module, which is good. However, record-level security rules (`ir.rule`) are also needed to ensure:

- **Students** can only read/write their own records (sessions, stats, evaluations, training, tickets)
- **Teachers** can see records for students in their groups/assignments
- **Corporate** users can see records within their entity
- **Admin/Developer** users have unrestricted access

Example rules needed (add to each module's `security/` directory):

```xml
<!-- encoach_stats/security/rules.xml -->
<record id="rule_stat_student_own" model="ir.rule">
    <field name="name">Students see own stats</field>
    <field name="model_id" ref="model_encoach_stat"/>
    <field name="groups" eval="[(4, ref('encoach_core.group_encoach_student'))]"/>
    <field name="domain_force">[('user_id', '=', user.id)]</field>
</record>
```

Models that need record rules:
- `encoach.session` -- students see own sessions only
- `encoach.stat` -- students see own stats only
- `encoach.evaluation` -- students see own evaluations only
- `encoach.training` -- students see own training only
- `encoach.ticket` -- students see own tickets, admins see all
- `encoach.assignment` -- students see assignments they're assigned to
- `encoach.exam` -- filtered by access field (public/private/entity)

---

## 5. Whisper Scaling

**SRS Reference:** Section 6.5

**Current:** Single lazy-loaded Whisper model instance in `whisper_service.py`
**SRS specifies:** 4 model instances with `ThreadPoolExecutor(max_workers=4)` for parallel transcription

Update `encoach_ai_media/services/whisper_service.py` to:
1. Load the configurable number of model instances (from `encoach.whisper_workers` system parameter, default 4)
2. Use `concurrent.futures.ThreadPoolExecutor` to process transcription requests in parallel
3. Round-robin or queue-based assignment of requests to model instances

This is important for production performance when multiple students submit speaking exams simultaneously.

---

## 6. FAISS Index Type

**SRS Reference:** Section 6.8

**Current:** `faiss.IndexFlatIP` (inner product)
**SRS specifies:** `faiss.IndexFlatL2` (L2/Euclidean distance)

The current implementation normalizes vectors and uses inner product, which effectively gives cosine similarity. This works correctly, but it's a deviation from the SRS. If the original `ielts-be` training data was built with L2 distance, the results may differ slightly. Please verify which index type the original system used and align accordingly.

---

## 7. Payment Webhook Endpoints

**SRS Reference:** Section 7

In addition to the payment service implementations (Item 1 above), the following webhook controller routes need to be added to `encoach_api/controllers/subscriptions.py`:

```python
@http.route('/api/stripe/webhook', type='http', auth='public', methods=['POST'], csrf=False, cors='*')
def stripe_webhook(self, **kwargs):
    """Handle Stripe webhook events (checkout.session.completed, etc.)."""
    ...

@http.route('/api/paymob/webhook', type='http', auth='public', methods=['POST'], csrf=False, cors='*')
def paymob_webhook(self, **kwargs):
    """Handle Paymob transaction callbacks."""
    ...
```

These must be `auth='public'` (no JWT) since they're called by external services.

---

## Summary of Action Items

| # | Item | Priority | Status |
|---|------|----------|--------|
| 1 | Payment integration (Stripe/PayPal/Paymob) | **Critical** | RESOLVED |
| 2 | Missing API endpoints (~20 endpoints) | **High** | RESOLVED |
| 3 | Evaluation status endpoint path alignment | **Medium** | RESOLVED |
| 4 | `ir.rule` record-level security rules | **High** | RESOLVED |
| 5 | Whisper multi-instance scaling | **Medium** | RESOLVED |
| 6 | FAISS index type verification | **Low** | RESOLVED |
| 7 | Payment webhook endpoints | **Critical** | RESOLVED |

---

## Changes Already Applied

The following small fixes have been applied directly to the codebase:

1. **`encoach_ai_media/__manifest__.py`** -- Added missing `external_dependencies`: `numpy`, `openai-whisper`, `librosa`, `soundfile`, `httpx`
2. **`encoach_training/__manifest__.py`** -- Added missing `external_dependencies`: `numpy`, `faiss-cpu`, `sentence-transformers`
3. **`requirements.txt`** -- Created at project root with all Python dependencies and versions from SRS Section 6.10
