docs: add project brief and fix request route types

This commit is contained in:
Replit Agent
2026-06-06 16:23:08 +03:00
parent c089f41b68
commit 94ccbf6fe4
2 changed files with 58 additions and 9 deletions
+1 -1
View File
@@ -116,7 +116,7 @@ router.get("/requests/:id", (req: Request, res: Response): void => {
// ─── Helper: find & update ────────────────────────────────────────────────────
function findAndUpdate(
id: string,
id: string | string[],
updater: (r: DonationRequest) => void,
res: Response
): void {
+57 -8
View File
@@ -3,6 +3,9 @@
> 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
@@ -40,15 +43,20 @@ This is a POC/demo: data is **in-memory mock data** (no real database, no real p
(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/ehsan-poc/src/App.tsx` — UI root: routing (wouter) + all context providers.
- `artifacts/api-server/src/routes/``health`, `requests`, `donors`, `stats`,
`whatsappLog`. Mounted in `routes/index.ts`.
- `artifacts/api-server/src/routes/requests.ts` — **the closed-loop logic and every
status transition** live here.
- `artifacts/api-server/src/lib/mockDb.ts` — types, in-memory seed data, the
`STATUS_STEP` map, and `checkEligibility`.
- 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)
```bash
pnpm install
pnpm --filter @workspace/api-server run dev # API
pnpm --filter @workspace/api-server run dev # API (port 5000 in dev)
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
@@ -57,6 +65,13 @@ 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`.
> **Apple Silicon caveat:** a full `pnpm run build` typechecks all packages but the
> `vite build` step fails locally on darwin-arm64 with
> `Cannot find module @rollup/rollup-darwin-arm64`. That is **by design** — the
> workspace `overrides` in `pnpm-workspace.yaml` strip every non-`linux-x64-gnu`
> native binary so the Docker (`linux/amd64`) build stays clean. The real build runs
> inside Docker; locally the `typecheck` result is the meaningful gate.
## 5. How it runs in production (Mac Mini, Docker)
Two services in `docker-compose.yml`:
- `api` — Express, internal only, listens on `PORT=8080`, healthcheck `/api/healthz`.
@@ -72,24 +87,58 @@ App is then served on the Mac Mini at `http://localhost:8080` (override with `WE
## 6. Deployment flow (how code travels)
```
Edit code → commit → push to Gitea (remote name: gitea, branch: main)
Edit code → commit → push to Gitea (branch: main)
→ on Mac Mini run ./deploy.sh → Docker rebuilds & restarts
```
- Central repo is **Gitea** (no GitHub). Remote name everywhere is `gitea`, branch `main`.
- Central repo is **Gitea** (no GitHub), branch `main`. The documented remote name is
`gitea`; on this Mac Mini checkout the remote may be named `origin` but still points
at the Gitea host — verify with `git remote -v`.
- `scripts/push-to-gitea.sh` pushes from a dev machine; `deploy.sh` redeploys 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`.
edit → test → `pnpm run build``git commit``git push <gitea-remote> main``./deploy.sh`.
## 7. Hard rules / gotchas — do NOT break these
## 7. Status lifecycle (create → close)
The case `status` (`RequestStatus`) and its step number (`STATUS_STEP` in `mockDb.ts`):
```
new (1)
→ pending_review (2)
→ verified (3)
→ published (4)
→ donated (5) ← reached ONLY when fully funded
→ delivered (6)
→ receipt_confirmed (7)
→ thank_you_submitted (8)
→ whatsapp_sent (9)
→ closed (10)
rejected (side path, step 2)
```
- **Eligibility on creation:** `POST /requests` checks `nationalId` via
`checkEligibility` → eligible ⇒ `verified`, not eligible ⇒ `rejected`, unknown ⇒
`pending_review`.
- **API transition endpoints:** `verify`, `publish`, `donate`, `deliver`,
`confirm-receipt`, `thank-you`, `send-whatsapp`, `close`, `reject`
(`POST /requests/:id/<action>`).
- **`donate` is the heart of the closed loop:** it only accepts donations while the
case is `published`, clamps each donation to the remaining amount
(`applied = min(amount, requestedAmount collectedAmount)`), and advances the case
to `donated` only once `collectedAmount >= requestedAmount`.
## 8. 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 use `node:24-bookworm-slim` (glibc, not
alpine) and `platform: 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.
- **Funding rule (Closed Donation Loop).** Donations accumulate and clamp to the
target; a case can never be over-funded and enters the fulfillment pipeline
(`donated` and beyond) 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.
- **Same-origin API.** The browser calls `/api/...` on the same domain (nginx proxies
it to the `api` service). Never add a separate frontend API URL.
- **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`.
@@ -101,7 +150,7 @@ Edit code → commit → push to Gitea (remote name: gitea, branch: main)
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
## 9. 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.