Skip to main content

Business Modules and Platform Policies

Business modules are the 32 independent systems that make up the Miqaat platform — AMS, VMS, Nikah, RMS, Scanning, and others. This document defines the rules every business module must follow to operate on the platform, the process by which a module is formally admitted into the ecosystem, and a concrete example of how a business module hands off a Core concern to a Core engine rather than solving it independently.


What This Document Is For

The platform has 32 business modules today. Each has been built independently, with its own logic for authentication, permissions, data access, and communication with other systems. That independence is the source of the current problems — duplicate rules, disconnected data, no single picture of anything.

Bringing those 32 modules into a coherent platform requires three things:

  1. Policies — decisions made once, written down, and enforced across all modules. Without these, every team continues making its own version of the same decision.
  2. A standard admission process — every new or re-evaluated module answers the same set of questions before any build begins.
  3. A clear example — RBAC Federation shows in concrete terms what it looks like when a business module correctly hands off a Core concern to a Core engine.

Part 1 — Platform Policies

Policies are not code. They make code possible.

A policy is a decision that is made once, written down, and enforced across all teams. Without written policies, every team makes their own version of the same decision. That inconsistency is a large part of why the current platform has duplicate data, disconnected systems, and rules that only engineers can change.

PolicyWhat it decides and why it mattersWhat happens without itOwnerLevel
Authentication Policy — ITS is the only identity providerAll systems accept only ITS tokens. No system issues its own login. Modules cannot create parallel user systems. Token format, expiry, and validation method are defined once.Each module builds its own login → same user has multiple accounts → data cannot be unified.ITSPlatform
Authorisation Policy — Core RBAC is the only permission storeNo module maintains its own role table. Every permission check is a call to Core RBAC. Roles are defined in one hierarchy, not per-module. 40+ department depth supported.Each module has its own roles → same person has different permissions in different apps → ops team cannot manage access centrally.CorePlatform
Data Ownership Policy — Each module owns its own dataModules do not share databases. Module A does not read Module B's DB directly. Data is shared via Core APIs or events — never via DB joins across module boundaries.Shared DB = tight coupling → one team's schema change breaks another team's queries → impossible to deploy independently.CorePlatform
Business Rule Policy — Rules live in Core, not in SQLEligibility rules, filter criteria, and allocation logic are configured in Core's Rule Engine. No business rule is hardcoded in a stored procedure. Ops teams can change rules without engineers.SQL-as-policy → every rule change needs an engineer → slow, error-prone, and inconsistent across modules.CorePlatform
API Versioning Policy — Breaking change = major version bumpAll Core APIs are versioned. A change that removes a field or changes a behaviour is a breaking change and requires a new major version. Old version must be supported for a defined deprecation period.Unversioned API changes → modules break without warning → no team can confidently build on Core.CoreTechnical
Communication Policy — Module-to-module only via events or Core APIsModules never call each other's internal APIs directly. Cross-module communication happens either by publishing an event to the bus, or by calling a Core engine API. Direct module-to-module calls are prohibited.Direct module calls → tight coupling → one module going down cascades to others → deployment independence lost.CoreTechnical
Deployment Independence Policy — Modules deploy on their own clockCore cannot require all modules to deploy at the same time. Core APIs must remain backward-compatible within a version. A Core deployment cannot break existing module deployments.Coupled deployments → every release requires coordination across 32 teams → deployment becomes a months-long event.TeamsOperational
Idempotency Policy — Every operation that consumes an event must be idempotentEvents can be delivered more than once. Any system that processes events must handle duplicate delivery gracefully using the idempotencyKey in the event envelope.Non-idempotent consumers → duplicate events → duplicate registrations, double payments, corrupted state.ModuleTechnical
Queue Fair Bypass Policy — Senior roles skip the queueWhen Queue Fair is active (high-traffic windows), specific roles (Aamil, Sadat Kiram) bypass it automatically. This is configured in Config Cascade at the Bethak level, not hardcoded per module.No policy → senior staff stuck in queue during operational windows → field ops disrupted during peak events.CoreOperational

Part 2 — Defining a New Business Module

