Developer Resourcesemi
EMI Module Backend Documentation
EMI Module - Backend Documentation
1. Backend Scope and Boundaries
EMI backend owns:
- global EMI enablement and available period configuration
- admin-managed bank catalog with active/inactive state
- mobile-composed customer inquiry submission for product-linked EMI interest
- admin inquiry review and status progression
The backend does not calculate installment amounts. It only exposes the product price snapshot and available month periods.
2. Module Composition
EmiModule composes:
EmiCoreModuleEmiAdminModuleEmiCustomerModule
Ownership model:
EmiCoreModulere-exportsDatabaseModuleandRedisModuleEmiAdminModuleowns admin controllers and write pathsEmiCustomerModuleowns mobile-composed read endpoints and inquiry submission throughMobileModule
3. Data Model (Drizzle / PostgreSQL)
emi_config
id serial primary keyis_enabled boolean not null default falseperiods integer[] not null default [3, 6, 12]created_at,updated_at- singleton enforcement:
CHECK (id = 1)
emi_bank
id serial primary keyname varchar(120) not nulllogo_url varchar(500) not nullis_active boolean not null default truedisplay_order integer not null default 0created_at,updated_at- indexes on
is_activeanddisplay_order
emi_inquiry
id serial primary keyproduct_id -> product.id ON DELETE RESTRICTproduct_name_snapshot varchar(255) not nullproduct_price_snapshot integer not nullcustomer_name,customer_email,customer_mobilehas_credit_card boolean not nulldown_payment_amount integer nullablemessage text nullablestatus emi_inquiry_status not null default pendingcreated_at,updated_at- indexes on
product_id,status,created_at,customer_email - non-negative checks for
product_price_snapshotanddown_payment_amount
emi_inquiry_bank
id serial primary keyinquiry_id -> emi_inquiry.id ON DELETE CASCADEbank_id -> emi_bank.id ON DELETE RESTRICT- indexes on
inquiry_idandbank_id - unique index on
(inquiry_id, bank_id)
4. Runtime Rules and Domain Invariants
- Config writes use upsert targeting
id = 1. - Missing config on read falls back to disabled defaults until the first admin write.
- Mobile/customer config and active-bank reads are cached in Redis.
- Admin config and bank mutations invalidate customer-visible caches.
- Inquiry submission is atomic:
emi_inquiryandemi_inquiry_bankrows are written in one DB transaction. - Inquiry submission validates product existence, EMI enablement, and active selected banks before writing.
5. Cache Strategy
| Key prefix | Invalidated by |
|---|---|
emi:config:* | Admin config update |
emi:banks:active:* | Bank create/update/deactivate |
EMI_CACHE_TTL_SECONDS controls public EMI cache TTL. Default fallback is 300.
6. Performance Notes
- Inquiry list uses paginated queries with a filter-matched count query.
- Inquiry
bankIdfiltering uses anEXISTSsubquery to avoid row explosion. - Inquiry detail fetches selected banks with a single join query.
- Public reads are cache-backed and deterministic because the cache keys are static prefixes.
7. File Map
packages/db/src/schema/emi/— schema source of truthapps/api/src/modules/emi/admin/— admin DTOs, services, controllersapps/api/src/modules/emi/customer/— public DTOs, service, controllerapps/api/src/modules/emi/emi-core.module.ts— shared infra moduleapps/api/src/modules/emi/emi.module.ts— aggregate module
8. Environment Variables
| Variable | Default | Description |
|---|---|---|
EMI_CACHE_TTL_SECONDS | 300 | Cache TTL for mobile EMI config and bank lists |