Skip to main content

TD4 — Module Build Guidance

Decision Status Labels ✅ Decided — confirmed in a stakeholder session. Can be built against. 🔍 Under Analysis — options identified. Do not build against yet. 📅 Pending Session — requires a specific session or external input before a decision can be made.


1. The Core Value Exchange

Before detailing what modules must do, it is worth stating what they get in return. Core compliance is not just a constraint — it is a trade. A module that integrates correctly with Core stops carrying problems it should never have owned in the first place.

✅ What modules stop building

ProblemWhat modules built before CoreWhat happens after Core
AuthenticationEach module managed its own session and user recordsITS handles login. Module receives a verified itsId from the Identity Bridge. No user records in the module.
PermissionsEach module maintained its own role tables, permission checks, and access logicModule registers resource types once. Every permission check is one API call to Core RBAC. No permission tables in the module.
EligibilityEach module implemented its own eligibility rules in code or SQLModule calls Core Eligibility Engine with the rule set to apply. No eligibility logic in the module.
ITS data syncEach module maintained its own copy of ITS master data, its own sync processModule queries Core for ITS-derived data. No ITS sync in the module. Core's single sync replaces all of them.
Business rules in SQLRules hardcoded in stored procedures, only engineers can change themRules configured in Core's Rule Engine. Ops teams change them without engineers. No rule logic in module code.
NotificationsEach module built its own notification sending (WhatsApp, SMS, email)Module triggers Core's Notification Dispatch Engine. No delivery logic in the module.
Cross-module dataModules called each other directly or shared databasesModules publish events and subscribe to others'. No direct inter-module calls. No shared databases.

✅ What Core provides in return

Every module gets the following from Core without building it:

  • A verified user identity (itsId) on every request
  • Platform-wide RBAC — one permission check call covers all 32 modules
  • Eligibility evaluation against ITS data, attendance history, and composite rules
  • Miqaat lifecycle state — phase, dates, capacity, configuration
  • Config Cascade values — hierarchical configuration at Global / Miqaat / [type-specific context levels]. The levels below Miqaat (e.g., City / Zone for Ashara Mubaraka, Phase / Session for Istefadah) depend on the Miqaat type.
  • Zone and resident mapping derived from ITS Jamaat data
  • Allocation decisions (city seats, capacity slots)
  • Notification delivery across all channels
  • An immutable audit trail — every significant action is logged automatically
  • A design system — tokens, components, Lisan ud Daawat handling

2. What Every Module Owns

Core provides the shared platform layer. Everything else is the module's responsibility. No matter how tightly a module integrates with Core, these remain entirely owned by the module team:

Data — the module is the sole source of truth for its own operational data. Core does not store it. No other module reads it directly. Changes are communicated via events, not DB access.

Business logic — the workflows, validations, and processes specific to the module's domain. VMS owns volunteer lifecycle logic. AMS owns attendance recording logic. Core owns only the cross-cutting decisions (eligibility, RBAC, allocation).

UI and user experience — the module team owns its screens, flows, and interactions. The design system (TD tokens and component library) provides the visual foundation, but the module team owns what is built on top of it.

Deployment — the module deploys on its own schedule. It does not coordinate with Core or other modules for releases. It honors the API versioning policy so its consumers are not broken.

Event contracts — the module owns the schema of the events it publishes. It is responsible for versioning those schemas, notifying subscribers of breaking changes, and maintaining backward compatibility through the deprecation window.

Its own API surface — the APIs the module exposes to its own clients (its UI, any partners) are the module's responsibility to design, version, and maintain.


3. The Non-Negotiables — What Every Module Must Do

These apply to all modules — greenfield and existing alike. There are no exceptions. These come directly from the platform policies in BusinessModulesAndPolicies.md and the technical decisions in TD1–TD3.