When a new system needs to be built — or when an existing system needs to be re-evaluated — it goes through a standard definition process. This process exists to ensure no system recreates what Core already provides, and no system skips the decisions that make it interoperable with the platform.

Every new module answers the same set of questions.

The Seven-Question System Definition Process

1 — Identity question: Who uses this system? All users authenticate via ITS. The system receives an itsId from the ITS token. The system never manages passwords, sessions, or user records itself. If a user type does not have an ITS account, that is a gap that must be raised with ITS — not solved by the module.

2 — Permission question: What can different roles do? Define roles and what they can do. Then ask: do these roles already exist in Core RBAC? If yes, use them. If no, propose new roles to the Core team. The system never maintains its own role table — it asks Core RBAC.

3 — Eligibility question: Who is eligible to use this system or attend this event? If eligibility depends on ITS data, prior attendance, learning records, or composite rules — this is a Core Eligibility engine call. The system defines which rules apply; it does not implement eligibility itself. If eligibility is simple and module-specific, it stays in the module.

4 — Data question: What data does this system own? Define clearly what data this module is the source of truth for. Define what data it reads from other systems (ITS, Core). Data it reads from others is never copied into its own database permanently — it queries when needed or subscribes to change events.

5 — Event question: What happens in this system that other systems care about? List every significant state change: registration submitted, payment completed, allocation confirmed, pass printed. Each becomes a domain event. Other modules subscribe to these events rather than polling for changes.

6 — Communication question: How does this system talk to others? Queries to Core engines: synchronous call to the Core API. Publishing state changes: event on the bus. Consuming others' state changes: subscribe to events. Direct calls to other modules' internal APIs: never. Define these interfaces before writing any code.

7 — Migration question: Is there an existing system that does this today? If yes: classify it (Contribute / Migrate / Rewrite). Define what changes the existing team needs to make and in which phase. If no: this is a greenfield build — Core compliance from day one, no migration debt.

The Output: System Definition Document

One page per system. Answers to all seven questions. Defines which Core engines it calls, which events it publishes, which events it subscribes to, and which migration type applies. This document is reviewed by the Core team before any implementation begins. It is the entry ticket into the Core ecosystem.


Part 3 — RBAC Federation: How a Business Module Delegates to a Core Engine

RBAC Federation is the clearest example of what the policies in Part 1 look like in practice. Every business module today maintains its own permission logic. RBAC Federation ends that — one Core engine handles permissions for all 32 modules. Each business module stops solving this problem independently and delegates it to Core.

The Problem — Four Failure Modes of Siloed Permissions

Today each of the 32 modules independently enforces its own permissions — its own role tables, its own permission checks, its own access logic.

  1. 32 places to get it wrong. Each module's permission logic drifts independently. A role change in one module has no effect in another. Access decisions diverge from intent.
  2. No platform-wide audit. There is no single answer to "what can itsId X do?" You must query 32 separate systems. Compliance reviews become operationally impossible.
  3. Cross-module role changes are coordination nightmares. Promoting a user to Miqaat Admin requires touching every module. Miss one, and they have inconsistent access across the platform.
  4. Every new module rebuilds RBAC from scratch. Months of duplicated work, with no consistency guarantee. Module 33 repeats what module 1 already solved.

The Model — What Each Business Module Does Instead

Each business module registers its resource types and permitted actions with Core once — at setup time. Core owns the role definitions and which roles get which actions on which resources. Every permission check at runtime is a call to Core, not a local table lookup.

Step 1 — Module registers its resources with Core (once, at setup)

VMS registers: { resource: "volunteer", actions: ["assign", "approve", "view", "revoke"] }
RMS registers: { resource: "raza", actions: ["issue", "supersede", "invalidate", "view"] }
Nikah registers: { resource: "nikah_application", actions: ["submit", "review", "approve"] }
AMS registers: { resource: "attendance", actions: ["record", "view", "export"] }
Scanning registers: { resource: "checkpoint", actions: ["scan", "override", "view_log"] }

Step 2 — Every permission check at runtime calls Core RBAC API

// replaces all local permission table lookups in every module
Core RBAC API
→ input: itsId + action + resource + miqaatId
→ output: allowed (bool) + role_matched + reason_code

