# EpfoService

EPFO / UAN **assisted-lookup** proxy for PPMS crewing — mirrors `GstService`.
Drives the EPFO member portal headlessly (Playwright) to fetch a member record
for a UAN, so Accounts can confirm a crew member's EPF details against the source.

## Why it differs from GstService

- The GST portal has an anonymous **captcha** lookup. The EPFO member portal does
  not — "Know your UAN" is gated by an **OTP to the member's registered mobile**.
  So the handshake is two steps (`/otp` then `/verify`).
- **Aadhaar is out of scope.** UIDAI restricts Aadhaar verification to licensed
  AUA/KUA via consented e-KYC; it cannot be portal-scraped. PPMS keeps Aadhaar
  **assisted-manual** (stores only the last 4 digits, masked).

## Endpoints

| Method | Path | Body | Returns |
|---|---|---|---|
| GET  | `/health` | — | `{ status, mode, sessionCount }` |
| POST | `/otp`    | `{ uan }` | `{ sessionId, mobileHint }` |
| POST | `/verify` | `{ sessionId, uan, otp }` | `{ matched, name, status }` |

## Modes

- **Stub (default):** `EPFO_LIVE` unset/`false`. Deterministic responses — OTP
  `000000` → matched member, anything else → not matched. Lets the app
  integration run end-to-end in dev/CI without the live portal.
- **Live:** `EPFO_LIVE=true`. Drives the real portal. **The page selectors and the
  OTP/captcha flow are marked `TODO(live)` and must be validated against a real
  session before enabling** — the portal layout is the source of truth.

## Env

```
PORT=3004
SESSION_TTL_MS=300000
EPFO_LIVE=false
EPFO_PORTAL_URL=https://unifiedportal-mem.epfindia.gov.in/memberinterface/
```

## Run

```
pnpm install
pnpm dev      # tsx watch
# or
pnpm build && pnpm start
```

The PPMS app reaches it via `EPFO_SERVICE_URL` (proxied through `/api/epfo`).
