feat(v3): restructure project + add complete frontend

- Restructure: move backend from new_project/ to backend/
- Add full React/TypeScript frontend (37 pages, 17 services, 16 type defs, 11 query hooks)
- Add docs/ with SRS specs, user stories, and workflow documentation
- Update .gitignore for new directory layout

Workflows implemented:
  WF1 User Signup, WF2 Placement Test, WF3 Exam Configuration,
  WF4 General English Exam, WF5 Course Generation,
  WF6 Entity Student Onboarding, AI Course Generation,
  Adaptive Learning Engine UI, White-Label Branding, Score Release

Made-with: Cursor
This commit is contained in:
Yamen Ahmad
2026-04-10 17:26:42 +04:00
commit 907a5c0e92
331 changed files with 23511 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import exam_session

View File

@@ -0,0 +1,43 @@
import logging
import time
import jwt as pyjwt
from odoo import http
from odoo.http import request
_logger = logging.getLogger(__name__)
class ExamSessionController(http.Controller):
def _generate_exam_jwt(self, user_id):
secret = request.env['ir.config_parameter'].sudo().get_param('encoach.jwt_secret')
if not secret:
return ''
return pyjwt.encode(
{'user_id': user_id, 'exp': int(time.time()) + 7200},
secret, algorithm='HS256',
)
@http.route('/exam/session/<int:attempt_id>', type='http',
auth='user', website=False)
def exam_session(self, attempt_id, **kw):
attempt = request.env['encoach.student.attempt'].sudo().browse(attempt_id)
if not attempt.exists() or attempt.student_id.id != request.env.user.id:
return request.not_found()
token = self._generate_exam_jwt(request.env.user.id)
return request.render('encoach_exam_session.exam_session_page', {
'attempt': attempt,
'session_token': token,
})
@http.route('/placement/test/<int:session_id>', type='http',
auth='user', website=True)
def placement_test(self, session_id, **kw):
session = request.env['encoach.cat.session'].sudo().browse(session_id)
if not session.exists() or session.student_id.id != request.env.user.id:
return request.not_found()
return request.render('encoach_exam_session.placement_session_page', {
'cat_session': session,
})