Skip to main content

TD1 — Core Tech Stack and Architecture

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. What Core Is — Architecturally

✅ Core is a decision layer, not a data store

Core does not own module operational data. It owns decisions — eligibility outcomes, allocation results, permission verdicts, configuration values, lifecycle state. The data that informs those decisions comes from two paths only:

  • Path 1 — ITS sync: Master data (Mumineen records, Jamaat hierarchy, ITS-managed tables) synced into Core via the ITS ↔ Core Sync Contract.
  • Path 2 — Module events: Significant state changes published by business modules to the event bus. Core subscribes to the events it needs (e.g., capacity.configured, khidmat.assigned) and updates its own decision state accordingly.

Core never reads a module's database directly. If Core needs something a module owns, that module must publish it as an event.

✅ Core is a single platform authority

Core is one platform — not 32 parallel systems, not a shared database, not a set of conventions. It is a deployed platform that every business module calls. One team owns it and operates it. From a governance perspective it is one unit. Internally, it is built as purpose-based microservices — different engines use the technology stack best suited to their workload (see Section 3). Business modules deploy independently on their own clock; Core deploys on its own.

✅ Federation model

The platform operates on three layers:

Core — decision authority. Owns engines, policies, event schema, RBAC.
Modules — business logic. Own their data, workflows, and UIs.
Contracts — the agreed boundary between Core and each module.
(Contracts are defined in TD3.)

No module talks to another module directly. Cross-module communication routes through Core APIs (for decisions) or through the event bus (for state changes).


2. Core Engines — The Confirmed List

✅ These engines are confirmed as belonging inside Core

All 15 engines below passed the three-question test: shared by more than one module, encodes a business rule, and duplicating would cause incorrect decisions.

Miqaat and Structure

EngineWhat it owns
Miqaat Lifecycle ManagementCreate, phase, configure, and archive miqaats. No module can create or transition a miqaat without Core.
Config Cascade EngineHierarchical configuration: Global → Miqaat → [type-specific context levels]. The intermediate levels (e.g., City → Zone for Ashara Mubaraka, Phase → Session for Istefadah) are defined by the Miqaat type at setup. One change propagates to all modules.
Zone ↔ Resident MappingMaps ITS Jamaat data to miqaat zones. Modules query Core for resident counts by zone — they do not derive this themselves.
Capacity Balance EngineSubscribes to capacity.configured events. Checks Vaaz / Mawaid / Kitchen ratios. Publishes capacity.imbalance.detected when ratios are violated.

Identity and Access

EngineWhat it owns
Identity BridgeWraps ITS SSO. Validates ITS tokens, extracts itsId, enforces session policy. Modules never handle tokens directly.
RBAC / Permission EngineSingle permission authority for all 32 modules. Role definitions, role-to-permission mappings, runtime evaluation. Every module calls this for every access boundary check.

Rules and Decisions

EngineWhat it owns
Rule Engine and Policy RuntimeEligibility rules, filter criteria, allocation logic — configured here, not hardcoded in modules or SQL. Ops teams change rules without engineers.
Eligibility Evaluation EngineEvaluates composite eligibility: ITS data, prior attendance, learning records, custom rules. Modules define which rules apply; this engine evaluates them.
Allocation EngineCity seat allocation, capacity slot distribution. Modules submit allocation requests; this engine resolves them.

Data and Events

EngineWhat it owns
ITS Sync EngineFull sync and delta sync of 9 ITS-managed tables into Core. Feeds Eligibility, Allocation, Zone Mapping, and HR Bank engines.
Audit Log BackboneImmutable, append-only event stream. Every allocation decision, permission check, role change, config override is recorded. Cannot be modified or deleted.
Domain Event Schema RegistryVersioned schema definitions for all events published on the bus. Modules must conform to Core's envelope schema.
HR BankCross-event khidmat history per itsId. Enforces the one-primary-khidmat rule. Feeds eligibility and volunteer matching decisions. Extension of the Mumin Info Aggregator.

Operational

EngineWhat it owns
Vendor and Procurement RegistryVendor registry, item master, budget envelope check API. Modules own indent creation and approval workflows; Core provides the reference data and budget check only.
Task Engine (Platform Layer)Platform-level task and checklist definitions that span multiple modules or miqaat phases. Module-specific checklists stay in the module.

3. Core Runtime Technology

✅ Purpose-based multi-language microservices — FastAPI (Python) + Node.js

