MongoDB Migration: Enterprise Identity Group Sync and Universal ReBAC
Required or No-Op
Database changes are required. This feature introduces new MongoDB collections and indexes for identity group sync, relationship provenance, policy change sets, Slack channel multi-resource grants, enforcement status, and drift findings.
No destructive migration is planned. Collections can be created lazily by the application, but production rollout should create indexes before enabling scheduled sync.
New Collections
identity_providers
Stores non-secret provider metadata and health state.
Indexes
- Unique:
{ id: 1 } - Query:
{ type: 1, status: 1 }
identity_group_sync_rules
Stores ordered regex mapping clusters.
Indexes
- Unique:
{ id: 1 } - Query:
{ provider_id: 1, enabled: 1, priority: 1 } - Query:
{ provider_id: 1, review_status: 1 }
external_groups
Stores discovered upstream group metadata.
Indexes
- Unique:
{ provider_id: 1, external_group_id: 1 } - Query:
{ provider_id: 1, normalized_name: 1 } - Query:
{ provider_id: 1, status: 1, last_seen_at: -1 }
external_group_team_links
Links external groups to CAIPE teams.
Indexes
- Unique:
{ provider_id: 1, external_group_id: 1, sync_rule_id: 1, relationship_role: 1 } - Query:
{ team_id: 1, status: 1 } - Query:
{ sync_rule_id: 1, status: 1 }
team_membership_sources
Tracks why a user has a team relationship.
Indexes
- Query:
{ team_id: 1, user_subject: 1, relationship: 1, status: 1 } - Query:
{ source_type: 1, provider_id: 1, external_group_id: 1, status: 1 } - Query:
{ sync_rule_id: 1, status: 1, last_seen_at: -1 } - Query:
{ user_subject: 1, status: 1 }
rebac_resources
Stores canonical resource metadata for graph and authoring views.
Indexes
- Unique:
{ resource_type: 1, resource_id: 1 } - Query:
{ resource_type: 1, status: 1 } - Query:
{ enforcement_status: 1, resource_type: 1 }
rebac_relationship_sources
Stores relationship provenance and status for tuples written to OpenFGA.
Indexes
- Query:
{ "resource.type": 1, "resource.id": 1, status: 1 } - Query:
{ "subject.type": 1, "subject.id": 1, status: 1 } - Query:
{ source_type: 1, source_id: 1, status: 1 } - Query:
{ status: 1, created_at: -1 }
policy_rules
Stores reusable relationship-generation rules.
Indexes
- Unique:
{ id: 1 } - Query:
{ scope: 1, status: 1 } - Query:
{ rule_type: 1, status: 1 }
policy_change_sets
Stores staged relationship grants/revocations and validation state.
Indexes
- Unique:
{ id: 1 } - Query:
{ status: 1, created_at: -1 } - Query:
{ created_by: 1, status: 1 }
slack_channel_grants
Stores Slack channel to resource grants for authoring and provenance.
Indexes
- Unique:
{ slack_workspace_id: 1, slack_channel_id: 1, resource_type: 1, resource_id: 1, relationship: 1 } - Query:
{ slack_workspace_id: 1, slack_channel_id: 1, status: 1 } - Query:
{ resource_type: 1, resource_id: 1, status: 1 }
identity_group_sync_runs
Stores dry-run and applied sync run summaries.
Indexes
- Unique:
{ id: 1 } - Query:
{ provider_id: 1, mode: 1, status: 1, started_at: -1 } - Query:
{ status: 1, started_at: -1 }
rbac_drift_findings
Stores reconciliation and enforcement drift findings.
Indexes
- Query:
{ status: 1, severity: 1, detected_at: -1 } - Query:
{ finding_type: 1, status: 1 } - Query:
{ "resource.type": 1, "resource.id": 1, status: 1 }
Existing Collection Updates
teams
Add optional fields:
sourcestatusowner_idexternal_group_linkscreated_byupdated_by
Indexes
- Ensure unique team slug index exists.
- Add query index
{ status: 1, source: 1 }.
Existing Slack channel mapping data
If the current stack stores one agent per channel, backfill equivalent slack_channel_grants records:
- Channel to existing agent as
allowed_agent. - Preserve original mapping source as
migration. - Do not infer tool or knowledge base access.
Data Movement
Backfill Team Membership Sources
For existing team membership records:
- Create
team_membership_sourcesrecords withsource_type: "migration". - Mark
managed: false. - Write active ReBAC team membership tuples if missing.
- Record skipped users whose Keycloak subject cannot be resolved.
Backfill Team Resource Relationships
For existing team resource assignments:
- Create
rebac_relationship_sourcesrecords withsource_type: "migration". - Write matching OpenFGA tuples for agents, tools, and knowledge bases.
- Keep existing Keycloak resource roles until the relevant runtime surface is
rebac_enforced.
Backfill Slack Channel Grants
For existing channel-agent mappings:
- Create
rebac_resourcesfor Slack workspaces/channels. - Create
slack_channel_grantsfor the mapped agent. - Write OpenFGA channel-resource relationships.
- Mark enforcement as
rebac_shadoweduntil Slack runtime checks are enabled.
Rollback
Rollback should be non-destructive:
- Disable scheduled identity group sync.
- Disable ReBAC-enforced runtime flags and return affected surfaces to
rebac_shadowedor role-gated mode. - Stop writing new tuples from sync runs.
- Preserve new MongoDB collections for audit unless a backup/restore plan is explicitly approved.
- If required, delete only tuples whose source is the rolled-back change set or sync run.
Environments
- Development: Collections and indexes can be created on application startup or by a local migration script.
- Staging: Create indexes, run migration backfills, verify graph/access checker, then enable scheduled sync in dry-run mode.
- Production: Take a MongoDB backup, create indexes, run idempotent backfills in batches, run drift detection, enable dry-run scheduled sync, then promote runtime surfaces to ReBAC enforcement incrementally.
OpenFGA Migration Dependency
The OpenFGA authorization model must support the target resource types and relations before backfills write new tuple types. Model rollout should precede tuple writers in each environment.
Keycloak Transition Dependency
Keycloak resource roles remain during migration. New implementation should avoid creating permanent per-resource roles for every resource and should move resource authorization to OpenFGA as surfaces become rebac_enforced.