# Sahakari Management System

Modern multi-tenant cooperative (sahakari) management system. Replaces legacy Laravel `akashdms-tenant`.

## Stack

- **Backend** (`artifacts/api-server`): NestJS 11 + TypeORM 0.3 + JWT + argon2.
  - Dev DB: `sql.js` (SQLite in-process; no native build needed). Files at `.data/landlord.sqlite` and `.data/tenants/<sub>.sqlite`.
  - Prod DB: Replit PostgreSQL (set `DB_DRIVER=postgres` via artifact.toml). Uses schema-per-tenant (`landlord` schema + `tenant_<sub>` schemas). Schemas auto-created on first connect. PG secrets (PGHOST/PGPORT/PGUSER/PGPASSWORD/PGDATABASE) injected automatically by Replit.
  - Production run: `cd artifacts/api-server && node dist/main.js` (required for pnpm module resolution — workspace node_modules symlinks must be relative to the package dir).
  - All API routes under `/api`, port `8080`, health at `/api/health/healthz`.
- **Frontend** (`artifacts/web`): React + Vite (Tailwind v4 + shadcn/ui + TanStack Query + wouter).
  - Substituted for Next.js (no Next.js artifact type available on Replit).
  - Uses path-based routing, base path `/`, port `22333`.

## Multi-Tenancy

- **Schema-per-tenant** isolation via TypeORM dynamic data sources.
- `AsyncLocalStorage` (`tenant-context.ts`) carries tenant info per request.
- `TenantConnectionService` caches per-tenant DataSource (LRU-ish).
- `TenantMiddleware` resolves tenant from `X-Tenant-Subdomain` header. Skip prefixes: `/api/health`, `/api/master`, `/api/tenants/register`.
- New tenants get a fresh schema seeded with default roles + permissions on registration.

## Authentication

- JWT (HS256) returned in body **and** set as httpOnly `access_token` cookie.
- Global `JwtAuthGuard` + `PermissionsGuard` (`@Public()` to bypass; `@Permissions('users.create')` to require).
- Bypass users (`isBypass=true`) get `permissions=['*']` automatically.
- Demo seed: tenant `demo`, user `admin@demo.local` / `admin12345`.

## Phase 0 Modules

- `auth` — login / logout / me
- `tenants` — public list + register (creates schema + admin)
- `users` — CRUD with roles + office assignment
- `roles` — CRUD with permission assignment; permissions list endpoint
- `offices` — hierarchical CRUD (head/branch/sub-branch/service-center)
- `health` — `/healthz` for deployment

## Architectural Blueprint

**`docs/ARCHITECTURE.md`** is the authoritative 10-story foundation diagram and stack-decision document. **`docs/MODULE_ROADMAP.md`** maps every legacy Laravel module to its new module + phase. Read both before adding new features.

## Frontend Foundation Primitives

All pages use these primitives (do **not** roll your own):

| Primitive | Location | Purpose |
|---|---|---|
| `AppShell` | `components/layout/app-shell.tsx` | Mobile-responsive shell with sidebar (Sheet on mobile), topbar, profile menu, ⌘K palette |
| `SidebarNav` | `components/layout/sidebar-nav.tsx` | Reads `MODULES`; auto-groups, filters by permission, shows phase badges |
| `CommandPalette` | `components/layout/command-palette.tsx` | ⌘K module switcher |
| `PageHeader` | `components/page/page-header.tsx` | Title + Devanagari subtitle + breadcrumbs + actions |
| `SectionCard` | `components/page/section-card.tsx` | Card with header/body/actions slots |
| `DataTable` | `components/data-table/data-table.tsx` | TanStack Table v8 with sort/search/pagination/loading/empty |
| `Field` | `components/form/field.tsx` | Label + error/hint wrapper for any input |
| `ComingSoonPage` | `components/coming-soon.tsx` | Placeholder for stub modules |

## Module Registry — single source of truth

`src/modules/registry.tsx` exports `MODULES: ModuleManifest[]`. Each entry declares `{ id, label, labelNe, group, icon, path, component, permission, phase }`. The registry drives:

1. The sidebar (grouping + phase badges + permission filter)
2. The command palette (search by English or Nepali label)
3. The router in `App.tsx`

**To add a module**: create `modules/<id>/<id>-page.tsx`, then append a `ModuleManifest` to `MODULES`. That's it. Sidebar entry, route, palette entry, and permission gate appear automatically.

## Module Folder Layout

```
src/modules/<id>/
  <id>-page.tsx         ← main page (default export)
  components/           ← module-specific UI
  hooks/                ← module-specific TanStack Query hooks
  types.ts              ← module types
```

API-side mirrors: `artifacts/api-server/src/modules/<id>/*`.

