Skip to main content

Core — Role and Responsibilities


Before Anything Else — Understand the Miqaat

You cannot understand what Core needs to do without first understanding what a Miqaat is, how it is structured, and why it is the spine of every digital system the community runs.

What a Miqaat Is

A Miqaat is a formally organized religious event conducted under the authority of the Dawoodi Bohra community. It is not a single gathering. It is a structured, multi-phase, multi-city operational event — involving tens of thousands of Mumineen, hundreds of Khidmat Guzaars, multiple physical venues, and a precise operational calendar.

Every Miqaat has a definite lifecycle: it is declared, planned, made live, run, and then closed. Between declaration and closure, every digital system in the platform serves that Miqaat. Registration is for a Miqaat. Passes are printed for a Miqaat. Attendance is taken at a Miqaat. HR quotas are set for a Miqaat. Venue capacity is calculated for a Miqaat.

The Miqaat is the spine of the entire digital platform. Everything hangs off it. Every module, every flow, every piece of data ultimately references a Miqaat.


The Structure of a Miqaat

A Miqaat does not have a single fixed hierarchy. The internal structure — whether it has cities, zones, venues, phases, or none of those — depends entirely on the type of Miqaat. Core models the structure as a configurable template, set up at the time the Miqaat is created. The platform does not assume a fixed shape.

The only universal truth is:

Safar
└── Miqaat
└── [Structural configuration — defined per Miqaat type at setup]

Safar is the campaign or travel identifier that groups one or more related Miqaat events. It is the cross-module reporting key. All modules use the canonical Safar code to correlate records across events.

Miqaat is the platform event record. It has a Hijri year, a type, a status (planning, live, closed), and a structural configuration specific to its type. The type determines what structural elements exist — not a universal schema.

Structural configuration varies by Miqaat type. Some examples:

Miqaat TypeStructural Shape
Ashara MubarakaAraz Cities (candidate) → Fasal City (host) + Relay Cities → Zones / Mohallas → Venues → Bethak / Vaaz sessions
IstefadahPhases → Kitab sessions → Groups → Venue assignments
Vajebaat BethakSingle Miqaat record → Bethak sessions → Attendance
Nikah / Aqeeqa / Rasm-e-SaifeeSingle event record → Ceremony slots → No city-level structure
Local BethakSingle venue → Sessions

What these structural elements mean — where they exist:

Araz City is a candidate city that submitted its readiness to host. This is specific to Miqaats where a host city selection process takes place (e.g., Ashara Mubaraka). Not all Miqaats have Araz cities.

Fasal City (Host City) is the officially declared city where the main proceedings occur, chosen from Araz candidates. Specific to multi-city Miqaats.

Relay City is a designated city for overflow accommodation and live relay. Specific to large-scale multi-city Miqaats.

Zones / Mohallas are geographic areas within a host city. Each zone has a set of local Mumineen (Muqimeen) belonging to that zone via their Jamaat. The zone drives capacity calculation: total venue capacity minus local resident count = available slots for arriving Mumineen (Mehmaaneen). Exists where a city-level structure is part of the Miqaat configuration.

Venue → Sub-venue is the physical setup. A primary venue hosts the Vaaz. Sub-venues handle overflow. Each has its own capacity figure, HVAC status, accessibility, Mawaid (meals) capacity, and kitchen support rating. Exists where venue configuration is part of the Miqaat structure.

Bethak / Vaaz Session is a specific gathering — a Vaaz, a Vajebaat Bethak, a Sharaf session — with its own eligibility rules, capacity limits, and attendance tracking. The shape of the session hierarchy varies by type (Istefadah uses Phase → Kitab, not the standard Bethak path).


The Miqaat Lifecycle

A Miqaat passes through distinct phases before, during, and after the event. These phases drive what is accessible, what is editable, and what is locked.

Phase 0 — Declaration The Miqaat record is created in Core via Platform Admin — its type, Hijri year, Safar assignment, and structural template are defined at this point. Core issues a miqaatId. This is now the platform's reference for this event. No modules are live yet. The structural configuration for this Miqaat type is established (e.g., for Ashara Mubaraka: Araz cities logged, Fasal not yet declared; for a Bethak: single venue configured immediately).