Identity and access

  • Use ITS for all user authentication. The module uses ITS login for its own session management, exactly as it does today. No module builds its own login page, issues its own tokens, or maintains its own user records.
  • Call Core RBAC for every permission check. No local permission table. Every time the module needs to know whether a user can perform an action on a resource, it calls POST /v1/rbac/check. No exceptions.
  • Register resource types with Core RBAC before build. The module declares its resources and permitted actions as part of the System Definition Document process.

Data

  • Own your data, share nothing directly. The module database is private. No other module reads it. No other module writes to it. Data is shared via Core APIs or events only.
  • Do not maintain your own ITS data copy. Any ITS-derived data the module needs is queried from Core. The module's own ITS sync process (if it has one today) is deprecated as part of migration.
  • Do not hardcode business rules. Eligibility rules, filter criteria, and allocation logic belong in Core's Rule Engine. If a rule currently lives in a stored procedure or application code and it is a platform rule (not module-specific logic), it is migrated to Core.

Communication

  • Publish events via the confirmed publish mechanism. Three authorization checks are required on every event publish: sourceModule must match the module's identity, eventType must be in the module's registered list, and the envelope must conform to the registered schema. Whether this is enforced via a Core gateway endpoint or direct bus publishing with bus-level ACLs is under analysis — see TD2 Section 3. The specific publish path will be confirmed once the messaging technology is decided.
  • Declare subscriptions in the System Definition Document. Module teams do not self-provision bus access. Core provisions topic access at onboarding based on the declared subscriptions.
  • Never call another module's internal API directly. Cross-module queries go through Core APIs. Cross-module state changes travel as events on the bus.
  • Make all event consumers idempotent. Events may be delivered more than once. The idempotencyKey in the envelope must be used to detect and safely skip duplicates.

Design

  • Import and use Core design tokens. All spacing, typography, color, and motion values come from the token file. No hardcoded hex values or pixel measurements.
  • Use <LisanText> for all Lisan ud Daawat content. No module attempts to render Lisan ud Daawat text outside this component.
  • Use the React component library if building in React. @miqaat-core/design-system — install it, use it, do not rebuild what it already provides.
  • Pass design review before shipping any new screen. The platform design team reviews against Layer 3 guidelines before release.

Process

  • Complete the System Definition Document before starting build. All seven questions answered. Core team reviewed and signed off. This is the entry ticket.
  • Version your own APIs. Breaking changes to the module's own APIs require a major version bump and a deprecation window for your own consumers.

4. Greenfield Module Guide

A greenfield module is built from scratch with no prior codebase. It has no migration debt and no legacy constraints. It is Core-compliant from day one.

✅ Step-by-step sequence for a new module

Step 1 — System Definition Document Answer all seven questions (BusinessModulesAndPolicies.md, Part 2). Identify which Core engines the module will call, which events it will publish, which events it will subscribe to. Submit to Core team for review. Do not start implementation until sign-off is received.

Step 2 — Get API key Request a module API key from Core team via Platform Admin. One key per environment (dev / staging / prod). Store securely — never committed to source control.

Step 3 — Register RBAC resource types Register the module's resources and permitted actions with the Core RBAC engine. This is done once at setup. Once registered, Core RBAC can evaluate permission checks for this module's resources immediately.

Step 4 — Register event schemas Register all event types the module will publish with the Domain Event Schema Registry. The registered schema becomes the module's event publish contract and the gateway's enforcement reference.

Step 5 — Set up design system

npm install @miqaat-core/design-system

Import the token file into the module's global stylesheet. Confirm Lisan ud Daawat font is loading. Run through the Layer 3 pattern library for the module's primary flows before building screens.

Step 6 — Implement ITS login The module handles its own ITS login flow (unchanged from how ITS login works today). On every call to Core, include the ITS token in the request — the Identity Bridge handles extraction and validation.

Step 7 — Build against Core API contracts For each Core engine the module calls, read the relevant contract in TD3 (C-010 onwards). Build the integration against the contract spec. Implement the standard error response handling. Test against both success and error response shapes.

Step 8 — Implement event publishing All event publishing goes to POST /v1/events/publish. Build the event envelope correctly — all required fields present, idempotencyKey generated per event instance, sourceModule set to this module's registered ID.