Core is not built on a single technology stack. Each engine is built on the stack best suited to its workload. The two confirmed runtimes are FastAPI (Python) and Node.js. The principle is: choose the stack that matches the engine's primary characteristic — computation and data processing go to FastAPI; high-concurrency I/O and event-driven workloads go to Node.js.

FastAPI (Python) — computation-heavy and data-processing engines

FastAPI is chosen for engines that do significant computation, data transformation, or will integrate closely with AI/ML utilities. Python's ecosystem (data processing libraries, AI/ML tooling) makes it the natural fit here.

EngineWhy FastAPI
Eligibility Evaluation EngineComplex rule evaluation across multiple data sources — computational logic, not I/O
Rule Engine and Policy RuntimeBusiness rule evaluation; Python's expressive syntax suits complex conditional logic
Allocation EngineOptimisation algorithms for seat and slot distribution — computation-intensive
ITS Sync EngineETL-like data transformation of 9 ITS tables — data processing workload
Capacity Balance EngineRatio calculations across event capacity data
HR BankData aggregation, cross-miqaat history computation

Node.js — high-concurrency I/O and event-driven engines

Node.js is chosen for engines that handle a very high volume of small, fast requests or that are inherently event-driven. The RBAC engine in particular is called on every access boundary across all 32 modules — it needs to handle thousands of concurrent permission checks with minimal latency.

EngineWhy Node.js
RBAC / Permission EngineHighest-frequency engine on the platform — called on every access check, needs low-latency concurrent handling
Identity BridgeToken validation at the API Gateway layer — pure I/O, high concurrency
Config Cascade EngineFast hierarchical key-value lookups with caching — I/O bound
Notification Dispatch EngineEvent-driven fan-out to multiple delivery channels — naturally async I/O
Audit Log BackboneHigh write-throughput, streaming append-only log
Miqaat Lifecycle ManagementWorkflow state transitions, primarily I/O and event publication
Domain Event Schema RegistrySchema validation and lookup — I/O bound
Zone ↔ Resident MappingLookup-heavy, low computation
Vendor and Procurement RegistryCRUD + reference data lookups
Task Engine (Platform Layer)Workflow and checklist state management

Note: The engine-to-language mapping above is the working direction. The Core team will finalise the exact assignment for each engine before build begins. Some engines may warrant a different split once detailed design is done.

✅ What must be shared across both runtimes

Two different technology stacks inside Core only work if the seams between them are explicitly managed. The following must be consistent regardless of which runtime is serving a request:

API Gateway — single entry point All Core API calls from modules route through a single API Gateway. Modules call one platform URL and never need to know whether the engine behind it is FastAPI or Node.js. The gateway handles token validation (Identity Bridge), routes to the correct engine, and enforces rate limits.

Event envelope schema — language-agnostic JSON The event schema Core owns is defined as a JSON Schema specification — not tied to Python or Node.js. Both runtimes produce and consume events that conform to the same envelope. The Domain Event Schema Registry (Node.js) validates schema conformance regardless of which engine published the event.

Consistent error response format Every Core API returns errors in the same structure, regardless of which runtime produced the error. This is defined once in the platform contract (TD3) and both FastAPI and Node.js services implement it. Modules should never receive a Python traceback or a Node.js stack dump in a production error response.

Structured logging format Both runtimes emit logs in the same JSON schema. This is what allows the Audit Log Backbone and observability tooling to work across the whole platform without language-specific parsers.

Health and readiness endpoints Every Core service — whether FastAPI or Node.js — exposes /health and /ready endpoints in the same response format. Platform Admin's Event Bus Health monitor and deployment tooling depend on this consistency.

Authentication passthrough The Identity Bridge (Node.js, at the gateway) validates the ITS token and extracts the itsId before the request reaches any engine. Downstream FastAPI and Node.js services receive the verified itsId in a standardised request header — they never re-validate the token themselves.

Configuration access Both runtimes read configuration from Core's Config Cascade Engine via a standard API call. No hardcoded environment-specific values in either runtime.

🔍 Internal service communication — within Core

When a FastAPI engine needs data from a Node.js engine (e.g., the Eligibility Engine calling the Config Cascade Engine), the internal communication pattern is under analysis. Options are synchronous HTTP calls between services (consistent with the module-to-Core pattern) or a more performant internal protocol (gRPC). Decision to be confirmed by the Core team before build begins.

🔍 Database technology per service

Each microservice within Core manages its own persistence. The database technology is not mandated to be the same across all services — the RBAC engine's query patterns (role hierarchy lookups) differ significantly from the Audit Log's (append-only, high write throughput) and the Config Cascade's (hierarchical key-value). Database choices per service are under analysis and will be confirmed before each engine's build begins.


