feat: initial backend codebase — EnCoach v3

Complete Odoo 19 backend with 25 custom addons:
- encoach_core: user/entity/role management
- encoach_api: REST API + JWT auth
- encoach_ai: OpenAI integration, AI settings, generation
- encoach_ai_course: AI-powered English & IELTS course generation
- encoach_exam_template/session: exam creation, structures, sessions
- encoach_scoring: AI auto-grading + manual approval
- encoach_vector: pgvector RAG integration
- encoach_adaptive: adaptive learning engine
- encoach_placement: placement testing
- encoach_taxonomy/resources: content taxonomy & resource management
- Plus 14 more modules for courses, branding, portal, etc.

Includes docs: user guide, generation report, developer workflow.

Made-with: Cursor
This commit is contained in:
Yamen Ahmad
2026-04-11 15:44:20 +04:00
commit 982d4bca30
371 changed files with 35211 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<template id="exam_session_page" name="Exam Session">
<html>
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>EnCoach Exam</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"/>
<style>
:root { --ec-primary: #4F46E5; --ec-bg: #F8FAFC; }
body { background: var(--ec-bg); font-family: system-ui, -apple-system, sans-serif; margin:0; }
.ec-topbar { background: var(--ec-primary); color:#fff; padding:12px 24px; display:flex; justify-content:space-between; align-items:center; }
.ec-topbar h1 { font-size:1.1rem; margin:0; font-weight:600; }
.ec-timer { font-size:1.25rem; font-weight:700; font-variant-numeric:tabular-nums; }
.ec-timer.warning { color:#FCD34D; }
.ec-timer.danger { color:#EF4444; animation:pulse 1s infinite; }
@keyframes pulse { 50% { opacity:.5; } }
.ec-sidebar { width:260px; background:#fff; border-right:1px solid #E2E8F0; padding:16px; overflow-y:auto; }
.ec-sidebar .section-title { font-weight:600; color:var(--ec-primary); margin:16px 0 8px; font-size:.85rem; text-transform:uppercase; letter-spacing:.05em; }
.ec-sidebar .q-btn { display:inline-flex; align-items:center; justify-content:center; width:40px; height:40px; border-radius:8px; border:2px solid #E2E8F0; background:#fff; cursor:pointer; font-weight:600; margin:3px; transition:.2s; }
.ec-sidebar .q-btn:hover { border-color:var(--ec-primary); }
.ec-sidebar .q-btn.active { background:var(--ec-primary); color:#fff; border-color:var(--ec-primary); }
.ec-sidebar .q-btn.answered { background:#D1FAE5; border-color:#10B981; color:#065F46; }
.ec-main { flex:1; padding:32px; overflow-y:auto; max-width:900px; margin:0 auto; }
.ec-card { background:#fff; border-radius:12px; box-shadow:0 1px 3px rgba(0,0,0,.1); padding:28px; margin-bottom:24px; }
.ec-question-stem { font-size:1.1rem; line-height:1.6; margin-bottom:20px; }
.ec-option { display:flex; align-items:center; padding:14px 18px; border:2px solid #E2E8F0; border-radius:10px; margin-bottom:10px; cursor:pointer; transition:.15s; }
.ec-option:hover { border-color:var(--ec-primary); background:#EEF2FF; }
.ec-option.selected { border-color:var(--ec-primary); background:#EEF2FF; }
.ec-option input { margin-right:12px; accent-color:var(--ec-primary); }
.ec-option-key { font-weight:700; color:var(--ec-primary); margin-right:10px; min-width:24px; }
.ec-nav { display:flex; justify-content:space-between; margin-top:24px; }
.ec-layout { display:flex; height:calc(100vh - 56px); }
.ec-progress-bar { height:4px; background:#E2E8F0; }
.ec-progress-fill { height:100%; background:var(--ec-primary); transition:width .3s; }
.ec-results { text-align:center; padding:48px; }
.ec-band { font-size:4rem; font-weight:800; color:var(--ec-primary); }
.ec-skill-row { display:flex; justify-content:space-between; padding:12px 0; border-bottom:1px solid #E2E8F0; }
</style>
</head>
<body>
<div class="ec-topbar">
<h1>EnCoach &#8212; <t t-out="attempt.exam_id.title"/></h1>
<div class="ec-timer" id="timer">Loading&#8230;</div>
</div>
<div class="ec-progress-bar"><div class="ec-progress-fill" id="progressBar" style="width:0%"/></div>
<div class="ec-layout">
<div class="ec-sidebar" id="sidebar"/>
<div class="ec-main" id="mainContent">
<div class="ec-card" style="text-align:center; padding:48px;">
<h2>Loading exam&#8230;</h2>
</div>
</div>
</div>
<div id="exam_session_app"
t-att-data-attempt-id="attempt.id"
t-att-data-exam-id="attempt.exam_id.id"
t-att-data-session-token="session_token"
style="display:none"/>
<script src="/encoach_exam_session/static/src/js/exam_delivery.js"/>
</body>
</html>
</template>
<template id="placement_session_page" name="Placement Session">
<t t-call="web.frontend_layout">
<t t-set="no_header" t-value="True"/>
<t t-set="no_footer" t-value="True"/>
<div id="placement_session_app"
t-att-data-session-id="cat_session.id"
t-att-data-student-id="cat_session.student_id.id"
class="ec-exam-fullscreen"/>
</t>
</template>
</odoo>