## Phase 0 Pages (using new primitives)

- `/login` (`modules/auth/login-page.tsx`)
- `/` (`modules/dashboard/dashboard-page.tsx`)
- `/users` (`modules/users/users-page.tsx`)
- `/roles` (`modules/roles/roles-page.tsx`)
- `/offices` (`modules/offices/offices-page.tsx`)

## Phase 1 — Members Module (complete)

- **Entity**: `member.entity.ts` — full KYC schema: citizenship, PAN, national ID, voters ID, driving license, passport, BS dates, Nepal addresses (7 provinces + 77 districts + local govt), business details, financial estimates, family names, photo/signature URLs.
- **MemberFamily entity**: `member-family.entity.ts` — related family members & nominees (cascade with member, stores relation, DOB, citizenship, isNominee, nomineeSharePercent).
- **Auto member ID**: Backend auto-generates 5-digit padded member ID on create if not supplied.
- **Photo upload**: `POST /api/members/upload` with multer; images saved to `uploads/members/` and served at `/api/uploads/`.
- **API**: CRUD + search (`GET /api/members?q=`) with family relation loaded in getOne.
- **Frontend primitives**: `NepaliDateInput`, `AddressPicker` (Province→District→LocalGovt), `PhotoUpload`, `FamilyTab`.
- **MembersPage**: DataTable with photo thumbnails, click-to-detail, search.
- **MemberFormDialog**: 7-tab form — Personal (incl. family names) / Address / Identity / Family & Nominees / Photo / Business / Other.
- **MemberDetailSheet**: Right-side read-only profile sheet with tabs; Edit button triggers the form dialog.

## Gap-Analysis Fill: New Modules (session 3 — complete)

All modules ported from legacy `akashdms-tenant-develop` Laravel system:

### Backend Entities Added
- `deposit-account.entity.ts` — FD/RD/special saving accounts (principal, interest%, duration, maturity, status)
- `blacklist.entity.ts` — defaulter blacklist records with whitelist support
- `activity-log.entity.ts` — system-wide audit trail (module, action, userId, ip, message)
- `taketa-patra.entity.ts` — loan recovery/collection notices (1st/2nd/3rd/final notice)
- `credit-renew.entity.ts` — loan renewal/extension requests

### Backend Modules Registered (in `app.module.ts` + `tenant-data-source.ts`)
`DepositAccountsModule`, `BlacklistModule`, `ActivityLogsModule`, `TaketaPatrasModule`, `CreditRenewModule`

### Frontend Pages + Registry
- `/deposit-accounts` (savings group) — Deposit Accounts with summary cards
- `/blacklist` (members group) — Blacklist with whitelist action
- `/activity-logs` (settings group) — Read-only audit log with filters
- `/taketa-patras` (loans group) — Collection notice CRUD
- `/credit-renew` (loans group) — Loan renewal CRUD

### Master Data Expansion (Lookup types now 22 types, 100+ entries)
Added types: `staff_position`, `center`, `group`, `document_type`, `insurance`, `microfinance_program`, `malpot_office`, `surveyor_office`, `yatayat_office`, `vehicle_provider`, `business_unit`, `department`, `committee_group`, `newspaper`, `occupation_type`, `relationship_type`. Lookup entity has `meta` text field (stores JSON extras like interestRate, address, phone).

All other modules in the sidebar are **stubs** showing `ComingSoonPage` until their phase ships.

## Important Conventions

- API responses are wrapped in `{ success, data }` envelope; `apiFetch` unwraps.
- Frontend stores session in `localStorage` and sends `Authorization: Bearer` + `X-Tenant-Subdomain` headers.
- All requests use `credentials: 'include'` so the cookie also flows.
- Default permission keys live in `artifacts/api-server/src/common/permissions.ts`.
- Bilingual UX: every user-facing label has English + Devanagari (Nepali) variant.
- Mobile-first: every primitive collapses gracefully below `md` breakpoint.

## Dev Workflows

- `artifacts/api-server: API Server` — `pnpm --filter @workspace/api-server run dev`
- `artifacts/web: web` — `pnpm --filter @workspace/web run dev`

## Phase 2 — Master + Darta-Chalani + Applications (complete)

