Geo Backend Documentation
Geo Backend Documentation Backend architecture, data model, services, seeding, and operational behavior for the Geo module.
Area Files Inspected Verified Details Module wiring apps/api/src/modules/geo/ (module files)Leaf composition, mobile registration Controllers customer/geo-customer.controller.tsRoutes, guards, rate limits Services customer/geo-customer.service.ts, shared lookup serviceOrdering, filter, FK conversion Schema packages/db/src/schema/geo/{province,district,municipality,enums}.tsTables, codes, empty municipality reference Seed packages/db/src/seed/seed-geo.ts, seed.tsIdempotent seeding, wiring
Province and district reference tables.
The two public read routes.
GeoLookupService — the single place a district uuid becomes a foreign key.
The municipality reference — the table ships empty by design; municipality.name is free text on addresses.
Shipping rates, addresses, or any customer data — geo only names places; other modules attach prices and addresses to them.
Concern Source of Truth Notes Reference data PostgreSQL (province, district) Seeded, never edited via API District→id resolution GeoLookupServiceSingle code path
Module Type Path Controllers Providers Exports Responsibility GeoCustomerModuleLeaf customer/GeoCustomerControllerService + lookup Service Public reads + lookup (mobile composition) — mobile.module.ts— — — Mounted under /api/mobile/geo
apps/api/src/modules/geo/
customer/
geo-customer.controller.ts
geo-customer.service.ts
geo-lookup.service.ts # the single FK-conversion path
dto/
packages/db/src/schema/geo/
province.ts district.ts municipality.ts enums.ts index.ts
packages/db/src/seed/seed-geo.ts
Key files:
File Purpose Key Exports Notes customer/geo-customer.service.tsList reads GeoCustomerServiceOfficial order for provinces, name order for districts customer/geo-lookup.service.tsFK conversion GeoLookupServiceShared by shipping and address seed/seed-geo.tsIdempotent seed seedGeo()db:seed:geo
packages/db/src/schema/geo/
province.ts district.ts municipality.ts enums.ts
Table Purpose Key points province7 provinces code (stable, e.g. bagmati), name (a label — renames happen), displayOrder (official order)district77 districts code unique (incl. the four merge-trap codes), province_id FK, name unique nationwidemunicipalityEmpty by design 753 names are not reproduced from memory; addresses store municipality_name as free text, municipality_id is always null
Method Called By Reads Writes Side Effects Errors listProvinces()controller province— — — listDistricts()controller district— — GEO_PROVINCE_NOT_FOUND
Method Called By Reads Writes Side Effects Errors resolveDistrict()shipping, address district— — GEO_DISTRICT_NOT_FOUND
The lookup is the single place a district uuid becomes an internal integer id. A new module that needs a district resolves it here — never by querying district directly.
No geo read is Redis-cached — 84 rows do not justify it. The cost of a miss is a single indexed lookup.
None. Geo is synchronous reads plus a seed script; there is no queue involvement.
Public routes (@Public()) throttled at PUBLIC_READ (60/min per IP) — for load, not secrecy.
No admin surface, no permissions, no writes through the API.
seed-geo.ts is idempotent: re-running never duplicates rows.
Runs with the normal db:seed; standalone via pnpm --filter @happy-shop/db db:seed:geo.
New environments must be seeded before address/shipping surfaces are exercised — an unseeded database returns empty lists, and GeoLookupService cannot resolve anything until districts exist.
Complete feature list, actor journeys, state flows, business rules, edge cases, and diagrams for the Geo module.
Complete API contracts for the Geo module, including routes, auth, DTOs, responses, errors, examples, and integration notes.