Step 9 — Implement event consumers Subscribe to the event types declared in the System Definition Document (bus access provisioned by Core at onboarding). Every consumer must be idempotent — check the idempotencyKey before processing, skip if already processed.

Step 10 — Design review Before shipping any screen, submit to the platform design team for Layer 3 review. Confirm all screens pass WCAG 2.1 AA — contrast, keyboard navigation, touch targets, Lisan ud Daawat handling.


5. Migration Guide — Existing Modules by Tier

Existing modules have constraints that greenfield modules do not. The migration path is tiered by current technical state. The pattern and policy are decided; the specific module-by-module sequencing is confirmed as part of each module's technical discovery session.

Tier B — Modern REST modules (FastAPI, Node.js)

These modules have clean codebases and can integrate directly with Core. Migration effort is moderate.

Phase 1 — Core API integration (Pattern A) Replace internal decision logic progressively with Core API calls. Start with the highest-value, highest-risk decisions: permission checks (replace local RBAC with Core RBAC), then eligibility checks, then config lookups. Run old and new in parallel during transition — log discrepancies, validate that Core's answers match the current behaviour before switching over.

Phase 2 — Event publishing (Pattern B) Add event publishing for the module's significant state changes. Events do not replace existing behaviour — they broadcast it. Publishing registration.confirmed does not change how registration works; it makes the confirmation visible to other platform subscribers. The exact publish path (Core gateway endpoint vs direct bus publishing with bus-level ACLs) is under analysis and will be confirmed once the messaging technology is decided (TD2 Section 6). Register event schemas with the Domain Event Schema Registry now — this is required regardless of which publish mechanism is confirmed.

Phase 3 — Deprecate ITS sync Once the module is reading ITS-derived data from Core instead of its own sync, decommission the module's ITS sync process. Coordinate with the Core team to confirm the data is being served correctly from the Core ITS Sync Engine before switching off.

Phase 4 — Design system adoption Import design tokens. Replace module-specific components with the React component library for new screens. Existing screens are migrated progressively — no big-bang rewrite.

Tier C — Legacy modules (.NET older versions)

These modules cannot easily adopt modern libraries but can make HTTP calls. Migration is in two steps.

Step 1 — HTTP calls to Core APIs (Pattern A only) This requires no new libraries — just standard HTTP calls from .NET. Replace permission checks with calls to Core RBAC. Replace ITS data reads with calls to Core's data endpoints. This step alone delivers significant value: a legacy module gets platform-wide RBAC and stops maintaining its own ITS sync without a rewrite.

Step 2 — Outbox pattern for event publishing (Pattern B) The module writes to a dedicated outbox table in its own database as part of its existing transactions. A Core-owned relay agent reads the outbox table and publishes events to the bus on the module's behalf. The application code change is minimal — add an outbox table write to existing transaction handlers. The relay agent handles all bus interaction.

Module transaction:
UPDATE main_table SET ...
INSERT INTO outbox (eventType, payload, createdAt) VALUES (...)

Core relay agent (separate process):
Reads unprocessed outbox rows
POSTs to /v1/events/publish
Marks rows as processed

Tier D — Stored-procedure-heavy modules

The stored procedure writes to an outbox table inside the same database transaction. The same Core-owned relay agent from Tier C reads the outbox and publishes to the bus. Application code change is minimal.

-- Existing SP — add outbox write inside the same transaction
BEGIN TRANSACTION
UPDATE main_table SET status = 'confirmed' WHERE id = @id
INSERT INTO core_outbox (event_type, payload, created_at)
VALUES ('registration.confirmed', @payloadJson, GETUTCDATE())
COMMIT

For Core API calls (Pattern A), any stored-proc-heavy module can still make HTTP calls from the application layer above the stored procedures. The SP handles data; the application layer handles Core API calls.

📅 Module-specific migration sequencing

Which specific modules move through which tier, in what order, and on what timeline is confirmed during each module's technical discovery session. For AMS and VMS specifically — the two highest-dependency existing modules — the technical discovery sessions with the ITS team are still pending. Adaptation plans cannot be finalised until those sessions are complete.


