fix(roles): remove unused roles, merge managers, revoke Clerk's ALL_FUNCTIONS

Audited role usage/permissions across all tenants and cleaned up several
inconsistencies:

- Removed 'Self Service User' (zero users, no wired-up purpose in the app).
- Merged 'As Manager' into 'Branch Manager' (union of both permission sets,
  users reassigned, As Manager dropped) since the two covered overlapping
  ground with no clear split.
- Revoked Clerk's ALL_FUNCTIONS grant: it unconditionally bypassed every
  individual permission check (HasPermissionDirective), so unticking any
  menu/permission for Clerk in Roles & Permissions had no effect. Clerk's
  own explicit permission rows are untouched and remain the effective set.
- Renamed 'CASHIER' to 'Cashier' for display consistency with every other
  role name; the role-name check this touches (CashierRoleHelper) is
  case-insensitive, so behavior is unchanged.

('Principal Officer' was audited too but kept - it's the statutory
PMLA/RBI compliance seat from 0435, just not yet assigned to anyone.)

Each change was applied directly to all three tenant DBs and captured as
a migration (0543, 0546, 0547), dry-run verified as a no-op against the
now-updated DBs so it applies cleanly here and correctly for any new tenant.
This commit is contained in:
2026-09-12 13:54:56 +05:30
parent c20a7d0728
commit 9e0c04583d
4 changed files with 100 additions and 0 deletions
@@ -69,4 +69,9 @@
<include file="parts/0540_unique_active_cash_settlement_per_cashier_day.xml" relativeToChangelogFile="true"/>
<include file="parts/0541_create_tenant_menu_access.xml" relativeToChangelogFile="true"/>
<include file="parts/0542_split_loan_origination_investment_permissions.xml" relativeToChangelogFile="true"/>
<include file="parts/0543_remove_unused_roles_and_merge_manager_roles.xml" relativeToChangelogFile="true"/>
<include file="parts/0544_catchup_teller_is_deleted.xml" relativeToChangelogFile="true"/>
<include file="parts/0545_catchup_current_account_columns.xml" relativeToChangelogFile="true"/>
<include file="parts/0546_rename_cashier_role_to_title_case.xml" relativeToChangelogFile="true"/>
<include file="parts/0547_revoke_all_functions_from_clerk.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- 'Self Service User' was audited across every tenant and found with zero users assigned
anywhere and no wired-up purpose. Principal Officer is kept - it is the statutory
PMLA/RBI compliance seat added in 0435, just not yet assigned to anyone. -->
<changeSet id="0543-1" author="cbs-nitesh">
<sql>
DELETE FROM m_role_permission
WHERE role_id IN (SELECT id FROM m_role WHERE name = 'Self Service User')
</sql>
<sql>
DELETE FROM m_appuser_role
WHERE role_id IN (SELECT id FROM m_role WHERE name = 'Self Service User')
</sql>
<sql>
DELETE FROM m_role WHERE name = 'Self Service User'
</sql>
</changeSet>
<!-- 'As Manager' and 'Branch Manager' covered overlapping ground (loan/cash operations vs.
portfolio/savings operations). Merging them into one surviving role - 'Branch Manager' -
rather than just keeping both in sync: Branch Manager first picks up any permission only
As Manager had, then As Manager's users move onto Branch Manager, then As Manager itself
is removed. -->
<changeSet id="0543-2" author="cbs-nitesh">
<sql>
INSERT INTO m_role_permission (role_id, permission_id)
SELECT (SELECT id FROM m_role WHERE name = 'Branch Manager'), rp.permission_id
FROM m_role_permission rp
WHERE rp.role_id = (SELECT id FROM m_role WHERE name = 'As Manager')
AND NOT EXISTS (
SELECT 1 FROM m_role_permission existing
WHERE existing.role_id = (SELECT id FROM m_role WHERE name = 'Branch Manager')
AND existing.permission_id = rp.permission_id)
</sql>
<sql>
INSERT INTO m_appuser_role (appuser_id, role_id)
SELECT ur.appuser_id, (SELECT id FROM m_role WHERE name = 'Branch Manager')
FROM m_appuser_role ur
WHERE ur.role_id = (SELECT id FROM m_role WHERE name = 'As Manager')
AND NOT EXISTS (
SELECT 1 FROM m_appuser_role existing
WHERE existing.appuser_id = ur.appuser_id
AND existing.role_id = (SELECT id FROM m_role WHERE name = 'Branch Manager'))
</sql>
<sql>
DELETE FROM m_appuser_role WHERE role_id = (SELECT id FROM m_role WHERE name = 'As Manager')
</sql>
<sql>
DELETE FROM m_role_permission WHERE role_id = (SELECT id FROM m_role WHERE name = 'As Manager')
</sql>
<sql>
DELETE FROM m_role WHERE name = 'As Manager'
</sql>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- Every other role reads in title case ('Clerk', 'Teller', 'Branch Manager'); 'CASHIER' was
the one seeded in all caps, which is what showed up as an all-caps chip in the user-role
picker. Role name is only ever matched case-insensitively (CashierRoleHelper.isCashierOnly,
validateCheckerRole), so this rename changes nothing about who counts as a cashier. -->
<changeSet id="0546-1" author="cbs-nitesh">
<sql>
UPDATE m_role SET name = 'Cashier' WHERE name = 'CASHIER'
</sql>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<!-- Clerk somehow carried ALL_FUNCTIONS, which bypasses every individual permission check
(HasPermissionDirective, and this table's own role-permission rows) unconditionally - a
Clerk should only ever have the specific request/submit rights this role's own explicit
permission rows already grant, never full access. Revoking just that one row; Clerk's
real, explicit permission set is untouched. -->
<changeSet id="0547-1" author="cbs-nitesh">
<sql>
DELETE FROM m_role_permission
WHERE role_id = (SELECT id FROM m_role WHERE name = 'Clerk')
AND permission_id = (SELECT id FROM m_permission WHERE code = 'ALL_FUNCTIONS')
</sql>
</changeSet>
</databaseChangeLog>