Shop It Docs
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:

  • EmiCoreModule
  • EmiAdminModule
  • EmiCustomerModule

Ownership model:

  • EmiCoreModule re-exports DatabaseModule and RedisModule
  • EmiAdminModule owns admin controllers and write paths
  • EmiCustomerModule owns mobile-composed read endpoints and inquiry submission through MobileModule

3. Data Model (Drizzle / PostgreSQL)

emi_config

  • id serial primary key
  • is_enabled boolean not null default false
  • periods integer[] not null default [3, 6, 12]
  • created_at, updated_at
  • singleton enforcement: CHECK (id = 1)

emi_bank

  • id serial primary key
  • name varchar(120) not null
  • logo_url varchar(500) not null
  • is_active boolean not null default true
  • display_order integer not null default 0
  • created_at, updated_at
  • indexes on is_active and display_order

emi_inquiry

  • id serial primary key
  • product_id -> product.id ON DELETE RESTRICT
  • product_name_snapshot varchar(255) not null
  • product_price_snapshot integer not null
  • customer_name, customer_email, customer_mobile
  • has_credit_card boolean not null
  • down_payment_amount integer nullable
  • message text nullable
  • status emi_inquiry_status not null default pending
  • created_at, updated_at
  • indexes on product_id, status, created_at, customer_email
  • non-negative checks for product_price_snapshot and down_payment_amount

emi_inquiry_bank

  • id serial primary key
  • inquiry_id -> emi_inquiry.id ON DELETE CASCADE
  • bank_id -> emi_bank.id ON DELETE RESTRICT
  • indexes on inquiry_id and bank_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_inquiry and emi_inquiry_bank rows are written in one DB transaction.
  • Inquiry submission validates product existence, EMI enablement, and active selected banks before writing.

5. Cache Strategy

Key prefixInvalidated 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 bankId filtering uses an EXISTS subquery 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 truth
  • apps/api/src/modules/emi/admin/ — admin DTOs, services, controllers
  • apps/api/src/modules/emi/customer/ — public DTOs, service, controller
  • apps/api/src/modules/emi/emi-core.module.ts — shared infra module
  • apps/api/src/modules/emi/emi.module.ts — aggregate module

8. Environment Variables

VariableDefaultDescription
EMI_CACHE_TTL_SECONDS300Cache TTL for mobile EMI config and bank lists