Files
falah-mobile/docs/auth-architecture-reference.md
T
wmj 5b08f8b041 docs: add system auth architecture reference (28 June 2026)
Comprehensive document covering:
- Auth chain (how login works end-to-end)
- Three-database architecture (UmmahID SQLite, V1 Mobile SQLite, Postgres)
- Password management (self-heal = single source of truth)
- FLH Islamic Finance endpoints and data flow
- Testing checklist for future verification
- Troubleshooting history
2026-06-28 21:29:54 +02:00

250 lines
9.0 KiB
Markdown

# Falah Mobile — System Reference & Auth Architecture
> **Last updated:** 28 June 2026
> **Purpose:** Single source of truth for understanding the database architecture, auth chain, password management, and FLH Islamic Finance setup across all FalahOS services.
---
## 1. Auth Chain (How Login Works)
```
Browser ──POST /mobile/api/auth/login──▶ V1 Mobile (Next.js)
Proxy to UmmahID
UmmahID (Node.js)
SQLite ledger.db
bcrypt.compare(password, hash)
┌─────┴─────┐
▼ ▼
✅ 200 ❌ 401
(JWT) (Invalid credentials)
```
### Detailed flow
1. Browser sends `POST /mobile/api/auth/login` with `{email, password}` to V1 Mobile.
2. V1 Mobile proxies the request to UmmahID service (`falah_ummahid:3000`).
3. UmmahID looks up user in **SQLite** (`/data/ledger.db`), compares password with bcrypt.
4. If valid, UmmahID returns a **JWT** token + user info.
5. V1 Mobile then **finds or creates** a local `User` record in its own SQLite (`/app/data/dev.db`) for app features (wallet balance, gamification, etc.).
6. Browser receives the JWT and uses it for subsequent API calls.
---
## 2. Database Architecture (Three Databases)
### 2.1 UmmahID SQLite — `ledger.db`
| Property | Value |
|----------|-------|
| **Container** | `falah_ummahid` (Swarm service) |
| **Path** | `/data/ledger.db` |
| **Host bind** | `/root/falah-ummahid-db/ledger.db` |
| **Engine** | sql.js (SQLite via Node.js) |
| **Auth** | **Yes** — single source of truth for passwords |
| **Tables** | `users`, `accounts`, `transactions`, `zakat_*`, `sadaqah_*`, `hibah_records`, `waqf_*`, `forum_*`, `learn_*` |
**Password column:** `password_hash` (bcrypt hash)
**GOOGLE_CRITICAL:** This is the **only** place where passwords are verified. The self-heal script (`startup-selfheal.js`) is the **sole authority** for the demo user's password.
### 2.2 V1 Mobile SQLite — `dev.db`
| Property | Value |
|----------|-------|
| **Container** | `falah_falah-mobile` (Swarm service) |
| **Path** | `/app/data/dev.db` |
| **Engine** | Prisma with SQLite provider |
| **Auth** | **No**`passwordHash` field is NULL for all users |
| **Tables** | `User`, `Listing`, `Purchase`, `Review`, `LearnCourse`, `ForumPost`, etc. |
**Password column:** `passwordHash` (always NULL — not used for auth)
**Purpose:** Stores app-level data: user profile, FLH balance cache, gamification (XP, streaks, levels), marketplace, learning progress, etc.
### 2.3 Postgres — `falahdb` (Community V2)
| Property | Value |
|----------|-------|
| **Container** | `falah_postgres` (Swarm service) |
| **Connection** | `ummahid-community` container via `DATABASE_URL=postgresql://postgres:@falah_postgres:5432/falahdb` |
| **Auth** | **No**`password_hash` column **removed** (28 June 2026) |
| **Tables** | `users`, `accounts`, `zakat_*`, `sadaqah_*`, `hibah_records`, `waqf_*`, `forum_*`, `learn_*` |
**Password column:** ❌ DELETED — this was the source of confusion. Auth is delegated to UmmahID SQLite or JWT verification.
**Purpose:** FLH Islamic Finance engine (zakat, sadaqah, hibah, waqf), community features (content, qard hasan, learn).
---
## 3. Password Management (The Self-Heal Script)
**File:** `/root/falah-ummahid-db/startup-selfheal.js`
**Mount:** Bind-mounted from host `/root/falah-ummahid-db/` → container `/data/`
### Behaviour
- Runs **every time** the `falah_ummahid` container starts.
- Re-hashes the demo password if it doesn't match `DEMO_PASSWORD`.
- Ensures `license_tier = 'premium'`.
- Creates the demo user + account if missing (100,000 FLH).
- **Single source of truth** — nothing else should write to the `users` or `accounts` tables in SQLite.
### Changing the Demo Password
```bash
# 1. Edit the self-heal script
vim /root/falah-ummahid-db/startup-selfheal.js
# Change: DEMO_PASSWORD='***'
# 2. Restart the UmmahID service
docker service update --force falah_ummahid
# 3. Done — no other database needs updating
```
### What NOT to do
- ❌ Do NOT write directly to SQLite `users.password_hash`
- ❌ Do NOT add `password_hash` column back to Postgres
- ❌ Do NOT run seed scripts that write passwords to Postgres
---
## 4. FLH Islamic Finance Architecture
### 4.1 Endpoints
| Category | V1 Mobile Proxy Route | V2 Community Backend Route |
|----------|----------------------|---------------------------|
| **Summary** | `/mobile/api/flh/summary` → | `/api/v2/flh/summary` |
| **Zakat** | `/mobile/api/flh/zakat/*` → | `/api/v2/zakat/*` |
| **Sadaqah** | `/mobile/api/flh/sadaqah/*` → | `/api/v2/sadaqah/*` |
| **Hibah** | `/mobile/api/flh/hibah/*` → | `/api/v2/hibah/*` |
| **Waqf** | `/mobile/api/flh/waqf/*` → | `/api/v2/waqf/*` |
| **Cron Health** | — | `/api/v2/flh/cron-health` |
### 4.2 Data Flow
```
V1 Mobile UI ──▶ V1 Mobile API Route (proxy) ──▶ ummahid-community (Postgres)
JWT auth via:
1. UmmahID API (preferred)
2. Local JWT verify (fallback)
```
### 4.3 Zakat Agents (18 pre-seeded)
Covers 9 countries: UAE, Bangladesh, Egypt, Indonesia, Malaysia, Pakistan, Saudi Arabia, Turkey.
### 4.4 Cron Jobs (6 scripts)
Located in `/root/ummahid-community/cron/`:
| Script | Schedule | Purpose |
|--------|----------|---------|
| `00-health.sh` | Every 15 min | Heartbeat check |
| `10-sadaqah-process.sh` | Every 6h | Process due recurring sadaqah |
| `20-hibah-expiry.sh` | Every 1h | Expire unaccepted hibah gifts |
| `30-waqf-yield.sh` | Daily midnight | Accrue waqf yield |
| `40-nisab-update.sh` | Daily 6am | Update nisab threshold |
| `50-zakat-reconcile.sh` | Weekly Mon 2am | Reconcile zakat pool |
---
## 5. Key Configuration Files
| File | Purpose |
|------|---------|
| `/root/falah-ummahid-db/startup-selfheal.js` | **Self-heal — single source of truth for demo password** |
| `/root/falah-mobile/.env.local` | V1 Mobile env vars (`COMMUNITY_URL`, `UMMAHID_URL`) |
| `/root/ummahid-community/config/community.env` | Community V2 env vars (`JWT_SECRET`, `UMMAHID_HOST`, `DATABASE_URL`) |
| `/root/falah-mobile/src/app/api/flh/zakat/calculate/route.ts` | Zakat calculate proxy (handles `amount=0` as status check) |
| `/root/falah-core/docker/services/ummahid-community/pg.js` | Postgres persistence layer for community V2 |
---
## 6. Testing Checklist
### 6.1 Login Verification
```bash
curl -X POST -H 'Content-Type: application/json' \
-d '{"email":"demo@falahos.my","password":"demo123"}' \
https://falahos.my/mobile/api/auth/login
# Expected: 200 with {"token":"eyJ...", "user":{...}}
```
### 6.2 FLH Dashboard
```bash
# Login first, extract token, then:
curl -H "Authorization: Bearer <token>" \
https://falahos.my/mobile/api/flh/summary
# Expected: {"success":true,"totalFlhBalance":5000,"pillars":{...}}
```
### 6.3 Password Consistency
Check that `password_hash` does NOT exist in Postgres:
```bash
docker exec falah_postgres.1.<id> psql -U postgres -d falahdb \
-c "SELECT column_name FROM information_schema.columns \
WHERE table_name='users' AND column_name='password_hash'"
# Expected: 0 rows
```
### 6.4 Self-Heal Status
```bash
docker logs falah_ummahid.1.<id> 2>&1 | grep selfheal
# Expected: "✓ Demo user OK — password matches, tier is premium"
```
### 6.5 V2 Community Health
```bash
curl -H "Authorization: Bearer <token>" \
https://falahos.my/api/v2/flh/cron-health
# Expected: 200 with health status
```
---
## 7. Troubleshooting History
### 28 June 2026 — Login Failure & Resolution
**Symptom:** `401 Invalid credentials` when logging in with `TestPass123!`.
**Root cause:** Three different passwords across three databases:
- Self-heal script had `DEMO_PASSWORD='falahdemo2026'`
- Postgres had stale hash for `password123`
- User expected `TestPass123!`
**Fix:**
1. Unified all references to `demo123`.
2. Deleted `password_hash` column from Postgres `users` table.
3. Locked self-heal as single source of truth.
4. Updated all debug scripts, seed files, and test suites.
### Previous — JWT_SECRET Mismatch
**Symptom:** Auth worked then failed after container restart.
**Root cause:** `falah_ummahid` used 64-char JWT_SECRET, but `ummahid-community` had a different one.
**Fix:** Harmonized JWT_SECRET across all services to the 64-char value from `falah_ummahid`.
---
> **⚠️ Golden Rule:** Auth = UmmahID SQLite. Postgres has NO password_hash. The self-heal script is the ONLY authority for the demo password. Do not add password storage anywhere else.