- **Lookup entity**: `lookup.entity.ts` — single table for all lookup/dropdown data; type+code unique index.
- **MasterService**: Seeds 35+ default lookups (loan_purpose, loan_title, saving_type, income_source, collateral_type, repayment_type) on demand; full CRUD.
- **MasterController**: `GET /api/master`, `GET /api/master/types`, `GET /api/master/:type/list`, `POST /api/master/seed`, `POST /api/master`, `PUT /api/master/:id`, `DELETE /api/master/:id`.
- **MasterPage** (`/master`): Type sidebar + DataTable per type; Add/Edit lookup dialog.
- **DartaChalani entity**: `darta-chalani.entity.ts` — type (darta/chalani), regNumber, fiscalYear, subject, party info, dates (AD+BS), soft delete.
- **DartaChalaniService**: Auto-assign reg numbers per type+fiscal year; search by subject/regNumber/partyName.
- **DartaChalaniPage** (`/darta-chalani`): Tabs (सबै/दर्ता/चलानी), register form dialog (विषय, मिति, पठाउने/पाउने, कार्यालय, ठेगाना, कैफियत).
- **Application entity**: `application.entity.ts` — full loan application (loan purpose/title, amounts, collateral, dates, status, fiscal year) + 4 child tables: `applicant_savings`, `applicant_incomes`, `applicant_charges`, `guarantors`.
- **ApplicationsService**: Auto-generates `APP-00001` style numbers; full CRUD + soft delete + status update; cascades sub-tables on update.
- **ApplicationsPage** (`/applications`): Status filter buttons + search; 5-tab form (आधारभूत/आय-खर्च/बचत/दायित्व/जमानतदार); right-side detail sheet with status transitions; Edit button.

## Phase 3 — Savings Module (complete)

- **Entities**: `savings-account.entity.ts`, `savings-transaction.entity.ts` with soft delete.
- **SavingsService**: Full CRUD + deposit/withdraw (balance updated in-place); auto `SAV-00001` account numbers.
- **SavingsController**: GET/POST `/savings`, GET/PATCH/DELETE `/savings/:id`, GET `/savings/:id/transactions`, POST `/savings/:id/deposit`, POST `/savings/:id/withdraw`.
- **SavingsPage** (`/savings`): 3 stat cards, status filter pills, DataTable with deposit/withdraw buttons, create/edit dialog, account detail sheet with transaction history.
- **Navigation**: New "बचत" sidebar group between Members and Loans.

## Universal App Config — `src/lib/app-config.ts`

**Single source of truth** for all app-wide constants. Change here → all pages/components update automatically:
- `APP_CONFIG.currencySymbol` / `currencyLocale` — used by ALL `formatMoney()` calls
- `APP_CONFIG.currentFiscalYear` — pre-filled in all new forms (savings, applications, darta-chalani)
- `APP_CONFIG.defaultSavingsInterestRate`, `defaultMinimumBalance` — default values in savings form
- `APP_CONFIG.features.*` — enable/disable dark mode, notifications, command palette app-wide
- `APP_CONFIG.nameNe`, `taglineNe` — shown on login page, footer, etc.
- `formatCurrency()` / `formatCurrencyCompact()` exported from `app-config.ts`
- `formatMoney()` / `formatMoneyCompact()` in `format.ts` also read from `APP_CONFIG`

## Theme System — `src/lib/theme.tsx`

- `ThemeProvider` wraps the app (in `App.tsx`) — adds `.dark` class to `<html>` on toggle
- `useTheme()` hook → `{ theme, resolvedTheme, setTheme, toggleTheme }`
- Persisted in `localStorage` key `sahakari_theme`
- Dark mode CSS variables already defined in `index.css` under `.dark`
- Sun/Moon toggle button in the topbar (only shown when `APP_CONFIG.features.darkMode === true`)

## Improved Components

- **AppShell** (`app-shell.tsx`): Dark mode toggle, notification bell, breadcrumb bar, Settings link in user menu, sidebar footer with version + settings link
- **SidebarNav** (`sidebar-nav.tsx`): Improved phase badges (Beta/WIP/Q2/Q3/Plan instead of P1-P5), better active state (dot indicator), cleaner visual hierarchy
- **Dashboard** (`dashboard-page.tsx`): Real stats from API (members/savings/loans/offices), Nepali time-based greeting (शुभ बिहान/दिउँसो/साँझ), quick action grid, recent savings + loan application feeds, fiscal year footer
- **Login page** (`login-page.tsx`): Full Nepali UI reading from APP_CONFIG (name, tagline, version)
- **Format utils** (`format.ts`): `formatMoneyCompact()`, `nepaliGreeting()` added; all monetary formatters read from `APP_CONFIG`

## Phase 4 — Loan Management Module (complete)

