Create `hammam-dev.md` at the repository root, containing a comprehensive English-language project brief for the EHSAN "Closed Donation Loop" POC, including tech stack, repo structure, and development/production run instructions. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 1fa9329f-0cec-4a2f-80e8-e26dbae3142e Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 365a3c6c-f69d-49c2-b185-bef6f758fdf7 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/4d696b13-86f2-4c9d-be0d-95b293430047/1fa9329f-0cec-4a2f-80e8-e26dbae3142e/Q5tQff9 Replit-Helium-Checkpoint-Created: true
6.1 KiB
Hammam Dev — EHSAN "Closed Donation Loop" (POC)
Onboarding brief for any developer or AI coding agent (e.g. OpenClaw) taking over this project. Read it fully before editing. The repo is hosted on a self-hosted Gitea server and runs on a Mac Mini via Docker.
1. What this product is
A bilingual (Arabic / English, full RTL + LTR) proof-of-concept charity donation web app inspired by the Saudi "EHSAN" (إحسان) platform. Its core idea is a Closed Donation Loop:
- Beneficiaries submit support requests (housing, food, electricity, water, health, court-ordered debt, appliances like A/C & refrigerator, etc.).
- Each request/opportunity has a funding target. Donations from multiple donors accumulate and are clamped to the target — a case can never be over-funded.
- A case only enters the "closed loop" fulfillment pipeline once it is fully funded. This is the central business rule. Do not break it.
- After funding, the flow continues to confirmation / tracking, and a simulated WhatsApp notification log records donor/beneficiary messaging.
This is a POC/demo: data is in-memory mock data (no real database, no real payments).
2. Tech stack
- Monorepo: pnpm workspaces, Node.js 24, TypeScript 5.9.
- Web app (
artifacts/ehsan-poc): React + Vite + wouter (routing) + TanStack Query (data) + Tailwind CSS + shadcn/ui components. - API (
artifacts/api-server): Express 5, all routes mounted under/api, health at/api/healthz. Data lives insrc/lib/mockDb.ts(in-memory; resets on restart). - Shared libs under
lib/:api-spec(OpenAPI source of truth),api-client-react(generated React Query hooks),api-zod(Zod schemas),db(Drizzle schema, not active at runtime since data is in-memory). - All workspace libs export TypeScript source directly (
./src/index.ts) — no lib pre-build step; Vite/esbuild consume the source.
3. Repo map
artifacts/ehsan-poc/src/pages/— screens: home, about, waqf, baraem, request, opportunities, donate/:id, cart, login, admin, track/:id, thank-you/:id, whatsapp-log, not-found.artifacts/ehsan-poc/src/contexts/—LanguageContext(ar/en + RTL),CartContext(multi-case donation cart),AuthContext(mock admin login).artifacts/ehsan-poc/src/components/—Riyal.tsx(renders the NEW Saudi Riyal symbol via an image mask),layout/(Header, AppLayout),ui/(shadcn components).artifacts/api-server/src/routes/—health,requests,donors,stats,whatsappLog. Mounted inroutes/index.ts.- Root deploy files:
Dockerfile.web,Dockerfile.api,docker/nginx.conf,docker-compose.yml,deploy.sh,scripts/push-to-gitea.sh,DEPLOYMENT.md.
4. How to run locally (development)
pnpm install
pnpm --filter @workspace/api-server run dev # API
pnpm --filter @workspace/ehsan-poc run dev # Web (needs PORT and BASE_PATH env)
pnpm run typecheck # full typecheck
pnpm run build # typecheck + build everything
Note: vite.config.ts REQUIRES PORT and BASE_PATH env vars even for build
(it throws otherwise), e.g.
PORT=8080 BASE_PATH=/ pnpm --filter @workspace/ehsan-poc run build.
5. How it runs in production (Mac Mini, Docker)
Two services in docker-compose.yml:
api— Express, internal only, listens onPORT=8080, healthcheck/api/healthz.web— nginx that serves the built Vite SPA and reverse-proxies/api/toapi:8080. The browser always calls same-origin/api/..., so there is NO frontend API URL to configure.
Deploy / redeploy on the Mac Mini:
./deploy.sh # git pull gitea main → docker compose down → build → up -d
App is then served on the Mac Mini at http://localhost:8080 (override with WEB_PORT).
6. Deployment flow (how code travels)
Edit code → commit → push to Gitea (remote name: gitea, branch: main)
→ on Mac Mini run ./deploy.sh → Docker rebuilds & restarts
- Central repo is Gitea (no GitHub). Remote name everywhere is
gitea, branchmain. scripts/push-to-gitea.shpushes from a dev machine;deploy.shredeploys on the Mac Mini.- An AI agent working directly on the Mac Mini clone should use this loop:
edit → test →
git commit→git push gitea main→./deploy.sh.
7. Hard rules / gotchas — do NOT break these
- amd64 / glibc ONLY. The pnpm workspace strips every native binary that is not
linux-x64-gnu. Docker build stages MUST usenode:24-bookworm-slim(glibc, not alpine) andplatform: linux/amd64(runs under Rosetta on Apple Silicon). Do not switch the build base to alpine or arm64 — rollup / tailwind-oxide / lightningcss will fail to find native binaries. - Funding rule. Donations accumulate and clamp to the target; a case enters the fulfillment pipeline only when fully funded. Preserve this.
- Bilingual + RTL. Every user-facing string must exist in both Arabic and English
via
LanguageContext. Don't hardcode single-language text. Keep RTL layout working. - Currency. Saudi Riyal uses the new official symbol rendered by the
<Riyal/>component (image mask), not the old "ر.س"/"SAR" text. Reuse<Riyal/>. - Routing base. The app is mounted under a base path via
import.meta.env.BASE_URL. Use it for routes/links; never hardcode root-relative/apiin a way that escapes the base — call same-origin/api/...through the proxy. - Data is ephemeral. mockDb is in-memory; restarting the
apicontainer resets it. If you add persistence, add a database service todocker-compose.ymlaccordingly. - HMR quirk (dev): if you see "useLanguage must be used within a LanguageProvider" while the code is correct, it's stale Fast Refresh state — restart the web dev server.
- Always run
pnpm run build(typecheck + build) before pushing to catch type errors.
8. Suggested first task for a new agent
Read DEPLOYMENT.md, artifacts/ehsan-poc/src/App.tsx, and
artifacts/api-server/src/routes/index.ts to confirm the routes and data model, then
summarize your understanding of the funding / closed-loop flow before making any change.