Phase 1 — Setup The Miqaat's structural configuration is fully populated. For multi-city Miqaats: host city confirmed, zones mapped, venues recorded. For session-based Miqaats: session schedule and eligibility rules configured. HR quotas established per department. Config Cascade is populated: global rules, Miqaat-level overrides, and any location or phase-level settings applicable to this Miqaat type.

Phase 2 — Registration and Allocation Registration opens. Eligibility checks run against the rules configured in Phase 1. Allocation engine begins assigning Bethaks, passes, and zones. Queue Fair activates during high-traffic windows. Modules consuming Core APIs go live one by one.

Phase 3 — Operations The Miqaat is live. Attendance is recorded at every session. Passes are scanned. Mawaid headcounts update. Procurement orders are in motion. HR attendance is tracked. The platform runs continuously at scale.

Phase 4 — Closure The Miqaat ends. Records are closed. Appraisals completed inside the respective modules. Audit logs sealed. HR Bank updated with khidmat history. Data archived. The platform awaits the next Miqaat declaration.


What This Means for the Platform

Thirty-two systems serve this lifecycle. All of them — Registration, VMS, BVMS, Istefaada, Misaaq, Rasm-e-Saifee, Vajebaat Bethak, Kiosk, Pass Engine, HR, Mawaid, Accommodation, Transport, Scanning, Broadcast, and the rest — are serving the same Miqaat.

The problem we had: each of those 32 systems independently answered the same questions.

  • Is this Mumin eligible? (each system had its own answer)
  • What is the capacity of this city? (each system had its own number)
  • Who has permission to approve this? (each system had its own role table)
  • What are the rules for this event? (each system had its own config)

When the same question has 32 different answers, the system is already broken before anyone reports a bug. That fragmentation is the architectural problem Core exists to solve.


The Platform Structure — Federation

The platform is built as a federation. Three parts, working together:

The Core is the shared infrastructure. It is built once and used by every module. It owns the decisions that cross module boundaries. It is small, stable, and slow to change on purpose. Everything that changes often lives in the modules, not in Core.

The Modules are the independent business units. Each module owns its own logic, its own data, its own screens, and its own release cycle. A module does not know what other modules exist. It does not call other modules directly. It does not share a database with anyone.

The Contracts are the agreements between them. "If you give me X, I give you Y." Versioned. Written before code starts. Never broken without notice.

This is the same structure as UPI (different banks, one contract, seamless payments), plumbing standards (any tap fits any pipe, change the tap without opening the wall), or a shopping mall (the mall provides parking, power, and lifts; each shop runs its own business; a new shop opens and the mall does not get rebuilt).

The Miqaat team benefits from this in a specific way: a new event module can plug into the platform without the Core team or any other module team rebuilding anything. The contracts hold. The events flow. The platform keeps running.


Core's Role — The Correct Definition

There is a common misconception to correct before going further.

Core is not a permission engine.

That is too narrow. Calling Core a permission engine is like calling a hospital an X-ray machine — it describes one function and ignores the whole.

Core is the centralized authority layer for the entire ITS ecosystem.

Its job: take everything that currently lives scattered across 32 systems — rules, eligibility logic, permissions, allocation state, notification delivery, configuration, event schemas, audit records — and assemble them into a single controlled environment. Defined once. Maintained by one team. Trusted by every module.

The Core rule: Whenever a module has to take a decision that reaches beyond its own boundary, that call comes to Core. Core evaluates it against centrally maintained rules. Core passes the answer back. The module — and only then — continues its own business process. No module can override this. No module can maintain its own conflicting version of a shared rule.

What Core is — in one sentence

Core is a Decision Layer. Not a data sync layer. Not a database. Core owns decisions.

Core never owns module data. A module's business records (indent lines, venue setup details, attendance sheets, pass assignments) live in the module's own database. Core only stores what it needs to answer cross-cutting questions: ITS identity data, RBAC role assignments, rule configurations, Miqaat config, allocation state, and audit records of every decision it made.

How Core gets the data it needs to make decisions

