In a single-team app, access control is a formality. The moment many teams and partners publish into one app, it's the load-bearing wall of the whole system. Here's the governance architecture — with code.
Here's how open platforms actually fail: not a dramatic breach, but slow drift. A permission granted once and never revoked. Direct-to-prod access that made sense at 3 developers and persists at 30. An approval step skipped, then removed, then forgotten. Each locally reasonable; together, a platform no one can safely reason about. Let's build the governance that prevents it.
Why the monolith's approach doesn't transfer
Single-team app:
everyone with deploy access is a trusted, known colleague
→ informal trust scales fine, access control is a backstop
Open platform:
many teams + business units + EXTERNAL partners publish into your app
→ informal trust breaks; formal governance is the only thing holding
→ "who can do what" becomes the load-bearing wall
Everything below assumes the platform case.
Pillar 1: capability follows role (granular RBAC)
Don't grant access to individuals ad hoc — that produces an unauditable sprawl. Define roles; individuals inherit capability by role. And make it granular — not "access to the platform" but access to specific capabilities, data, and actions:
roles:
developer:
can: [create_miniapp, edit_own_miniapp, submit_for_review, deploy_to_sandbox]
cannot: [approve_own, deploy_to_production, modify_permissions]
reviewer:
can: [review_submission, approve, reject, request_changes]
cannot: [deploy, edit_miniapp_code] # approve, but don't ship
operator:
can: [deploy_to_production, rollback, configure_rollout]
cannot: [edit_code, approve_own_deploys]
partner_developer: # external — most constrained
can: [create_miniapp, deploy_to_sandbox, submit_for_review]
scope: own_tenant_only
capability_ceiling: [user:readProfile] # can't even request more
admin:
can: [manage_roles, configure_governance, view_all_audit]
cannot: [delete_audit_logs] # nobody can — immutable
Granularity at the level of APIs, menus, and individual capabilities is the difference between a legible permission surface and a sprawl.
Pillar 2: separation of duties, enforced structurally
The person who builds isn't the person who approves isn't the person who deploys. Enforced by the system, not by policy:
// Structural enforcement — not "please don't approve your own work"
async function approve(submission, approver) {
if (submission.author === approver.id) {
throw new SeparationOfDutiesError(
"author cannot approve own submission" // the SYSTEM refuses
);
}
if (!approver.hasRole("reviewer")) {
throw new PermissionError("approval requires reviewer role");
}
await audit.record({
action: "approve",
submission: submission.id,
approver: approver.id, // approval logged against identity
timestamp: Date.now()
});
return submission.markApproved(approver.id);
}
The production path — three identities, no shortcuts:
developer submits → reviewer approves → operator deploys
no single actor reaches production alone
This one principle catches honest mistakes and dishonest intent through the same mechanism.
Pillar 3: immutable, complete audit
Every consequential action logged against an identity, unalterable, exportable:
audit:
logged_actions:
- miniapp_published
- version_updated
- permission_changed # especially this
- submission_approved
- deployed_to_production
- rolled_back
- role_assigned
record: [actor_identity, action, target, before_state, after_state, timestamp]
immutability: append_only # cannot edit or delete, even as admin
export: compliance_ready
// Permission changes are the highest-value audit target —
// this is where drift hides
audit.onPermissionChange((change) => {
log.record({
who: change.actor,
granted_to: change.subject,
capability: change.capability,
from: change.oldValue,
to: change.newValue,
justification: change.reason, // require a reason for the grant
expires: change.expiry // grants CAN expire — fights drift
});
});
The audit trail isn't surveillance — it's what lets you extend autonomy. You can safely let many people do many things precisely because you can always reconstruct what was done.
Fighting drift structurally
Since drift is the real failure mode, build in the counters:
anti_drift:
permission_expiry: true # temporary grants auto-expire
periodic_review:
cadence: quarterly
surfaces: [unused_permissions, direct_prod_access, stale_partner_grants]
least_privilege_default: true # new roles start with minimum
revoke_on_role_change: true # leaving a team drops the team's caps
zero_usage_flagging: true # permissions never exercised → flagged for removal
permission_expiry alone eliminates the single most common drift source: the grant that outlived its reason.
The reframe: governance sets the openness ceiling
Weak governance → safe only for a small trusted circle → never an ecosystem
Strong governance → safe for hundreds, including partners → can actually scale
Governance isn't the tax on openness. It's the enabler of it.
Your "who can do what" system sets the ceiling on how many
contributors you can safely say yes to.
This is why FinClip builds RBAC into its management platform at the level of APIs, menus, and individual capabilities, with strict separation of development/release/operations roles (DevSecOps-aligned), approval workflows gating production, and complete exportable audit — the governance that lets 40+ securities firms and banks open mini-app ecosystems to many contributors while always knowing who can do what, and who did.
The test
- Is access granted by role (auditable) or per-individual ad hoc (sprawl)?
- Can the author of a change approve their own change? (They must not be able to.)
- Are build, approve, and deploy three separate identities?
- Is every permission change logged immutably against an identity — with a reason?
- Do temporary grants expire, or accumulate forever? (Drift lives here.)
If someone can approve their own deploy and permissions never expire, your platform is governed by trust and habit — which caps it at the size a few trusted people can watch. Which pillar is missing? 👇
More on platform governance, RBAC architecture, and access control for open ecosystems → https://super-apps.ai/

Top comments (0)