Bite #30K.3A — Legacy Identity Dependency Elimination - RodrigoMattosoSilveira/EnterpriseRemoteSystems GitHub Wiki
Bite #30K.3A — Legacy Identity Dependency Elimination
Manual Promotion Test Suite
Branch: 30k3a
Passing SHA: 2b1fff6b14bcda09be2082f50dc77a1b566e4419
Automated status: make local-check and CI pass.
Purpose
These manual tests verify that the user-visible identity and authorization behavior still works after 30K.3A removed live runtime/writer dependence on the retired identity fields, and that newly created identity records do not write those retired fields.
The intended canonical identity path is:
Authentication Account → AccountActor → Person-Tenant Membership → Global Person → Collaborator Journey
The legacy columns remain physically present for this bite, but new runtime writes must not populate them.
Test data used by this suite
Create and use this deterministic identity during the tests:
| Field | Value |
|---|---|
| First name | ThirtyKThreeA |
| Last name | ManualPerson |
| Nickname | 30K3A Person Only |
| CPF | 31415926590 |
| RG | 30K3A-MANUAL-001 |
| Cellular | 11987654321 |
| Email / future login | [email protected] |
| Country | Brasil |
| PIX key | [email protected] |
| Street | Rua Manual 30K3A |
| State | PA |
| CEP | 66000-000 |
| City | Manual City |
| Bank | Manual Bank |
| Bank number | 001 |
| Checking account | 30K3A-001 |
| Emergency contact | Manual Emergency |
| Emergency cellular | 11999990000 |
| Emergency email | [email protected] |
| Temporary authentication password | Manual-30K3A-Password-1! |
Use Tenant A for the tenant-scoped tests.
Required sign-in identities
- Application Administrator: sign in with
[email protected]using the existing local Application Administrator password. - Tenant A Tenant Administrator: sign in as
[email protected]using the existing local Tenant Administrator password. - 30K3A Person: after Test 03 creates the Authentication Account, sign in with
[email protected].
If [email protected] already exists from an earlier attempt, delete/reset only that manual test data before starting. Do not reuse an ambiguous pre-existing record.
Test 01 — Application Administrator remains global/control-plane only
Identity
Sign in as Application Administrator:
Required context
Select Administration / Global administration. Do not select or assume Tenant A.
Steps
- Sign out of any existing session.
- Sign in as
[email protected]. - Confirm the header/context identifies the session as the Application Administrator in the global Administration context.
- Open Administration → Authentication.
- Open Administration → Tenants.
- Confirm both pages load without 403 errors or application exceptions.
- Confirm the Application Administrator is not silently switched into Tenant A merely by visiting these pages.
- If the UI exposes a tenant/context selector, confirm the Application Administrator's standing identity remains the global/control-plane identity.
Expected result
- Authentication Administration loads.
- Tenant Administration loads.
- No tenant-scoped Person or Collaborator identity is implicitly attached to the Application Administrator.
- No 403/500/application error occurs during normal global administration navigation.
PASS
PASS only if all expected results occur.
Promotion blocker
Block promotion if the Application Administrator requires a tenant identity to use global administration, is silently assigned a Tenant Actor, or receives a 403/500 caused by identity resolution.
Test 02 — Create a complete Person through the Tenant A UI
Identity
Sign in as the Tenant A Tenant Administrator:
Required context
Select Tenant A.
Steps
- Sign out of the Application Administrator session.
- Sign in as the Tenant A Tenant Administrator.
- Confirm the selected context is Tenant A.
- Navigate through the UI to People.
- Choose Create Person.
- Enter the following values exactly:
- First name:
ThirtyKThreeA - Last name:
ManualPerson - Nickname:
30K3A Person Only - CPF:
31415926590 - RG:
30K3A-MANUAL-001 - Cellular:
11987654321 - Email:
[email protected] - Country:
Brasil - PIX key:
[email protected] - Street:
Rua Manual 30K3A - State:
PA - CEP:
66000-000 - City:
Manual City - Bank:
Manual Bank - Bank number:
001 - Checking account:
30K3A-001 - Emergency contact:
Manual Emergency - Emergency cellular:
11999990000 - Emergency email:
[email protected]
- First name:
- Complete any other UI-required field with the normal valid Tenant A value.
- Save the Person.
- Return to the People list using the UI.
- Search for
30K3A Person Only. - Open the Person from the search result.
- Confirm the displayed email is
[email protected]. - Confirm the Person is an active member of Tenant A.
- Confirm there is not yet a Collaborator Journey for this Person.
Expected result
The Person is created and is visible through the normal Tenant A People UI without any legacy-identity-related error.
PASS
PASS only if the Person can be created, found again through the UI, and opened successfully in Tenant A.
Promotion blocker
Block promotion for a 400/403/500 error, duplicate/incorrect Person projection, inability to find the newly created Person, or creation of an unexpected Collaborator Journey.
Test 03 — Create a Person-only Authentication Account and verify self-service
Identity
Start as Application Administrator:
Then sign in as the newly created Person:
Required context
For account creation, use Administration / Global administration.
For the Person sign-in, select Tenant A if the application asks for a tenant after authentication.
Steps
- Sign out of the Tenant A Tenant Administrator session.
- Sign in as
[email protected]. - Navigate to Administration → Authentication.
- Choose the UI action to create/provision an Authentication Account.
- Select Tenant A as the target tenant if the form asks for the tenant.
- Select the Person whose email is
[email protected]. - Set the temporary password to
Manual-30K3A-Password-1!. - Submit the account creation form.
- Confirm the account appears in Authentication Administration and is associated with the expected Person and Tenant A Actor/Membership projection.
- Sign out.
- Sign in as
[email protected]usingManual-30K3A-Password-1!. - If the application requires a password change on first login, complete it and record the new password in your test notes.
- Select Tenant A if prompted.
- Navigate through the normal UI to the signed-in Person's own Person information.
- Confirm the page belongs to
30K3A Person Only. - Navigate to the Person's Current Account/history view.
- Confirm the page loads successfully even though this Person has never yet been a Collaborator.
- Confirm the Person does not receive Tenant Administrator, Expense Operator, or other delegated administrative permissions merely because an Authentication Account exists.
Expected result
A Person who has never been a Collaborator can authenticate through the canonical Account/AccountActor/Membership graph and can use intrinsic Person self-service.
PASS
PASS only if the Person can sign in, see their own Person record and Current Account/history, and does not receive delegated administrative privileges.
Promotion blocker
Block promotion if account creation fails because a legacy actor_id, Actor person_id, legacy Person projection, or Collaborator identity is absent; if login fails; or if delegated permissions appear unexpectedly.
Test 04 — Make the same Person a Collaborator without changing Authentication identity
Identity
First sign in as the Tenant A Tenant Administrator.
Then sign in again as:
Required context
Use Tenant A throughout.
Steps
- Sign out of the 30K3A Person session.
- Sign in as the Tenant A Tenant Administrator.
- Confirm Tenant A is selected.
- Navigate to Collaborators through the UI.
- Choose Create Collaborator.
- Select the existing Person
30K3A Person Only. - Use valid Tenant A reference-data choices. When these labels are available, use:
- Payment method:
Daily - Daily/payment value:
100 - Sector:
Mining - Location:
Main Mine - Task:
Miner
- Payment method:
- Use today's date as the Journey start date.
- Use a default end date at least 30 days after the start date.
- Save the Collaborator Journey.
- Return to the Collaborators list.
- Search for
30K3A Person Only. - Open the newly created Collaborator Journey.
- Confirm the Person shown is
30K3A Person Only. - Record the Collaborator Journey ID displayed by the UI.
- Sign out.
- Sign in again as
[email protected]. - Select Tenant A.
- Confirm the same Authentication Account still works; no second account or re-provisioning step should be required.
- Navigate to the user's work/Collaborator features.
- Confirm current Collaborator features are now available in addition to the Person self-service features verified in Test 03.
- Re-open the user's Person information and Current Account/history to confirm the original Person self-service remains available.
Expected result
Collaborator status is derived from the canonical Membership/Journey relationship. Turning the Person into a Collaborator must not require or create a new legacy identity linkage.
PASS
PASS only if the same Authentication Account continues to work and the user's permissions expand appropriately from Person-only to current-Collaborator capabilities.
Promotion blocker
Block promotion if the user must be re-provisioned, receives a different Person identity, loses Person self-service, cannot reach Collaborator features, or receives an identity-resolution error.
Test 05 — Verify the new records contain canonical identity only
This is a database-level verification because the retired physical columns are intentionally not exposed in the UI.
Identity
No application sign-in is required for the SQL portion.
Prerequisites
Tests 02–04 must have passed.
Stop the backend before inspecting or mutating the local database.
Steps
From the repository root, run:
sqlite3 -header -column backend/data/app.db "
SELECT
gp.id AS global_person_id,
gp.email,
m.id AS membership_id,
m.tenant_id,
m.legacy_person_id
FROM global_people gp
JOIN person_tenant_memberships m
ON m.person_id = gp.id
WHERE lower(gp.email) = lower('[email protected]');
"
Record the returned global_person_id, membership_id, and tenant_id.
Then run:
sqlite3 -header -column backend/data/app.db "
SELECT
a.id AS account_id,
a.login,
a.actor_id AS legacy_account_actor_id,
ap.person_id AS canonical_person_id,
aa.actor_id AS canonical_actor_id,
aa.scope_type,
aa.tenant_id,
aa.membership_id,
aa.is_primary AS legacy_is_primary,
az.person_id AS legacy_actor_person_id,
az.collaborator_id AS legacy_actor_collaborator_id
FROM auth_user_accounts a
JOIN auth_account_people ap
ON ap.account_id = a.id
JOIN auth_account_actors aa
ON aa.account_id = a.id
JOIN authz_actors az
ON az.id = aa.actor_id
WHERE lower(a.login) = lower('[email protected]');
"
Then run:
sqlite3 -header -column backend/data/app.db "
SELECT
cj.id AS collaborator_journey_id,
cj.tenant_id,
cj.membership_id,
cj.person_id AS legacy_collaborator_person_id,
m.person_id AS canonical_person_id
FROM collaborator_journeys cj
JOIN person_tenant_memberships m
ON m.id = cj.membership_id
AND m.tenant_id = cj.tenant_id
JOIN global_people gp
ON gp.id = m.person_id
WHERE lower(gp.email) = lower('[email protected]')
ORDER BY cj.created_at DESC;
"
Finally run:
sqlite3 -header -column backend/data/app.db "
SELECT COUNT(*) AS legacy_people_rows
FROM people
WHERE lower(email) = lower('[email protected]');
"
Expected result
For the 30K3A Person:
- exactly one canonical Global Person is returned;
- the Tenant A Membership exists;
person_tenant_memberships.legacy_person_idisNULL;- the Authentication Account exists;
auth_user_accounts.actor_idisNULL;- an
auth_account_peoplePerson binding exists; - a TENANT
auth_account_actorsbinding exists; - its
membership_idmatches the Person's Tenant A Membership; auth_account_actors.is_primaryremains0;authz_actors.person_idisNULL;authz_actors.collaborator_idisNULL;- the Collaborator Journey uses the canonical
membership_id; collaborator_journeys.person_idisNULL;- the legacy
peopletable contains 0 rows for[email protected].
PASS
PASS only if every expected result is true.
Promotion blocker
Any newly populated retired identity field is a promotion blocker.
Test 06 — Verify the database rejects attempts to reintroduce legacy identity writes
This is intentionally SQL-based because 30K.3A's write-prohibition triggers are a database invariant.
Keep the backend stopped.
Run each command separately.
06A — Legacy Authentication Account actor_id
sqlite3 backend/data/app.db "
UPDATE auth_user_accounts
SET actor_id = (
SELECT aa.actor_id
FROM auth_account_actors aa
WHERE aa.account_id = auth_user_accounts.id
AND aa.scope_type = 'TENANT'
LIMIT 1
)
WHERE lower(login) = lower('[email protected]');
"
Expected error contains:
legacy_authentication_actor_write_prohibited
06B — Legacy AccountActor is_primary
sqlite3 backend/data/app.db "
UPDATE auth_account_actors
SET is_primary = 1
WHERE account_id = (
SELECT id
FROM auth_user_accounts
WHERE lower(login) = lower('[email protected]')
);
"
Expected error contains:
legacy_primary_actor_write_prohibited
06C — Legacy Actor person_id
sqlite3 backend/data/app.db "
UPDATE authz_actors
SET person_id = (
SELECT ap.person_id
FROM auth_account_people ap
JOIN auth_user_accounts a
ON a.id = ap.account_id
WHERE lower(a.login) = lower('[email protected]')
)
WHERE id = (
SELECT aa.actor_id
FROM auth_account_actors aa
JOIN auth_user_accounts a
ON a.id = aa.account_id
WHERE lower(a.login) = lower('[email protected]')
AND aa.scope_type = 'TENANT'
LIMIT 1
);
"
Expected error contains:
legacy_actor_identity_write_prohibited
06D — Legacy Membership legacy_person_id
sqlite3 backend/data/app.db "
UPDATE person_tenant_memberships
SET legacy_person_id = '30k3a-forbidden-legacy-person'
WHERE id = (
SELECT aa.membership_id
FROM auth_account_actors aa
JOIN auth_user_accounts a
ON a.id = aa.account_id
WHERE lower(a.login) = lower('[email protected]')
AND aa.scope_type = 'TENANT'
LIMIT 1
);
"
Expected error contains:
legacy_membership_person_write_prohibited
06E — Legacy Collaborator person_id
sqlite3 backend/data/app.db "
UPDATE collaborator_journeys
SET person_id = '30k3a-forbidden-legacy-person'
WHERE id = (
SELECT cj.id
FROM collaborator_journeys cj
JOIN person_tenant_memberships m
ON m.id = cj.membership_id
JOIN global_people gp
ON gp.id = m.person_id
WHERE lower(gp.email) = lower('[email protected]')
ORDER BY cj.created_at DESC
LIMIT 1
);
"
Expected error contains:
legacy_collaborator_person_write_prohibited
Final verification
Re-run all four read-only queries from Test 05.
Expected result
- Every prohibited update fails with the specified trigger error.
- None of the retired fields changes.
- The canonical rows remain intact.
PASS
PASS only if all five prohibited writes are rejected and the subsequent read-only verification is unchanged.
Promotion blocker
Block promotion if any prohibited write succeeds, if the wrong row is modified, or if canonical identity becomes inconsistent after a rejected write.
Final promotion decision
Promote Bite #30K.3A only if:
- Test 01 passes — Application Administrator remains global/control-plane only.
- Test 02 passes — a new Tenant A Person can be created through the UI.
- Test 03 passes — a Person-only Authentication Account can authenticate and use Person self-service.
- Test 04 passes — the same account gains current-Collaborator behavior from the canonical Journey/Membership relationship.
- Test 05 passes — all newly created identity uses canonical rows and every retired identity field remains empty.
- Test 06 passes — every attempted legacy identity write is rejected.
- No unexpected 400, 403, 500, JavaScript exception, tenant-switching anomaly, or cross-tenant authorization leak is observed.
If all items pass, manual promotion testing for Bite #30K.3A is complete.