If Core does not own module data, how does it answer cross-cutting questions? Two paths only — and both are controlled, explicit, and contract-driven.

Path 1 — Direct sync from ITS

ITS52.org is the community's master record. It holds every Mumin's identity, Jamaat, sub-grade, family structure, and HOF relationship. Core has a direct, scheduled sync with ITS governed by the ITS ↔ Core Sync Contract (C-005). This is the only external data Core actively pulls into its own store.

From this sync, Core can answer: who is this Mumin, what is their sub-grade, which Jamaat do they belong to, which zone does that Jamaat fall in. These are the facts Core needs to evaluate eligibility, compute zone-to-resident mapping, and resolve RBAC hierarchy. Core reads from ITS. Core never writes back to ITS.

Path 2 — Events that modules publish to the bus

For anything that happens inside a module — a capacity figure is set, a khidmat assignment is made, a job completes — Core does not go and read the module's database. It cannot. It should not. That would violate module independence.

Instead, the module publishes an event to the event bus when something worth knowing happens. Core subscribes to the events it needs.

Module finalises venue capacity
→ publishes: capacity.configured { miqaatId, venue, capacity }
→ Core Capacity Balance Engine subscribes
→ Core checks balance, alerts if mismatched
→ Core does not store the capacity figure permanently
Module assigns a Mumin to khidmat
→ publishes: khidmat.assigned { itsId, miqaatId, department, role }
→ Core HR Bank subscribes
→ Core adds this to the Mumin's cross-event khidmat record
→ Module's own attendance and scheduling data stays in the module

Core receives only what modules choose to announce. Core never reads a module's internal database. Core never calls a module's private API. The moment a module publishes an event, it is making a deliberate declaration to the platform — and Core, like any other subscriber, can act on it.

What this means in practice

When a module calls Core and asks "is this Mumin eligible for Miqaat X?", Core does not go and fetch data in real time from 32 places. It already has what it needs:

  • Identity and sub-grade — from the ITS sync
  • Attendance history — from events published by scanning modules at past Miqaats
  • Learning record — from events published by Istefaada when a Kitab is completed
  • Eligibility rule for this Miqaat — from the Rule Engine, configured by the ops team

Core assembles the answer from its own store, which was built and kept current through these two paths. The decision is fast. The data is clean. The module gets a clear answer and moves on.


Core's Responsibilities — The Full Map

Core is responsible for all of the following. These are not separate tools — they are one integrated authority layer with multiple capabilities.

1. Miqaat Creation and Lifecycle Management

Core owns the authoritative Miqaat record as a platform operational entity. This is distinct from ITS's community and administrative record of a Safar. ITS knows that Ashara Mubaraka 1446H is happening as a community event. Core creates a platform record — with a miqaatId, a type, a lifecycle state, and a structural configuration — that all 32 modules and all 15 Core engines use as their shared reference.

When a new event is declared, it is created in Core via Platform Admin. The Miqaat ID issued by Core is the identifier every module uses. There is no parallel Miqaat record in any module. Modules reference Core's Miqaat — they do not manage their own version of it.

The structural configuration is defined by the Miqaat type — it is not fixed. When a Miqaat is created in Platform Admin, its type determines what structural elements are relevant: whether it has cities and zones, or phases and sessions, or simply a single venue. A Nikah Miqaat does not need an Araz city. An Istefadah does not need Relay cities. These structural choices are configuration, not schema.

Core manages:

  • Miqaat creation (type, Hijri year, Safar assignment, structural template selection)
  • Miqaat status transitions (declaration → setup → live → closed)
  • Structural configuration relevant to the Miqaat type (cities, zones, venues, phases, sessions — as applicable)
  • Zone registration and zone-to-resident mapping (where the Miqaat type includes zones)
  • Miqaat-level phase transitions and associated rule locking

When a Miqaat moves from planning to live, Core changes the status. Modules listen to the miqaat.status.changed event and activate their own flows accordingly. No module has the authority to change a Miqaat's status independently.

2. Hierarchical Configuration — Config Cascade

Every Miqaat has rules that apply at different levels of the hierarchy. Some rules apply globally (across all events). Some apply to one Miqaat. Some apply only to one city within a Miqaat. Some apply only to one zone.