// example: VMS checking whether user can approve a volunteer assignment
{ itsId: "ITS-1234567", action: "approve", resource: "volunteer", miqaatId: "MQ-1447-KHI" }
→ { allowed: true, role_matched: "VMS_Coordinator", reason: "role grants approve on volunteer" }

Ownership Split

Owned by CoreOwned by each Business Module
Role definitions (Miqaat Admin, City Admin, Zone Admin, Module Coordinator, Read-Only…)Resource type definition — what it manages and what actions are possible
Role-to-permission mappings (which role gets which action on which resource type)The API call to Core RBAC at every access boundary
Role-scope assignments (itsId → role → scope: global / miqaat / city / zone)UI rendering based on Core's allowed / denied response
RBAC evaluation engine — the runtime that answers allowed / deniedNothing else — no local permission tables, no local role checks
Role registry — all 32 modules register their resource types here
Audit record of every permission check and every role change

Migration Path — 32 Business Modules, Phased Adoption

Phase 1 — Core RBAC engine first Core RBAC engine goes live. Role definitions, registry API, and permission check API are stable and tested. Platform Admin can assign roles. No module is migrated yet — this phase hardens the engine under zero module load.

Phase 2 — New modules adopt natively Every module built after this point adopts Core RBAC from day one — no local permission tables. RMS (in active build) is the first. Nikah, Rasme Saifee, Dynamic Forms follow. These modules get RBAC for free — register resource types, call Core, done.

Phase 3 — High-risk existing modules Migrate existing modules by risk and operational volume first: VMS, AMS, Miqaat Scanning, Kiosk, Support Queries. These have the most impact on live miqaat operations — centralising their RBAC eliminates the highest-frequency access-control inconsistencies.

Phase 4 — Remaining modules All remaining modules migrate in order of operational dependency. Until migrated, a module may maintain its own RBAC in parallel — but Core is the authority. Where both checks are present, Core's response takes precedence.

Why the migration cost is worth paying: Once complete, a miqaat admin assigns a role once in Platform Admin — all 32 modules enforce it instantly. Super Admin can audit the full access picture for any itsId across the entire platform in one place. Any new module (33, 34…) gets RBAC for free — register resource types, inherit the existing role structure. Role structure changes (new admin tier, new hierarchy level) propagate platform-wide from one config change. The cost is per-module migration work. The benefit compounds with every module on the platform.


Part 4 — The Communication Problem We Are Solving

No team has event-driven architecture today. That is the problem we are solving.

Every integration today is manual — Excel exports, WhatsApp forwards, copy-paste between systems. Automating that with webhooks and point-to-point polling only makes the dirty sync faster, not cleaner. It recreates the dependency graph that already exists. One team goes down, others fail. No replay, no ordering guarantees.

Database-level sync — shared databases, direct reads across module boundaries — destroys deployment independence. Schema changes in one module break all others. This is explicitly prohibited under the Data Ownership Policy.

The platform's goal is to give every business module — regardless of its current state — a path to proper, decoupled communication. Not all at once. In phases. The policies in Part 1 set the rules. The system definition process in Part 2 makes those rules concrete per module. The detailed technical approach for the event bus is under analysis and will be documented separately.


Part 5 — Existing Business Module Audit

The 32 existing business modules are not starting from zero — they have established codebases, data models, and workflows. For modules like AMS and VMS, adoption of Core is not a greenfield decision; it is a migration.

Before any existing module is brought into the Core ecosystem, the following must be completed:

Audit of what exists: document the current architecture, data model, permission logic, and inter-system dependencies of the module as it stands today.

Gap analysis — what needs to change: map the current module against the seven-question System Definition process. Identify what must change to comply with platform policies (authentication, authorisation, data ownership, communication).

Adaptation plan: define the migration type (Contribute / Migrate / Rewrite), the phased sequence of changes, and the change management required for the teams operating the module.

Note on technical discovery: The detailed technical discovery sessions with the ITS team for existing module integration are still pending. Until those sessions are completed, the adaptation plans for AMS, VMS, and other high-dependency modules cannot be finalised. This is on the critical path for Phase 3 of the RBAC migration and for any module-level integration work.