diff --git a/base_tier_validation/__manifest__.py b/base_tier_validation/__manifest__.py
index 3d2ad910..9e5cd041 100644
--- a/base_tier_validation/__manifest__.py
+++ b/base_tier_validation/__manifest__.py
@@ -15,6 +15,7 @@
"depends": ["mail"],
"data": [
# Security
+ "security/tier_validation_groups.xml",
"security/ir.model.access.csv",
"security/tier_validation_security.xml",
# Data
diff --git a/base_tier_validation/readme/CONFIGURE.md b/base_tier_validation/readme/CONFIGURE.md
index 4bd817e6..423d7127 100644
--- a/base_tier_validation/readme/CONFIGURE.md
+++ b/base_tier_validation/readme/CONFIGURE.md
@@ -1,10 +1,16 @@
To configure this module, you need to:
-1. Go to *Settings \> Technical \> Tier Validations \> Tier
- Definition*.
+1. Go to *Tier Validations \> Tier Definition* (top-level menu, no
+ Settings / Technical access required).
2. Create as many tiers as you want for any model having tier
validation functionality.
+The *Tier Validations* menu is gated by the **Tier Validation
+Administrator** group. Assign it to trusted key users (Settings \>
+Users \> *Tier Validation* category) so they can manage definitions and
+exceptions **without** granting them Settings / Technical access.
+System administrators receive this group automatically.
+
**Note:**
- If check *Notify Reviewers on Creation*, all possible reviewers will
diff --git a/base_tier_validation/readme/HISTORY.md b/base_tier_validation/readme/HISTORY.md
index 740cd6ca..4812ccbb 100644
--- a/base_tier_validation/readme/HISTORY.md
+++ b/base_tier_validation/readme/HISTORY.md
@@ -1,3 +1,14 @@
+## 19.0.2.0.0 (2026-05-17)
+
+Features:
+
+- New **Tier Validation Administrator** security group. Trusted key
+ users can now manage tier definitions and exceptions without being
+ granted Settings / Technical access. System administrators receive
+ the group automatically (back-compat).
+- The *Tier Validations* menu has moved out of *Settings > Technical*
+ to a top-level menu, gated by the new group.
+
## 19.0.1.0.1 (2026-05-12)
Fixes:
diff --git a/base_tier_validation/security/ir.model.access.csv b/base_tier_validation/security/ir.model.access.csv
index 82c76c65..ef2066fa 100644
--- a/base_tier_validation/security/ir.model.access.csv
+++ b/base_tier_validation/security/ir.model.access.csv
@@ -9,3 +9,6 @@ access_tier_definition_settings,tier.definition.settings,model_tier_definition,b
access_comment_wizard,access.comment.wizard,model_comment_wizard,base.group_user,1,1,1,1
access_tier_validation_exceptions_all,tier.validation.exceptions,model_tier_validation_exception,base.group_user,1,0,0,0
access_tier_validation_exceptions_settings,tier.validation.exceptions,model_tier_validation_exception,base.group_system,1,1,1,1
+access_tier_definition_manager,tier.definition.manager,model_tier_definition,base_tier_validation.group_tier_validation_manager,1,1,1,1
+access_tier_validation_exceptions_manager,tier.validation.exceptions.manager,model_tier_validation_exception,base_tier_validation.group_tier_validation_manager,1,1,1,1
+access_tier_review_manager,tier.review.manager,model_tier_review,base_tier_validation.group_tier_validation_manager,1,1,1,1
diff --git a/base_tier_validation/security/tier_validation_groups.xml b/base_tier_validation/security/tier_validation_groups.xml
new file mode 100644
index 00000000..cea08a10
--- /dev/null
+++ b/base_tier_validation/security/tier_validation_groups.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ Tier Validation
+ 20
+
+
+ Tier Validation
+
+
+
+ Administrator
+
+
+
+
+
+
+
diff --git a/base_tier_validation/tests/test_tier_validation.py b/base_tier_validation/tests/test_tier_validation.py
index 344004fd..a6b8b55b 100644
--- a/base_tier_validation/tests/test_tier_validation.py
+++ b/base_tier_validation/tests/test_tier_validation.py
@@ -7,9 +7,9 @@
from lxml import etree
from odoo import Command
-from odoo.exceptions import ValidationError
+from odoo.exceptions import AccessError, ValidationError
from odoo.fields import Domain
-from odoo.tests import Form
+from odoo.tests import Form, new_test_user
from odoo.tests.common import tagged
from ..models.tier_validation import BASE_EXCEPTION_FIELDS as BEF
@@ -1454,6 +1454,38 @@ def test_34_test_duplicate_new_user_should_not_have_review_ids(self):
# Review_ids should not be copied when duplicating a user
self.assertFalse(new_user.review_ids.ids)
+ def test_35_manager_group_can_configure_without_technical(self):
+ """A trusted key user holding only the Tier Validation
+ Administrator group (no system / erp_manager / Technical) can
+ manage tier definitions; a plain internal user cannot; and the
+ system admin implies the manager group for back-compat."""
+ manager = new_test_user(
+ self.env,
+ name="Tier Manager",
+ login="tier_manager",
+ groups="base.group_user,base_tier_validation.group_tier_validation_manager",
+ )
+ plain = new_test_user(
+ self.env, name="Plain", login="plain_user", groups="base.group_user"
+ )
+ vals = {
+ "model_id": self.tester_model.id,
+ "review_type": "individual",
+ "reviewer_id": self.test_user_1.id,
+ "definition_domain": "[('test_field', '=', 1.0)]",
+ }
+ definition = self.env["tier.definition"].with_user(manager).create(dict(vals))
+ self.assertTrue(definition.id)
+ definition.with_user(manager).write({"sequence": 99})
+ with self.assertRaises(AccessError):
+ self.env["tier.definition"].with_user(plain).create(dict(vals))
+ # Back-compat: system administrators implicitly get the new group.
+ self.assertTrue(
+ self.test_user_1.has_group(
+ "base_tier_validation.group_tier_validation_manager"
+ )
+ )
+
@tagged("at_install")
class TierTierValidationView(CommonTierValidation):
diff --git a/base_tier_validation/views/tier_definition_view.xml b/base_tier_validation/views/tier_definition_view.xml
index 922727ed..5203e9df 100644
--- a/base_tier_validation/views/tier_definition_view.xml
+++ b/base_tier_validation/views/tier_definition_view.xml
@@ -160,7 +160,9 @@