diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..a14f254b877f28adbae9d417b4b95cd0d9aca6a9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,49 @@
+# sphinx build directories
+_build/
+
+# dotfiles
+.*
+!.gitignore
+!.github
+!.mailmap
+# compiled python files
+*.py[co]
+__pycache__/
+# setup.py egg_info
+*.egg-info
+# emacs backup files
+*~
+# hg stuff
+*.orig
+status
+# odoo filestore
+odoo/filestore
+# maintenance migration scripts
+odoo/addons/base/maintenance
+
+# generated for windows installer?
+install/win32/*.bat
+install/win32/meta.py
+
+# needed only when building for win32
+setup/win32/static/less/
+setup/win32/static/wkhtmltopdf/
+setup/win32/static/postgresql*.exe
+
+# js tooling
+node_modules
+jsconfig.json
+tsconfig.json
+package-lock.json
+package.json
+.husky
+
+# various virtualenv
+/bin/
+/build/
+/dist/
+/include/
+/lib/
+/man/
+/share/
+/src/
diff --git a/s_license/__init__.py b/s_license/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..09a4456971f06d44387f749bd18ff12a94e2bb93
--- /dev/null
+++ b/s_license/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+from . import models
+from . import controllers
+from . import wizards
diff --git a/s_license/__manifest__.py b/s_license/__manifest__.py
new file mode 100644
index 0000000000000000000000000000000000000000..ddf00a90aaf5c86be4b847846e44b6bd80229cd0
--- /dev/null
+++ b/s_license/__manifest__.py
@@ -0,0 +1,22 @@
+{
+    'name': 'Custom License',
+    'version': '1.0',
+    'depends': ['base', 'mail', 'website'],
+    'author': 'HngQun',
+    'website': 'https://snine.vn/',
+    'category': 'License Module',
+    'description': """
+        A module to demonstrate custom license in Odoo 16.
+    """,
+    'data': [
+        'security/access_groups.xml',
+        'security/ir.model.access.csv',
+        'wizards/popup_wizards.xml',
+        'views/license_views.xml',
+        'views/license_register.xml',
+        'views/license_menu.xml',
+    ],
+    'license': 'LGPL-3',
+    'installable': True,
+    'application': True,
+}
diff --git a/s_license/controllers/__init__.py b/s_license/controllers/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..9e9b01988d5742109830d90b3c5608a653b37220
--- /dev/null
+++ b/s_license/controllers/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+from . import license_controller
diff --git a/s_license/controllers/license_controller.py b/s_license/controllers/license_controller.py
new file mode 100644
index 0000000000000000000000000000000000000000..07a1cf3fa109d77da14d7cec8f4448b3ff0ecc6d
--- /dev/null
+++ b/s_license/controllers/license_controller.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from odoo import http
+from odoo.http import request
+import json
+
+class LicenseController(http.Controller):
+
+    @http.route('/viewlicense', type='http', auth='public', website=True)
+    def register_license_page(self, **kwargs):
+        return request.render('s_license.license_register')
+
+    @http.route('/register_license', type='http', method=['POST'], auth='public', website=True)
+    def register_license_submit(self, **kwargs):
+        request.env['license.management'].sudo().create({
+            'name': kwargs.get('name'),
+            'start_date': kwargs.get('start_date'),
+            'end_date': kwargs.get('end_date'),
+            'key': kwargs.get('uuid'),
+            'note': '',
+        })
+        return request.render('s_license.license_register')
diff --git a/s_license/models/__init__.py b/s_license/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..c531a69c327ff3160725f5c7054711644f05cfe0
--- /dev/null
+++ b/s_license/models/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+from . import license
diff --git a/s_license/models/license.py b/s_license/models/license.py
new file mode 100644
index 0000000000000000000000000000000000000000..984f1d49d817ad69f96fc1b5fad6947302ac1901
--- /dev/null
+++ b/s_license/models/license.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+from odoo import api, models, fields, _
+from odoo.exceptions import UserError, ValidationError
+from datetime import datetime
+
+class LicenseManager(models.Model):
+    _name = 'license.management'
+    _description = 'License Management'
+    _inherit = ['mail.thread', 'mail.activity.mixin']
+
+    name = fields.Char(string='Name', required=True, tracking=True)
+    start_date = fields.Date(string='Start Date', required=True, tracking=True)
+    end_date = fields.Date(string='End Date', required=True, tracking=True)
+    key = fields.Char(string='Key', required=True, tracking=True)
+    note = fields.Text(string='Note')
+    status = fields.Selection([
+        ('pending', 'Pending'),
+        ('active', 'Active'),
+        ('deactivate', 'Deactivate'),
+        ('cancelled', 'Cancelled'),
+    ], string='Status', default='pending', tracking=True, readonly=True)
+
+    def action_show_popup(self, action):
+        return {
+            'name': _('Reason'),
+            'res_model': 'license.wizard',
+            'view_mode': 'form',
+            'target': 'new',
+            'type': 'ir.actions.act_window',
+            'context': {
+                'default_state': action,
+                'active_id': self.id,
+            }
+        }
+
+    @api.constrains('name', 'start_date', 'end_date', 'key')
+    def check_status(self):
+        for rec in self:
+            if rec.status != 'pending':
+                rec.status = 'pending'
+
+    def action_active(self):
+        return self.action_show_popup('active')
+
+    def action_cancel(self):
+        return self.action_show_popup('cancelled')
+
+    def action_deactivate(self):
+        return self.action_show_popup('deactivate')
diff --git a/s_license/security/access_groups.xml b/s_license/security/access_groups.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7605035eadde4b32c21995a4e1df24f57ffc92cc
--- /dev/null
+++ b/s_license/security/access_groups.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+    <record model="ir.module.category" id="ls_category">
+        <field name="name">Security for license</field>
+        <field name="sequence">45</field>
+    </record>
+
+    <record id="group_license" model="res.groups">
+        <field name="name">User</field>
+        <field name="category_id" ref="s_license.ls_category"/>
+    </record>
+
+</odoo>
diff --git a/s_license/security/ir.model.access.csv b/s_license/security/ir.model.access.csv
new file mode 100644
index 0000000000000000000000000000000000000000..d34ca02b11fd86d7fb010b1a61d1ccd1ff7e30a6
--- /dev/null
+++ b/s_license/security/ir.model.access.csv
@@ -0,0 +1,3 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_license,access_license,model_license_management,group_license,1,1,1,1
+access_license_wizard,access_license_wizard,model_license_wizard,,1,1,1,1
diff --git a/s_license/views/license_menu.xml b/s_license/views/license_menu.xml
new file mode 100644
index 0000000000000000000000000000000000000000..da23bae18b0b7f88bc798efd870153780a8505ba
--- /dev/null
+++ b/s_license/views/license_menu.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<odoo>
+    <menuitem id="menu_license_root" name="Licenses" sequence="10"/>
+    <menuitem id="menu_license" name="Licenses" parent="menu_license_root" action="action_license" sequence="10"/>
+</odoo>
diff --git a/s_license/views/license_register.xml b/s_license/views/license_register.xml
new file mode 100644
index 0000000000000000000000000000000000000000..f93716b9a47b6a44326ba97a0923308f02696e35
--- /dev/null
+++ b/s_license/views/license_register.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<odoo>
+    <template id="license_register" name="License Template">
+        <t t-call="website.layout">
+            <div class="container mt16 mb16">
+                <h1>Register License</h1>
+                <br/>
+                <form id="register_form" action="/register_license" method="post">
+                    <input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
+
+                    <div class="form-group">
+                        <label for="name">Name:</label>
+                        <input type="text" class="form-control" id="name" name="name"/>
+                    </div>
+
+                    <div class="form-group">
+                        <label for="uuid">UUID:</label>
+                        <input type="text" class="form-control" id="uuid" name="uuid" required="required"/>
+                    </div>
+
+                    <div class="form-group">
+                        <label for="date_start">Start Date:</label>
+                        <input type="date" class="form-control" id="start_date" name="start_date" required="required"/>
+                    </div>
+
+                    <div class="form-group">
+                        <label for="date_end">End Date:</label>
+                        <input type="date" class="form-control" id="end_date" name="end_date" required="required"/>
+                    </div>
+                    <br/>
+                    <button type="submit" class="btn btn-primary">Register</button>
+                </form>
+            </div>
+        </t>
+    </template>
+</odoo>
diff --git a/s_license/views/license_views.xml b/s_license/views/license_views.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b98d1ab7fc6d34f3b03c02c0dfd51b41ba9b6ed6
--- /dev/null
+++ b/s_license/views/license_views.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<odoo>
+    <data>
+        <record id="view_license_form" model="ir.ui.view">
+            <field name="name">license.management.form</field>
+            <field name="model">license.management</field>
+            <field name="arch" type="xml">
+                <form string="License">
+                    <header>
+
+                        <button name="action_active" string="Confirm"
+                                attrs="{'invisible': [('status', 'in', ['active','deactivate','cancelled'])]}"
+                                type="object" class="oe_highlight"/>
+
+                        <button name="action_cancel" string="Cancel"
+                                attrs="{'invisible': [('status', 'in', ['active','cancelled','deactivate'])]}"
+                                type="object" class="oe_highlight"/>
+
+                        <button name="action_deactivate" string="Deactivate"
+                                attrs="{'invisible': [('status', 'in', ['pending','cancelled','deactivate'])]}"
+                                type="object" class="oe_highlight"/>
+
+                        <field name="status" widget="statusbar"
+                               statusbar_visible="pending, active, cancelled, deactivate"
+                               class="btn btn_primary"/>
+
+                    </header>
+
+                    <sheet>
+                        <group>
+                            <group>
+                                <field name="name"/>
+                                <field name="start_date"/>
+                                <field name="end_date"/>
+                            </group>
+                            <group>
+                                <field name="key"/>
+                                <field name="note"/>
+                            </group>
+                        </group>
+                    </sheet>
+
+                    <notebook>
+                        <page name="public" string="Work Information">
+
+                        </page>
+                        <page name="public" string="Demo ĂŒnormation">
+
+                        </page>
+                    </notebook>
+
+                    <div class="oe_chatter">
+                        <field name="message_follower_ids" groups="base.group_user" options="{'post_refresh': 'recipients'}"/>
+                        <field name="activity_ids"/>
+                        <field name="message_ids"/>
+                    </div>
+                </form>
+            </field>
+        </record>
+
+        <record id="view_license_search" model="ir.ui.view">
+            <field name="name">license.management.search</field>
+            <field name="model">license.management</field>
+            <field eval="10" name="priority"/>
+            <field name="arch" type="xml">
+                <search string="Student Search">
+                    <field name="name"/>
+                    <field name="start_date"/>
+                    <field name="end_date"/>
+                    <field name="key"/>
+                    <field name="note"/>
+                    <field name="status"/>
+
+                    <group expand='0' string='Filters'>
+                        <separator/>
+                        <filter name="pending_filter" string="pending" domain="[('status', '=',  'pending')]"/>
+                        <filter name="cancelled_filter" string="cancelled" domain="[('status', '=',  'cancelled')]"/>
+                        <filter name="active_filter" string="active" domain="[('status', '=',  'active')]"/>
+                        <filter name="inactive_filter" string="inactive" domain="[('status', '=',  'inactive')]"/>
+                    </group>
+
+                    <group expand='0' string='Group by...'>
+                        <filter string='Status' name="status_group" context="{'group_by': 'status'}"/>
+                    </group>
+                </search>
+            </field>
+        </record>
+
+        <record id="view_license_tree" model="ir.ui.view">
+            <field name="name">license.management.tree</field>
+            <field name="model">license.management</field>
+            <field name="arch" type="xml">
+                <tree string="License">
+                    <field name="name"/>
+                    <field name="start_date"/>
+                    <field name="end_date"/>
+                    <field name="key"/>
+                    <field name="status"/>
+                </tree>
+            </field>
+        </record>
+
+        <record id="view_license_kanban" model="ir.ui.view">
+            <field name="name">license.management.kanban</field>
+            <field name="model">license.management</field>
+            <field name="arch" type="xml">
+                <kanban default_group_by="status">
+                    <field name="name"/>
+                    <field name="start_date"/>
+                    <field name="end_date"/>
+                    <field name="key"/>
+                    <field name="status"/>
+
+                    <templates>
+                        <t t-name="kanban-box">
+                            <div t-att-data-id="record.id" class="oe_kanban_card oe_kanban_global_click">
+                                <div class="oe_kanban_details">
+
+                                    <div class="o_kanban_record_title">
+                                        <t t-esc="record.name.value" style="font-weight: bold; font-size: large;"/>
+                                    </div>
+
+                                    <ul class="o_kanban_ul_details">
+                                        <li t-if="record.start_date.value">
+                                            <i class="fa fa-calendar-check-o" aria-hidden="true"></i>
+                                            <strong> Start Date:</strong> <t t-esc="record.start_date.value"/>
+                                        </li>
+                                        <li t-if="record.end_date.value">
+                                            <i class="fa fa-calendar-times-o" aria-hidden="true"></i>
+                                            <strong> End Date:</strong> <t t-esc="record.end_date.value"/>
+                                        </li>
+                                        <li t-if="record.key.value">
+                                            <i class="fa fa-key" aria-hidden="true"></i>
+                                            <strong> Key:</strong> <t t-esc="record.key.value"/>
+                                        </li>
+                                    </ul>
+
+                                    <div class="o_kanban_badge" t-attf-class="o_kanban_badge_#{record.status.value}">
+                                        <span t-esc="record.status.value"/>
+                                    </div>
+                                </div>
+                            </div>
+                        </t>
+                    </templates>
+                </kanban>
+            </field>
+        </record>
+
+        <record id="action_license" model="ir.actions.act_window">
+            <field name="name">Licenses</field>
+            <field name="res_model">license.management</field>
+            <field name="view_mode">tree,kanban,form</field>
+            <field name="view_id" ref="view_license_tree"></field>
+        </record>
+   </data>
+</odoo>
diff --git a/s_license/wizards/__init__.py b/s_license/wizards/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..2fcecdcafd3b354a38bd23d1b18d4455c93947bd
--- /dev/null
+++ b/s_license/wizards/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+from . import popup_wizard
diff --git a/s_license/wizards/popup_wizard.py b/s_license/wizards/popup_wizard.py
new file mode 100644
index 0000000000000000000000000000000000000000..f9df1ea4d2d3a05ef82d7e2291ebe2cdbe7c34f1
--- /dev/null
+++ b/s_license/wizards/popup_wizard.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from odoo import models, fields, api, _
+
+class LicensePopupWizard(models.TransientModel):
+    _name = 'license.wizard'
+    _description = 'License Wizard'
+
+    reason = fields.Text(string='Reason', required=True)
+
+    def action_confirm(self):
+        active_id = self.env.context.get('active_id')
+        if active_id:
+            license_record = self.env['license.management'].browse(active_id)
+            today_str = fields.Date.today().strftime('%d/%m/%Y')
+            license_record.write({
+                'status': self.env.context.get('default_state'),
+                'note': f"{today_str} - {self.reason}\n{license_record.note or ''}"
+            })
+        return {'type': 'ir.actions.act_window_close'}
diff --git a/s_license/wizards/popup_wizards.xml b/s_license/wizards/popup_wizards.xml
new file mode 100644
index 0000000000000000000000000000000000000000..54006758371806566dabf1750779f84c5e0d30a2
--- /dev/null
+++ b/s_license/wizards/popup_wizards.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<odoo>
+    <record id="view_license_wizard_form" model="ir.ui.view">
+        <field name="name">license.wizard.form</field>
+        <field name="model">license.wizard</field>
+        <field name="arch" type="xml">
+            <form string="License Wizard">
+                <group>
+                    <field name="reason"/>
+                </group>
+                <footer>
+                    <button string="Confirm" type="object" name="action_confirm" class="btn-primary"/>
+                    <button string="Cancel" class="btn-secondary" special="cancel"/>
+                </footer>
+            </form>
+        </field>
+    </record>
+</odoo>