Core's Config Cascade engine owns this hierarchy:

Global Config
└── Miqaat Config
└── City Config
└── Zone Config

A module never maintains its own event configuration. It reads the resolved config from Core for its context — and gets the most specific rule that applies. If a zone has no override, it falls back to city. City falls back to Miqaat. Miqaat falls back to global.

Examples of what Config Cascade governs: registration open/close dates, pass type availability by zone, Queue Fair bypass roles for this Miqaat, eligibility rule set active for this event, capacity limits by city.

3. Identity — ITS Bridge

Every person who interacts with the platform is a Mumin with an ITS identity (itsId). ITS52.org is the sole identity provider. No module issues its own login. No module maintains its own user table.

Core's Identity/ITS Bridge wraps ITS SSO. The API Gateway validates every incoming token. If the token is invalid or expired, the request never reaches a module. The itsId inside the validated token is the key that all Core engines and all modules use to refer to a person.

4. Authorisation — RBAC Engine

Core's RBAC (Role-Based Access Control) engine is the only permission store in the platform. No module maintains its own role table. Every permission check is an API call to Core RBAC.

The RBAC engine covers 40+ hierarchy levels — from Daai at the top through Shehzada Saheb, Saadaat Kiraam, Aamil, Masool, PMO roles, department heads, local Idara roles, and field operators. Permissions are defined by resource and action: { resource: "volunteer", action: "approve", context: miqaatId }.

When a module needs to check if a person can do something, it asks Core. It does not implement its own access control.

5. Eligibility — Eligibility Engine

For any regulated Miqaat event, not every Mumin is automatically eligible. Eligibility depends on composite conditions: sub-grade standing, attendance history at prior events, learning records (Kitab completion), prior Misaaq status, age, and custom rules configured per Miqaat.

Core's Eligibility Engine evaluates all of these conditions and returns a binary answer with a reason code: eligible or not, and why. The calling module acts on the answer. It does not implement eligibility itself — that would result in 32 different definitions of eligible.

The four data sources the Eligibility Engine draws from: ITS data (identity, sub-grade), prior Miqaat attendance records, Istefaada learning records (Kitab history), and the Rule Engine configuration for this specific Miqaat.

6. Rules — Rule Engine

The Rule Engine is Core's configurable brain. Business rules — eligibility conditions, filter criteria, allocation priorities, bypass conditions — are configured here as expressions, not hardcoded in SQL or application code.

When a rule changes (e.g., the eligibility condition for Ashara Mubaraka is updated for the coming year), it changes in one place: the Rule Engine. Every module that calls Core's eligibility API immediately gets the updated answer. No code deployment. No SQL migration. No team coordination required.

This is the engine that makes rules auditable, reversible, and non-technical to change.

7. Allocation — Allocation Engine

Allocating a seat, a Bethak slot, or a zone assignment requires shared state. If two modules could independently write to the same allocation pool, double-booking becomes inevitable.

Core's Allocation Engine holds the shared seat/slot state for every Miqaat. When a module needs to allocate something, it calls Core. Core checks available inventory, applies the configured priority rules, marks the slot as reserved, and returns the result. The allocation is the single source of truth. No module maintains parallel allocation state.

8. Communication — Event Bus

The event bus is how modules publish state changes to the rest of the platform. Registration confirms a Mumin? It publishes mumin.registration.confirmed. Pass Engine allocates a slot? It publishes pass.allocated. Attendance is taken? attendance.recorded.

Any module that cares about these events subscribes. The publisher does not know who is listening. If a new module joins the platform next year, it starts subscribing to existing events without any other team making changes.

Core owns the bus infrastructure and the event envelope schema that every event must conform to. Without a standard schema, the bus is unusable. The specific messaging technology (NATS JetStream, SQS, or alternatives) is under analysis and will be decided separately.

9. Audit — Audit Log

Every action across all modules that involves a cross-cutting decision produces an audit record. Who called Core, what decision was made, when, under which rule version. This log is immutable. It is the accountability layer for the entire platform — not just for one module.

10. Zone ↔ Resident Mapping