6. Ownership Summary

ConcernModule ownsCore provides
User authentication flowITS login session managementIdentity (itsId) via Identity Bridge
Permission checksAPI call to Core RBACRole definitions, evaluation, audit
Eligibility logicDeclaring which rules applyEvaluating the rules against ITS data
ITS master dataNothing (deprecated)Single synced copy, query via API
Business rulesTriggering the right Core rule setStoring, evaluating, and changing rules
Module operational dataFull ownership, private DBNothing — Core never touches it
Event publishingEvent envelope content, schema registrationGateway validation, bus delivery
Event consumingConsumer logic, idempotency handlingBus access provisioning, DLQ monitoring
NotificationsTriggering via Core Notification EngineDelivery across all channels
UI foundationScreens and flows built on topDesign tokens, component library, guidelines
DeploymentModule deploys on its own clockCore APIs remain backward-compatible
Audit trailPublishing events with correct fieldsImmutable capture of the full event stream

7. Module Build Checklist

A practical pre-go-live checklist for any module — greenfield or migrated.

Before build begins

  • System Definition Document completed — all 7 questions answered
  • Core team sign-off received
  • API key obtained (dev environment)
  • RBAC resource types registered
  • Event schemas registered with Domain Event Schema Registry
  • Bus subscription access provisioned by Core team

During build

  • Design tokens imported — no hardcoded hex or pixel values
  • React component library installed (if React module)
  • All Lisan ud Daawat content uses <LisanText>
  • All permission checks call Core RBAC — no local permission table
  • All ITS-derived data read from Core — no module ITS sync
  • All event publishing uses the confirmed publish mechanism (gateway vs direct bus — decision pending TD2 Section 6)
  • All event consumers handle idempotency via idempotencyKey
  • No direct calls to other modules' internal APIs

Before go-live

  • API keys obtained for staging and production environments
  • All Core API integrations tested against contract error responses (not just happy path)
  • Event publishing verified — events appearing in Platform Admin Event Bus Health
  • Consumer lag acceptable under load test conditions
  • Design review passed for all new screens
  • WCAG 2.1 AA verified — contrast, keyboard navigation, touch targets
  • Module's own API versioning confirmed — no breaking changes without a major version bump

Decision Summary

DecisionStatusNotes
Modules stop building their own RBAC, eligibility, ITS sync, notification delivery✅ DecidedCore provides these — modules call Core APIs
Modules own their data, business logic, UI, deployment, and event contracts✅ DecidedCore never owns module operational data
System Definition Document required before any module build begins✅ DecidedCore team reviews and signs off
All permission checks call Core RBAC — no local permission tables✅ DecidedAuthorisation Policy
All ITS-derived data read from Core — no module ITS syncs✅ DecidedCore is the single ITS sync point
Event publish authorization requirements (sourceModule, eventType, schema)✅ DecidedThree checks required on every publish
Event publish enforcement mechanism (gateway vs direct bus)🔍 Under AnalysisTied to messaging technology decision — see TD2 Section 3
All event consumers must be idempotent✅ DecidedIdempotency Policy
Design tokens mandatory for all modules✅ DecidedNo hardcoded values
React component library mandatory for React modules✅ Decided@miqaat-core/design-system
<LisanText> for all Lisan ud Daawat content✅ DecidedNo exceptions
Design review gate before any new screen ships✅ DecidedPlatform design team reviews
Four-tier migration path (Greenfield / REST / .NET / Stored-proc)✅ DecidedTier confirmed per module at discovery session
Outbox pattern for Tier C and D event publishing✅ DecidedCore-owned relay agent publishes on module's behalf
Module tech stack — module teams choose their own✅ DecidedCore does not mandate module language or framework
Module-specific migration sequence and timeline📅 Pending SessionTechnical discovery session per module
AMS and VMS adaptation plans📅 Pending SessionITS technical discovery sessions still pending