Frontend
The admin portal and the client websites.
The portal
platform-portal is the admin tool journalists file copy in, mostly in Arabic and on
deadline.
Data flows one way: service → query hook → component.
src/services/: all HTTP goes through one client. Nothing fetches outside this layer.src/hooks/queries/: TanStack Query wrappers. All server state lives here.src/mappers/: transform API responses before a component sees them.src/components/: consume hooks.
Right-to-left is the default
Most tenants run the portal in Arabic. Use logical CSS properties, always:
| Not this | This |
|---|---|
pl-4 / pr-4 | ps-4 / pe-4 |
ml-2 / mr-2 | ms-2 / me-2 |
left-0 / right-0 | start-0 / end-0 |
text-left | text-start |
Do not reach for rtl:flex-row-reverse to fix a position. If something sits on the wrong
side, a physical property below it is almost always the cause, and reversing the container
moves everything, including what was already right.
Two cases do need direction-aware values: transforms (-translate-x-1/2 rtl:translate-x-1/2)
and directional icons (rtl:rotate-180).
Test both directions, and assert on geometry, not class names.
One image, any tenant
The portal reads NEXT_PUBLIC_* values at runtime, not at build time. One image serves any
tenant, and the API URL is set on the container.
Client websites
A client website is a Next.js app that asks the Public API for a page and renders its widgets.
It dispatches on each widget’s style, and a style with no component renders nothing. See
Application Architecture.
The shared @mangopulse/* packages come from a private registry. Installing them needs a
classic GitHub token with read:packages.