Skip to main content

Core Modules and Policies

This document covers three things: how individual business modules connect to and operate within the Core platform, the platform policies that govern all of them, and the process for defining any new module. It does not cover technical architecture, contracts, or infrastructure — those are addressed in separate files.


What This Document Is For

Thirty-two modules currently operate as isolated systems. Each has its own logic for authentication, permissions, data access, and inter-system communication. That isolation is the problem. This document explains:

  1. How a module integrates with Core — using RBAC Federation as the worked example
  2. What platform policies every module must comply with, and why
  3. How every new (or re-evaluated) module is formally defined before any build begins
  4. Why the current state of cross-module communication is a problem that the platform must solve

Part 1 — RBAC Federation: The Reference Module

RBAC Federation is the first module built inside Core that every other module connects to. It is documented here in full because it illustrates the pattern: Core owns the rule, every module is a consumer.

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 Core RBAC Federation Model

Core becomes the single permission authority. Each 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 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 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 2 — Platform Policies

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.

Policies are not code. They make code possible.

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 3 — Defining a New System

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 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 system — regardless of its current state — a path to proper, decoupled communication. Not all at once. In phases. The policies in Part 2 set the rules. The system definition process in Part 3 makes those rules concrete per module. The event bus is the long-term infrastructure goal; the detailed technical approach is under analysis and will be documented separately.


Part 5 — Existing Module Audit

The 32 existing 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.