How many Mumineen belong to each zone? This number drives capacity calculation (available guest slots = total venue capacity minus locals), Raza quota per zone, pass allocation, and Istefaada grouping.

Core computes this from ITS data. Jamaat → HOF → Mumin records come in via the ITS sync. Core maps Mumineen to zones using the city's zone configuration. Modules query Core for this number — they do not maintain their own lists.

11. Capacity Balance

Before a Miqaat goes live, the platform checks that venue capacity (Vaaz), Mawaid capacity, and Kitchen capacity are broadly in sync. A venue that seats 8,000 paired with a kitchen supporting 3,000 is an operational failure waiting to happen.

Core subscribes to capacity.configured events published by each module as they set up their configurations. Core checks the ratios, and if they are significantly mismatched, it publishes a capacity.imbalance.detected alert visible in Platform Admin.

12. HR Bank — Platform Khidmat History

Khidmat history follows the person across events. The same Mumin performs khidmat in Ashara, in Istefaada, in a Bethak. Without a central record, that history is invisible. The AMS team surfaced this directly — "hidden talent" is a real operational problem.

Core's HR Bank maintains a cross-event khidmat history per itsId: which events, which department, which role, how long, any significant flag. This feeds the Eligibility Engine (past khidmat as an eligibility signal), the RBAC Engine (past role as a trust signal), and Platform Admin reports.

The one-primary-khidmat rule — a Mumin can hold only one primary role at a time across all events — can only be enforced from a central engine that sees all active assignments.

13. Vendor and Procurement Registry

Any event that sources goods and services — chairs, tents, generators, kitchen equipment, security uniforms — needs a vendor catalog. If AMS and a future event module independently negotiate with the same limited vendor with no shared visibility, coordination fails.

Core maintains the vendor registry (shared across all events) and standard item codes. Modules query Core before raising procurement actions. Core also provides a Budget Envelope Check API — has this Miqaat's procurement cap been exceeded? The approval decision itself stays in the module with the department head — Core has no opinion on whether any specific item should be purchased.

14. Task Engine — Platform Governance Layer

Cross-cutting platform tasks — things that span multiple teams and are tracked at the governance level — belong to Core's thin Task Engine. Examples: "C-001 ITS Token Contract must be signed off before Phase 0 closes." This is not a task for one module; it concerns all teams simultaneously.

Module-specific operational checklists (venue setup steps, construction task lists) stay inside each module. The distinction: if a task's failure would block multiple modules or a platform go-live decision, it is a Core task.

15. Platform Utilities

