Rakezum
A multi-tenant CRM and marketing-automation platform for agencies in Saudi Arabia. Arabic-first and fully right-to-left, with tenant isolation enforced by the database rather than by application code. Live, and still shipping.
- screens, each in Arabic and English
- 47screens, each in Arabic and English
- row-level security policies
- 38row-level security policies
- tests against a real database
- 140tests against a real database
- Engagement
- Web & API development, since 2026
- Sector
- SaaS / Marketing automation
- Duration
- Since 2026, ongoing
- Stack
- Next.jsFastifyPostgreSQLDocker
What I walked into
An agency signs up, then creates sub-accounts for each of its own clients. Every sub-account is a separate business, and no user may ever see another sub-account's contacts, deals or conversations. That is the whole backbone of the product, and it is also the thing that quietly destroys platforms like this: the usual approach is to filter by tenant in application code, which works until one query somewhere is missing its filter. Nobody notices, because nothing breaks. One day a customer sees a stranger's contact list.
The second constraint was the language. Arabic-first is not a stylesheet flip late in the build. Every screen mirrors, the numerals change, the icons and the chart axes reverse, and all of it has to hold in light and dark. Retrofitting that onto a finished English product is a rewrite, so it had to be designed in from the first screen.
What I did about it
Tenancy is enforced in Postgres with Row-Level Security: 38 policies across every business table. The API connects as a role that physically cannot read across tenants, so a missing filter in application code returns an empty result instead of somebody else's data. The failure mode is a visible bug rather than a silent breach. Cross-tenant tests run against a real Postgres, not a mock, because a mock would have happily passed either way.
47 screens were built from the Figma, each one in Arabic right-to-left and English left-to-right, in light and dark. A script walks all of them in both languages and both themes and flags any text below a readable contrast ratio, which is how a dark-on-dark button that looked fine in the design was caught before the client saw it.
The stack is self-hosted on one server with Docker Compose: Caddy for TLS and HSTS, Postgres 17, Logto for authentication, Valkey for rate limits. Only the reverse proxy publishes a public port, because Docker-published ports bypass the firewall and that is an easy way to expose a database without realising.
One bug is worth describing, because finding it is the job. After roughly ten days signed in, every page started failing. Logto had rotated the refresh token, which it does by default at 70% of the token lifetime, and server-side rendering could not save the replacement, so the stored token was dead and every request died with it. It was invisible until it had happened 43 times in the logs. The fix was to turn off rotation for that application and route any token failure to a clean sign-in instead of a crash, then prove it by shortening the token lifetime to 60 seconds and reproducing the whole thing on the live system.