Logo Lanfrica

AyaHA20/Casbah

Domaine:

digital infrastructure

Type de record:

software
Créateur:
Aya
Hôte:
COD e-commerce platform for Algerian clothing shops — storefront + admin order dashboard. React, TypeScript, Express, Prisma, Supabase,PostgreSQL. # Casbah A cash-on-delivery storefront and admin dashboard for small clothing shops in Algeria, built around how these shops actually sell: no online payment, orders confirmed by phone, and a high return rate that the software has to treat as normal rather than exceptional. The dashboard is the real product — it replaces the shop owner's WhatsApp thread and paper notebook. --- ## Live | | | |---|---| | **Storefront** | *(add your Vercel URL)* | | **Dashboard** | *(add your Vercel URL)*`/admin/login` | | **Demo login** | `demo@casbah.dz` / `demo1234` | The demo account is **read-only**: it can browse orders, products and stock, but every write is refused by the server. Enforcement lives in `server/src/middleware/reject-read-only.ts`, not in the UI, so hiding a button is not what protects the data. --- ## Screenshots | Storefront | Product page | |---|---| | | | | Orders | Order detail | |---|---| | | | | Stock | Arabic (RTL) | |---|---| | | | --- ## Stack **Client** — React · Vite · TypeScript · Tailwind v4 (CSS-first `@theme`, no config file) · React Router **Server** — Node · Express 5 · TypeScript · Zod · JWT · bcrypt **Data** — PostgreSQL (Neon) · Prisma 7 with the `prisma-client` generator and the `@prisma/adapter-pg` driver adapter **Storage** — Supabase Storage, uploaded to directly from the browser via signed URLs so the service-role key never leaves the server **Deploy** — Vercel (client) · Railway (API) French and Arabic throughout, with full RTL. Mobile-first: most traffic here is phones. --- ## Three decisions worth reading about ### 1. Prices are never taken from the client The order payload carries no prices at all — no `unitPrice`, no `subtotal`, no `shipping`, no `total`. Zod strips unknown keys by default, so a request that helpfully includes `"total": 1` has it discarded before any code could read it, and the order service never touches `req.body` for money. Every figure is looked up server-side: the unit price from …