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:
4
custom_addons/encoach_course_gen/models/__init__.py
Normal file
4
custom_addons/encoach_course_gen/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from . import gap_profile
|
||||
from . import course_extension
|
||||
from . import course_section
|
||||
from . import course_module
|
||||
21
custom_addons/encoach_course_gen/models/course_extension.py
Normal file
21
custom_addons/encoach_course_gen/models/course_extension.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class OpCourseExtension(models.Model):
|
||||
_inherit = 'op.course'
|
||||
|
||||
generation_source = fields.Selection([
|
||||
('manual', 'Manual'),
|
||||
('auto_gap', 'Auto from Gap'),
|
||||
('ai_english', 'AI English'),
|
||||
('ai_ielts', 'AI IELTS'),
|
||||
])
|
||||
gap_profile_id = fields.Many2one('encoach.gap.profile', ondelete='set null')
|
||||
progression_model = fields.Selection([
|
||||
('linear', 'Linear'),
|
||||
('parallel', 'Parallel'),
|
||||
('adaptive', 'Adaptive'),
|
||||
], default='linear')
|
||||
target_band = fields.Float()
|
||||
study_hours_week = fields.Integer()
|
||||
entity_id = fields.Many2one('encoach.entity', ondelete='set null')
|
||||
37
custom_addons/encoach_course_gen/models/course_module.py
Normal file
37
custom_addons/encoach_course_gen/models/course_module.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class EncoachCourseModule(models.Model):
|
||||
_name = 'encoach.course.module'
|
||||
_description = 'Course Module'
|
||||
|
||||
name = fields.Char(size=200, required=True)
|
||||
course_id = fields.Many2one('op.course', required=True, ondelete='cascade')
|
||||
cefr_target = fields.Selection([
|
||||
('pre_a1', 'Pre-A1'),
|
||||
('a1', 'A1'),
|
||||
('a2', 'A2'),
|
||||
('b1', 'B1'),
|
||||
('b2', 'B2'),
|
||||
('c1', 'C1'),
|
||||
('c2', 'C2'),
|
||||
])
|
||||
auto_generated = fields.Boolean(default=False)
|
||||
generation_brief = fields.Text()
|
||||
completion_criteria = fields.Selection([
|
||||
('all_resources', 'All Resources'),
|
||||
('score_threshold', 'Score Threshold'),
|
||||
('teacher_approval', 'Teacher Approval'),
|
||||
], default='all_resources')
|
||||
score_threshold = fields.Float()
|
||||
prerequisite_module_id = fields.Many2one('encoach.course.module', ondelete='set null')
|
||||
status = fields.Selection([
|
||||
('locked', 'Locked'),
|
||||
('available', 'Available'),
|
||||
('in_progress', 'In Progress'),
|
||||
('completed', 'Completed'),
|
||||
('skipped', 'Skipped'),
|
||||
], default='locked', required=True)
|
||||
sequence = fields.Integer(default=10)
|
||||
section_id = fields.Many2one('encoach.course.section', ondelete='set null')
|
||||
resource_ids = fields.Many2many('encoach.resource', string='Resources')
|
||||
21
custom_addons/encoach_course_gen/models/course_section.py
Normal file
21
custom_addons/encoach_course_gen/models/course_section.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class EncoachCourseSection(models.Model):
|
||||
_name = 'encoach.course.section'
|
||||
_description = 'Course Section'
|
||||
_order = 'sequence'
|
||||
|
||||
name = fields.Char(size=200, required=True)
|
||||
course_id = fields.Many2one('op.course', required=True, ondelete='cascade')
|
||||
skill = fields.Selection([
|
||||
('listening', 'Listening'),
|
||||
('reading', 'Reading'),
|
||||
('writing', 'Writing'),
|
||||
('speaking', 'Speaking'),
|
||||
('grammar', 'Grammar'),
|
||||
('vocabulary', 'Vocabulary'),
|
||||
('overall', 'Overall'),
|
||||
])
|
||||
sequence = fields.Integer(default=10)
|
||||
module_ids = fields.One2many('encoach.course.module', 'section_id', string='Modules')
|
||||
18
custom_addons/encoach_course_gen/models/gap_profile.py
Normal file
18
custom_addons/encoach_course_gen/models/gap_profile.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class EncoachGapProfile(models.Model):
|
||||
_name = 'encoach.gap.profile'
|
||||
_description = 'Student Gap Profile'
|
||||
|
||||
student_id = fields.Many2one('res.users', required=True, ondelete='cascade', index=True)
|
||||
source_type = fields.Selection([
|
||||
('placement', 'Placement'),
|
||||
('exam', 'Exam'),
|
||||
], required=True)
|
||||
source_id = fields.Integer()
|
||||
skill_gaps = fields.Text()
|
||||
question_type_weaknesses = fields.Text()
|
||||
topic_weaknesses = fields.Text()
|
||||
entity_id = fields.Many2one('encoach.entity', ondelete='set null')
|
||||
created_at = fields.Datetime(default=fields.Datetime.now)
|
||||
Reference in New Issue
Block a user