4. API Gateway

✅ Core has a single API Gateway — concept confirmed

Core is built as multiple microservices (FastAPI and Node.js engines). Without something in front of them, a module calling Core would need to know which service handles which endpoint — RBAC on one address, Eligibility on another, Config Cascade on a third. That breaks the abstraction entirely. Modules must call one Core URL. The API Gateway is what makes that possible.

Beyond routing, three things already confirmed in this document require a single entry point:

  • API key validation — must happen before any engine sees the request (TD2, Section 3)
  • ITS token validation — the Identity Bridge extracts itsId before passing to any engine (Section 6 below)
  • Rate limiting per module — enforced at one point, not duplicated across 15 services

The API Gateway is a Core responsibility. It sits in front of all Core engine services. It is the only entry point modules call. Internally it:

  1. Receives the inbound request from the module
  2. Validates the API key → resolves X-Module-Id
  3. Validates the ITS token if present → resolves X-Its-Id
  4. Routes the request to the correct Core engine (FastAPI or Node.js)
  5. Returns the engine's response to the module

No engine is exposed directly to modules. All traffic enters through the gateway.

🔍 API Gateway technology — under analysis

The technology implementing the gateway is under analysis and tied to the infrastructure decision in TD5. Three realistic options:

OptionDescriptionTrade-off
Managed gateway (AWS API Gateway, Kong Cloud, Azure APIM)Fully managed — routing, auth plugins, rate limiting, SSL includedLow operational burden but ties to a cloud provider
Self-hosted gateway (Kong, Traefik, Nginx, Envoy)Cloud-agnostic, Core team operates itMore control, more operational responsibility
Core-built lightweight gateway (Node.js service)Simple service built and owned by Core teamSimplest to control, trades features for ownership

The decision will be confirmed in TD5 once the infrastructure session is complete. Until then, no Core service should be built with a hard dependency on a specific gateway technology.


5. Core's API Surface — How Modules Talk to Core

✅ Synchronous HTTP for decisions

When a module needs an answer before it can proceed — eligibility check, RBAC check, config lookup, allocation request — it makes a synchronous HTTP call to the relevant Core engine API. Core computes and returns the answer. This pattern works with any module stack (.NET 4.5, FastAPI, Node.js — all can make HTTP calls).

✅ API versioning — breaking change = major version bump

All Core APIs are versioned. A change that removes a field, renames a field, or changes a response behaviour is a breaking change and requires a new major version. The old version must be supported through a defined deprecation window. Modules are not required to be on the latest version but must upgrade before the deprecation window closes.

This is a platform commitment, not a preference. Teams building on Core APIs need this guarantee to deploy independently.

🔍 API protocol — HTTP/REST vs alternatives

The synchronous decision call pattern is confirmed as HTTP. The specific API design standard (REST, gRPC, GraphQL) is under analysis. REST is the working assumption given compatibility with the widest range of existing module stacks, but this will be confirmed before the first Core API contract is written (see TD3).


6. Core's Internal Data

✅ What Core must persist

Core is a decision layer but it is not stateless. It must persist the inputs and state that its engines need to make decisions:

DataOwner engineNotes
Miqaat state (phase, dates, capacity, rules)Miqaat LifecycleCreated and updated only through Core
Role assignments (itsId → role → scope)RBAC EngineWritten by Platform Admin only
Config cascade values (global / miqaat / type-specific context levels)Config CascadeHierarchical overrides tracked with change history. Intermediate levels vary by Miqaat type.
ITS-synced master data (9 tables)ITS Sync EngineRead from ITS, owned by ITS — Core holds a sync copy
Audit log (immutable event stream)Audit Log BackboneAppend-only. Never modified.
Event schema versionsDomain Event Schema RegistryVersioned schema definitions
Khidmat history per itsIdHR BankCross-miqaat record
Vendor and item masterProcurement RegistryReference data only — no indent or PO data

🔍 Database technology per engine

As noted in Section 3, each Core microservice manages its own persistence and may use a different database technology suited to its query patterns. The choice per engine is under analysis. A decision will be confirmed before each engine's build begins.


7. Identity Bridge — ITS Integration

✅ ITS is the only identity provider

Confirmed under the Authentication Policy. No module creates its own login, issues its own token, or maintains its own user records. Every user on the platform is authenticated via ITS. Core's Identity Bridge is the single point through which ITS tokens are validated before any module receives a verified itsId.

✅ Core's role in identity