Core also provides pluggable capabilities — utilities that are not Core engines (they don't encode shared business rules) but are provided centrally to avoid every module rebuilding the same capability.

UtilityWhat it provides
Queue FairVirtual waiting room during high-traffic windows (registration opens, Ashara). Bypass roles configured via Config Cascade. Senior roles skip automatically.
File StoreShared document, photo, and certificate storage (AWS S3 / MinIO). Access-controlled per Miqaat.
WhatsApp Business APIOne delivery channel for the Notifications engine. Core wraps it.
Cropping AIAuto-crops individuals from group Sharaf photos. Highest-leverage AI candidate in the platform.
Design SystemShared UI component library. Same buttons, same fonts, same Lisan ud Daawat text handling. All modules use this — giving Mumineen one consistent feel across all apps.
Mobile Push ShellShared iOS/Android app shell. Modules deliver features into it rather than building separate apps.
PDF GenerationReport and letter generation utility.
Job Queue + WorkersCore engines run background jobs (allocation runs, notifications, AI photo processing, certificate printing) through Core's own queue. Core owns this entirely. Modules manage their own background jobs independently.

How a Miqaat Comes to Life Through Core

The sequence below uses Ashara Mubaraka as the example — a large multi-city Miqaat with Araz, Fasal, and Relay cities. The same Core mechanics apply to all Miqaat types; only the structural configuration differs.

Step 1 — Declaration. The Miqaat team creates the Miqaat record in Core via Platform Admin: event type (Ashara Mubaraka), Hijri year, Safar assignment, and structural template (multi-city with Araz/Fasal/Relay). Core issues a miqaatId. This is now the platform's reference for this event. A miqaat.created event is published to the bus.

Step 2 — City declaration. The Fasal is decided. Core updates the Miqaat record: one Araz City becomes the Host City (Fasal City). Relay cities are designated. A miqaat.fasal.declared event goes out. Modules that need to set up city-specific configurations begin. (For a session-based Miqaat type, this step is replaced by session schedule configuration — no city designation involved.)

Step 3 — Config setup. The Config Cascade is populated for this Miqaat: registration dates, eligibility rule version, pass types, zone capacity overrides, Queue Fair bypass roles, Mawaid ratio limits. This is all done in Core's admin layer — not in any module.

Step 4 — Zone and venue configuration. Zones are mapped for the host city. The zone-to-Jamaat mapping is resolved from ITS data — Core knows how many local Mumineen fall in each zone. Venue records are set up (in the venue module), and capacity figures flow into Core via capacity.configured events. Core checks balance.

Step 5 — HR quota setup. Department quotas are established for the Miqaat. Core's HR Bank is updated with the quota configuration. HR module teams in AMS and other systems draw from this.

Step 6 — Registration opens. The Miqaat status transitions to live in Core. The miqaat.status.changed event fires. Queue Fair activates. Registration module starts accepting Mumin requests. Each registration triggers a Core Eligibility check — Core evaluates the configured rules and returns eligible/not. The Allocation Engine begins assigning slots. Every confirmed registration produces a mumin.registration.confirmed event on the bus. Pass Engine listens and allocates a pass. Accommodation listens and reserves a room per quota. Mawaid listens and adjusts headcount. Notifications sends a confirmation. None of these modules called each other. They all read from the same notice board.


What Core Does NOT Own

It is as important to know what does not belong in Core as what does.

Core does not own anything that is specific to one module's business. The following stay in their respective modules:

  • The indent approval workflow in AMS (who approves, who rejects, at what level)
  • The specific task lists for venue construction and washroom setup
  • VMS volunteer assignment flows and scheduling
  • Istefaada Kitab session content and grading
  • Module-level reporting and document generation
  • HR appraisal details and khidmat performance narratives
  • Meeting records and minutes within a department

The test: if removing something from Core would break only one module, it does not belong in Core. If removing it would break multiple modules or produce inconsistent answers platform-wide, it belongs in Core.


The Core Team's Job

The Core team is small, senior, and opinionated. Their job is to be invisible most of the time.

When Core works well, module teams barely notice it exists. Eligibility checks return in milliseconds. Permissions are consistent. Events flow. Config changes propagate instantly. The platform feels like one coherent system even though 32 independent teams built it.

The Core team owns: the engines above, the contracts between all modules and Core, the design system, the API Gateway configuration, the event bus infrastructure, and the Platform Admin surface (the operational dashboard for platform-level health and governance).

The Core team does not build module features. They do not own module data. They do not manage module queues. Their focus is the stability and correctness of the shared decision layer. Core teams keep the platform stable. Module teams ship features fast. Both jobs matter, neither can do the other's.


The Three Questions — Core Engine Test

Before any capability is added to Core, it must pass three questions:

  1. Is it shared by more than one module? If only one module ever uses it, it belongs in that module.
  2. Does it encode a business rule or policy? If it is just a capability (fetch a file, crop a photo), it is a utility, not a Core engine.
  3. Would duplicating it cause incorrect decisions? If every module independently maintained this, would they produce different answers? If yes, it belongs in Core.

All three must be yes. One or two is not enough.


Summary — What Core Is

AspectThe answer
What Core isThe centralized decision and authority layer for the entire Miqaat platform
What Core ownsDecisions, rules, allocation state, identity, permissions, Miqaat configuration, events
What Core does NOT ownModule data, module business flows, module-specific rules
Who manages CoreOne small, senior Core team
How modules use CoreHTTP calls for decisions (synchronous), event bus for state changes (asynchronous)
The spine it servesThe Miqaat — every system, every record, every flow is anchored to a Miqaat that Core created as a platform entity. ITS owns the community record; Core owns the operational record.
What happens without Core32 systems each answer the same question differently — the fragmentation we already have today