- **Entities**: `loan-account.entity.ts`, `loan-payment.entity.ts` with soft delete.
- **LoanAccount fields**: loanNumber (LON-00001), applicationId (link to Application), memberId, officeId, loanType, loanPurpose, loanTitle, sanctionedAmount, disbursedAmount, outstandingBalance, totalInterestPaid, totalPrincipalPaid, penaltyBalance, interestRate, termMonths, repaymentType, emiAmount (auto-calculated), disbursementDate/BS, maturityDate/BS, lastPaymentDate/BS, closeDate/BS, collateralType/description/value/ownerName/ownerRelation, insuranceCompany/policyNo/expiryBs, status (active/closed/NPL/written_off/restructured), nplDate, overdueDays, fiscalYear, remarks.
- **LoanPayment fields**: loanAccountId, voucherNumber, paymentDate/BS, principalAmount, interestAmount, penaltyAmount, totalAmount, balanceAfter, paymentType (regular/advance/partial/final_settlement), description, createdBy.
- **LoansService**: `findAll` (with search + status + loanType filters + full summary stats), `findOne`, `findPayments`, `create` (auto LON-xxxxx number + EMI calculation), `update`, `makePayment` (reduces outstanding, tracks total paid, auto-closes at zero balance), `remove`.
- **LoansController**: GET/POST `/loans`, GET/PATCH/DELETE `/loans/:id`, GET `/loans/:id/payments`, POST `/loans/:id/payment`.
- **LoansPage** (`/loans`): 4 stat cards (active loans, total outstanding, NPL count, total disbursed), status filter pills (All/Active/Closed/NPL/Written-off), search, DataTable, 3-tab create/edit dialog (आधारभूत/शर्त-किस्ता/धितो-बिमा), payment dialog (principal+interest+penalty+type+voucher+date with total preview), loan detail sheet with 3 tabs (विवरण/धितो/भुक्तानी इतिहास), delete confirmation.
- **EMI calculation**: `LoansService.calcEmi()` uses standard reducing-balance formula; stored on loan account on create.
- **Permission keys**: `loans.view`, `loans.create`, `loans.update`, `loans.payment`, `loans.delete`.
- **Navigation**: "ऋण खाता" entry in the Loans sidebar group (order 2, below Applications).

## Phase 5 — Extended Master + Credit Analysis + Collateral (complete)

All 19 entities ported from legacy `akashdms-tenant-develop` system:

### Backend Entities Added
- `board-member.entity.ts` — Board of Directors member records
- `center.entity.ts` — Collection center/branch centers
- `group.entity.ts` — Member groups (attached to centers)
- `staff-position.entity.ts` — Staff job position definitions
- `insurance.entity.ts` — Insurance company directory
- `document-type.entity.ts` — Document/collateral type list
- `valuator.entity.ts` — Property valuator/assessor directory
- `newspaper-publish.entity.ts` — Newspapers for legal notice publication
- `business-unit.entity.ts` — Business unit/cost center definitions
- `department.entity.ts` — Department hierarchy
- `committee-group.entity.ts` — Committee/board group types
- `credit-analysis-title.entity.ts` + `credit-analysis-option.entity.ts` — 5C credit factor setup
- `old-credit-analysis.entity.ts` — Legacy 5-criteria credit scoring (member + loan linkage)
- `new-credit-analysis.entity.ts` — Modern quantitative credit analysis
- `mortgage-appraisal.entity.ts` + `mortgage-appraisal-land.entity.ts` — Land collateral appraisal with kitta parcels
- `additional-withholding.entity.ts` + `withholding-kitta.entity.ts` — Additional loan hold/withholding with land parcel details

### Backend Modules Registered
`BoardMembersModule`, `ExtendedMasterModule` (handles all 11 lookup-style entities + credit analysis titles/options), `CreditAnalysisModule`, `MortgageAppraisalModule`, `AdditionalWithholdingModule`

### Frontend Pages + Registry
- `/board-members` (master group) — Board members CRUD
- `/centers` (master group) — Collection centers CRUD
- `/groups` (master group) — Member groups CRUD
- `/staff-positions` (master group) — Staff positions CRUD
- `/insurance` (master group) — Insurance companies CRUD
- `/document-types` (master group) — Document types CRUD
- `/valuators` (master group) — Valuators/assessors CRUD
- `/newspapers` (master group) — Newspaper publish directory CRUD
- `/business-units` (master group) — Business units CRUD
- `/departments` (master group) — Departments CRUD
- `/committee-groups` (master group) — Committee groups CRUD
- `/credit-analysis-setup` (credit group) — 5C title+option configuration
- `/old-credit-analysis` (credit group) — Legacy 5C credit scoring forms
- `/new-credit-analysis` (credit group) — Modern credit analysis forms
- `/mortgage-appraisal` (collateral group) — Land mortgage appraisals
- `/additional-withholding` (collateral group) — Additional loan withholdings

### New NavGroups Added to Registry
- `credit` — ऋण विश्लेषण (Credit Analysis)
- `collateral` — धितो (Collateral)

## Roadmap

See `docs/MODULE_ROADMAP.md` for legacy → new mapping. **Next up:** Reports, Accounting vouchers, or CRM/Forwarding workflow.
