diff --git a/.gitignore b/.gitignore index 9864cb1f..6f493b62 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,10 @@ Thumbs.db # Frontend repo (separate repository) new_project/encoach_frontend_new_v1/ +# Node modules +node_modules/ +frontend/node_modules/ + # Local dev artifacts miniconda3/ pgdata/ @@ -50,6 +54,7 @@ new_project/enterprise-17/ # Third-party modules (downloaded separately) new_project/openeducat_erp-19.0/ +backend/openeducat_erp-19.0/ new_project/openeducat_erp-19.0.zip new_project/openeducate_enterprise-17.zip new_project/encoach_frontend_new_v1-main.zip diff --git a/backend/custom_addons/clarity_backend_theme_bits/__init__.py b/backend/custom_addons/clarity_backend_theme_bits/__init__.py new file mode 100755 index 00000000..72f4562d --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/__init__.py @@ -0,0 +1 @@ +from . import controller \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/__manifest__.py b/backend/custom_addons/clarity_backend_theme_bits/__manifest__.py new file mode 100755 index 00000000..772a7922 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/__manifest__.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +################################################################################# +# Author : Terabits Technolab () +# Copyright(c): 2021-25 +# All Rights Reserved. +# +# This module is copyright property of the author mentioned above. +# You can`t redistribute it and/or modify it. +# +################################################################################# + +{ + "name": "Clarity Backend Theme for community", + "version": "19.0.1.0.2", + 'author': "Terabits Technolab", + 'summary': """ + Clarity backend theme + Odoo Backend Theme, Odoo Community Backend Theme, Web backend Theme, Web Responsive Odoo Theme, New theme design, New design, Multi Level Menu, + Web Responsive , Odoo Theme, Odoo Modern Theme, Odoo Modern Backend Theme Odoo, Advance Theme Backend Advanced, Left sidebar menu, + All in one, New advanced Odoo Menu, Sidebar apps, Web menu, Odoo backend menu, Web Responsive menu, Sidebar dark, + Advance Menu Odoo App Menu Apps, Advanced Apps Menu, Elegant Menu, Web App Menu Backend, Menu Odoo Backend, Collapse Menu, Light Sidebar, + Expand Menu, Collapsed Menu, Expanded Menu, New Style Menus, Advanced Sidebar Menu, Advance Sidebar Menu, Responsive Menu Sidebar, Sidebar Theme, + Responsive Sidebar, Hide menu, Show Menu, Hide Sidebar, Show Sidebar, Toggle Menu, Toggle Sidebar, Menu Theme, + Quick Backend Menu, Dropdown Menu, Parent Menus, Shortcut Menus, Menu Icons, Collapsible menu Odoo, + Menu Dynamic Sidebar, Advanced Menu, Backend Odoo Web, Elegant Theme Simple, Advance List View Manager, + Arc Backend Theme, Fully Functional Theme, Flexible Backend Theme, Fast Backend Theme, Advance Material Backend Theme, Customizable Backend Theme, + Attractive Theme for Backend, Elegant Backend Theme, Responsive Web Client, Backend UI, Mobile Responsive for Odoo Community, + Flexible Enterprise Theme, Enterprise Backend Theme + """, + 'description': """ + Clarity backend theme + Odoo Backend Theme, Odoo Community Backend Theme, Web backend Theme, Web Responsive Odoo Theme, New theme design, New design, Multi Level Menu, + Web Responsive , Odoo Theme, Odoo Modern Theme, Odoo Modern Backend Theme Odoo, Advance Theme Backend Advanced, Left sidebar menu, + All in one, New advanced Odoo Menu, Sidebar apps, Web menu, Odoo backend menu, Web Responsive menu, Sidebar dark, + Advance Menu Odoo App Menu Apps, Advanced Apps Menu, Elegant Menu, Web App Menu Backend, Menu Odoo Backend, Collapse Menu, Light Sidebar, + Expand Menu, Collapsed Menu, Expanded Menu, New Style Menus, Advanced Sidebar Menu, Advance Sidebar Menu, Responsive Menu Sidebar, Sidebar Theme, + Responsive Sidebar, Hide menu, Show Menu, Hide Sidebar, Show Sidebar, Toggle Menu, Toggle Sidebar, Menu Theme, + Quick Backend Menu, Dropdown Menu, Parent Menus, Shortcut Menus, Menu Icons, Collapsible menu Odoo, + Menu Dynamic Sidebar, Advanced Menu, Backend Odoo Web, Elegant Theme Simple, Advance List View Manager, + Arc Backend Theme, Fully Functional Theme, Flexible Backend Theme, Fast Backend Theme, Advance Material Backend Theme, Customizable Backend Theme, + Attractive Theme for Backend, Elegant Backend Theme, Responsive Web Client, Backend UI, Mobile Responsive for Odoo Community, + Flexible Enterprise Theme, Enterprise Backend Theme + """, + "sequence": 7, + "license": "OPL-1", + "category": "Themes/Backend", + "website": "https://www.terabits.xyz/apps/19.0/clarity_backend_theme_bits", + "depends": ["web"], + "data": [ + 'views/res_config_setting.xml', + 'views/res_users.xml', + 'views/webclient_templates.xml' + ], + "assets": { + "web.assets_frontend": [ + 'clarity_backend_theme_bits/static/src/scss/login.scss' + ], + "web.assets_backend": [ + 'clarity_backend_theme_bits/static/src/xml/WebClient.xml', + 'clarity_backend_theme_bits/static/src/xml/navbar/sidebar.xml', + 'clarity_backend_theme_bits/static/src/xml/systray_items/user_menu.xml', + 'clarity_backend_theme_bits/static/src/js/SidebarBottom.js', + 'clarity_backend_theme_bits/static/src/js/WebClient.js', + 'clarity_backend_theme_bits/static/src/scss/layout.scss', + 'clarity_backend_theme_bits/static/src/scss/navbar.scss', + 'clarity_backend_theme_bits/static/src/js/navbar.js', + ], + }, + 'installable': True, + 'application': True, + 'auto_install': False, + 'images': [ + 'static/description/logo.gif', + 'static/description/theme_screenshot.gif', + ], +} diff --git a/backend/custom_addons/clarity_backend_theme_bits/controller/__init__.py b/backend/custom_addons/clarity_backend_theme_bits/controller/__init__.py new file mode 100755 index 00000000..deec4a8b --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/controller/__init__.py @@ -0,0 +1 @@ +from . import main \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/controller/main.py b/backend/custom_addons/clarity_backend_theme_bits/controller/main.py new file mode 100755 index 00000000..0acb95a6 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/controller/main.py @@ -0,0 +1,17 @@ +import datetime +import pytz +from odoo import http, models, fields, api, tools +from odoo.http import request + +class BackThemeBits(http.Controller): + @http.route(['/get/menu_data'], type='jsonrpc', auth='public') + def get_irmenu_icondata(self, **kw): + menuobj = request.env['ir.ui.menu'] + menu_recs = request.env['ir.ui.menu'].sudo().search( + [('id', 'in', kw.get('menu_ids'))]) + + app_menu_dict = {} + for menu in menu_recs: + menu_dict = menu.read(set(menuobj._fields)) + app_menu_dict[menu.id] = menu_dict + return app_menu_dict \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/icon.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/icon.png new file mode 100755 index 00000000..873c613f Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/icon.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/1.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/1.png new file mode 100755 index 00000000..14725d09 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/1.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/2.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/2.png new file mode 100755 index 00000000..b2774c6c Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/2.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/3.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/3.png new file mode 100755 index 00000000..c0c1ce1e Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/3.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/4.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/4.png new file mode 100755 index 00000000..8b22c4d9 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/4.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/5.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/5.png new file mode 100755 index 00000000..b7288748 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/5.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/6.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/6.png new file mode 100755 index 00000000..07b4536b Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/6.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/7.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/7.png new file mode 100755 index 00000000..9ce68515 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/7.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/8.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/8.png new file mode 100755 index 00000000..c71be246 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/8.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/9.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/9.png new file mode 100755 index 00000000..deeb181a Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/9.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/analytix_banner.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/analytix_banner.png new file mode 100755 index 00000000..ecf24122 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/analytix_banner.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/banner.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/banner.png new file mode 100755 index 00000000..a37266e5 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/banner.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_feat_bg_02.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_feat_bg_02.png new file mode 100755 index 00000000..972b822b Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_feat_bg_02.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_post_bg_01.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_post_bg_01.png new file mode 100755 index 00000000..1dbb707a Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_post_bg_01.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_ss_bg_03.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_ss_bg_03.png new file mode 100755 index 00000000..a91b9677 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blog_ss_bg_03.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blogpost_header_img.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blogpost_header_img.png new file mode 100755 index 00000000..e7d21621 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/blogpost_header_img.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/clarity_pro_banner.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/clarity_pro_banner.png new file mode 100755 index 00000000..d6330b1f Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/clarity_pro_banner.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/faqs_icon.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/faqs_icon.png new file mode 100644 index 00000000..c4538179 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/faqs_icon.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/icon_img.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/icon_img.png new file mode 100755 index 00000000..12db9a72 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/icon_img.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/main-b.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/main-b.png new file mode 100755 index 00000000..a988f5d2 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/main-b.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/new-sam-banner.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/new-sam-banner.gif new file mode 100755 index 00000000..4feda0a7 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/new-sam-banner.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/release_date_bg.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/release_date_bg.png new file mode 100644 index 00000000..45df6938 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/release_date_bg.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/release_icon.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/release_icon.png new file mode 100644 index 00000000..6cd33e2e Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/release_icon.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/simplify_banner_bg.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/simplify_banner_bg.png new file mode 100755 index 00000000..1b35c619 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/simplify_banner_bg.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/images/suggest-app-bg.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/suggest-app-bg.png new file mode 100644 index 00000000..04590264 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/images/suggest-app-bg.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/index.html b/backend/custom_addons/clarity_backend_theme_bits/static/description/index.html new file mode 100755 index 00000000..aa2d45e5 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/description/index.html @@ -0,0 +1,757 @@ + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+
+ + +
+
+
+ +
+ +
+

+ Clarity Backend Theme +

+

+ Odoo community backend theme +

+

+ The clarity backend theme have amazing appearance on any device and is easy to
+ switch between all screen sizes. Clicking on any menu is made simple with an
+ contemporary and modern sidebar. You can browse across different apps using
+ elegant sidebar menu.The theme is designed, keeping in mind the delivery of
+ great user experience and user-friendly interface to your users. +

+
+ +
+
+
+
+

+ App Drawer design for Community Addition +

+
+
+ +
+
+

+ Login & Signup Redesign +

+
+
+ +
+
+

+ Customized Discuss view design +

+
+
+ +
+
+

+ Show brand's logo in menu +

+
+
+ +
+
+

+ Customzed List, Form, Kanban view design +

+
+
+ +
+
+

+ Responsive sidebar design +

+
+
+ + +
+
+ +
+ +
+
+
+
+
+ + + + + +
+
+ + +
+
+ +
+
+
+ +
+
+

+ Custom discuss view +

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Interactive and clean design +

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Custom list view design +

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Custom kanban view design +

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Custom form view design +

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Custom sign up design +

+
(The login/signup design will appear only the backend login/signup view. + It will not appear in the website login/signup view.) +
+
+ +
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Custom login design +

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Custom reset form design +

+
+
+ +
+ +
+
+ +
+
+
+ +
+
+

+ Set company logo +

+
+
+ +
+ +
+
+ +
+
+
+
+ + + + + + + + + + + +
+
+ + +
+ +
+ +
+

+ Clarity Pro Backend Theme

+

+ The clarity backend theme have amazing appearance on any device and is easy to switch between all screen sizes. + The theme is designed, keeping in mind the delivery of great user experience and user-friendly interface to your users. +

+ +
+ + Main menu for community + + + Sidebar menu/top menu + + + Multi tabs management +
+ +
+ + Global search + + + Global search in record + + + Global search in menu +
+ +
+ + Multi font style + + + Multi icon style + + + Custom color schemes +
+ +
+ + Full-screen switch + + + Bookmark management + + + Attractive dark mode +
+ +
+ + Kanban & list view style + + + Checkbox & radio style + + + RTL support +
+ + +
+ +
+ + + +
+
+ +
+
+
+ + + + + + + + + + +
+
+ + +
+
+
+

Recommended Apps

+
+ +
+
+ + + + + + + + + + + + +
+
+
+
+
+
+ + + + +
+
+
+
+
+
+ +
+
+

+ Need any help for this module? +

+

+ Contact us + info@terabits.xyz + for your queries +

