The problem
A generic storefront template that spoke Arabic as an afterthought and could not tell the brand’s story. Every photo and banner change went through a developer, images lived in chat threads and USB sticks, distributor enquiries arrived by WhatsApp with no record, and the admin login was shared.
What we built
Angular 20 with Signals and OnPush, Home, About and Contact prerendered through SSR. Catalogue with category and brand filters, product pages with gallery, specifications and related products, and a contact form that actually records the enquiry.
Marketing runs the site themselves now. A MinIO media library with folders and drag-and-drop, hero slides and USPs reordered from the CMS, and 35 permissions deciding who can touch what, checked at the route and again at the API.
Inside the system
- Arabic-first with a full English mode. 736 keys per language, parity enforced in CI.
- Hash-based CSP, XHR-only cookie sessions, JWT with refresh tokens.
- A rate-limit policy on every mapped route, with a test that fails if one is missing.
- Soft deletes on catalogue data; the production seed refuses weak admin passwords.
- Playwright end-to-end suite; Docker behind Nginx with Let’s Encrypt.
Screens