mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-27 01:32:15 +00:00
feat: add administrator repository (#11803)
Introduces the `administrators` relational table and repository layer for the v3 backend, unifying instance, organization, project, and project-grant membership into a single scoped model. Closes #10220 ## Changes - **Domain**: `Administrator` struct, `AdministratorScope` enum, `AdministratorRepository` interface with typed CRUD, column, condition, and change helpers. Generated enumer and GoMock. - **Migration** (`016`): `zitadel.administrators` table with a generated `id`, scope-alignment check constraint, cascading foreign keys, and a child `administrator_roles` table. - **Repository**: CTE-based role mutations (`AddRole`, `RemoveRole`, `SetRoles`) for atomicity. Roles aggregated via `ARRAY_AGG`. - **Projection**: Event reducers for `member.added/changed/removed/cascade_removed` across all four admin scopes. - **Fixes**: `Rows.Close()` error wrapping; `TextArray` nil-safe scan + full `pgtype` array interface; `authorization` and `projectGrant` scan helpers fixed for `ARRAY_AGG` under `database/sql`; removed unused `ctx` parameter from `callReduce`. --------- Co-authored-by: Marco Ardizzone <[email protected]>
This commit is contained in:
co-authored by
Marco Ardizzone
parent
6d90a120a6
commit
f138082b64
@@ -0,0 +1,16 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed 016_administrators_table/up.sql
|
||||
up016AdministratorsTable string
|
||||
//go:embed 016_administrators_table/down.sql
|
||||
down016AdministratorsTable string
|
||||
)
|
||||
|
||||
func init() {
|
||||
registerSQLMigration(16, up016AdministratorsTable, down016AdministratorsTable)
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
DROP TABLE IF EXISTS zitadel.administrator_roles;
|
||||
DROP TABLE IF EXISTS zitadel.administrators;
|
||||
DROP TYPE IF EXISTS zitadel.administrator_scope;
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
CREATE TYPE zitadel.administrator_scope AS ENUM (
|
||||
'instance',
|
||||
'organization',
|
||||
'project',
|
||||
'project_grant'
|
||||
);
|
||||
|
||||
CREATE TABLE zitadel.administrators(
|
||||
instance_id TEXT NOT NULL
|
||||
, user_id TEXT NOT NULL
|
||||
, scope zitadel.administrator_scope NOT NULL
|
||||
|
||||
, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
|
||||
, organization_id TEXT
|
||||
, project_id TEXT
|
||||
, project_grant_id TEXT
|
||||
|
||||
, id TEXT GENERATED ALWAYS AS (
|
||||
user_id || ':' ||
|
||||
CASE scope
|
||||
WHEN 'instance'::zitadel.administrator_scope
|
||||
THEN 'instance:' || instance_id
|
||||
WHEN 'organization'::zitadel.administrator_scope
|
||||
THEN 'organization:' || organization_id
|
||||
WHEN 'project'::zitadel.administrator_scope
|
||||
THEN 'project:' || project_id
|
||||
WHEN 'project_grant'::zitadel.administrator_scope
|
||||
THEN 'project_grant:' || project_grant_id
|
||||
END
|
||||
) STORED
|
||||
|
||||
, CONSTRAINT administrators_scope_alignment_chk CHECK (
|
||||
(scope = 'instance'
|
||||
AND organization_id IS NULL
|
||||
AND project_id IS NULL
|
||||
AND project_grant_id IS NULL)
|
||||
OR
|
||||
(scope = 'organization'
|
||||
AND organization_id IS NOT NULL
|
||||
AND project_id IS NULL
|
||||
AND project_grant_id IS NULL)
|
||||
OR
|
||||
(scope = 'project'
|
||||
AND organization_id IS NULL
|
||||
AND project_id IS NOT NULL
|
||||
AND project_grant_id IS NULL)
|
||||
OR
|
||||
(scope = 'project_grant'
|
||||
AND organization_id IS NULL
|
||||
AND project_id IS NULL
|
||||
AND project_grant_id IS NOT NULL)
|
||||
)
|
||||
|
||||
, PRIMARY KEY (instance_id, id)
|
||||
, FOREIGN KEY (instance_id) REFERENCES zitadel.instances(id) ON DELETE CASCADE
|
||||
, FOREIGN KEY (instance_id, user_id) REFERENCES zitadel.users(instance_id, id) ON DELETE CASCADE
|
||||
, FOREIGN KEY (instance_id, organization_id) REFERENCES zitadel.organizations(instance_id, id) ON DELETE CASCADE
|
||||
, FOREIGN KEY (instance_id, project_id) REFERENCES zitadel.projects(instance_id, id) ON DELETE CASCADE
|
||||
, FOREIGN KEY (instance_id, project_grant_id) REFERENCES zitadel.project_grants(instance_id, id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE zitadel.administrator_roles(
|
||||
instance_id TEXT NOT NULL
|
||||
, administrator_id TEXT NOT NULL
|
||||
, role_name TEXT NOT NULL CHECK (role_name <> '')
|
||||
|
||||
, PRIMARY KEY (instance_id, administrator_id, role_name)
|
||||
, FOREIGN KEY (instance_id, administrator_id) REFERENCES zitadel.administrators(instance_id, id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TRIGGER trigger_set_updated_at
|
||||
BEFORE UPDATE
|
||||
ON zitadel.administrators
|
||||
FOR EACH ROW
|
||||
WHEN (NEW.updated_at IS NULL)
|
||||
EXECUTE FUNCTION zitadel.set_updated_at();
|
||||
Reference in New Issue
Block a user