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
9.0 KiB
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
- Browser sends
POST /mobile/api/auth/loginwith{email, password}to V1 Mobile. - V1 Mobile proxies the request to UmmahID service (
falah_ummahid:3000). - UmmahID looks up user in SQLite (
/data/ledger.db), compares password with bcrypt. - If valid, UmmahID returns a JWT token + user info.
- V1 Mobile then finds or creates a local
Userrecord in its own SQLite (/app/data/dev.db) for app features (wallet balance, gamification, etc.). - 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_ummahidcontainer 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
usersoraccountstables in SQLite.
Changing the Demo Password
# 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_hashcolumn 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
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
# 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:
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
docker logs falah_ummahid.1.<id> 2>&1 | grep selfheal
# Expected: "✓ Demo user OK — password matches, tier is premium"
6.5 V2 Community Health
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:
- Unified all references to
demo123. - Deleted
password_hashcolumn from Postgresuserstable. - Locked self-heal as single source of truth.
- 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.