The Identity Bridge engine (Node.js, API Gateway layer) intercepts every inbound request, validates the ITS token, extracts the itsId, and passes it downstream as a verified header. Both FastAPI and Node.js Core services downstream receive the itsId already validated — they never see or handle the raw token.

📅 Token format and session detail — pending ITS technical session

The exact format of the ITS SSO token, session duration, refresh mechanism, and validation endpoint are not yet confirmed. These require a direct technical session with the ITS engineering team. Until that session is complete:

  • The Identity Bridge engine cannot be fully specified
  • The ITS ↔ Core Sync Contract (C-005) cannot be finalised
  • Any module that depends on itsId behaviour beyond "ITS provides it" should flag this as a dependency

This is the first external dependency on the critical path.


8. Event Bus — Architecture Position

The event bus is where asynchronous communication between modules happens. Its architectural position is confirmed: Core owns the event envelope schema, Core monitors bus health via Platform Admin, and all cross-module state changes flow through it. Module-to-module direct calls are prohibited.

The communication patterns — synchronous Core API calls for decisions, event publication for state changes — are fully decided and documented in TD2 — Event Driven Structure.

🔍 Messaging technology

The specific technology powering the event bus is under analysis. Options include managed services and self-hosted alternatives. The decision will be confirmed in TD2 after the analysis is complete. No Core engine or module should be built with a hard dependency on a specific messaging technology before that decision is made.


9. Core Deployment Model

✅ Core is one platform, internally decomposed as microservices

Core is owned and operated by one team. Externally it presents as one platform. Internally it is decomposed into purpose-built microservices — each Core engine is a deployable service, built in either FastAPI or Node.js as appropriate, each managing its own data. The Core team owns all of these services collectively.

✅ Modules deploy independently

Core's deployment cannot break existing module deployments. The API versioning policy (Section 4) and the Deployment Independence Policy enforce this. A Core release that changes behaviour must do so under a new major version. Existing module integrations continue working until they choose to upgrade.

📅 Deployment infrastructure — pending ITS infrastructure session

Cloud provider, container orchestration, environment strategy (dev / staging / prod), and scaling model are not yet confirmed. These will be covered in TD5 — Infrastructure Recommendations after the ITS infrastructure session is completed. Both FastAPI and Node.js services will be containerised (Docker), making the choice of orchestration platform independent of the runtime choice.


Decision Summary

DecisionStatusNotes
Core is a decision layer, not a data store✅ DecidedFoundational to the entire architecture
Core is a single platform authority, one team✅ DecidedInternally decomposed as microservices
Federation model (Core + Modules + Contracts)✅ DecidedCross-module calls prohibited
15 Core engines confirmed✅ DecidedSee Section 2
Core runtime: FastAPI (Python) + Node.js, purpose-based✅ DecidedSee Section 3 for engine-to-language mapping
Shared API Gateway — single entry point for modules✅ DecidedHides internal multi-language decomposition
Event envelope schema — language-agnostic JSON Schema✅ DecidedBoth runtimes conform to the same spec
Consistent error response format across both runtimes✅ DecidedDefined in TD3
Structured logging format — shared JSON schema✅ DecidedEnables unified audit and observability
Health/readiness endpoint standard across all services✅ Decided/health and /ready on every service
Authentication passthrough via Identity Bridge at gateway✅ DecidedDownstream services receive verified itsId only
API Gateway exists — single entry point for all module calls to Core✅ DecidedHandles routing, API key validation, token validation
API Gateway technology (managed / self-hosted / Core-built)🔍 Under AnalysisDecision in TD5 after infrastructure session
Synchronous HTTP for decision calls✅ DecidedAll module stacks can call HTTP
API versioning — breaking change = major version✅ DecidedPlatform commitment to modules
ITS is the only identity provider✅ DecidedAuthentication Policy
Core owns event envelope schema✅ DecidedFull detail in TD2
Modules deploy independently of Core✅ DecidedDeployment Independence Policy
Both runtimes containerised (Docker)✅ DecidedOrchestration platform TBD in TD5
Engine-to-language mapping (final)🔍 Under AnalysisCore team to confirm before each build
Internal service communication within Core🔍 Under AnalysisHTTP vs gRPC — Core team decision
Database technology per engine🔍 Under AnalysisConfirmed before each engine build begins
API protocol (REST vs gRPC vs GraphQL)🔍 Under AnalysisREST is working assumption
Messaging / event bus technology🔍 Under AnalysisDecision in TD2
ITS token format and session detail📅 Pending SessionITS technical session — critical path
Deployment infrastructure📅 Pending SessionITS infrastructure session → TD5