Skip to content
Case study · 01 / 09← All work

Vimo

One site, one portal and one login for a suite of SaaS products for small businesses in Argentina.

Role
Design implementation, architecture and frontend
Stack
Next.js 16, React 19, TypeScript, Clerk, Turborepo, Playwright
Public site
Public siteOne login across subdomains
(01) The problem

Vimo groups seven products, and each one lived in its own repo. There was no site that sold them together, no portal after sign-in and no shared brand. The design repeated each product's price and color on four different screens.

My roleI turned a design handoff into a working monorepo and made the products share one login.
(02) ResultsCounted in the code
7products defined once, in one shared catalog
5shared packages used across the apps
59Playwright tests, on desktop and at 375px
(03) Architecture

Three decisions that shaped it.

  1. 01

    One login across subdomains

    Why. Each product deploys on its own subdomain. One Clerk instance shares the session through the parent domain. The contracted modules travel in the session token, so apps check access without a database call.

    Trade-off. The token has a size limit, so only module ids go in it. A product on its own domain stays outside the shared login.

  2. 02

    Brand and pricing as code, not copy

    Why. Colors, names and prices live once in TypeScript packages. The pricing calculator and the plan recommender call the same pure functions. Design tokens compile to CSS, so a React Native app can import the same values later.

    Trade-off. Tokens need a generation step. If someone edits the TypeScript and skips it, the CSS is stale.

  3. 03

    Local dev on subdomains, not ports

    Why. Browsers share cookies across ports, so a login test on localhost passes for the wrong reason. A Caddy proxy serves each app on a vimo.localhost subdomain. Tests now see the same cookie rules as production.

    Trade-off. Running locally needs Docker and a few more steps. The E2E suite also starts four sibling repos.

(04) GalleryKeep scrolling →
Public site
Public site · The home page that sells the suite. Product data comes from the shared catalog.
Pricing calculator
Pricing calculator · Prices are computed by the same functions that power the plan recommender.
Portal after sign-in
Portal after sign-in · Contracted products link to their app. The rest link to a page that prices the add-on.
Nivel, inside the suite
Nivel, inside the suite · The stock and point-of-sale product keeps its own UI and embeds the shared product switcher.
(05) What I'd do next
01Add CI. The repo has no workflow, so typecheck, lint, unit tests and the 59 E2E tests only run by hand.
02Sync contracted modules from billing to Clerk with a webhook. Today they are set by hand through the API.
03Move NEXORA onto the shared auth and shell packages. It joined the workspace but still uses its own login.
Next project · 02 / 09
Reality Graph →An interactive knowledge graph in 3D, in English and Spanish
Case study · 01 / 09

Vimo

One site, one portal and one login for a suite of SaaS products for small businesses in Argentina.

Role
Design implementation, architecture and frontend
Stack
Next.js 16, React 19, TypeScript, Clerk, Turborepo, Playwright
Vimo
(01) The problem

Vimo groups seven products, and each one lived in its own repo. There was no site that sold them together, no portal after sign-in and no shared brand. The design repeated each product's price and color on four different screens.

My roleI turned a design handoff into a working monorepo and made the products share one login.
(02) Results
7products defined once, in one shared catalog
5shared packages used across the apps
59Playwright tests, on desktop and at 375px
(03) Architecture

Three decisions that shaped it.

01

One login across subdomains

Why. Each product deploys on its own subdomain. One Clerk instance shares the session through the parent domain. The contracted modules travel in the session token, so apps check access without a database call.

Trade-off. The token has a size limit, so only module ids go in it. A product on its own domain stays outside the shared login.

02

Brand and pricing as code, not copy

Why. Colors, names and prices live once in TypeScript packages. The pricing calculator and the plan recommender call the same pure functions. Design tokens compile to CSS, so a React Native app can import the same values later.

Trade-off. Tokens need a generation step. If someone edits the TypeScript and skips it, the CSS is stale.

03

Local dev on subdomains, not ports

Why. Browsers share cookies across ports, so a login test on localhost passes for the wrong reason. A Caddy proxy serves each app on a vimo.localhost subdomain. Tests now see the same cookie rules as production.

Trade-off. Running locally needs Docker and a few more steps. The E2E suite also starts four sibling repos.

(04) Gallery
Public site
Public site · The home page that sells the suite. Product data comes from the shared catalog.
Pricing calculator
Pricing calculator · Prices are computed by the same functions that power the plan recommender.
Portal after sign-in
Portal after sign-in · Contracted products link to their app. The rest link to a page that prices the add-on.
Nivel, inside the suite
Nivel, inside the suite · The stock and point-of-sale product keeps its own UI and embeds the shared product switcher.
(05) What I'd do next
01Add CI. The repo has no workflow, so typecheck, lint, unit tests and the 59 E2E tests only run by hand.
02Sync contracted modules from billing to Clerk with a webhook. Today they are set by hand through the API.
03Move NEXORA onto the shared auth and shell packages. It joined the workspace but still uses its own login.
Next projectReality Graph →
Nahuel SantillánEN