+
+
+
+
+ + + +
+
diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/logo.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/logo.gif new file mode 100755 index 00000000..33625610 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/logo.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/access-group.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/access-group.png new file mode 100644 index 00000000..665d6167 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/access-group.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-1.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-1.png new file mode 100644 index 00000000..c3e7a454 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-1.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-2.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-2.png new file mode 100644 index 00000000..bcc93b87 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-2.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-3.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-3.png new file mode 100644 index 00000000..0086b5c2 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-3.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-4.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-4.png new file mode 100644 index 00000000..4e5547cc Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-4.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-5.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-5.png new file mode 100644 index 00000000..a4f66967 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-5.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-6.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-6.png new file mode 100644 index 00000000..426afeeb Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/app-6.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/import-export.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/import-export.png new file mode 100644 index 00000000..6a27df98 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/import-export.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/law-firm.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/law-firm.gif new file mode 100644 index 00000000..fef50198 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/law-firm.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/login-withany-user.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/login-withany-user.png new file mode 100644 index 00000000..5aed9edf Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/login-withany-user.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/login_user_with_user_audit.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/login_user_with_user_audit.png new file mode 100644 index 00000000..a365c566 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/login_user_with_user_audit.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/new-sam-banner.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/new-sam-banner.gif new file mode 100644 index 00000000..4feda0a7 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/new-sam-banner.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/real-estate.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/real-estate.gif new file mode 100644 index 00000000..593c44f5 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/real-estate.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/sam.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/sam.gif new file mode 100644 index 00000000..883f004e Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/sam.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/soft-restrict.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/soft-restrict.png new file mode 100644 index 00000000..89f2a9e3 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/soft-restrict.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/user-audit.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/user-audit.gif new file mode 100644 index 00000000..c0e2f678 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/user-audit.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/wp-connector.png b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/wp-connector.png new file mode 100644 index 00000000..38527433 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/modules/wp-connector.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/new-sam-banner.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/new-sam-banner.gif new file mode 100755 index 00000000..4feda0a7 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/new-sam-banner.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/description/theme_screenshot.gif b/backend/custom_addons/clarity_backend_theme_bits/static/description/theme_screenshot.gif new file mode 100755 index 00000000..cf48b8fa Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/description/theme_screenshot.gif differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/img/logo.png b/backend/custom_addons/clarity_backend_theme_bits/static/img/logo.png new file mode 100755 index 00000000..0bb577d9 Binary files /dev/null and b/backend/custom_addons/clarity_backend_theme_bits/static/img/logo.png differ diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/js/Headerbar.js b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/Headerbar.js new file mode 100755 index 00000000..541c44cf --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/Headerbar.js @@ -0,0 +1,193 @@ +/** @odoo-module **/ + +import { Dropdown } from "@web/core/dropdown/dropdown"; +import { useService } from "@web/core/utils/hooks"; +import { registry } from "@web/core/registry"; +import { debounce } from "@web/core/utils/timing"; +import { ErrorHandler } from "@web/core/utils/components"; +import { NavBarDropdownItem,MenuDropdown } from '@web/static/src/webclient/navbar/navbar'; +import { + Component, + onWillDestroy, + useExternalListener, + useEffect, + useRef, + onWillUnmount, +} from "@odoo/owl"; +const systrayRegistry = registry.category("systray"); + +const getBoundingClientRect = Element.prototype.getBoundingClientRect; + +export class HeaderBar extends NavBar { + setup() { + this.currentAppSectionsExtra = []; + this.actionService = useService("action"); + this.menuService = useService("menu"); + this.root = useRef("root"); + this.appSubMenus = useRef("appSubMenus"); + const debouncedAdapt = debounce(this.adapt.bind(this), 250); + onWillDestroy(() => debouncedAdapt.cancel()); + useExternalListener(window, "resize", debouncedAdapt); + + let adaptCounter = 0; + const renderAndAdapt = () => { + adaptCounter++; + this.render(); + }; + + systrayRegistry.addEventListener("UPDATE", renderAndAdapt); + this.env.bus.addEventListener("MENUS:APP-CHANGED", renderAndAdapt); + + onWillUnmount(() => { + systrayRegistry.removeEventListener("UPDATE", renderAndAdapt); + this.env.bus.removeEventListener("MENUS:APP-CHANGED", renderAndAdapt); + }); + + // We don't want to adapt every time we are patched + // rather, we adapt only when menus or systrays have changed. + useEffect( + () => { + this.adapt(); + }, + () => [adaptCounter] + ); + } + + handleItemError(error, item) { + // remove the faulty component + item.isDisplayed = () => false; + Promise.resolve().then(() => { + throw error; + }); + } + + get currentApp() { + return this.menuService.getCurrentApp(); + } + + get currentAppSections() { + return ( + (this.currentApp && this.menuService.getMenuAsTree(this.currentApp.id).childrenTree) || + [] + ); + } + + // This dummy setter is only here to prevent conflicts between the + // Enterprise NavBar extension and the Website NavBar patch. + set currentAppSections(_) {} + + get systrayItems() { + return systrayRegistry + .getEntries() + .map(([key, value]) => ({ key, ...value })) + .filter((item) => ("isDisplayed" in item ? item.isDisplayed(this.env) : true)) + .reverse(); + } + + // This dummy setter is only here to prevent conflicts between the + // Enterprise NavBar extension and the Website NavBar patch. + set systrayItems(_) {} + + /** + * Adapt will check the available width for the app sections to get displayed. + * If not enough space is available, it will replace by a "more" menu + * the least amount of app sections needed trying to fit the width. + * + * NB: To compute the widths of the actual app sections, a render needs to be done upfront. + * By the end of this method another render may occur depending on the adaptation result. + */ + async adapt() { + if (!this.root.el) { + /** @todo do we still need this check? */ + // currently, the promise returned by 'render' is resolved at the end of + // the rendering even if the component has been destroyed meanwhile, so we + // may get here and have this.el unset + return; + } + + // ------- Initialize ------- + // Get the sectionsMenu + const sectionsMenu = this.appSubMenus.el; + if (!sectionsMenu) { + // No need to continue adaptations if there is no sections menu. + return; + } + + // Save initial state to further check if new render has to be done. + const initialAppSectionsExtra = this.currentAppSectionsExtra; + const firstInitialAppSectionExtra = [...initialAppSectionsExtra].shift(); + const initialAppId = firstInitialAppSectionExtra && firstInitialAppSectionExtra.appID; + + // Restore (needed to get offset widths) + const sections = [ + ...sectionsMenu.querySelectorAll(":scope > *:not(.o_menu_sections_more)"), + ]; + for (const section of sections) { + section.classList.remove("d-none"); + } + this.currentAppSectionsExtra = []; + + // ------- Check overflowing sections ------- + // use getBoundingClientRect to get unrounded values for width in order to avoid rounding problem + // with offsetWidth. + const sectionsAvailableWidth = getBoundingClientRect.call(sectionsMenu).width; + const sectionsTotalWidth = sections.reduce( + (sum, s) => sum + getBoundingClientRect.call(s).width, + 0 + ); + if (sectionsAvailableWidth < sectionsTotalWidth) { + // Sections are overflowing + // Initial width is harcoded to the width the more menu dropdown will take + let width = 46; + for (const section of sections) { + if (sectionsAvailableWidth < width + section.offsetWidth) { + // Last sections are overflowing + const overflowingSections = sections.slice(sections.indexOf(section)); + overflowingSections.forEach((s) => { + // Hide from normal menu + s.classList.add("d-none"); + // Show inside "more" menu + const sectionId = + s.dataset.section || + s.querySelector("[data-section]").getAttribute("data-section"); + const currentAppSection = this.currentAppSections.find( + (appSection) => appSection.id.toString() === sectionId + ); + this.currentAppSectionsExtra.push(currentAppSection); + }); + break; + } + width += section.offsetWidth; + } + } + + // ------- Final rendering ------- + const firstCurrentAppSectionExtra = [...this.currentAppSectionsExtra].shift(); + const currentAppId = firstCurrentAppSectionExtra && firstCurrentAppSectionExtra.appID; + if ( + initialAppSectionsExtra.length === this.currentAppSectionsExtra.length && + initialAppId === currentAppId + ) { + // Do not render if more menu items stayed the same. + return; + } + return this.render(); + } + + onNavBarDropdownItemSelection(menu) { + if (menu) { + this.menuService.selectMenu(menu); + } + } + + getMenuItemHref(payload) { + const parts = [`menu_id=${payload.id}`]; + if (payload.actionID) { + parts.push(`action=${payload.actionID}`); + } + return "#" + parts.join("&"); + } +} +HeaderBar.template = "web.NavBar"; +HeaderBar.components = { Dropdown, NavBarDropdownItem, MenuDropdown, ErrorHandler }; +HeaderBar.props = {}; diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/js/SidebarBottom.js b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/SidebarBottom.js new file mode 100755 index 00000000..d9a1e1f3 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/SidebarBottom.js @@ -0,0 +1,46 @@ +/** @odoo-module **/ + +import { Dropdown } from "@web/core/dropdown/dropdown"; +import { DropdownItem } from "@web/core/dropdown/dropdown_item"; +import { CheckBox } from "@web/core/checkbox/checkbox"; +import { browser } from "@web/core/browser/browser"; +import { registry } from "@web/core/registry"; +import { Component } from "@odoo/owl"; +import { user } from "@web/core/user"; +import { session } from "@web/session"; + + +const userMenuRegistry = registry.category("user_menuitems"); + +export class SidebarBottom extends Component { + setup() { + this.user = user; + this.dbName = session.db; + if (!this.user.userId || !this.env) { + return; + } + const { origin } = browser.location; + this.source = `${origin}/web/image?model=res.users&field=avatar_128&id=${this.user.userId}`; + } + + getElements() { + const sortedItems = userMenuRegistry + .getAll() + .map((element) => element(this.env)) + .sort((x, y) => { + const xSeq = x.sequence ? x.sequence : 100; + const ySeq = y.sequence ? y.sequence : 100; + return xSeq - ySeq; + }); + return sortedItems; + } +} + +SidebarBottom.template = "SidebarBottom"; +SidebarBottom.components = { Dropdown, DropdownItem, CheckBox }; +SidebarBottom.props = {}; + +registry.category("systray").add("SidebarBottom", { + Component: SidebarBottom, + sequence: 100, // Increased to avoid conflicts with MessagingMenu +}); \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/js/WebClient.js b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/WebClient.js new file mode 100755 index 00000000..6e096a0b --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/WebClient.js @@ -0,0 +1,110 @@ +/** @odoo-module **/ + +import { WebClient } from "@web/webclient/webclient"; +import { useService } from "@web/core/utils/hooks"; +import { useRef, onMounted } from "@odoo/owl"; +import { patch } from "@web/core/utils/patch"; +import { SidebarBottom } from "./SidebarBottom"; +import { rpc } from "@web/core/network/rpc"; +import { user } from "@web/core/user"; + +patch(WebClient.prototype, { + setup() { + super.setup(); + this.root = useRef("root"); + this.rpc = rpc; + this.menuService = useService("menu"); + this.currentCompany = user.activeCompanies && user.activeCompanies.length ? user.activeCompanies[0] : {}; + onMounted(() => { + this.fetchMenuData(); + }); + }, + + toggleSidebar(ev) { + const toggleEl = ev.currentTarget; + toggleEl.classList.toggle("visible"); + const navWrapper = document.querySelector(".nav-wrapper-bits"); + if (navWrapper) { + navWrapper.classList.toggle("toggle-show"); + } + }, + + + async fetchMenuData() { + try { + const menuData = this.menuService.getApps(); + const menuIds = menuData.map((app) => app.id); + const result = await this.rpc("/get/menu_data", { menu_ids: menuIds }); + for (const menu of menuData) { + const targetElem = this.root.el?.querySelector( + `.primary-nav a.main_link[data-menu="${menu.id}"] .app_icon` + ); + if (!targetElem) continue; + + targetElem.innerHTML = ""; + const prRecord = result[menu.id]?.[0]; + if (!prRecord) continue; + + menu.id = prRecord.id; + menu.use_icon = prRecord.use_icon; + menu.icon_class_name = prRecord.icon_class_name; + menu.icon_img = prRecord.icon_img; + + let iconImage; + if (prRecord.use_icon) { + if (prRecord.icon_class_name) { + iconImage = ``; + } else if (prRecord.icon_img) { + iconImage = ``; + } else if (prRecord.web_icon) { + const [iconPath, iconExt] = prRecord.web_icon.split("/icon."); + if (iconExt === "svg") { + const webSvgIcon = prRecord.web_icon.replace(",", "/"); + iconImage = ``; + } else { + iconImage = ``; + } + } else { + iconImage = ``; + } + } else { + if (prRecord.icon_img) { + iconImage = ``; + } else if (prRecord.web_icon) { + const [iconPath, iconExt] = prRecord.web_icon.split("/icon."); + if (iconExt === "svg") { + const webSvgIcon = prRecord.web_icon.replace(",", "/"); + iconImage = ``; + } else { + iconImage = ``; + } + } else { + iconImage = ``; + } + } + targetElem.innerHTML = iconImage; + } + } catch (error) { + console.error("Failed to fetch menu data:", error); + } + }, + + BackMenuToggle(ev) { + const parent = ev.currentTarget.parentElement; + if (parent) { + parent.classList.remove("show"); + } + }, + + get currentMenuId() { + const actionParams = window.location.hash; + const params = new URLSearchParams(actionParams.substring(1)); + return params.get("menu_id"); + }, + +}); + +patch(WebClient, { + components: { ...WebClient.components, SidebarBottom }, + // components: { ...WebClient.components, SidebarBottom, Transition }, +}); \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/js/navbar.js b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/navbar.js new file mode 100755 index 00000000..633b254a --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/js/navbar.js @@ -0,0 +1,67 @@ +/** @odoo-module **/ + +import { NavBar } from "@web/webclient/navbar/navbar"; +import { useService } from "@web/core/utils/hooks"; +import { patch } from "@web/core/utils/patch"; +import { useEnvDebugContext } from "@web/core/debug/debug_context"; +import { useState } from "@odoo/owl"; +import { rpc } from "@web/core/network/rpc"; +import { user } from "@web/core/user"; + +patch(NavBar.prototype, { + setup() { + super.setup(); + this.debugContext = useEnvDebugContext(); + this.rpc = rpc; + this.currentCompany = user.activeCompanies && user.activeCompanies.length ? user.activeCompanies[0] : {}; + this.menuService = useService("menu"); + this.state = useState({ + ...this.state, + isSidebarOpen: false, + }); + this.getMenuItemHref = this.getMenuItemHref.bind(this); + }, + + onNavBarDropdownItemSelection(menu) { + if (menu) { + this.menuService.selectMenu(menu); + } + }, + + get currentApp() { + return this.menuService.getCurrentApp(); + }, + + getMenuItemHref(payload) { + if (!payload || (!payload.actionPath && !payload.actionID)) { + return "#"; + } + return `/odoo/${payload.actionPath || "action-" + (payload.actionID || "")}`; + }, + + toggleSidebar(ev) { + this.state.isSidebarOpen = !this.state.isSidebarOpen; + const toggleEl = ev.currentTarget; + toggleEl.classList.toggle("visible"); + toggleEl.classList.toggle("sidebar-open"); + const navWrapper = document.querySelector(".nav-wrapper-bits"); + if (navWrapper) { + navWrapper.classList.toggle("toggle-show"); + } + }, + + BackMenuToggle() { + const subMenu = document.querySelector(".sub-menu-dropdown.show"); + if (subMenu) { + subMenu.classList.remove("show"); + } + }, + + get appsMenuProps() { + return { + getMenuItemHref: this.getMenuItemHref, + onNavBarDropdownItemSelection: this.onNavBarDropdownItemSelection.bind(this), + isSmall: this.state.isSmall, + }; + }, +}); \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/layout.scss b/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/layout.scss new file mode 100755 index 00000000..3e3dd9ca --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/layout.scss @@ -0,0 +1,680 @@ +body.o_web_client{ + flex-flow: row !important; + .wrapper-container-bits{ + display: flex; + width: 100%; + .content-wrapper-bits{ + width: 100%; + overflow-x: clip; + @media (max-width: 1540px) { + height: 100%; + // overflow: auto; + } + .btn-link{ + color: #282828 !important; + } + .btn.btn-primary{ + background-color: #282828 !important; + color: #fff !important; + border-color: #fff; + border: 1px solid #282828; + &:focus,&:active,&:hover{ + background-color: #fff !important; + color: #282828 !important; + border-color: #282828 !important; + } + } + .btn.btn-secondary{ + background-color: #f1eef5 !important; + color: #282828 !important; + // border-color: #282828; + // border: 1px solid #282828; + &:focus,&:active,&:hover{ + background-color: #f1eef5 !important; + // color: #fff !important; + // border-color: #f1eef5 !important; + } + } + .o_main_navbar{ + padding: 0 10px; + .o_menu_systray{ + align-items: center; + .o_user_menu{ + display: none !important; + } + button.dropdown-toggle{ + background-color: #282828; + margin: 0px 4px; + width: 35px; + height: 35px; + text-align: center; + justify-content: center; + border-radius: 6px; + i{ + color: #fff; + font-size: 16px !important; + } + .badge.rounded-pill{ + position: absolute; + right: -10px; + top: 2px; + background-color: #ffffff; + border-color: #282828; + border: 1px solid #282828; + color: #282828; + } + &.o_mobile_menu_toggle{ + padding: 15px !important; + } + } + .o_mobile_preview{ + a.o_nav_entry{ + + } + } + .o_website_switcher_container,.o_edit_website_container,.o_new_content_container,.o_mobile_preview{ + button.dropdown-toggle,a.o_nav_entry,.o_nav_entry,a.btn{ + width: auto !important; + background-color: #282828 !important; + margin: 0px 4px; + height: 35px !important; + text-align: center; + justify-content: center; + border-radius: 6px !important; + color: #fff !important; + } + + } + .o_menu_systray_item{ + a{ + .d-none.d-md-block.ms-1{ + color: #282828 !important; + } + } + } + // header button popup + .o-mail-DiscussSystray{ + box-shadow: 0px 1px 5px #abababed; + border-radius: 16px; + .o-mail-MessagingMenu-header{ + button.fw-bold{ + border-bottom: 1px solid #282828; + } + } + } + .o_mobile_menu_toggle{ + display: none !important; + } + } + .sidebar-toggler{ + cursor: pointer; + .sidebar-toggle-bits{ + font-size: 12px; + color: #282828; + i.back-arrow{ + width: 0px !important; + visibility: hidden; + opacity: 0; + } + } + &:hover{ + .sidebar-toggle-bits{ + i.toggle{ + width: 0px !important; + display: none !important; + } + i.back-arrow{ + visibility: visible; + opacity: 1; + transition: all 0.2s; + width: 100% !important; + font-size: 18px; + font-weight: 600; + margin-top: 4px; + } + } + } + } + } + .o_action_manager{ + height: 100%; + width: 100%; + .o_control_panel{ + padding: 10px 14px !important; + .o_control_panel_main{ + // create button + .o_control_panel_breadcrumbs{ + .o_control_panel_main_buttons{ + .btn-outline-primary{ + color: #282828 !important; + border-color: #282828 !important; + &:hover,&:focus,&:active{ + color: #fff !important; + background-color: #282828 !important; + } + } + } + .breadcrumb{ + .breadcrumb-item{ + a{ + color: #282828 !important; + } + } + } + } + // action button + .o_control_panel_actions{ + .btn-outline-secondary{ + border-color: #282828 !important; + i{ + color: #282828 !important; + } + span{ + color: #282828 !important; + } + } + .o_cp_searchview .o_searchview{ + border-radius: 8px 1px 1px 8px; + border-color: #282828; + } + .o-dropdown{ + button.o_searchview_dropdown_toggler{ + border-radius: 0px 8px 8px 0px; + } + } + .o_search_bar_menu{ + i{ + color: #282828 !important; + } + } + } + // navigation + .o_control_panel_navigation{ + .o_pager_counter{ + span{ + font-size: 18px; + } + } + button{ + font-size: 0.875rem; + border-radius: 6px !important; + border-color: #282828; + background-color: #fff !important; + color: #282828 !important; + height: 35px; + margin: 0px 3px; + &.active{ + background-color: #2828282e !important; + } + // width: 35px; + @media (max-width: 768px) { + width:auto !important; + } + } + } + } + } + // Discuss module in community + .o-mail-Discuss{ + width: 100%; + } + .o_content{ + overflow: auto !important; + height: 100vh; + margin-bottom: 60px; + max-height: calc(100vh - 100px); + } + // config setting view + .o-settings-form-view{ + .o_setting_container{ + .settings_tab{ + .app_name{ + font-size: 15px !important; + } + } + } + } + // form view + .o_form_view_container{ + .o_form_sheet_bg{ + .o_form_statusbar{ + // overflow: hidden; + .o_statusbar_buttons{ + .btn-primary{ + background-color: #71639e !important; + border-color: #71639e !important; + &:hover{ + background-color: #fff !important; + } + } + .btn-secondary{ + background-color: #fff !important; + border-color: #71639e !important; + &:hover{ + background-color: #71639e !important; + } + } + } + .o_arrow_button{ + border-color: #71639e !important; + background-color: #fff; + &:after{ + border-color: #fff; + } + } + .o_statusbar_status{ + .o_arrow_button{ + border: none !important; + } + } + //////////////////////////////////////////////////////////////// + .o_statusbar_status { + .o_arrow_button { + font-size: 14px; + text-align: center; + cursor: default; + margin: 0 3px; + padding: 5px 25px; + float: left; + position: relative; + background-color: #d9e3f7 !important; + user-select: none; + transition: background-color 0.2s ease; + &:after,&:before{ + content: " "; + position: absolute; + top: 0; + right: -17px; + width: 0; + height: 0; + border-top: 15px solid transparent; + border-bottom: 15px solid transparent; + border-left: 17px solid #d9e3f7; + z-index: 2; + transition: border-color 0.2s ease; + } + &:hover{ + color: #282828 !important; + } + &:before{ + right: auto; + left: 0; + border-left: 17px solid #f8f9fa; + z-index: 0; + } + &:first-child{ + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + &:before { + border: none; + } + } + &.o_arrow_button_current{ + color: #fff !important; + span{ + color: #fff !important; + } + background-color: #71639e !important; + &:after{ + border-left: 17px solid #71639e; + } + } + } + } + } + //////////////////////////////////////////////////////////////// + .o_form_sheet{ + border-radius: 8px; + box-shadow: 0px 0px 3px #919191; + border: none; + .o_cell{ + label,span,a{ + font-size: 15px !important; + } + } + .o_form_uri{ + span:first-child{ + color: #282828 !important; + } + } + .o_notebook{ + .o_notebook_headers{ + .nav.nav-tabs{ + border-top: 1px solid #dee2e6; + padding: 0px !important; + .nav-item .nav-link{ + color: #484848; + display: block; + border-right: 1px solid #2828286b !important; + padding: 10px; + font-weight: 500; + &:after{ + height: 5px; + background-color: #282828; + } + &:before{ + height: 5px; + background-color: #282828; + } + &.active{ + border-bottom: 2px solid #31485e; + background: #f9f9f9 !important; + font-weight: 600; + } + } + } + } + } + } + .o_list_renderer{ + table{ + a{ + color: #000730 !important; + } + } + } + } + } + // kanban view + .o_kanban_view{ + .o_kanban_record{ + margin: 14px 5px 0px !important; + border-radius: 15px; + .oe_kanban_card,.oe_kanban_global_click{ + border-radius: 8px; + border-color: #2828286e; + border: 1px solid #28282812; + box-shadow: 0px 3px 4px 0px rgba(0, 0, 0, 0.03); + padding: 14px; + } + } + } + // list view + .o_list_view.o_action{ + height: 100%; + .o_content{ + padding: 10px 14px; + } + .o_list_renderer{ + border: 0px !important; + border-radius: 8px; + box-shadow: 0px 0px 3px #919191; + .o_list_table{ + table-layout: auto !important; + thead{ + th{ + padding: 10px 12px; + background-color: #282828; + color: #fff !important; + button{ + color: #fff !important; + } + .form-check-input{ + background-color: #fff !important; + } + } + } + tbody{ + tr{ + border-color: #28282899; + border: none ; + td{ + border: none; + padding: 14px 12px; + color: #282828 !important; + font-size: 15px !important; + font-weight: 500; + } + &.o_data_row{ + border-bottom-width: 1px !important; + border-bottom-style: dashed !important; + } + } + box-shadow: 0px 1px 2px #e2e2e2; + border-radius: 12px; + } + tfoot{ + tr{ + td{ + border: none; + padding: 10px 12px; + color: #282828 !important; + } + } + } + } + .form-check{ + .form-check-input{ + &:checked{ + background-color: #282828 !important; + border-color: #282828 !important; + } + } + } + } + } + // graph view + .o_graph_view { + .o_content { + height: calc(100vh - 100px); + } + } + // discuss view + .o-mail-Discuss{ + background: #fff !important; + .o-mail-DiscussSidebar{ + margin: 7px; + border: none !important; + box-shadow: 0px 1px 4px #9191912e; + border-radius: 14px; + .o-mail-DiscussSidebar-item{ + background: #e3e3e39e; + color: #282828 !important; + border-radius: 7px !important; + margin: 5px 10px; + padding: 10px 0 !important; + font-weight: 600 !important; + } + } + //changed name in odoo 19 + .o-mail-DiscussContent-core{ + height: calc(100vh - 90px) !important; + overflow: scroll !important; + .o-mail-Discuss-header{ + border-bottom: none !important; + } + .o-mail-Thread{ + overflow: scroll; + margin: 7px; + box-shadow: 0px 0px 6px #413d3d3b !important; + border: 1px solid #28282800; + border-radius: 14px; + //msg section + .o-mail-Message{ + margin-top: 16px !important; + .o-mail-Message-core{ + //right content / msg content + .o-min-width-0{ + .o-mail-Message-header{ + .o-mail-Message-author{ + font-size: 16px; + margin: 8px 0px; + } + } + .o-mail-Message-content{ + .o-mail-Message-bubble{ + border-radius: 0px 10px 6px 10px !important; + .o-mail-Message-body{ + padding: 15px 25px !important; + } + } + } + } + } + } + } + .o-mail-Composer{ + .o-mail-Composer-coreMain{ + .btn{ + color: #282828 !important; + } + .o-mail-Composer-send{ + background: #282828 !important; + margin: 0 !important; + opacity: 1; + color: #fff !important; + } + + } + } + } + } + } + #terabits-link{ + h2{ + padding: 12px 28px; + background: #eee; + font-size: 15px !important; + } + } + } + } + &.editor_has_snippets_hide_backend_navbar{ + .nav-wrapper-bits{ + display: none; + } + } +} +.menu { + display: block; + width: 250px; + height: 100%; + transition: all 0.45s cubic-bezier(0.77, 0, 0.175, 1); + z-index: 999; + .icon { + position: absolute; + top: 12px; + right: 10px; + pointer-events: none; + width: 24px; + height: 24px; + color: #fff; + } + a { + display: block; + white-space: nowrap; + } +} + +.menu, +.menu a, +.menu a:visited { + color: #aaa; + text-decoration: none!important; + position: relative; +} +.new-wrapper { + position: absolute; + left: 50px; + width: calc(100% - 50px); + transition: transform .45s cubic-bezier(0.77, 0, 0.175, 1); +} + +#menu:checked + ul.menu-dropdown { + left: 0; + -webkit-animation: all .45s cubic-bezier(0.77, 0, 0.175, 1); + animation: all .45s cubic-bezier(0.77, 0, 0.175, 1); +} +.sub-menu-checkbox:checked + ul.sub-menu-dropdown { + display: block!important; + -webkit-animation: grow .45s cubic-bezier(0.77, 0, 0.175, 1); + animation: grow .45s cubic-bezier(0.77, 0, 0.175, 1); +} +.openNav .new-wrapper { + position: absolute; + transform: translate3d(200px, 0, 0); + width: calc(100% - 250px); + transition: transform .45s cubic-bezier(0.77, 0, 0.175, 1); +} + +.downarrow { + background: transparent; + position: absolute; + right: 50px; + top: 12px; + color: #777; + width: 24px; + height: 24px; + text-align: center; + display: block; +} +.downarrow:hover { + color: #fff; +} +.menu-dropdown { + top: 0; + overflow-y: auto; +} +.overflow-container { + position: relative; + height: 100% !important; + overflow-y: auto; + z-index: -1; + display:block; +} +.sub-menu-dropdown { + background-color: #333; +} +.openNav .menu { + top: 73px; + transform: translate3d(200px, 0, 0); + transition: transform .45s cubic-bezier(0.77, 0, 0.175, 1); +} + + +@-webkit-keyframes grow { + + 0% { + display: none; + opacity: 0; + } + 50% { + display: block; + opacity: 0.5; + } + 100% { + opacity: 1; + } + +} + +@keyframes grow { + + 0% { + display: none; + opacity: 0; + } + 50% { + display: block; + opacity: 0.5; + } + 100% { + opacity: 1 + } + +} +.o_navbar_apps_menu{ + height: 100%; +} +//neutralized title fix ui in odoo +#oe_neutralize_banner{ + position: fixed !important; + top: 0; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + justify-content: center; + z-index: 99999 !important; + width: auto; +} diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/login.scss b/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/login.scss new file mode 100755 index 00000000..24813adc --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/login.scss @@ -0,0 +1,70 @@ +#wrapwrap{ + .login-view-bits{ + .oe_login_form,.oe_signup_form,.oe_reset_password_form{ + .input-group{ + a.btn{ + background-color: #282828; + color: #fff !important; + border-radius: 0px 8px 8px 0px !important; + display: flex !important; + align-items: center; + i{ + color: #fff !important; + padding-left: 5px; + margin-top: -4px; + } + } + } + input,.form-control{ + display: block; + width: 100%; + padding: 0.775rem 1rem; + font-size: 1.1rem; + font-weight: 500; + line-height: 1.5; + color: #4B5675; + appearance: none; + background-clip: padding-box; + border: 1px solid #DBDFE9; + border-radius: 0.475rem; + transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; + &#db{ + border-radius: 8px 0px 0px 8px !important; + } + } + .col-form-label,.form-label{ + font-size: 14px !important; + font-weight: bold !important; + } + } + .card-body{ + + box-shadow: 0px 0px 10px #d2d1d1; + border-radius: 30px; + } + .oe_login_buttons{ + .btn-primary[type=submit]{ + padding: 14px; + border-radius: 8px; + background: #282828; + color: #fff; + font-size: 14px; + &:hover,&:active,&:focus{ + color: #282828; + background: #fff; + border: 1px solid #282828; + } + } + a,button.btn{ + font-size: 12px; + font-weight: 600; + } + } + div.small{ + a,button.btn{ + font-size: 12px; + font-weight: 600; + } + } + } +} \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/navbar.scss b/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/navbar.scss new file mode 100755 index 00000000..be689cb6 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/scss/navbar.scss @@ -0,0 +1,301 @@ +body.o_web_client{ + .nav-wrapper-bits{ + display: none ; + &.toggle-show{ + display: flex; + flex-direction: column; + justify-content: space-between; + background-color: #282828; + height: 100%; + z-index: 999; + header{ + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + } + .sytray-container-bits{ + margin: 5px 5px; + background-color: none !important; + button{ + width: 100%; + border: none !important; + box-shadow: none !important; + background: #343434; + border-radius: 10px; + img{ + width: 35px; + border-radius: 30px !important; + } + } + mark{ + font-size: 14px; + margin-top: 8px; + background: #fff !important; + padding: 7px; + border-radius: 8px; + } + .o_user_menu{ + .o-dropdown--menu{ + min-width: 15rem !important; + .dropdown-item{ + padding: 5px 20px !important; + } + // @media (max-width: 768px) { + // width: 100%; + // height: 100%; + // display: flex; + // justify-content: center; + // align-items: center; + + // } + } + } + + .powered-by{ + display: none; + } + &:hover{ + .powered-by{ + display: block !important; + color: #fff; + a{ + color: #aab6ff !important; + } + } + } + } + } + .btm-user-menu{ + z-index: 999; + width: 250px; + } + @media (max-width: 768px) { + position: absolute; + top: 0; + bottom: 0; + height: 100%; + z-index: 11; + } + } + header.o_navbar{ + nav{ + background-color: transparent !important; + border-bottom: none !important; + height: 100%; + } + .o-mail-DiscussSystray-class{ + background-color: #282828 !important; + margin: 0px 4px; + width: 35px; + height: 35px; + text-align: center; + justify-content: center; + border-radius: 6px; + } + .o_company_logo{ + padding: 8px 20px !important; + display: flex; + align-items: center; + justify-content: space-between; + background: #343434; + border-radius: 10px; + margin: 5px 5px; + i{ + color: #fff !important; + font-size: 20px; + display: none; + @media (max-width: 768px) { + display: block; + } + } + img{ + width: 150px; + height: 70px; + object-fit: contain; + } + } + } + .primary-nav{ + flex: 1 1 0 !important; + overflow-y: auto; + .overflow-container{ + .main_link{ + .app_icon{ + height: 25px !important; + width: 25px !important; + display: inline-flex; + img{ + object-fit: contain; + } + } + } + } + ul#menu-dropdown{ + list-style-type: none !important; + padding-left: 5px !important; + li a.main_link{ + display: flex; + align-items: center !important; + padding: 1em; + font-size: 14px; + } + ul.header-sub-menus.main{ + list-style-type: none !important; + z-index: 3; + position: absolute; + left: 0; + background-color: #282828 !important; + height: 100%; + top: 0; + width: 100%; + padding: 0px 12px; + // &:not(.show){ + // left: 100% !important; + // } + &:not(.show){ + display: none; + width: 0% ; + } + .back_main_menu{ + position: relative; + margin-left: -18px; + h3{ + color: #ffff !important; + cursor: pointer; + } + } + li{ + margin-left: 10px ; + background: #282828; + .header-sub-menus{ + list-style-type: none !important; + border-left: 1px solid #717171; + padding: 0; + } + .sub-main-menu{ + cursor: pointer !important; + font-size: 14px; + color: #fff; + font-weight: 600; + background: #282828; + } + } + // @media (max-width: 768px) { + // position: relative !important; + // .back_main_menu{ + // display: none !important; + // } + // } + // &.show{ + // li{ + // .collapse{ + // display: block; + // } + // } + // } + a{ + padding: 0.5rem !important; + font-size: 12px !important; + } + &.show{ + li{ + .sub-main-menu{ + background: #eeeeee14; + padding: 5px 10px !important; + border-radius: 8px; + margin: 8px 0px; + } + } + } + } + } + ::-webkit-scrollbar-track + { + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); + background-color: #F5F5F5; + } + + ::-webkit-scrollbar + { + width: 6px; + background-color: #F5F5F5; + } + + ::-webkit-scrollbar-thumb + { + background-color: #575757; + } + } +} +.button_bg_hover:hover { + background-color: gray; + color:black; +} +.menu-hasdropdown { + .button_bg_hover { + margin-right: 7%; + } +} + +.header-sub-menus .button_bg_hover { + margin-right: 0; +} + +.sidebar-toggler { + .sidebar-toggle-bits { + .chevron-toggle { + transition: transform 0.3s ease; + } + + &.sidebar-open .chevron-toggle { + transform: rotate(180deg); + } + + &:not(.sidebar-open) .chevron-toggle { + transform: rotate(0deg); + } + } +} + +.sub-main-menu { + .chevron-toggle { + transition: transform 0.3s ease; + } + + &[aria-expanded="true"] .chevron-toggle { + transform: rotate(90deg); + } + + &[aria-expanded="false"] .chevron-toggle { + transform: rotate(0deg); + } +} +.o_user_avatar{ + height: 15%; + width: 15%; +} +.user-avtar-bits { + position: relative; + overflow: hidden; + transition: max-height 0.3s ease; + max-height: 100px; +} + +.user-avtar-bits:hover { + max-height: 120px; +} + +.powered-by { + opacity: 0; + transform: translateY(10px); + transition: opacity 0.3s ease, transform 0.3s ease; + pointer-events: none; + margin-top: 5px; +} + +.user-avtar-bits:hover .powered-by { + opacity: 1; + transform: translateY(0); + pointer-events: auto; +} diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/WebClient.xml b/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/WebClient.xml new file mode 100755 index 00000000..4eefd60f --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/WebClient.xml @@ -0,0 +1,33 @@ + + + + +
+ +
+ + + + + +
+
+
+
+
\ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/navbar/sidebar.xml b/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/navbar/sidebar.xml new file mode 100755 index 00000000..33c6e181 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/navbar/sidebar.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/systray_items/user_menu.xml b/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/systray_items/user_menu.xml new file mode 100755 index 00000000..88472684 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/static/src/xml/systray_items/user_menu.xml @@ -0,0 +1,64 @@ + + + + + + + User + + + + + +
+ + + + + + + + + \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/views/res_config_setting.xml b/backend/custom_addons/clarity_backend_theme_bits/views/res_config_setting.xml new file mode 100755 index 00000000..72ff3124 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/views/res_config_setting.xml @@ -0,0 +1,29 @@ + + + + res.config.settings.view.form.inherit.base + res.config.settings + + + + + + + + + \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/views/res_users.xml b/backend/custom_addons/clarity_backend_theme_bits/views/res_users.xml new file mode 100755 index 00000000..0818285f --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/views/res_users.xml @@ -0,0 +1,23 @@ + + + + res.users.form + res.users + + + + + + + + + \ No newline at end of file diff --git a/backend/custom_addons/clarity_backend_theme_bits/views/webclient_templates.xml b/backend/custom_addons/clarity_backend_theme_bits/views/webclient_templates.xml new file mode 100755 index 00000000..adb879b9 --- /dev/null +++ b/backend/custom_addons/clarity_backend_theme_bits/views/webclient_templates.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/new_project/custom_addons/encoach_adaptive/__init__.py b/backend/custom_addons/encoach_adaptive/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/__init__.py rename to backend/custom_addons/encoach_adaptive/__init__.py diff --git a/new_project/custom_addons/encoach_adaptive/__manifest__.py b/backend/custom_addons/encoach_adaptive/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/__manifest__.py rename to backend/custom_addons/encoach_adaptive/__manifest__.py diff --git a/new_project/custom_addons/encoach_adaptive/controllers/__init__.py b/backend/custom_addons/encoach_adaptive/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/controllers/__init__.py rename to backend/custom_addons/encoach_adaptive/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_adaptive/controllers/adaptive.py b/backend/custom_addons/encoach_adaptive/controllers/adaptive.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/controllers/adaptive.py rename to backend/custom_addons/encoach_adaptive/controllers/adaptive.py diff --git a/new_project/custom_addons/encoach_adaptive/data/ir_cron.xml b/backend/custom_addons/encoach_adaptive/data/ir_cron.xml similarity index 100% rename from new_project/custom_addons/encoach_adaptive/data/ir_cron.xml rename to backend/custom_addons/encoach_adaptive/data/ir_cron.xml diff --git a/new_project/custom_addons/encoach_adaptive/models/__init__.py b/backend/custom_addons/encoach_adaptive/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/models/__init__.py rename to backend/custom_addons/encoach_adaptive/models/__init__.py diff --git a/new_project/custom_addons/encoach_adaptive/models/adaptive_event.py b/backend/custom_addons/encoach_adaptive/models/adaptive_event.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/models/adaptive_event.py rename to backend/custom_addons/encoach_adaptive/models/adaptive_event.py diff --git a/new_project/custom_addons/encoach_adaptive/models/adaptive_path.py b/backend/custom_addons/encoach_adaptive/models/adaptive_path.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/models/adaptive_path.py rename to backend/custom_addons/encoach_adaptive/models/adaptive_path.py diff --git a/new_project/custom_addons/encoach_adaptive/models/adaptive_settings.py b/backend/custom_addons/encoach_adaptive/models/adaptive_settings.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/models/adaptive_settings.py rename to backend/custom_addons/encoach_adaptive/models/adaptive_settings.py diff --git a/new_project/custom_addons/encoach_adaptive/security/ir.model.access.csv b/backend/custom_addons/encoach_adaptive/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_adaptive/security/ir.model.access.csv rename to backend/custom_addons/encoach_adaptive/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_adaptive/services/__init__.py b/backend/custom_addons/encoach_adaptive/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/services/__init__.py rename to backend/custom_addons/encoach_adaptive/services/__init__.py diff --git a/new_project/custom_addons/encoach_adaptive/services/adaptive_engine.py b/backend/custom_addons/encoach_adaptive/services/adaptive_engine.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/services/adaptive_engine.py rename to backend/custom_addons/encoach_adaptive/services/adaptive_engine.py diff --git a/new_project/custom_addons/encoach_adaptive/services/alert_service.py b/backend/custom_addons/encoach_adaptive/services/alert_service.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/services/alert_service.py rename to backend/custom_addons/encoach_adaptive/services/alert_service.py diff --git a/new_project/custom_addons/encoach_adaptive/services/style_matcher.py b/backend/custom_addons/encoach_adaptive/services/style_matcher.py similarity index 100% rename from new_project/custom_addons/encoach_adaptive/services/style_matcher.py rename to backend/custom_addons/encoach_adaptive/services/style_matcher.py diff --git a/new_project/custom_addons/encoach_adaptive/static/src/css/signal_timeline.css b/backend/custom_addons/encoach_adaptive/static/src/css/signal_timeline.css similarity index 100% rename from new_project/custom_addons/encoach_adaptive/static/src/css/signal_timeline.css rename to backend/custom_addons/encoach_adaptive/static/src/css/signal_timeline.css diff --git a/new_project/custom_addons/encoach_adaptive/static/src/js/signal_timeline.js b/backend/custom_addons/encoach_adaptive/static/src/js/signal_timeline.js similarity index 100% rename from new_project/custom_addons/encoach_adaptive/static/src/js/signal_timeline.js rename to backend/custom_addons/encoach_adaptive/static/src/js/signal_timeline.js diff --git a/new_project/custom_addons/encoach_adaptive/static/src/xml/signal_timeline.xml b/backend/custom_addons/encoach_adaptive/static/src/xml/signal_timeline.xml similarity index 100% rename from new_project/custom_addons/encoach_adaptive/static/src/xml/signal_timeline.xml rename to backend/custom_addons/encoach_adaptive/static/src/xml/signal_timeline.xml diff --git a/new_project/custom_addons/encoach_adaptive/views/adaptive_event_views.xml b/backend/custom_addons/encoach_adaptive/views/adaptive_event_views.xml similarity index 100% rename from new_project/custom_addons/encoach_adaptive/views/adaptive_event_views.xml rename to backend/custom_addons/encoach_adaptive/views/adaptive_event_views.xml diff --git a/new_project/custom_addons/encoach_adaptive/views/adaptive_menus.xml b/backend/custom_addons/encoach_adaptive/views/adaptive_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_adaptive/views/adaptive_menus.xml rename to backend/custom_addons/encoach_adaptive/views/adaptive_menus.xml diff --git a/new_project/custom_addons/encoach_adaptive/views/adaptive_path_views.xml b/backend/custom_addons/encoach_adaptive/views/adaptive_path_views.xml similarity index 100% rename from new_project/custom_addons/encoach_adaptive/views/adaptive_path_views.xml rename to backend/custom_addons/encoach_adaptive/views/adaptive_path_views.xml diff --git a/new_project/custom_addons/encoach_adaptive/views/adaptive_settings_views.xml b/backend/custom_addons/encoach_adaptive/views/adaptive_settings_views.xml similarity index 100% rename from new_project/custom_addons/encoach_adaptive/views/adaptive_settings_views.xml rename to backend/custom_addons/encoach_adaptive/views/adaptive_settings_views.xml diff --git a/new_project/custom_addons/encoach_adaptive/views/signal_timeline_action.xml b/backend/custom_addons/encoach_adaptive/views/signal_timeline_action.xml similarity index 100% rename from new_project/custom_addons/encoach_adaptive/views/signal_timeline_action.xml rename to backend/custom_addons/encoach_adaptive/views/signal_timeline_action.xml diff --git a/new_project/custom_addons/encoach_ai_course/__init__.py b/backend/custom_addons/encoach_ai_course/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/__init__.py rename to backend/custom_addons/encoach_ai_course/__init__.py diff --git a/new_project/custom_addons/encoach_ai_course/__manifest__.py b/backend/custom_addons/encoach_ai_course/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/__manifest__.py rename to backend/custom_addons/encoach_ai_course/__manifest__.py diff --git a/new_project/custom_addons/encoach_ai_course/controllers/__init__.py b/backend/custom_addons/encoach_ai_course/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/controllers/__init__.py rename to backend/custom_addons/encoach_ai_course/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_ai_course/controllers/ai_course.py b/backend/custom_addons/encoach_ai_course/controllers/ai_course.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/controllers/ai_course.py rename to backend/custom_addons/encoach_ai_course/controllers/ai_course.py diff --git a/new_project/custom_addons/encoach_ai_course/models/__init__.py b/backend/custom_addons/encoach_ai_course/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/models/__init__.py rename to backend/custom_addons/encoach_ai_course/models/__init__.py diff --git a/new_project/custom_addons/encoach_ai_course/models/ai_generation_log.py b/backend/custom_addons/encoach_ai_course/models/ai_generation_log.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/models/ai_generation_log.py rename to backend/custom_addons/encoach_ai_course/models/ai_generation_log.py diff --git a/new_project/custom_addons/encoach_ai_course/models/ai_ielts_generation_log.py b/backend/custom_addons/encoach_ai_course/models/ai_ielts_generation_log.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/models/ai_ielts_generation_log.py rename to backend/custom_addons/encoach_ai_course/models/ai_ielts_generation_log.py diff --git a/new_project/custom_addons/encoach_ai_course/security/ir.model.access.csv b/backend/custom_addons/encoach_ai_course/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_ai_course/security/ir.model.access.csv rename to backend/custom_addons/encoach_ai_course/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_ai_course/services/__init__.py b/backend/custom_addons/encoach_ai_course/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/services/__init__.py rename to backend/custom_addons/encoach_ai_course/services/__init__.py diff --git a/new_project/custom_addons/encoach_ai_course/services/english_pipeline.py b/backend/custom_addons/encoach_ai_course/services/english_pipeline.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/services/english_pipeline.py rename to backend/custom_addons/encoach_ai_course/services/english_pipeline.py diff --git a/new_project/custom_addons/encoach_ai_course/services/ielts_pipeline.py b/backend/custom_addons/encoach_ai_course/services/ielts_pipeline.py similarity index 100% rename from new_project/custom_addons/encoach_ai_course/services/ielts_pipeline.py rename to backend/custom_addons/encoach_ai_course/services/ielts_pipeline.py diff --git a/new_project/custom_addons/encoach_ai_course/views/ai_course_menus.xml b/backend/custom_addons/encoach_ai_course/views/ai_course_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_ai_course/views/ai_course_menus.xml rename to backend/custom_addons/encoach_ai_course/views/ai_course_menus.xml diff --git a/new_project/custom_addons/encoach_ai_course/views/ai_generation_log_views.xml b/backend/custom_addons/encoach_ai_course/views/ai_generation_log_views.xml similarity index 100% rename from new_project/custom_addons/encoach_ai_course/views/ai_generation_log_views.xml rename to backend/custom_addons/encoach_ai_course/views/ai_generation_log_views.xml diff --git a/new_project/custom_addons/encoach_ai_course/views/ai_ielts_log_views.xml b/backend/custom_addons/encoach_ai_course/views/ai_ielts_log_views.xml similarity index 100% rename from new_project/custom_addons/encoach_ai_course/views/ai_ielts_log_views.xml rename to backend/custom_addons/encoach_ai_course/views/ai_ielts_log_views.xml diff --git a/new_project/custom_addons/encoach_ai_course/views/ai_review_views.xml b/backend/custom_addons/encoach_ai_course/views/ai_review_views.xml similarity index 100% rename from new_project/custom_addons/encoach_ai_course/views/ai_review_views.xml rename to backend/custom_addons/encoach_ai_course/views/ai_review_views.xml diff --git a/new_project/custom_addons/encoach_ai_course/views/ielts_review_views.xml b/backend/custom_addons/encoach_ai_course/views/ielts_review_views.xml similarity index 100% rename from new_project/custom_addons/encoach_ai_course/views/ielts_review_views.xml rename to backend/custom_addons/encoach_ai_course/views/ielts_review_views.xml diff --git a/new_project/custom_addons/encoach_api/__init__.py b/backend/custom_addons/encoach_api/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_api/__init__.py rename to backend/custom_addons/encoach_api/__init__.py diff --git a/new_project/custom_addons/encoach_api/__manifest__.py b/backend/custom_addons/encoach_api/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_api/__manifest__.py rename to backend/custom_addons/encoach_api/__manifest__.py diff --git a/new_project/custom_addons/encoach_api/controllers/__init__.py b/backend/custom_addons/encoach_api/controllers/__init__.py similarity index 50% rename from new_project/custom_addons/encoach_api/controllers/__init__.py rename to backend/custom_addons/encoach_api/controllers/__init__.py index 0e444493..736bd7e7 100644 --- a/new_project/custom_addons/encoach_api/controllers/__init__.py +++ b/backend/custom_addons/encoach_api/controllers/__init__.py @@ -1 +1,2 @@ from . import base +from . import auth diff --git a/backend/custom_addons/encoach_api/controllers/auth.py b/backend/custom_addons/encoach_api/controllers/auth.py new file mode 100644 index 00000000..4b4b4226 --- /dev/null +++ b/backend/custom_addons/encoach_api/controllers/auth.py @@ -0,0 +1,146 @@ +import logging +import time + +import jwt as pyjwt + +from odoo import http, fields +from odoo.http import request +from odoo.exceptions import AccessDenied + +from .base import ( + _json_response, _error_response, _get_json_body, _get_jwt_secret, validate_token, +) + +_logger = logging.getLogger(__name__) + + +class EncoachAuthController(http.Controller): + + # ------------------------------------------------------------------ + # POST /api/login + # ------------------------------------------------------------------ + @http.route('/api/login', type='http', auth='public', + methods=['POST'], csrf=False) + def login(self, **kw): + try: + body = _get_json_body() + login = (body.get('login') or body.get('email') or '').strip().lower() + password = body.get('password', '') + + if not login or not password: + return _error_response('login and password are required', 400) + + # Odoo 19: session.authenticate(env, credential_dict) + credential = { + 'type': 'password', + 'login': login, + 'password': password, + } + try: + request.session.authenticate(request.env, credential) + uid = request.session.uid + if not uid: + return _error_response('Invalid email or password', 401) + except AccessDenied: + return _error_response('Invalid email or password', 401) + except Exception as auth_err: + _logger.warning('Auth error for %s: %s', login, auth_err) + return _error_response('Invalid email or password', 401) + + user = request.env['res.users'].sudo().browse(uid) + + # Generate JWT token + secret = _get_jwt_secret() + if not secret: + return _error_response('JWT not configured on server', 500) + + token = pyjwt.encode( + {'user_id': user.id, 'exp': int(time.time()) + 86400}, + secret, algorithm='HS256', + ) + + # Get permissions + permissions = [] + if hasattr(user, 'get_all_permissions'): + permissions = user.get_all_permissions().mapped('code') + + # Update last login + user.write({'last_login': fields.Datetime.now()}) + + return _json_response({ + 'token': token, + 'user': self._user_to_dict(user), + 'permissions': permissions, + }) + + except Exception as e: + _logger.exception('login failed') + return _error_response(str(e), 500) + + # ------------------------------------------------------------------ + # GET /api/user (returns current authenticated user) + # ------------------------------------------------------------------ + @http.route('/api/user', type='http', auth='public', + methods=['GET'], csrf=False) + def get_current_user(self, **kw): + try: + user = validate_token() + if not user: + return _error_response('Authentication required', 401) + + permissions = [] + if hasattr(user, 'get_all_permissions'): + permissions = user.get_all_permissions().mapped('code') + + return _json_response({ + 'user': self._user_to_dict(user), + 'permissions': permissions, + }) + + except Exception as e: + _logger.exception('get_current_user failed') + return _error_response(str(e), 500) + + # ------------------------------------------------------------------ + # POST /api/logout + # ------------------------------------------------------------------ + @http.route('/api/logout', type='http', auth='public', + methods=['POST'], csrf=False) + def logout(self, **kw): + # JWT is stateless — client clears token. Server just returns OK. + return _json_response({'ok': True}) + + # ------------------------------------------------------------------ + # helpers + # ------------------------------------------------------------------ + def _user_to_dict(self, user): + """Convert res.users to the dict shape the React frontend expects.""" + entities = [] + if hasattr(user, 'entity_ids'): + entities = [ + {'id': e.id, 'name': e.name, 'role': ''} + for e in user.entity_ids + ] + + classrooms = [] + + return { + 'id': user.id, + 'name': user.name or '', + 'email': user.email or '', + 'login': user.login or '', + 'user_type': getattr(user, '_api_user_type', lambda: user.user_type or 'student')() + if callable(getattr(user, '_api_user_type', None)) + else (user.user_type or 'student'), + 'avatar': bool(getattr(user, 'encoach_avatar', False)), + 'phone': user.phone or '', + 'country': '', + 'timezone': '', + 'bio': '', + 'gender': getattr(user, 'gender', '') or '', + 'student_id': '', + 'is_verified': getattr(user, 'is_verified', False), + 'entities': entities, + 'classrooms': classrooms, + 'expiry_date': '', + } diff --git a/new_project/custom_addons/encoach_api/controllers/base.py b/backend/custom_addons/encoach_api/controllers/base.py similarity index 100% rename from new_project/custom_addons/encoach_api/controllers/base.py rename to backend/custom_addons/encoach_api/controllers/base.py diff --git a/new_project/custom_addons/encoach_branding/__init__.py b/backend/custom_addons/encoach_branding/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_branding/__init__.py rename to backend/custom_addons/encoach_branding/__init__.py diff --git a/new_project/custom_addons/encoach_branding/__manifest__.py b/backend/custom_addons/encoach_branding/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_branding/__manifest__.py rename to backend/custom_addons/encoach_branding/__manifest__.py diff --git a/new_project/custom_addons/encoach_branding/controllers/__init__.py b/backend/custom_addons/encoach_branding/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_branding/controllers/__init__.py rename to backend/custom_addons/encoach_branding/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_branding/controllers/branding.py b/backend/custom_addons/encoach_branding/controllers/branding.py similarity index 100% rename from new_project/custom_addons/encoach_branding/controllers/branding.py rename to backend/custom_addons/encoach_branding/controllers/branding.py diff --git a/new_project/custom_addons/encoach_branding/models/__init__.py b/backend/custom_addons/encoach_branding/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_branding/models/__init__.py rename to backend/custom_addons/encoach_branding/models/__init__.py diff --git a/new_project/custom_addons/encoach_branding/models/branding.py b/backend/custom_addons/encoach_branding/models/branding.py similarity index 100% rename from new_project/custom_addons/encoach_branding/models/branding.py rename to backend/custom_addons/encoach_branding/models/branding.py diff --git a/new_project/custom_addons/encoach_branding/security/ir.model.access.csv b/backend/custom_addons/encoach_branding/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_branding/security/ir.model.access.csv rename to backend/custom_addons/encoach_branding/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_branding/views/branding_menus.xml b/backend/custom_addons/encoach_branding/views/branding_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_branding/views/branding_menus.xml rename to backend/custom_addons/encoach_branding/views/branding_menus.xml diff --git a/new_project/custom_addons/encoach_branding/views/branding_views.xml b/backend/custom_addons/encoach_branding/views/branding_views.xml similarity index 100% rename from new_project/custom_addons/encoach_branding/views/branding_views.xml rename to backend/custom_addons/encoach_branding/views/branding_views.xml diff --git a/new_project/custom_addons/encoach_core/__init__.py b/backend/custom_addons/encoach_core/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_core/__init__.py rename to backend/custom_addons/encoach_core/__init__.py diff --git a/new_project/custom_addons/encoach_core/__manifest__.py b/backend/custom_addons/encoach_core/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_core/__manifest__.py rename to backend/custom_addons/encoach_core/__manifest__.py diff --git a/new_project/custom_addons/encoach_core/data/encoach_permissions.xml b/backend/custom_addons/encoach_core/data/encoach_permissions.xml similarity index 100% rename from new_project/custom_addons/encoach_core/data/encoach_permissions.xml rename to backend/custom_addons/encoach_core/data/encoach_permissions.xml diff --git a/new_project/custom_addons/encoach_core/models/__init__.py b/backend/custom_addons/encoach_core/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/__init__.py rename to backend/custom_addons/encoach_core/models/__init__.py diff --git a/new_project/custom_addons/encoach_core/models/code.py b/backend/custom_addons/encoach_core/models/code.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/code.py rename to backend/custom_addons/encoach_core/models/code.py diff --git a/new_project/custom_addons/encoach_core/models/encoach_entity.py b/backend/custom_addons/encoach_core/models/encoach_entity.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/encoach_entity.py rename to backend/custom_addons/encoach_core/models/encoach_entity.py diff --git a/new_project/custom_addons/encoach_core/models/encoach_user.py b/backend/custom_addons/encoach_core/models/encoach_user.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/encoach_user.py rename to backend/custom_addons/encoach_core/models/encoach_user.py diff --git a/new_project/custom_addons/encoach_core/models/entity_level_mapping.py b/backend/custom_addons/encoach_core/models/entity_level_mapping.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/entity_level_mapping.py rename to backend/custom_addons/encoach_core/models/entity_level_mapping.py diff --git a/new_project/custom_addons/encoach_core/models/invite.py b/backend/custom_addons/encoach_core/models/invite.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/invite.py rename to backend/custom_addons/encoach_core/models/invite.py diff --git a/new_project/custom_addons/encoach_core/models/permission.py b/backend/custom_addons/encoach_core/models/permission.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/permission.py rename to backend/custom_addons/encoach_core/models/permission.py diff --git a/new_project/custom_addons/encoach_core/models/role.py b/backend/custom_addons/encoach_core/models/role.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/role.py rename to backend/custom_addons/encoach_core/models/role.py diff --git a/new_project/custom_addons/encoach_core/models/user_entity_rel.py b/backend/custom_addons/encoach_core/models/user_entity_rel.py similarity index 100% rename from new_project/custom_addons/encoach_core/models/user_entity_rel.py rename to backend/custom_addons/encoach_core/models/user_entity_rel.py diff --git a/new_project/custom_addons/encoach_core/security/encoach_security.xml b/backend/custom_addons/encoach_core/security/encoach_security.xml similarity index 100% rename from new_project/custom_addons/encoach_core/security/encoach_security.xml rename to backend/custom_addons/encoach_core/security/encoach_security.xml diff --git a/new_project/custom_addons/encoach_core/security/ir.model.access.csv b/backend/custom_addons/encoach_core/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_core/security/ir.model.access.csv rename to backend/custom_addons/encoach_core/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_core/static/src/css/dashboard.css b/backend/custom_addons/encoach_core/static/src/css/dashboard.css similarity index 100% rename from new_project/custom_addons/encoach_core/static/src/css/dashboard.css rename to backend/custom_addons/encoach_core/static/src/css/dashboard.css diff --git a/new_project/custom_addons/encoach_core/static/src/js/dashboard.js b/backend/custom_addons/encoach_core/static/src/js/dashboard.js similarity index 100% rename from new_project/custom_addons/encoach_core/static/src/js/dashboard.js rename to backend/custom_addons/encoach_core/static/src/js/dashboard.js diff --git a/new_project/custom_addons/encoach_core/static/src/xml/dashboard.xml b/backend/custom_addons/encoach_core/static/src/xml/dashboard.xml similarity index 100% rename from new_project/custom_addons/encoach_core/static/src/xml/dashboard.xml rename to backend/custom_addons/encoach_core/static/src/xml/dashboard.xml diff --git a/new_project/custom_addons/encoach_core/views/dashboard_action.xml b/backend/custom_addons/encoach_core/views/dashboard_action.xml similarity index 100% rename from new_project/custom_addons/encoach_core/views/dashboard_action.xml rename to backend/custom_addons/encoach_core/views/dashboard_action.xml diff --git a/new_project/custom_addons/encoach_core/views/encoach_entity_views.xml b/backend/custom_addons/encoach_core/views/encoach_entity_views.xml similarity index 100% rename from new_project/custom_addons/encoach_core/views/encoach_entity_views.xml rename to backend/custom_addons/encoach_core/views/encoach_entity_views.xml diff --git a/new_project/custom_addons/encoach_core/views/encoach_menus.xml b/backend/custom_addons/encoach_core/views/encoach_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_core/views/encoach_menus.xml rename to backend/custom_addons/encoach_core/views/encoach_menus.xml diff --git a/new_project/custom_addons/encoach_core/views/entity_level_mapping_views.xml b/backend/custom_addons/encoach_core/views/entity_level_mapping_views.xml similarity index 100% rename from new_project/custom_addons/encoach_core/views/entity_level_mapping_views.xml rename to backend/custom_addons/encoach_core/views/entity_level_mapping_views.xml diff --git a/new_project/custom_addons/encoach_course_gen/__init__.py b/backend/custom_addons/encoach_course_gen/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/__init__.py rename to backend/custom_addons/encoach_course_gen/__init__.py diff --git a/new_project/custom_addons/encoach_course_gen/__manifest__.py b/backend/custom_addons/encoach_course_gen/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/__manifest__.py rename to backend/custom_addons/encoach_course_gen/__manifest__.py diff --git a/new_project/custom_addons/encoach_course_gen/controllers/__init__.py b/backend/custom_addons/encoach_course_gen/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/controllers/__init__.py rename to backend/custom_addons/encoach_course_gen/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_course_gen/controllers/course.py b/backend/custom_addons/encoach_course_gen/controllers/course.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/controllers/course.py rename to backend/custom_addons/encoach_course_gen/controllers/course.py diff --git a/new_project/custom_addons/encoach_course_gen/models/__init__.py b/backend/custom_addons/encoach_course_gen/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/models/__init__.py rename to backend/custom_addons/encoach_course_gen/models/__init__.py diff --git a/new_project/custom_addons/encoach_course_gen/models/course_extension.py b/backend/custom_addons/encoach_course_gen/models/course_extension.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/models/course_extension.py rename to backend/custom_addons/encoach_course_gen/models/course_extension.py diff --git a/new_project/custom_addons/encoach_course_gen/models/course_module.py b/backend/custom_addons/encoach_course_gen/models/course_module.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/models/course_module.py rename to backend/custom_addons/encoach_course_gen/models/course_module.py diff --git a/new_project/custom_addons/encoach_course_gen/models/course_section.py b/backend/custom_addons/encoach_course_gen/models/course_section.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/models/course_section.py rename to backend/custom_addons/encoach_course_gen/models/course_section.py diff --git a/new_project/custom_addons/encoach_course_gen/models/gap_profile.py b/backend/custom_addons/encoach_course_gen/models/gap_profile.py similarity index 100% rename from new_project/custom_addons/encoach_course_gen/models/gap_profile.py rename to backend/custom_addons/encoach_course_gen/models/gap_profile.py diff --git a/new_project/custom_addons/encoach_course_gen/security/ir.model.access.csv b/backend/custom_addons/encoach_course_gen/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_course_gen/security/ir.model.access.csv rename to backend/custom_addons/encoach_course_gen/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_course_gen/static/src/css/gap_analysis.css b/backend/custom_addons/encoach_course_gen/static/src/css/gap_analysis.css similarity index 100% rename from new_project/custom_addons/encoach_course_gen/static/src/css/gap_analysis.css rename to backend/custom_addons/encoach_course_gen/static/src/css/gap_analysis.css diff --git a/new_project/custom_addons/encoach_course_gen/static/src/js/gap_analysis.js b/backend/custom_addons/encoach_course_gen/static/src/js/gap_analysis.js similarity index 100% rename from new_project/custom_addons/encoach_course_gen/static/src/js/gap_analysis.js rename to backend/custom_addons/encoach_course_gen/static/src/js/gap_analysis.js diff --git a/new_project/custom_addons/encoach_course_gen/static/src/xml/gap_analysis.xml b/backend/custom_addons/encoach_course_gen/static/src/xml/gap_analysis.xml similarity index 100% rename from new_project/custom_addons/encoach_course_gen/static/src/xml/gap_analysis.xml rename to backend/custom_addons/encoach_course_gen/static/src/xml/gap_analysis.xml diff --git a/new_project/custom_addons/encoach_course_gen/views/course_gen_menus.xml b/backend/custom_addons/encoach_course_gen/views/course_gen_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_course_gen/views/course_gen_menus.xml rename to backend/custom_addons/encoach_course_gen/views/course_gen_menus.xml diff --git a/new_project/custom_addons/encoach_course_gen/views/course_module_views.xml b/backend/custom_addons/encoach_course_gen/views/course_module_views.xml similarity index 100% rename from new_project/custom_addons/encoach_course_gen/views/course_module_views.xml rename to backend/custom_addons/encoach_course_gen/views/course_module_views.xml diff --git a/new_project/custom_addons/encoach_course_gen/views/course_section_views.xml b/backend/custom_addons/encoach_course_gen/views/course_section_views.xml similarity index 100% rename from new_project/custom_addons/encoach_course_gen/views/course_section_views.xml rename to backend/custom_addons/encoach_course_gen/views/course_section_views.xml diff --git a/new_project/custom_addons/encoach_course_gen/views/gap_analysis_action.xml b/backend/custom_addons/encoach_course_gen/views/gap_analysis_action.xml similarity index 100% rename from new_project/custom_addons/encoach_course_gen/views/gap_analysis_action.xml rename to backend/custom_addons/encoach_course_gen/views/gap_analysis_action.xml diff --git a/new_project/custom_addons/encoach_course_gen/views/gap_profile_views.xml b/backend/custom_addons/encoach_course_gen/views/gap_profile_views.xml similarity index 100% rename from new_project/custom_addons/encoach_course_gen/views/gap_profile_views.xml rename to backend/custom_addons/encoach_course_gen/views/gap_profile_views.xml diff --git a/new_project/custom_addons/encoach_entity_onboard/__init__.py b/backend/custom_addons/encoach_entity_onboard/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/__init__.py rename to backend/custom_addons/encoach_entity_onboard/__init__.py diff --git a/new_project/custom_addons/encoach_entity_onboard/__manifest__.py b/backend/custom_addons/encoach_entity_onboard/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/__manifest__.py rename to backend/custom_addons/encoach_entity_onboard/__manifest__.py diff --git a/new_project/custom_addons/encoach_entity_onboard/controllers/__init__.py b/backend/custom_addons/encoach_entity_onboard/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/controllers/__init__.py rename to backend/custom_addons/encoach_entity_onboard/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_entity_onboard/controllers/entity_onboard.py b/backend/custom_addons/encoach_entity_onboard/controllers/entity_onboard.py similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/controllers/entity_onboard.py rename to backend/custom_addons/encoach_entity_onboard/controllers/entity_onboard.py diff --git a/new_project/custom_addons/encoach_entity_onboard/security/ir.model.access.csv b/backend/custom_addons/encoach_entity_onboard/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/security/ir.model.access.csv rename to backend/custom_addons/encoach_entity_onboard/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_entity_onboard/services/__init__.py b/backend/custom_addons/encoach_entity_onboard/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/services/__init__.py rename to backend/custom_addons/encoach_entity_onboard/services/__init__.py diff --git a/new_project/custom_addons/encoach_entity_onboard/services/credential_service.py b/backend/custom_addons/encoach_entity_onboard/services/credential_service.py similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/services/credential_service.py rename to backend/custom_addons/encoach_entity_onboard/services/credential_service.py diff --git a/new_project/custom_addons/encoach_entity_onboard/services/csv_parser.py b/backend/custom_addons/encoach_entity_onboard/services/csv_parser.py similarity index 100% rename from new_project/custom_addons/encoach_entity_onboard/services/csv_parser.py rename to backend/custom_addons/encoach_entity_onboard/services/csv_parser.py diff --git a/new_project/custom_addons/encoach_exam_session/__init__.py b/backend/custom_addons/encoach_exam_session/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_exam_session/__init__.py rename to backend/custom_addons/encoach_exam_session/__init__.py diff --git a/new_project/custom_addons/encoach_exam_session/__manifest__.py b/backend/custom_addons/encoach_exam_session/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_exam_session/__manifest__.py rename to backend/custom_addons/encoach_exam_session/__manifest__.py diff --git a/new_project/custom_addons/encoach_exam_session/controllers/__init__.py b/backend/custom_addons/encoach_exam_session/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_exam_session/controllers/__init__.py rename to backend/custom_addons/encoach_exam_session/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_exam_session/controllers/exam_session.py b/backend/custom_addons/encoach_exam_session/controllers/exam_session.py similarity index 100% rename from new_project/custom_addons/encoach_exam_session/controllers/exam_session.py rename to backend/custom_addons/encoach_exam_session/controllers/exam_session.py diff --git a/new_project/custom_addons/encoach_exam_session/security/ir.model.access.csv b/backend/custom_addons/encoach_exam_session/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_exam_session/security/ir.model.access.csv rename to backend/custom_addons/encoach_exam_session/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_exam_session/static/src/css/exam_session.css b/backend/custom_addons/encoach_exam_session/static/src/css/exam_session.css similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/css/exam_session.css rename to backend/custom_addons/encoach_exam_session/static/src/css/exam_session.css diff --git a/new_project/custom_addons/encoach_exam_session/static/src/js/exam_app.js b/backend/custom_addons/encoach_exam_session/static/src/js/exam_app.js similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/js/exam_app.js rename to backend/custom_addons/encoach_exam_session/static/src/js/exam_app.js diff --git a/new_project/custom_addons/encoach_exam_session/static/src/js/exam_delivery.js b/backend/custom_addons/encoach_exam_session/static/src/js/exam_delivery.js similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/js/exam_delivery.js rename to backend/custom_addons/encoach_exam_session/static/src/js/exam_delivery.js diff --git a/new_project/custom_addons/encoach_exam_session/static/src/js/placement_app.js b/backend/custom_addons/encoach_exam_session/static/src/js/placement_app.js similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/js/placement_app.js rename to backend/custom_addons/encoach_exam_session/static/src/js/placement_app.js diff --git a/new_project/custom_addons/encoach_exam_session/static/src/js/question_renderers.js b/backend/custom_addons/encoach_exam_session/static/src/js/question_renderers.js similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/js/question_renderers.js rename to backend/custom_addons/encoach_exam_session/static/src/js/question_renderers.js diff --git a/new_project/custom_addons/encoach_exam_session/static/src/xml/exam_app.xml b/backend/custom_addons/encoach_exam_session/static/src/xml/exam_app.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/xml/exam_app.xml rename to backend/custom_addons/encoach_exam_session/static/src/xml/exam_app.xml diff --git a/new_project/custom_addons/encoach_exam_session/static/src/xml/placement_app.xml b/backend/custom_addons/encoach_exam_session/static/src/xml/placement_app.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/xml/placement_app.xml rename to backend/custom_addons/encoach_exam_session/static/src/xml/placement_app.xml diff --git a/new_project/custom_addons/encoach_exam_session/static/src/xml/question_renderers.xml b/backend/custom_addons/encoach_exam_session/static/src/xml/question_renderers.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_session/static/src/xml/question_renderers.xml rename to backend/custom_addons/encoach_exam_session/static/src/xml/question_renderers.xml diff --git a/new_project/custom_addons/encoach_exam_session/views/exam_session_templates.xml b/backend/custom_addons/encoach_exam_session/views/exam_session_templates.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_session/views/exam_session_templates.xml rename to backend/custom_addons/encoach_exam_session/views/exam_session_templates.xml diff --git a/new_project/custom_addons/encoach_exam_template/__init__.py b/backend/custom_addons/encoach_exam_template/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/__init__.py rename to backend/custom_addons/encoach_exam_template/__init__.py diff --git a/new_project/custom_addons/encoach_exam_template/__manifest__.py b/backend/custom_addons/encoach_exam_template/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/__manifest__.py rename to backend/custom_addons/encoach_exam_template/__manifest__.py diff --git a/new_project/custom_addons/encoach_exam_template/controllers/__init__.py b/backend/custom_addons/encoach_exam_template/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/controllers/__init__.py rename to backend/custom_addons/encoach_exam_template/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_exam_template/controllers/custom_exam.py b/backend/custom_addons/encoach_exam_template/controllers/custom_exam.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/controllers/custom_exam.py rename to backend/custom_addons/encoach_exam_template/controllers/custom_exam.py diff --git a/new_project/custom_addons/encoach_exam_template/controllers/ielts_exam.py b/backend/custom_addons/encoach_exam_template/controllers/ielts_exam.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/controllers/ielts_exam.py rename to backend/custom_addons/encoach_exam_template/controllers/ielts_exam.py diff --git a/new_project/custom_addons/encoach_exam_template/controllers/templates.py b/backend/custom_addons/encoach_exam_template/controllers/templates.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/controllers/templates.py rename to backend/custom_addons/encoach_exam_template/controllers/templates.py diff --git a/new_project/custom_addons/encoach_exam_template/data/ielts_templates.xml b/backend/custom_addons/encoach_exam_template/data/ielts_templates.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/data/ielts_templates.xml rename to backend/custom_addons/encoach_exam_template/data/ielts_templates.xml diff --git a/new_project/custom_addons/encoach_exam_template/data/sample_passages.xml b/backend/custom_addons/encoach_exam_template/data/sample_passages.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/data/sample_passages.xml rename to backend/custom_addons/encoach_exam_template/data/sample_passages.xml diff --git a/new_project/custom_addons/encoach_exam_template/data/sample_questions.xml b/backend/custom_addons/encoach_exam_template/data/sample_questions.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/data/sample_questions.xml rename to backend/custom_addons/encoach_exam_template/data/sample_questions.xml diff --git a/new_project/custom_addons/encoach_exam_template/models/__init__.py b/backend/custom_addons/encoach_exam_template/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/__init__.py rename to backend/custom_addons/encoach_exam_template/models/__init__.py diff --git a/new_project/custom_addons/encoach_exam_template/models/audio_file.py b/backend/custom_addons/encoach_exam_template/models/audio_file.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/audio_file.py rename to backend/custom_addons/encoach_exam_template/models/audio_file.py diff --git a/new_project/custom_addons/encoach_exam_template/models/exam_assignment.py b/backend/custom_addons/encoach_exam_template/models/exam_assignment.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/exam_assignment.py rename to backend/custom_addons/encoach_exam_template/models/exam_assignment.py diff --git a/new_project/custom_addons/encoach_exam_template/models/exam_custom.py b/backend/custom_addons/encoach_exam_template/models/exam_custom.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/exam_custom.py rename to backend/custom_addons/encoach_exam_template/models/exam_custom.py diff --git a/new_project/custom_addons/encoach_exam_template/models/exam_custom_section.py b/backend/custom_addons/encoach_exam_template/models/exam_custom_section.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/exam_custom_section.py rename to backend/custom_addons/encoach_exam_template/models/exam_custom_section.py diff --git a/new_project/custom_addons/encoach_exam_template/models/exam_template.py b/backend/custom_addons/encoach_exam_template/models/exam_template.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/exam_template.py rename to backend/custom_addons/encoach_exam_template/models/exam_template.py diff --git a/new_project/custom_addons/encoach_exam_template/models/passage.py b/backend/custom_addons/encoach_exam_template/models/passage.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/passage.py rename to backend/custom_addons/encoach_exam_template/models/passage.py diff --git a/new_project/custom_addons/encoach_exam_template/models/question.py b/backend/custom_addons/encoach_exam_template/models/question.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/question.py rename to backend/custom_addons/encoach_exam_template/models/question.py diff --git a/new_project/custom_addons/encoach_exam_template/models/rubric.py b/backend/custom_addons/encoach_exam_template/models/rubric.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/rubric.py rename to backend/custom_addons/encoach_exam_template/models/rubric.py diff --git a/new_project/custom_addons/encoach_exam_template/models/speaking_card.py b/backend/custom_addons/encoach_exam_template/models/speaking_card.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/speaking_card.py rename to backend/custom_addons/encoach_exam_template/models/speaking_card.py diff --git a/new_project/custom_addons/encoach_exam_template/models/writing_prompt.py b/backend/custom_addons/encoach_exam_template/models/writing_prompt.py similarity index 100% rename from new_project/custom_addons/encoach_exam_template/models/writing_prompt.py rename to backend/custom_addons/encoach_exam_template/models/writing_prompt.py diff --git a/new_project/custom_addons/encoach_exam_template/security/ir.model.access.csv b/backend/custom_addons/encoach_exam_template/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_exam_template/security/ir.model.access.csv rename to backend/custom_addons/encoach_exam_template/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_exam_template/static/src/css/content_pool.css b/backend/custom_addons/encoach_exam_template/static/src/css/content_pool.css similarity index 100% rename from new_project/custom_addons/encoach_exam_template/static/src/css/content_pool.css rename to backend/custom_addons/encoach_exam_template/static/src/css/content_pool.css diff --git a/new_project/custom_addons/encoach_exam_template/static/src/js/content_pool.js b/backend/custom_addons/encoach_exam_template/static/src/js/content_pool.js similarity index 100% rename from new_project/custom_addons/encoach_exam_template/static/src/js/content_pool.js rename to backend/custom_addons/encoach_exam_template/static/src/js/content_pool.js diff --git a/new_project/custom_addons/encoach_exam_template/static/src/js/exam_validation.js b/backend/custom_addons/encoach_exam_template/static/src/js/exam_validation.js similarity index 100% rename from new_project/custom_addons/encoach_exam_template/static/src/js/exam_validation.js rename to backend/custom_addons/encoach_exam_template/static/src/js/exam_validation.js diff --git a/new_project/custom_addons/encoach_exam_template/static/src/xml/content_pool.xml b/backend/custom_addons/encoach_exam_template/static/src/xml/content_pool.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/static/src/xml/content_pool.xml rename to backend/custom_addons/encoach_exam_template/static/src/xml/content_pool.xml diff --git a/new_project/custom_addons/encoach_exam_template/static/src/xml/exam_validation.xml b/backend/custom_addons/encoach_exam_template/static/src/xml/exam_validation.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/static/src/xml/exam_validation.xml rename to backend/custom_addons/encoach_exam_template/static/src/xml/exam_validation.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/audio_file_views.xml b/backend/custom_addons/encoach_exam_template/views/audio_file_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/audio_file_views.xml rename to backend/custom_addons/encoach_exam_template/views/audio_file_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/content_pool_action.xml b/backend/custom_addons/encoach_exam_template/views/content_pool_action.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/content_pool_action.xml rename to backend/custom_addons/encoach_exam_template/views/content_pool_action.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/exam_assignment_views.xml b/backend/custom_addons/encoach_exam_template/views/exam_assignment_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/exam_assignment_views.xml rename to backend/custom_addons/encoach_exam_template/views/exam_assignment_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/exam_custom_views.xml b/backend/custom_addons/encoach_exam_template/views/exam_custom_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/exam_custom_views.xml rename to backend/custom_addons/encoach_exam_template/views/exam_custom_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/exam_template_menus.xml b/backend/custom_addons/encoach_exam_template/views/exam_template_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/exam_template_menus.xml rename to backend/custom_addons/encoach_exam_template/views/exam_template_menus.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/exam_template_views.xml b/backend/custom_addons/encoach_exam_template/views/exam_template_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/exam_template_views.xml rename to backend/custom_addons/encoach_exam_template/views/exam_template_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/exam_validation_action.xml b/backend/custom_addons/encoach_exam_template/views/exam_validation_action.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/exam_validation_action.xml rename to backend/custom_addons/encoach_exam_template/views/exam_validation_action.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/passage_views.xml b/backend/custom_addons/encoach_exam_template/views/passage_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/passage_views.xml rename to backend/custom_addons/encoach_exam_template/views/passage_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/question_views.xml b/backend/custom_addons/encoach_exam_template/views/question_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/question_views.xml rename to backend/custom_addons/encoach_exam_template/views/question_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/rubric_views.xml b/backend/custom_addons/encoach_exam_template/views/rubric_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/rubric_views.xml rename to backend/custom_addons/encoach_exam_template/views/rubric_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/speaking_card_views.xml b/backend/custom_addons/encoach_exam_template/views/speaking_card_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/speaking_card_views.xml rename to backend/custom_addons/encoach_exam_template/views/speaking_card_views.xml diff --git a/new_project/custom_addons/encoach_exam_template/views/writing_prompt_views.xml b/backend/custom_addons/encoach_exam_template/views/writing_prompt_views.xml similarity index 100% rename from new_project/custom_addons/encoach_exam_template/views/writing_prompt_views.xml rename to backend/custom_addons/encoach_exam_template/views/writing_prompt_views.xml diff --git a/new_project/custom_addons/encoach_ielts_validation/__init__.py b/backend/custom_addons/encoach_ielts_validation/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_ielts_validation/__init__.py rename to backend/custom_addons/encoach_ielts_validation/__init__.py diff --git a/new_project/custom_addons/encoach_ielts_validation/__manifest__.py b/backend/custom_addons/encoach_ielts_validation/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_ielts_validation/__manifest__.py rename to backend/custom_addons/encoach_ielts_validation/__manifest__.py diff --git a/new_project/custom_addons/encoach_ielts_validation/security/ir.model.access.csv b/backend/custom_addons/encoach_ielts_validation/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_ielts_validation/security/ir.model.access.csv rename to backend/custom_addons/encoach_ielts_validation/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_ielts_validation/services/__init__.py b/backend/custom_addons/encoach_ielts_validation/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_ielts_validation/services/__init__.py rename to backend/custom_addons/encoach_ielts_validation/services/__init__.py diff --git a/new_project/custom_addons/encoach_ielts_validation/services/validator.py b/backend/custom_addons/encoach_ielts_validation/services/validator.py similarity index 100% rename from new_project/custom_addons/encoach_ielts_validation/services/validator.py rename to backend/custom_addons/encoach_ielts_validation/services/validator.py diff --git a/new_project/custom_addons/encoach_it/__init__.py b/backend/custom_addons/encoach_it/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_it/__init__.py rename to backend/custom_addons/encoach_it/__init__.py diff --git a/new_project/custom_addons/encoach_it/__manifest__.py b/backend/custom_addons/encoach_it/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_it/__manifest__.py rename to backend/custom_addons/encoach_it/__manifest__.py diff --git a/new_project/custom_addons/encoach_it/security/ir.model.access.csv b/backend/custom_addons/encoach_it/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_it/security/ir.model.access.csv rename to backend/custom_addons/encoach_it/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_it/services/__init__.py b/backend/custom_addons/encoach_it/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_it/services/__init__.py rename to backend/custom_addons/encoach_it/services/__init__.py diff --git a/new_project/custom_addons/encoach_it/services/code_scorer.py b/backend/custom_addons/encoach_it/services/code_scorer.py similarity index 100% rename from new_project/custom_addons/encoach_it/services/code_scorer.py rename to backend/custom_addons/encoach_it/services/code_scorer.py diff --git a/new_project/custom_addons/encoach_math/__init__.py b/backend/custom_addons/encoach_math/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_math/__init__.py rename to backend/custom_addons/encoach_math/__init__.py diff --git a/new_project/custom_addons/encoach_math/__manifest__.py b/backend/custom_addons/encoach_math/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_math/__manifest__.py rename to backend/custom_addons/encoach_math/__manifest__.py diff --git a/new_project/custom_addons/encoach_math/security/ir.model.access.csv b/backend/custom_addons/encoach_math/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_math/security/ir.model.access.csv rename to backend/custom_addons/encoach_math/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_math/services/__init__.py b/backend/custom_addons/encoach_math/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_math/services/__init__.py rename to backend/custom_addons/encoach_math/services/__init__.py diff --git a/new_project/custom_addons/encoach_math/services/math_scorer.py b/backend/custom_addons/encoach_math/services/math_scorer.py similarity index 100% rename from new_project/custom_addons/encoach_math/services/math_scorer.py rename to backend/custom_addons/encoach_math/services/math_scorer.py diff --git a/new_project/custom_addons/encoach_pdf_report/__init__.py b/backend/custom_addons/encoach_pdf_report/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_pdf_report/__init__.py rename to backend/custom_addons/encoach_pdf_report/__init__.py diff --git a/new_project/custom_addons/encoach_pdf_report/__manifest__.py b/backend/custom_addons/encoach_pdf_report/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_pdf_report/__manifest__.py rename to backend/custom_addons/encoach_pdf_report/__manifest__.py diff --git a/new_project/custom_addons/encoach_pdf_report/controllers/__init__.py b/backend/custom_addons/encoach_pdf_report/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_pdf_report/controllers/__init__.py rename to backend/custom_addons/encoach_pdf_report/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_pdf_report/controllers/reports.py b/backend/custom_addons/encoach_pdf_report/controllers/reports.py similarity index 100% rename from new_project/custom_addons/encoach_pdf_report/controllers/reports.py rename to backend/custom_addons/encoach_pdf_report/controllers/reports.py diff --git a/new_project/custom_addons/encoach_pdf_report/security/ir.model.access.csv b/backend/custom_addons/encoach_pdf_report/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_pdf_report/security/ir.model.access.csv rename to backend/custom_addons/encoach_pdf_report/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_pdf_report/services/__init__.py b/backend/custom_addons/encoach_pdf_report/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_pdf_report/services/__init__.py rename to backend/custom_addons/encoach_pdf_report/services/__init__.py diff --git a/new_project/custom_addons/encoach_pdf_report/services/pdf_generator.py b/backend/custom_addons/encoach_pdf_report/services/pdf_generator.py similarity index 100% rename from new_project/custom_addons/encoach_pdf_report/services/pdf_generator.py rename to backend/custom_addons/encoach_pdf_report/services/pdf_generator.py diff --git a/new_project/custom_addons/encoach_placement/__init__.py b/backend/custom_addons/encoach_placement/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_placement/__init__.py rename to backend/custom_addons/encoach_placement/__init__.py diff --git a/new_project/custom_addons/encoach_placement/__manifest__.py b/backend/custom_addons/encoach_placement/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_placement/__manifest__.py rename to backend/custom_addons/encoach_placement/__manifest__.py diff --git a/new_project/custom_addons/encoach_placement/controllers/__init__.py b/backend/custom_addons/encoach_placement/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_placement/controllers/__init__.py rename to backend/custom_addons/encoach_placement/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_placement/controllers/placement.py b/backend/custom_addons/encoach_placement/controllers/placement.py similarity index 100% rename from new_project/custom_addons/encoach_placement/controllers/placement.py rename to backend/custom_addons/encoach_placement/controllers/placement.py diff --git a/new_project/custom_addons/encoach_placement/models/__init__.py b/backend/custom_addons/encoach_placement/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_placement/models/__init__.py rename to backend/custom_addons/encoach_placement/models/__init__.py diff --git a/new_project/custom_addons/encoach_placement/models/cat_session.py b/backend/custom_addons/encoach_placement/models/cat_session.py similarity index 100% rename from new_project/custom_addons/encoach_placement/models/cat_session.py rename to backend/custom_addons/encoach_placement/models/cat_session.py diff --git a/new_project/custom_addons/encoach_placement/models/student_ability.py b/backend/custom_addons/encoach_placement/models/student_ability.py similarity index 100% rename from new_project/custom_addons/encoach_placement/models/student_ability.py rename to backend/custom_addons/encoach_placement/models/student_ability.py diff --git a/new_project/custom_addons/encoach_placement/security/ir.model.access.csv b/backend/custom_addons/encoach_placement/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_placement/security/ir.model.access.csv rename to backend/custom_addons/encoach_placement/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_placement/services/__init__.py b/backend/custom_addons/encoach_placement/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_placement/services/__init__.py rename to backend/custom_addons/encoach_placement/services/__init__.py diff --git a/new_project/custom_addons/encoach_placement/services/cat_engine.py b/backend/custom_addons/encoach_placement/services/cat_engine.py similarity index 100% rename from new_project/custom_addons/encoach_placement/services/cat_engine.py rename to backend/custom_addons/encoach_placement/services/cat_engine.py diff --git a/new_project/custom_addons/encoach_placement/services/cefr_mapper.py b/backend/custom_addons/encoach_placement/services/cefr_mapper.py similarity index 100% rename from new_project/custom_addons/encoach_placement/services/cefr_mapper.py rename to backend/custom_addons/encoach_placement/services/cefr_mapper.py diff --git a/new_project/custom_addons/encoach_placement/views/cat_session_views.xml b/backend/custom_addons/encoach_placement/views/cat_session_views.xml similarity index 100% rename from new_project/custom_addons/encoach_placement/views/cat_session_views.xml rename to backend/custom_addons/encoach_placement/views/cat_session_views.xml diff --git a/new_project/custom_addons/encoach_placement/views/placement_menus.xml b/backend/custom_addons/encoach_placement/views/placement_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_placement/views/placement_menus.xml rename to backend/custom_addons/encoach_placement/views/placement_menus.xml diff --git a/new_project/custom_addons/encoach_placement/views/student_ability_views.xml b/backend/custom_addons/encoach_placement/views/student_ability_views.xml similarity index 100% rename from new_project/custom_addons/encoach_placement/views/student_ability_views.xml rename to backend/custom_addons/encoach_placement/views/student_ability_views.xml diff --git a/new_project/custom_addons/encoach_portal/__init__.py b/backend/custom_addons/encoach_portal/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_portal/__init__.py rename to backend/custom_addons/encoach_portal/__init__.py diff --git a/new_project/custom_addons/encoach_portal/__manifest__.py b/backend/custom_addons/encoach_portal/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_portal/__manifest__.py rename to backend/custom_addons/encoach_portal/__manifest__.py diff --git a/new_project/custom_addons/encoach_portal/controllers/__init__.py b/backend/custom_addons/encoach_portal/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_portal/controllers/__init__.py rename to backend/custom_addons/encoach_portal/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_portal/controllers/portal.py b/backend/custom_addons/encoach_portal/controllers/portal.py similarity index 100% rename from new_project/custom_addons/encoach_portal/controllers/portal.py rename to backend/custom_addons/encoach_portal/controllers/portal.py diff --git a/new_project/custom_addons/encoach_portal/security/ir.model.access.csv b/backend/custom_addons/encoach_portal/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_portal/security/ir.model.access.csv rename to backend/custom_addons/encoach_portal/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_portal/static/src/css/portal.css b/backend/custom_addons/encoach_portal/static/src/css/portal.css similarity index 100% rename from new_project/custom_addons/encoach_portal/static/src/css/portal.css rename to backend/custom_addons/encoach_portal/static/src/css/portal.css diff --git a/new_project/custom_addons/encoach_portal/static/src/js/onboarding_wizard.js b/backend/custom_addons/encoach_portal/static/src/js/onboarding_wizard.js similarity index 100% rename from new_project/custom_addons/encoach_portal/static/src/js/onboarding_wizard.js rename to backend/custom_addons/encoach_portal/static/src/js/onboarding_wizard.js diff --git a/new_project/custom_addons/encoach_portal/static/src/js/password_strength.js b/backend/custom_addons/encoach_portal/static/src/js/password_strength.js similarity index 100% rename from new_project/custom_addons/encoach_portal/static/src/js/password_strength.js rename to backend/custom_addons/encoach_portal/static/src/js/password_strength.js diff --git a/new_project/custom_addons/encoach_portal/static/src/xml/onboarding_wizard.xml b/backend/custom_addons/encoach_portal/static/src/xml/onboarding_wizard.xml similarity index 100% rename from new_project/custom_addons/encoach_portal/static/src/xml/onboarding_wizard.xml rename to backend/custom_addons/encoach_portal/static/src/xml/onboarding_wizard.xml diff --git a/new_project/custom_addons/encoach_portal/views/portal_menus.xml b/backend/custom_addons/encoach_portal/views/portal_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_portal/views/portal_menus.xml rename to backend/custom_addons/encoach_portal/views/portal_menus.xml diff --git a/new_project/custom_addons/encoach_portal/views/templates.xml b/backend/custom_addons/encoach_portal/views/templates.xml similarity index 100% rename from new_project/custom_addons/encoach_portal/views/templates.xml rename to backend/custom_addons/encoach_portal/views/templates.xml diff --git a/new_project/custom_addons/encoach_quality_gate/__init__.py b/backend/custom_addons/encoach_quality_gate/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/__init__.py rename to backend/custom_addons/encoach_quality_gate/__init__.py diff --git a/new_project/custom_addons/encoach_quality_gate/__manifest__.py b/backend/custom_addons/encoach_quality_gate/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/__manifest__.py rename to backend/custom_addons/encoach_quality_gate/__manifest__.py diff --git a/new_project/custom_addons/encoach_quality_gate/models/__init__.py b/backend/custom_addons/encoach_quality_gate/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/models/__init__.py rename to backend/custom_addons/encoach_quality_gate/models/__init__.py diff --git a/new_project/custom_addons/encoach_quality_gate/models/ielts_standards_check.py b/backend/custom_addons/encoach_quality_gate/models/ielts_standards_check.py similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/models/ielts_standards_check.py rename to backend/custom_addons/encoach_quality_gate/models/ielts_standards_check.py diff --git a/new_project/custom_addons/encoach_quality_gate/security/ir.model.access.csv b/backend/custom_addons/encoach_quality_gate/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/security/ir.model.access.csv rename to backend/custom_addons/encoach_quality_gate/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_quality_gate/services/__init__.py b/backend/custom_addons/encoach_quality_gate/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/services/__init__.py rename to backend/custom_addons/encoach_quality_gate/services/__init__.py diff --git a/new_project/custom_addons/encoach_quality_gate/services/content_gate.py b/backend/custom_addons/encoach_quality_gate/services/content_gate.py similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/services/content_gate.py rename to backend/custom_addons/encoach_quality_gate/services/content_gate.py diff --git a/new_project/custom_addons/encoach_quality_gate/services/quality_checker.py b/backend/custom_addons/encoach_quality_gate/services/quality_checker.py similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/services/quality_checker.py rename to backend/custom_addons/encoach_quality_gate/services/quality_checker.py diff --git a/new_project/custom_addons/encoach_quality_gate/views/ielts_check_views.xml b/backend/custom_addons/encoach_quality_gate/views/ielts_check_views.xml similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/views/ielts_check_views.xml rename to backend/custom_addons/encoach_quality_gate/views/ielts_check_views.xml diff --git a/new_project/custom_addons/encoach_quality_gate/views/quality_menus.xml b/backend/custom_addons/encoach_quality_gate/views/quality_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_quality_gate/views/quality_menus.xml rename to backend/custom_addons/encoach_quality_gate/views/quality_menus.xml diff --git a/new_project/custom_addons/encoach_resources/__init__.py b/backend/custom_addons/encoach_resources/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_resources/__init__.py rename to backend/custom_addons/encoach_resources/__init__.py diff --git a/new_project/custom_addons/encoach_resources/__manifest__.py b/backend/custom_addons/encoach_resources/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_resources/__manifest__.py rename to backend/custom_addons/encoach_resources/__manifest__.py diff --git a/new_project/custom_addons/encoach_resources/models/__init__.py b/backend/custom_addons/encoach_resources/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_resources/models/__init__.py rename to backend/custom_addons/encoach_resources/models/__init__.py diff --git a/new_project/custom_addons/encoach_resources/models/resource.py b/backend/custom_addons/encoach_resources/models/resource.py similarity index 100% rename from new_project/custom_addons/encoach_resources/models/resource.py rename to backend/custom_addons/encoach_resources/models/resource.py diff --git a/new_project/custom_addons/encoach_resources/security/ir.model.access.csv b/backend/custom_addons/encoach_resources/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_resources/security/ir.model.access.csv rename to backend/custom_addons/encoach_resources/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_resources/views/resource_views.xml b/backend/custom_addons/encoach_resources/views/resource_views.xml similarity index 100% rename from new_project/custom_addons/encoach_resources/views/resource_views.xml rename to backend/custom_addons/encoach_resources/views/resource_views.xml diff --git a/new_project/custom_addons/encoach_scoring/__init__.py b/backend/custom_addons/encoach_scoring/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/__init__.py rename to backend/custom_addons/encoach_scoring/__init__.py diff --git a/new_project/custom_addons/encoach_scoring/__manifest__.py b/backend/custom_addons/encoach_scoring/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/__manifest__.py rename to backend/custom_addons/encoach_scoring/__manifest__.py diff --git a/new_project/custom_addons/encoach_scoring/controllers/__init__.py b/backend/custom_addons/encoach_scoring/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/controllers/__init__.py rename to backend/custom_addons/encoach_scoring/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_scoring/controllers/exam_session.py b/backend/custom_addons/encoach_scoring/controllers/exam_session.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/controllers/exam_session.py rename to backend/custom_addons/encoach_scoring/controllers/exam_session.py diff --git a/new_project/custom_addons/encoach_scoring/controllers/grading.py b/backend/custom_addons/encoach_scoring/controllers/grading.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/controllers/grading.py rename to backend/custom_addons/encoach_scoring/controllers/grading.py diff --git a/new_project/custom_addons/encoach_scoring/controllers/score_release.py b/backend/custom_addons/encoach_scoring/controllers/score_release.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/controllers/score_release.py rename to backend/custom_addons/encoach_scoring/controllers/score_release.py diff --git a/new_project/custom_addons/encoach_scoring/models/__init__.py b/backend/custom_addons/encoach_scoring/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/models/__init__.py rename to backend/custom_addons/encoach_scoring/models/__init__.py diff --git a/new_project/custom_addons/encoach_scoring/models/feedback.py b/backend/custom_addons/encoach_scoring/models/feedback.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/models/feedback.py rename to backend/custom_addons/encoach_scoring/models/feedback.py diff --git a/new_project/custom_addons/encoach_scoring/models/score.py b/backend/custom_addons/encoach_scoring/models/score.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/models/score.py rename to backend/custom_addons/encoach_scoring/models/score.py diff --git a/new_project/custom_addons/encoach_scoring/models/student_answer.py b/backend/custom_addons/encoach_scoring/models/student_answer.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/models/student_answer.py rename to backend/custom_addons/encoach_scoring/models/student_answer.py diff --git a/new_project/custom_addons/encoach_scoring/models/student_attempt.py b/backend/custom_addons/encoach_scoring/models/student_attempt.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/models/student_attempt.py rename to backend/custom_addons/encoach_scoring/models/student_attempt.py diff --git a/new_project/custom_addons/encoach_scoring/models/student_progress.py b/backend/custom_addons/encoach_scoring/models/student_progress.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/models/student_progress.py rename to backend/custom_addons/encoach_scoring/models/student_progress.py diff --git a/new_project/custom_addons/encoach_scoring/security/ir.model.access.csv b/backend/custom_addons/encoach_scoring/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_scoring/security/ir.model.access.csv rename to backend/custom_addons/encoach_scoring/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_scoring/services/__init__.py b/backend/custom_addons/encoach_scoring/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/services/__init__.py rename to backend/custom_addons/encoach_scoring/services/__init__.py diff --git a/new_project/custom_addons/encoach_scoring/services/speaking_evaluator.py b/backend/custom_addons/encoach_scoring/services/speaking_evaluator.py similarity index 100% rename from new_project/custom_addons/encoach_scoring/services/speaking_evaluator.py rename to backend/custom_addons/encoach_scoring/services/speaking_evaluator.py diff --git a/new_project/custom_addons/encoach_scoring/views/feedback_views.xml b/backend/custom_addons/encoach_scoring/views/feedback_views.xml similarity index 100% rename from new_project/custom_addons/encoach_scoring/views/feedback_views.xml rename to backend/custom_addons/encoach_scoring/views/feedback_views.xml diff --git a/new_project/custom_addons/encoach_scoring/views/score_views.xml b/backend/custom_addons/encoach_scoring/views/score_views.xml similarity index 100% rename from new_project/custom_addons/encoach_scoring/views/score_views.xml rename to backend/custom_addons/encoach_scoring/views/score_views.xml diff --git a/new_project/custom_addons/encoach_scoring/views/scoring_menus.xml b/backend/custom_addons/encoach_scoring/views/scoring_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_scoring/views/scoring_menus.xml rename to backend/custom_addons/encoach_scoring/views/scoring_menus.xml diff --git a/new_project/custom_addons/encoach_scoring/views/student_answer_views.xml b/backend/custom_addons/encoach_scoring/views/student_answer_views.xml similarity index 100% rename from new_project/custom_addons/encoach_scoring/views/student_answer_views.xml rename to backend/custom_addons/encoach_scoring/views/student_answer_views.xml diff --git a/new_project/custom_addons/encoach_scoring/views/student_attempt_views.xml b/backend/custom_addons/encoach_scoring/views/student_attempt_views.xml similarity index 100% rename from new_project/custom_addons/encoach_scoring/views/student_attempt_views.xml rename to backend/custom_addons/encoach_scoring/views/student_attempt_views.xml diff --git a/new_project/custom_addons/encoach_scoring/views/student_progress_views.xml b/backend/custom_addons/encoach_scoring/views/student_progress_views.xml similarity index 100% rename from new_project/custom_addons/encoach_scoring/views/student_progress_views.xml rename to backend/custom_addons/encoach_scoring/views/student_progress_views.xml diff --git a/new_project/custom_addons/encoach_signup/__init__.py b/backend/custom_addons/encoach_signup/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_signup/__init__.py rename to backend/custom_addons/encoach_signup/__init__.py diff --git a/new_project/custom_addons/encoach_signup/__manifest__.py b/backend/custom_addons/encoach_signup/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_signup/__manifest__.py rename to backend/custom_addons/encoach_signup/__manifest__.py diff --git a/new_project/custom_addons/encoach_signup/controllers/__init__.py b/backend/custom_addons/encoach_signup/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_signup/controllers/__init__.py rename to backend/custom_addons/encoach_signup/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_signup/controllers/auth.py b/backend/custom_addons/encoach_signup/controllers/auth.py similarity index 100% rename from new_project/custom_addons/encoach_signup/controllers/auth.py rename to backend/custom_addons/encoach_signup/controllers/auth.py diff --git a/new_project/custom_addons/encoach_signup/models/__init__.py b/backend/custom_addons/encoach_signup/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_signup/models/__init__.py rename to backend/custom_addons/encoach_signup/models/__init__.py diff --git a/new_project/custom_addons/encoach_signup/models/otp.py b/backend/custom_addons/encoach_signup/models/otp.py similarity index 100% rename from new_project/custom_addons/encoach_signup/models/otp.py rename to backend/custom_addons/encoach_signup/models/otp.py diff --git a/new_project/custom_addons/encoach_signup/models/student_profile.py b/backend/custom_addons/encoach_signup/models/student_profile.py similarity index 100% rename from new_project/custom_addons/encoach_signup/models/student_profile.py rename to backend/custom_addons/encoach_signup/models/student_profile.py diff --git a/new_project/custom_addons/encoach_signup/security/ir.model.access.csv b/backend/custom_addons/encoach_signup/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_signup/security/ir.model.access.csv rename to backend/custom_addons/encoach_signup/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_signup/services/__init__.py b/backend/custom_addons/encoach_signup/services/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_signup/services/__init__.py rename to backend/custom_addons/encoach_signup/services/__init__.py diff --git a/new_project/custom_addons/encoach_signup/services/captcha_service.py b/backend/custom_addons/encoach_signup/services/captcha_service.py similarity index 100% rename from new_project/custom_addons/encoach_signup/services/captcha_service.py rename to backend/custom_addons/encoach_signup/services/captcha_service.py diff --git a/new_project/custom_addons/encoach_signup/services/otp_service.py b/backend/custom_addons/encoach_signup/services/otp_service.py similarity index 100% rename from new_project/custom_addons/encoach_signup/services/otp_service.py rename to backend/custom_addons/encoach_signup/services/otp_service.py diff --git a/new_project/custom_addons/encoach_signup/views/otp_views.xml b/backend/custom_addons/encoach_signup/views/otp_views.xml similarity index 100% rename from new_project/custom_addons/encoach_signup/views/otp_views.xml rename to backend/custom_addons/encoach_signup/views/otp_views.xml diff --git a/new_project/custom_addons/encoach_signup/views/signup_menus.xml b/backend/custom_addons/encoach_signup/views/signup_menus.xml similarity index 100% rename from new_project/custom_addons/encoach_signup/views/signup_menus.xml rename to backend/custom_addons/encoach_signup/views/signup_menus.xml diff --git a/new_project/custom_addons/encoach_signup/views/student_profile_views.xml b/backend/custom_addons/encoach_signup/views/student_profile_views.xml similarity index 100% rename from new_project/custom_addons/encoach_signup/views/student_profile_views.xml rename to backend/custom_addons/encoach_signup/views/student_profile_views.xml diff --git a/new_project/custom_addons/encoach_taxonomy/__init__.py b/backend/custom_addons/encoach_taxonomy/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/__init__.py rename to backend/custom_addons/encoach_taxonomy/__init__.py diff --git a/new_project/custom_addons/encoach_taxonomy/__manifest__.py b/backend/custom_addons/encoach_taxonomy/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/__manifest__.py rename to backend/custom_addons/encoach_taxonomy/__manifest__.py diff --git a/new_project/custom_addons/encoach_taxonomy/controllers/__init__.py b/backend/custom_addons/encoach_taxonomy/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/controllers/__init__.py rename to backend/custom_addons/encoach_taxonomy/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_taxonomy/controllers/taxonomy.py b/backend/custom_addons/encoach_taxonomy/controllers/taxonomy.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/controllers/taxonomy.py rename to backend/custom_addons/encoach_taxonomy/controllers/taxonomy.py diff --git a/new_project/custom_addons/encoach_taxonomy/data/default_subjects.xml b/backend/custom_addons/encoach_taxonomy/data/default_subjects.xml similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/data/default_subjects.xml rename to backend/custom_addons/encoach_taxonomy/data/default_subjects.xml diff --git a/new_project/custom_addons/encoach_taxonomy/data/math_it_taxonomy.xml b/backend/custom_addons/encoach_taxonomy/data/math_it_taxonomy.xml similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/data/math_it_taxonomy.xml rename to backend/custom_addons/encoach_taxonomy/data/math_it_taxonomy.xml diff --git a/new_project/custom_addons/encoach_taxonomy/models/__init__.py b/backend/custom_addons/encoach_taxonomy/models/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/models/__init__.py rename to backend/custom_addons/encoach_taxonomy/models/__init__.py diff --git a/new_project/custom_addons/encoach_taxonomy/models/domain.py b/backend/custom_addons/encoach_taxonomy/models/domain.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/models/domain.py rename to backend/custom_addons/encoach_taxonomy/models/domain.py diff --git a/new_project/custom_addons/encoach_taxonomy/models/learning_objective.py b/backend/custom_addons/encoach_taxonomy/models/learning_objective.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/models/learning_objective.py rename to backend/custom_addons/encoach_taxonomy/models/learning_objective.py diff --git a/new_project/custom_addons/encoach_taxonomy/models/subject.py b/backend/custom_addons/encoach_taxonomy/models/subject.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/models/subject.py rename to backend/custom_addons/encoach_taxonomy/models/subject.py diff --git a/new_project/custom_addons/encoach_taxonomy/models/topic.py b/backend/custom_addons/encoach_taxonomy/models/topic.py similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/models/topic.py rename to backend/custom_addons/encoach_taxonomy/models/topic.py diff --git a/new_project/custom_addons/encoach_taxonomy/security/ir.model.access.csv b/backend/custom_addons/encoach_taxonomy/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/security/ir.model.access.csv rename to backend/custom_addons/encoach_taxonomy/security/ir.model.access.csv diff --git a/new_project/custom_addons/encoach_taxonomy/views/taxonomy_views.xml b/backend/custom_addons/encoach_taxonomy/views/taxonomy_views.xml similarity index 100% rename from new_project/custom_addons/encoach_taxonomy/views/taxonomy_views.xml rename to backend/custom_addons/encoach_taxonomy/views/taxonomy_views.xml diff --git a/new_project/custom_addons/encoach_verification/__init__.py b/backend/custom_addons/encoach_verification/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_verification/__init__.py rename to backend/custom_addons/encoach_verification/__init__.py diff --git a/new_project/custom_addons/encoach_verification/__manifest__.py b/backend/custom_addons/encoach_verification/__manifest__.py similarity index 100% rename from new_project/custom_addons/encoach_verification/__manifest__.py rename to backend/custom_addons/encoach_verification/__manifest__.py diff --git a/new_project/custom_addons/encoach_verification/controllers/__init__.py b/backend/custom_addons/encoach_verification/controllers/__init__.py similarity index 100% rename from new_project/custom_addons/encoach_verification/controllers/__init__.py rename to backend/custom_addons/encoach_verification/controllers/__init__.py diff --git a/new_project/custom_addons/encoach_verification/controllers/verify.py b/backend/custom_addons/encoach_verification/controllers/verify.py similarity index 100% rename from new_project/custom_addons/encoach_verification/controllers/verify.py rename to backend/custom_addons/encoach_verification/controllers/verify.py diff --git a/new_project/custom_addons/encoach_verification/security/ir.model.access.csv b/backend/custom_addons/encoach_verification/security/ir.model.access.csv similarity index 100% rename from new_project/custom_addons/encoach_verification/security/ir.model.access.csv rename to backend/custom_addons/encoach_verification/security/ir.model.access.csv diff --git a/new_project/Developer Workflow Manual.txt b/docs/Developer Workflow Manual.txt similarity index 100% rename from new_project/Developer Workflow Manual.txt rename to docs/Developer Workflow Manual.txt diff --git a/docs/ENCOACH_USER_STORIES.md b/docs/ENCOACH_USER_STORIES.md new file mode 100644 index 00000000..0658c71c --- /dev/null +++ b/docs/ENCOACH_USER_STORIES.md @@ -0,0 +1,2125 @@ +# EnCoach Platform -- Granular User Stories (English Only) + +**Document Version:** 2.0 +**Date:** April 2026 +**Status:** Active -- Ready for Development +**Scope:** English Language Only (General English + IELTS). Math/IT deferred to future phase. +**Audience:** Odoo Developer (full-stack, using Cursor IDE) + +--- + +## Companion Documents + +| Document | Version | Purpose | +|----------|---------|---------| +| `ENCOACH_WORKFLOWS_FRONTEND_SRS.md` | v1.1 | Frontend technical specification | +| `ENCOACH_WORKFLOWS_BACKEND_SRS.md` | v1.1 | Backend technical specification | +| `ENCOACH_USER_STORIES_OVERVIEW.md` | v1.0 | High-level overview (superseded by this document for development) | + +--- + +## How to Read This Document + +Each user story follows this format: + +> **US-[ACTOR]-[NUMBER]: [Title]** +> **As a** [single role], **I want to** [one specific action], **so that** [one clear benefit]. + +**One story = one function = one testable unit.** + +### Actor Prefixes + +| Prefix | Actor | Section | +|--------|-------|---------| +| SL | Self-Learning Student | Section 1 | +| ES | Entity/University Student | Section 2 | +| AD | Admin / Teacher | Section 3 | +| PV | Public Verifier | Section 3 (end) | + +### Priority Legend + +| Priority | Meaning | +|----------|---------| +| **Must Have** | Core functionality. Cannot launch without this. | +| **Should Have** | Important. Can be deferred briefly if needed. | +| **Could Have** | Desirable enhancement. Implement if time permits. | + +--- + +# SECTION 1 -- SELF-LEARNING STUDENT JOURNEY + +The complete end-to-end journey of an individual student who registers independently, pays for access, and learns on their own. + +--- + +## 1A. Registration + +### US-SL-01: Register a New Account + +**As a** self-learning student, **I want to** create an account by providing my name, email, password, and selecting "Self-Learner" as my role, **so that** I can access the platform independently. + +**Acceptance Criteria:** +- [ ] Registration page is accessible at `/register` without authentication +- [ ] Form fields: Full Name, Email, Password, Confirm Password, Role (select "Self-Learner"), CAPTCHA +- [ ] Password strength indicator updates in real time (Weak/Medium/Strong) +- [ ] Email uniqueness checked on blur; inline error if taken +- [ ] CAPTCHA must be completed before submission +- [ ] On success, redirect to `/verify-email?email={email}` +- [ ] On validation error, show field-level error messages + +**Flow:** +1. Student opens `/register` +2. Fills in all fields, selects "Self-Learner" role +3. Completes CAPTCHA +4. Clicks "Create Account" +5. System creates account, sends 6-digit OTP to email +6. Redirect to email verification page + +**Error / Edge Cases:** +- Duplicate email: inline error on blur +- CAPTCHA failure: "Please complete the CAPTCHA" +- Network error: toast "Something went wrong. Please try again." + +**SRS Reference:** Frontend 4, Backend 12 +**Priority:** Must Have + +--- + +### US-SL-02: Verify Email Address + +**As a** self-learning student who just registered, **I want to** enter a 6-digit verification code sent to my email, **so that** the platform confirms I own this email address. + +**Acceptance Criteria:** +- [ ] Page shows "We've sent a 6-digit verification code to {email}" +- [ ] 6-digit OTP input auto-focuses first digit, advances focus automatically +- [ ] "Verify" button enabled only when all 6 digits entered +- [ ] On valid OTP: redirect to `/onboarding` +- [ ] On invalid OTP: clear input, show "Invalid verification code. Please try again." +- [ ] On expired OTP: show "This code has expired. Please request a new one." +- [ ] "Resend code" disabled for 60 seconds after each send (countdown shown) +- [ ] Maximum 3 resend attempts; after 3: "Maximum resend attempts reached. Please contact support." +- [ ] Code expires after 15 minutes (countdown timer shown) + +**Flow:** +1. Student lands on `/verify-email?email={email}` +2. Checks email for OTP +3. Enters 6 digits +4. Clicks "Verify" +5. On success, proceeds to onboarding wizard + +**Error / Edge Cases:** +- Wrong code: input clears, retry allowed +- Code expired: must request new one +- All 3 resends exhausted: contact support +- Browser closed: returns to verification on next login (account still unverified) + +**SRS Reference:** Frontend 5, Backend 13 +**Priority:** Must Have + +--- + +## 1B. Onboarding + +### US-SL-03: Select Learning Goal + +**As a** self-learning student, **I want to** select my learning goal (General English, IELTS Academic, or IELTS General Training) in Step 1 of the onboarding wizard, **so that** the platform tailors my experience to my objective. + +**Acceptance Criteria:** +- [ ] Step 1 of 4 in the onboarding wizard at `/onboarding` +- [ ] Progress bar shows "Step 1 of 4" +- [ ] Radio card group displays available goals loaded from `GET /api/onboarding/goals` +- [ ] English-related options: General English, IELTS Academic, IELTS General Training +- [ ] Each card has: icon, title, description +- [ ] User must select one goal before clicking "Next" +- [ ] "Back" button is hidden on Step 1 + +**Flow:** +1. Student lands on onboarding wizard +2. Views available learning goals +3. Selects one goal (e.g., "IELTS Academic") +4. Clicks "Next" to proceed to Step 2 + +**SRS Reference:** Frontend 6, Backend 14 +**Priority:** Must Have + +--- + +### US-SL-04: Set Target Level and Timeline + +**As a** self-learning student, **I want to** set my target band/CEFR level and optionally an exam date in Step 2, **so that** the platform knows what I'm aiming for and by when. + +**Acceptance Criteria:** +- [ ] Step 2 of 4 in the onboarding wizard +- [ ] For IELTS goals: band score slider 4.0-9.0 in 0.5 steps +- [ ] For General English goals: CEFR level select (A1-C2) +- [ ] Optional exam date picker: "I have an upcoming exam on..." +- [ ] Checkbox: "I don't have a specific exam date" hides the date picker +- [ ] "Back" returns to Step 1 without losing data +- [ ] "Next" proceeds to Step 3 + +**Flow:** +1. Student sets target band/CEFR level +2. Optionally selects exam date or checks "no specific date" +3. Clicks "Next" + +**SRS Reference:** Frontend 6, Backend 14 +**Priority:** Must Have + +--- + +### US-SL-05: Set Study Preferences + +**As a** self-learning student, **I want to** configure my study hours per week, study mode, and learning style in Step 3, **so that** the platform personalises content delivery to my preferences. + +**Acceptance Criteria:** +- [ ] Step 3 of 4 in the onboarding wizard +- [ ] Hours per week: slider, 1-40, default 10. Shows estimated completion time +- [ ] Study mode: radio group -- "Self-study" or "With a teacher" +- [ ] Learning style: checkbox group (multi-select, at least one) -- Visual, Audio, Reading, Mixed +- [ ] "Back" returns to Step 2 without losing data +- [ ] "Next" proceeds to Step 4 + +**Flow:** +1. Student adjusts study hours slider +2. Selects study mode +3. Selects one or more learning styles +4. Clicks "Next" + +**SRS Reference:** Frontend 6, Backend 14 +**Priority:** Must Have + +--- + +### US-SL-06: Choose Placement Test Decision + +**As a** self-learning student, **I want to** decide whether to take the placement test now or skip it in Step 4, **so that** I can either get an accurate level assessment or start at a default level. + +**Acceptance Criteria:** +- [ ] Step 4 of 4 in the onboarding wizard +- [ ] Heading: "Ready to find your level?" +- [ ] Description explains the test (~20-30 minutes) +- [ ] "Take Placement Test Now" button: submits wizard data, navigates to `/student/placement` +- [ ] "Skip for Now" button: shows warning "Without a placement test, we'll start you at B1 (intermediate) level. You can take the test anytime from your dashboard." Submits wizard data, navigates to `/student/dashboard` +- [ ] On submission, account status changes to `activated` +- [ ] All 4 steps of wizard data submitted via `POST /api/onboarding/complete` + +**Flow:** +1. Student reads the placement test description +2. Chooses "Take Placement Test Now" or "Skip for Now" +3. Wizard data is submitted +4. Account is activated +5. Redirect to placement test or dashboard + +**Error / Edge Cases:** +- Browser closed mid-wizard: data lost, user restarts wizard on next login (account still `unactivated`) +- Skip chosen: default level B1, dashboard banner prompts test later + +**SRS Reference:** Frontend 6, Backend 14 +**Priority:** Must Have + +--- + +## 1C. Placement Test + +### US-SL-07: View Placement Test Briefing + +**As a** self-learning student, **I want to** see an overview of the placement test before starting, **so that** I know what to expect (sections, duration, adaptive nature). + +**Acceptance Criteria:** +- [ ] Briefing page at `/student/placement` +- [ ] Shows: subject (English), estimated duration (20-30 min), section count (4), adaptive note +- [ ] Dimension breakdown table: Grammar (~30 MCQ, ~8 min), Vocabulary (~20 items, ~5 min), Reading (~10 Q / 2 passages, ~10 min), Speaking (3 prompts, ~5 min) +- [ ] "Begin Test" button starts the test +- [ ] If an active incomplete session exists, "Begin Test" resumes from where the student left off + +**Flow:** +1. Student navigates to `/student/placement` +2. Reviews test overview +3. Clicks "Begin Test" +4. System creates CAT session and navigates to test interface + +**SRS Reference:** Frontend 7, Backend 15 +**Priority:** Must Have + +--- + +### US-SL-08: Take Placement Test -- Grammar Section + +**As a** self-learning student, **I want to** answer adaptive grammar questions one at a time, **so that** the system accurately assesses my grammar proficiency. + +**Acceptance Criteria:** +- [ ] Full-screen distraction-free interface (no sidebar) +- [ ] Top bar: elapsed timer, section name "Grammar", progress "Question X of ~30" +- [ ] Each question fetched one at a time from backend (no pre-loading) +- [ ] After each answer, next question adapts in difficulty (IRT algorithm) +- [ ] Question types: MCQ (single answer), MCQ (multiple answers) +- [ ] "Previous" button disabled (no going back in CAT) +- [ ] Auto-save every 10 seconds; "Saved" indicator shown +- [ ] When backend returns `section_complete: true`, show transition: "Grammar section complete. Next: Vocabulary" with countdown or "Continue" button + +**Flow:** +1. First grammar question appears +2. Student selects answer, clicks "Next" +3. Backend returns next (adapted) question +4. Repeat until section complete +5. Transition screen to Vocabulary section + +**Error / Edge Cases:** +- Network loss: auto-save ensures no data loss; resume on reconnection +- Browser close: resume from last save on next login + +**SRS Reference:** Frontend 8, Backend 15-16 +**Priority:** Must Have + +--- + +### US-SL-09: Take Placement Test -- Vocabulary Section + +**As a** self-learning student, **I want to** answer adaptive vocabulary questions, **so that** the system assesses my vocabulary range. + +**Acceptance Criteria:** +- [ ] Section name shows "Vocabulary", progress updates +- [ ] Question types: MCQ, gap fill, definition match +- [ ] Same CAT adaptive behaviour as Grammar section +- [ ] Auto-save every 10 seconds +- [ ] On section complete, transition to Reading section + +**Flow:** +1. First vocabulary question appears after Grammar transition +2. Student answers adaptive questions +3. Section completes, transition to Reading + +**SRS Reference:** Frontend 8, Backend 15-16 +**Priority:** Must Have + +--- + +### US-SL-10: Take Placement Test -- Reading Section + +**As a** self-learning student, **I want to** read passages and answer comprehension questions, **so that** the system assesses my reading proficiency. + +**Acceptance Criteria:** +- [ ] Section name shows "Reading", progress updates +- [ ] Split view: passage on left, questions on right (desktop). Scrollable passage above questions (mobile). +- [ ] Question types: MCQ, True/False/Not Given +- [ ] Passages progress from easy to difficult (CAT adaptation) +- [ ] Auto-save every 10 seconds +- [ ] On section complete, transition to Speaking section + +**Flow:** +1. First reading passage and questions appear +2. Student reads passage, answers questions +3. Repeat for second passage +4. Section completes, transition to Speaking + +**SRS Reference:** Frontend 8, Backend 15-16 +**Priority:** Must Have + +--- + +### US-SL-11: Take Placement Test -- Speaking Section + +**As a** self-learning student, **I want to** record spoken responses to 3 prompts, **so that** the system can evaluate my speaking ability via AI. + +**Acceptance Criteria:** +- [ ] Microphone permission prompt appears at the start of the section +- [ ] If permission denied: section skipped with note "Speaking section skipped. Your placement will be based on the other three sections." +- [ ] 3 speaking prompts, each showing: prompt text, "Start Recording" button, 60-second countdown +- [ ] During recording: waveform visualiser, "Stop" button +- [ ] After recording: playback controls, "Re-record" (max 1 re-record per prompt), "Submit Recording" +- [ ] Audio uploaded as blob via `POST /api/placement/speaking-upload` +- [ ] On final prompt submission, "Finish Test" button navigates to results page + +**Flow:** +1. Microphone permission requested +2. First speaking prompt displayed +3. Student clicks "Start Recording", speaks for up to 60 seconds +4. Clicks "Stop", reviews via playback +5. Optionally re-records once +6. Clicks "Submit Recording" +7. Repeats for prompts 2 and 3 +8. Clicks "Finish Test" + +**SRS Reference:** Frontend 8, Backend 18 +**Priority:** Must Have + +--- + +### US-SL-12: View Placement Results + +**As a** self-learning student, **I want to** see my overall CEFR level and per-dimension scores after completing the placement test, **so that** I understand my current proficiency. + +**Acceptance Criteria:** +- [ ] Results page at `/student/placement/results?session={id}` +- [ ] Overall CEFR level displayed prominently (e.g., "B2" with coloured badge) +- [ ] Per-dimension scores in a radar chart: Grammar, Vocabulary, Reading, Speaking +- [ ] Score table: Dimension, Score %, CEFR Level, Gap to Target +- [ ] If Speaking evaluation is pending: row shows "Pending" badge, polls `GET /api/placement/speaking-status` every 30 seconds until complete +- [ ] "Continue" button at the bottom navigates to learning path preview + +**Flow:** +1. Student lands on results page after test completion +2. Views overall CEFR level +3. Reviews per-dimension breakdown +4. Waits for Speaking evaluation if pending +5. Clicks "Continue" + +**Error / Edge Cases:** +- Speaking pending: "Pending" badge with polling +- Network error loading results: retry button + +**SRS Reference:** Frontend 9, Backend 15, 17 +**Priority:** Must Have + +--- + +### US-SL-13: View Personalised Learning Path Preview + +**As a** self-learning student, **I want to** see a personalised learning path based on my placement results BEFORE any payment prompt, **so that** I understand what I will study and can make an informed decision about subscribing. + +**Acceptance Criteria:** +- [ ] Learning path preview section on the results page (below scores) +- [ ] Course outline card: estimated duration, module count, study hours per week +- [ ] Skill gap modules listed by priority (largest gap first) with: module name, estimated hours, resource type icons (PDF, Video, Audio, Exercise), difficulty level +- [ ] "View Full Course Plan" button expands the detailed module breakdown +- [ ] This is shown BEFORE any payment prompt (key design principle) + +**Flow:** +1. Student views placement results +2. Scrolls down to learning path preview +3. Reviews proposed modules and estimated effort +4. Clicks "Continue" to proceed to payment options + +**SRS Reference:** Frontend 9, Backend 15 +**Priority:** Must Have + +--- + +### US-SL-14: Choose Payment or Access Option + +**As a** self-learning student, **I want to** choose between full subscription, free trial, or skip, **so that** I can start learning immediately or decide later. + +**Acceptance Criteria:** +- [ ] Three pricing cards at `/student/placement/access`: + - "Unlock Full Course" -> navigates to `/student/subscription` + - "Try Free for 7 Days" -> activates trial, navigates to dashboard + - "Continue to Dashboard" -> navigates to dashboard with persistent banner +- [ ] Free trial: limited access to first 3 modules only +- [ ] Skip: persistent banner on dashboard "Unlock your personalised course -- Subscribe now" + +**Flow:** +1. Student views three pricing options +2. Selects one +3. Proceeds to subscription, dashboard (trial), or dashboard (skip) + +**SRS Reference:** Frontend 10 +**Priority:** Should Have + +--- + +## 1D. Exam Taking + +### US-SL-15: Start an Assigned Exam Session + +**As a** self-learning student, **I want to** open an exam that has been assigned to me and enter the distraction-free exam interface, **so that** I can take the exam under controlled conditions. + +**Acceptance Criteria:** +- [ ] Full-screen interface at `/student/exam/:examId/session` (no sidebar, minimal header) +- [ ] Top bar: exam title, current section name, section countdown timer, overall progress bar +- [ ] All sections and questions pre-loaded (unlike CAT) +- [ ] First section starts immediately with its countdown timer +- [ ] Auto-save every 10 seconds; "Saved" indicator shown + +**Flow:** +1. Student navigates to the exam session +2. Exam loads with all sections +3. First section countdown begins +4. Student starts answering questions + +**Error / Edge Cases:** +- Exam not assigned: redirect with error "This exam is not available to you" +- Access window expired: "This exam's access window has closed" + +**SRS Reference:** Frontend 17, Backend 25 +**Priority:** Must Have + +--- + +### US-SL-16: Answer Listening Questions + +**As a** self-learning student taking an IELTS exam, **I want to** listen to audio recordings and answer questions for each Listening part, **so that** my listening comprehension is assessed. + +**Acceptance Criteria:** +- [ ] Audio player with play/pause, progress bar, volume control +- [ ] Audio plays once (IELTS standard). No replay unless configured for practice mode. +- [ ] Question types: MCQ (single), MCQ (multiple), gap fill +- [ ] Section timer counts down; warning at 5 min and 1 min remaining +- [ ] "Next" navigates to next question; "Previous" navigates back within the section +- [ ] "Flag for Review" marks the question with a flag icon +- [ ] On timer expiry: answers auto-submit, student moves to next section + +**Flow:** +1. Listening section begins, audio plays +2. Student answers questions while listening +3. Navigates between questions +4. Flags uncertain questions +5. Section ends (timer or manual submit) + +**SRS Reference:** Frontend 17, Backend 25 +**Priority:** Must Have + +--- + +### US-SL-17: Answer Reading Questions + +**As a** self-learning student taking an IELTS exam, **I want to** read passages and answer comprehension questions for each Reading part, **so that** my reading comprehension is assessed. + +**Acceptance Criteria:** +- [ ] Split view: passage on left, questions on right (desktop) +- [ ] Question types: MCQ, True/False/Not Given, gap fill, matching +- [ ] Section timer with warnings at 5 min and 1 min +- [ ] Previous/Next navigation within section +- [ ] "Flag for Review" available +- [ ] Auto-save every 10 seconds + +**Flow:** +1. Reading section begins +2. Student reads passage, answers questions +3. Navigates between questions and passages +4. Section ends (timer or manual submit) + +**SRS Reference:** Frontend 17, Backend 25 +**Priority:** Must Have + +--- + +### US-SL-18: Complete Writing Tasks + +**As a** self-learning student taking an IELTS exam, **I want to** write responses to Writing Task 1 and Task 2 using a rich text editor, **so that** my writing ability is assessed. + +**Acceptance Criteria:** +- [ ] Rich text editor with word count displayed +- [ ] Task 1: minimum 150 words (indicator turns red below minimum) +- [ ] Task 2: minimum 250 words (indicator turns red below minimum) +- [ ] Submission is NOT blocked by low word count (student may choose to submit anyway) +- [ ] Section timer with warnings +- [ ] Auto-save every 10 seconds + +**Flow:** +1. Writing section begins +2. Student reads Task 1 prompt, writes response +3. Monitors word count +4. Moves to Task 2, writes response +5. Section ends (timer or manual submit) + +**SRS Reference:** Frontend 17, Backend 25 +**Priority:** Must Have + +--- + +### US-SL-19: Record Speaking Responses in Exam + +**As a** self-learning student taking an IELTS exam, **I want to** record spoken responses for each Speaking part, **so that** my speaking ability is assessed. + +**Acceptance Criteria:** +- [ ] Same audio recording interface as placement test (US-SL-11) +- [ ] Part 1: Familiar topic questions +- [ ] Part 2: Cue card long turn (1 min prep + 2 min speaking) +- [ ] Part 3: Abstract discussion linked to Part 2 topic +- [ ] Microphone permission prompt +- [ ] Playback and re-record (max 1) per prompt +- [ ] Audio uploaded on submission + +**Flow:** +1. Speaking section begins +2. Student records responses for Parts 1, 2, and 3 +3. Reviews each recording +4. Submits recordings + +**SRS Reference:** Frontend 17, Backend 25 +**Priority:** Must Have + +--- + +### US-SL-20: Review and Submit Exam + +**As a** self-learning student, **I want to** review a summary of my answers before final submission, **so that** I can ensure I haven't missed any questions. + +**Acceptance Criteria:** +- [ ] Review summary page shows per section: answered count, unanswered count, flagged count +- [ ] Flagged questions listed with "Go to Question" links +- [ ] "Submit Exam" button with confirmation dialog: "Are you sure? You cannot change your answers after submission." +- [ ] After submission, navigate to submission confirmation page + +**Flow:** +1. Student completes all sections +2. Review summary appears +3. Student reviews flagged/unanswered items +4. Optionally returns to fix answers +5. Clicks "Submit Exam" +6. Confirmation dialog -> final submit + +**SRS Reference:** Frontend 17, Backend 25 +**Priority:** Must Have + +--- + +### US-SL-21: View Exam Results (Auto-Release) + +**As a** self-learning student whose exam has auto-release enabled, **I want to** see my results immediately after submission, **so that** I know my score right away. + +**Acceptance Criteria:** +- [ ] Results page at `/student/exam/:examId/results` +- [ ] Overall band score displayed prominently (e.g., "6.5") +- [ ] CEFR equivalent shown +- [ ] Per-skill radar chart and table: Skill, Band, CEFR, Gap to Target +- [ ] Listening and Reading: auto-scored, shown immediately +- [ ] Writing and Speaking: if pending teacher grading, show "Pending Review" with estimated wait time +- [ ] Feedback section: per-question feedback (expandable accordions per section) +- [ ] "Areas to improve" summary: top 3 weakness areas +- [ ] "Download PDF Report" button +- [ ] "View Recommended Course" button + +**Flow:** +1. Student is redirected to results page after submission +2. Sees auto-scored L/R results immediately +3. W/S show "Pending Review" until teacher grades them +4. Once all skills graded, full results display + +**SRS Reference:** Frontend 19, Backend 27 +**Priority:** Must Have + +--- + +### US-SL-22: Receive Post-Exam Routing (Pass) + +**As a** self-learning student who met or exceeded my target band, **I want to** see a congratulatory message with options to register for the official IELTS exam or continue studying, **so that** I know I've reached my goal. + +**Acceptance Criteria:** +- [ ] Action card: "Congratulations! You've reached your target." +- [ ] "Register for Official IELTS Exam" button -> navigates to `/student/exam-registration` +- [ ] "Continue Studying" button -> navigates to `/student/dashboard` + +**Flow:** +1. Student views results showing target met +2. Action card appears at bottom +3. Student chooses next step + +**SRS Reference:** Frontend 20 +**Priority:** Should Have + +--- + +### US-SL-23: Receive Post-Exam Routing (Below Target) + +**As a** self-learning student who scored below my target band, **I want to** see my skill gaps and an option to start adaptive training, **so that** I can work on my weaknesses. + +**Acceptance Criteria:** +- [ ] Action card: "Let's build a plan to reach your target." +- [ ] Skill gap summary shown inline +- [ ] "Start Adaptive Training" button -> navigates to `/student/course/generate?from=exam&examId={id}` + +**Flow:** +1. Student views results showing target not met +2. Action card with gap summary appears +3. Student clicks "Start Adaptive Training" + +**SRS Reference:** Frontend 20 +**Priority:** Should Have + +--- + +## 1E. Course Learning + +### US-SL-24: View Gap Analysis + +**As a** self-learning student, **I want to** see a detailed skill gap analysis from my exam or placement results, **so that** I understand which areas need the most work. + +**Acceptance Criteria:** +- [ ] Gap analysis page at `/student/course/generate` +- [ ] Bar chart: skills ranked by gap size (largest first), current vs target +- [ ] Table: Skill, Current Level, Target Level, Gap, Priority (High/Medium/Low), Est. Hours +- [ ] Question-type weaknesses expandable per skill +- [ ] Topic weaknesses grouped by category +- [ ] "Generate Course" button to auto-generate a course + +**Flow:** +1. Student navigates to gap analysis +2. Reviews skill gaps and weakness breakdowns +3. Clicks "Generate Course" + +**SRS Reference:** Frontend 21, Backend 29 +**Priority:** Must Have + +--- + +### US-SL-25: Start Auto-Generated Course + +**As a** self-learning student, **I want to** view an auto-generated course structure based on my gap analysis and start learning immediately, **so that** I don't have to wait for a teacher to build a course. + +**Acceptance Criteria:** +- [ ] Read-only course preview: title, duration estimate, module list with skill assignments, hours, resource icons +- [ ] "Start Course" button begins the course +- [ ] "Customize" button (optional) allows minor adjustments (reorder modules, skip low-priority skills) +- [ ] Course is created via `POST /api/course/auto-generate` + +**Flow:** +1. System generates course structure from gap analysis +2. Student reviews the proposed course +3. Clicks "Start Course" +4. Course page opens with modules available + +**SRS Reference:** Frontend 22, Backend 30 +**Priority:** Must Have + +--- + +### US-SL-26: Start AI-Generated General English Course + +**As a** self-learning student studying General English, **I want to** launch an AI-generated course tailored to my CEFR level and learning style, **so that** I receive personalised content without waiting for a teacher. + +**Acceptance Criteria:** +- [ ] Confirmation screen shows: Current CEFR Level, Target CEFR Level (editable), Learning Style (editable), Estimated Duration +- [ ] "Start AI Course" triggers content generation via `POST /api/ai-course/english/create` +- [ ] Progress indicator during generation: "Generating your personalised course... Step 2/5: Creating grammar exercises." (1-2 min) +- [ ] Three parallel module tracks: Grammar Track, Skills Track, Vocabulary Track +- [ ] Each module: title, completion status, estimated time, "Start" / "Continue" button +- [ ] Level-up celebration modal when a level is achieved + +**Flow:** +1. Student reviews profile settings +2. Clicks "Start AI Course" +3. Waits for generation (1-2 min) +4. Course appears with three parallel tracks +5. Student progresses through modules + +**SRS Reference:** Frontend 28, Backend 36 +**Priority:** Must Have + +--- + +### US-SL-27: Start AI-Generated IELTS Course + +**As a** self-learning student preparing for IELTS, **I want to** launch an AI-generated IELTS course that targets my weakest skills, **so that** I get focused practice aligned with real IELTS standards. + +**Acceptance Criteria:** +- [ ] Profile summary: Exam Type, Current Bands per skill, Target Band (editable), Skills ranked by gap, Weak question types +- [ ] "Start AI IELTS Course" triggers per-skill content generation +- [ ] Generation progress per skill: "Listening: Generating... Creating audio scripts for Parts 1-4" +- [ ] Four parallel skill paths: Writing, Reading, Speaking, Listening +- [ ] Readiness check modal when engine determines target band likely reached +- [ ] Practice exam option for band confirmation + +**Flow:** +1. Student reviews IELTS gap profile +2. Clicks "Start AI IELTS Course" +3. Waits for per-skill generation +4. Progresses through four skill paths +5. Takes practice exam when prompted + +**SRS Reference:** Frontend 29, Backend 37 +**Priority:** Must Have + +--- + +### US-SL-28: Progress Through Course Modules + +**As a** self-learning student, **I want to** progress through my course modules, viewing my completion status and unlocking new modules, **so that** I learn systematically. + +**Acceptance Criteria:** +- [ ] Course page at `/student/course/:courseId` +- [ ] Header: title, overall progress %, estimated time remaining +- [ ] Module list with collapsible sections per skill +- [ ] Each module: status (locked/available/in-progress/completed), progress bar, resource list with type icons and completion checkmarks +- [ ] "Start" / "Continue" button per module +- [ ] Adaptive indicators (if adaptive progression): "Recommended Next" badge, "Unlocked!" animation, "Skipped" badge for mastered modules + +**Flow:** +1. Student opens course page +2. Sees module list with statuses +3. Opens the next available module +4. Progresses through resources + +**SRS Reference:** Frontend 24, Backend 31 +**Priority:** Must Have + +--- + +### US-SL-29: View In-Platform Resources + +**As a** self-learning student, **I want to** view course resources (PDF, video, audio, exercises) directly on the platform without downloading, **so that** I can learn seamlessly. + +**Acceptance Criteria:** +- [ ] PDF: embedded viewer (browser native or react-pdf) +- [ ] Video: HTML5 `