20260801_420_unified_responsibilities.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. """Add hierarchical, delegated and policy-driven governance responsibility."""
  2. from alembic import op
  3. revision = "20260801_420"
  4. down_revision = "20260731_410"
  5. branch_labels = None
  6. depends_on = None
  7. def upgrade() -> None:
  8. op.execute(
  9. """
  10. ALTER TABLE public.governance_responsibility_scopes
  11. DROP CONSTRAINT IF EXISTS
  12. governance_responsibility_scopes_resource_type_check;
  13. ALTER TABLE public.governance_responsibility_scopes
  14. ADD CONSTRAINT
  15. governance_responsibility_scopes_resource_type_check
  16. CHECK (
  17. resource_type IN (
  18. 'business_domain','device_asset','device_ontology',
  19. 'device_mapping','device_quality','fault_classification',
  20. 'quality_issue','organization','data_asset','semantic_term',
  21. 'data_standard','quality_policy','data_product','agent'
  22. )
  23. ) NOT VALID;
  24. ALTER TABLE public.governance_responsibility_scopes
  25. VALIDATE CONSTRAINT
  26. governance_responsibility_scopes_resource_type_check;
  27. ALTER TABLE public.governance_responsibility_assignments
  28. DROP CONSTRAINT IF EXISTS
  29. governance_responsibility_assignments_responsibility_role_check;
  30. ALTER TABLE public.governance_responsibility_assignments
  31. ADD CONSTRAINT
  32. governance_responsibility_assignments_responsibility_role_check
  33. CHECK (
  34. responsibility_role IN (
  35. 'organization_owner','domain_owner','data_steward',
  36. 'data_architect','asset_manager','term_steward',
  37. 'standard_owner','quality_owner','product_owner','agent_owner'
  38. )
  39. ) NOT VALID;
  40. ALTER TABLE public.governance_responsibility_assignments
  41. VALIDATE CONSTRAINT
  42. governance_responsibility_assignments_responsibility_role_check;
  43. CREATE TABLE public.governance_responsibility_hierarchy (
  44. uid UUID PRIMARY KEY,
  45. resource_type VARCHAR(40) NOT NULL,
  46. resource_uid VARCHAR(120) NOT NULL,
  47. parent_type VARCHAR(40) NOT NULL,
  48. parent_uid VARCHAR(120) NOT NULL,
  49. revision INTEGER NOT NULL DEFAULT 1 CHECK (revision > 0),
  50. updated_by UUID NOT NULL REFERENCES public.users(id),
  51. created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  52. updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  53. UNIQUE (resource_type, resource_uid),
  54. CHECK (
  55. resource_type IN (
  56. 'organization','business_domain','data_asset','semantic_term',
  57. 'data_standard','quality_policy','data_product','agent'
  58. )
  59. ),
  60. CHECK (
  61. parent_type IN (
  62. 'organization','business_domain','data_asset','semantic_term',
  63. 'data_standard','quality_policy','data_product','agent'
  64. )
  65. ),
  66. CHECK (
  67. resource_type <> parent_type OR resource_uid <> parent_uid
  68. )
  69. );
  70. CREATE INDEX idx_governance_responsibility_hierarchy_parent
  71. ON public.governance_responsibility_hierarchy(
  72. parent_type, parent_uid
  73. );
  74. CREATE TABLE public.governance_responsibility_delegations (
  75. uid UUID PRIMARY KEY,
  76. source_user_uid UUID NOT NULL REFERENCES public.users(id),
  77. delegate_user_uid UUID NOT NULL REFERENCES public.users(id),
  78. scope_type VARCHAR(40),
  79. scope_uid VARCHAR(120),
  80. responsibility_role VARCHAR(40),
  81. delegation_type VARCHAR(30) NOT NULL CHECK (
  82. delegation_type IN ('temporary','departure_transfer')
  83. ),
  84. starts_at TIMESTAMPTZ NOT NULL,
  85. ends_at TIMESTAMPTZ,
  86. reason VARCHAR(500) NOT NULL,
  87. status VARCHAR(20) NOT NULL CHECK (
  88. status IN ('active','revoked','expired')
  89. ),
  90. current_version INTEGER NOT NULL DEFAULT 1 CHECK (
  91. current_version > 0
  92. ),
  93. created_by UUID NOT NULL REFERENCES public.users(id),
  94. updated_by UUID NOT NULL REFERENCES public.users(id),
  95. created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  96. updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  97. CHECK (source_user_uid <> delegate_user_uid),
  98. CHECK ((scope_type IS NULL) = (scope_uid IS NULL)),
  99. CHECK (
  100. scope_type IS NULL OR scope_type IN (
  101. 'organization','business_domain','data_asset','semantic_term',
  102. 'data_standard','quality_policy','data_product','agent'
  103. )
  104. ),
  105. CHECK (
  106. responsibility_role IS NULL OR responsibility_role IN (
  107. 'organization_owner','domain_owner','data_steward',
  108. 'data_architect','asset_manager','term_steward',
  109. 'standard_owner','quality_owner','product_owner','agent_owner'
  110. )
  111. ),
  112. CHECK (
  113. (delegation_type = 'temporary' AND ends_at > starts_at)
  114. OR
  115. (delegation_type = 'departure_transfer' AND ends_at IS NULL)
  116. )
  117. );
  118. CREATE UNIQUE INDEX uq_governance_responsibility_active_delegation
  119. ON public.governance_responsibility_delegations(
  120. source_user_uid,
  121. COALESCE(scope_type, ''), COALESCE(scope_uid, ''),
  122. COALESCE(responsibility_role, '')
  123. ) WHERE status = 'active';
  124. CREATE INDEX idx_governance_responsibility_delegate
  125. ON public.governance_responsibility_delegations(
  126. delegate_user_uid, status, ends_at
  127. );
  128. CREATE TABLE public.governance_responsibility_policies (
  129. uid UUID PRIMARY KEY,
  130. code VARCHAR(120) NOT NULL UNIQUE,
  131. name VARCHAR(300) NOT NULL,
  132. policy_type VARCHAR(30) NOT NULL CHECK (
  133. policy_type IN ('central_policy','joint_review')
  134. ),
  135. scope_type VARCHAR(40) NOT NULL CHECK (
  136. scope_type IN (
  137. 'organization','business_domain','data_asset','semantic_term',
  138. 'data_standard','quality_policy','data_product','agent'
  139. )
  140. ),
  141. scope_uid VARCHAR(120) NOT NULL,
  142. status VARCHAR(20) NOT NULL CHECK (
  143. status IN ('draft','published','retired')
  144. ),
  145. current_version INTEGER NOT NULL DEFAULT 1 CHECK (
  146. current_version > 0
  147. ),
  148. active_version_uid UUID,
  149. created_by UUID NOT NULL REFERENCES public.users(id),
  150. created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  151. updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
  152. );
  153. CREATE TABLE public.governance_responsibility_policy_versions (
  154. uid UUID PRIMARY KEY,
  155. policy_uid UUID NOT NULL
  156. REFERENCES public.governance_responsibility_policies(uid),
  157. version INTEGER NOT NULL CHECK (version > 0),
  158. status VARCHAR(20) NOT NULL CHECK (
  159. status IN ('draft','published','superseded')
  160. ),
  161. definition JSONB NOT NULL,
  162. created_by UUID NOT NULL REFERENCES public.users(id),
  163. created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
  164. published_by UUID REFERENCES public.users(id),
  165. published_at TIMESTAMPTZ,
  166. UNIQUE (policy_uid, version),
  167. CHECK (jsonb_typeof(definition) = 'object')
  168. );
  169. ALTER TABLE public.governance_responsibility_policies
  170. ADD CONSTRAINT governance_responsibility_active_version_fk
  171. FOREIGN KEY (active_version_uid)
  172. REFERENCES public.governance_responsibility_policy_versions(uid);
  173. CREATE UNIQUE INDEX uq_governance_responsibility_published_version
  174. ON public.governance_responsibility_policy_versions(policy_uid)
  175. WHERE status = 'published';
  176. CREATE INDEX idx_governance_responsibility_policy_scope
  177. ON public.governance_responsibility_policies(
  178. scope_type, scope_uid, status
  179. );
  180. """
  181. )
  182. def downgrade() -> None:
  183. raise RuntimeError(
  184. "responsibility delegation and policy evidence is retained; "
  185. "downgrade requires an approved archival migration"
  186. )