Skip to content
Fusion

Flatbox — an integrated service

Flatbox is an app in the sidebar like any other, but it's different in one important way: its data lives in a separate service, not this app's database. Where ProcessN and the other domains are in-process (the app owns their tables and rules), Flatbox is reached over HTTP, and it computes its own permissions. It's the example's blueprint for "wire in a system you don't own."

Flatbox is a (lightly modelled) document-review system: BIM/drawing review sessions, the packages and documents in them, and review comments. The app shows read-only views of all of it.

Coming from Django? This is the difference between a model you query directly and a third-party API you call with requests and a token — except the call is a server function and the remote service tells you what the user may edit.

Where it lives

LayerFiles
Routessrc/routes/_authed.flatbox.projects.tsx · …sessions.tsx · …packages.tsx · …comments.tsx
Server functionssrc/lib/flatbox-integration-server.ts (HTTP → the Flatbox server)
Tablesnone in this app — Flatbox owns its own database
The other serviceexample/flatbox/ (a separate TanStack Start app + DB)

The seam: HTTP + a delegated permission flag

A Flatbox page loader calls a server function, which makes an authenticated HTTP request to the Flatbox server with a Bearer API token. The response already says, per row, what the user may do:

Loading diagram...

So authorization is delegated: this app doesn't replicate Flatbox's rules, it trusts the canEdit the other service computed. (The in-process domains are the opposite — this app enforces everything itself.) Users map by email: the Flatbox seed creates accounts with the same emails as the main seed, so the token's Flatbox user lines up with a real Portfolio login. The wired-up demo user is Sara Lindqvist (sara.lindqvist.tikab@p4o.se).

It degrades gracefully

Like every capability, the integration is safe when it isn't configured:

  • No FLATBOX_API_TOKEN → the server function returns 503 with a hint to run bun run db:seed:flatbox.
  • Flatbox unreachable502 ("is bun run dev:flatbox running?").
  • On the dashboard, the Flatbox card swallows any failure and yields nothing, so one down integration never breaks the page. Because it's the slow, cross-server card, the dashboard streams — fast in-process cards render first, the Flatbox card arrives after.

Run it

Flatbox uses the same Postgres server as the app, in a separate database:

docker compose up -d postgres   # shared Postgres
bun run db:create:flatbox       # create the flatbox database
bun run db:migrate:flatbox      # apply its migrations
bun run db:seed:flatbox         # seed it — prints FLATBOX_API_TOKEN at the end
bun run dev:flatbox             # serve Flatbox on http://localhost:3100

Paste the values the seed prints into the main app's .env.local, then start it:

example/.env.local
FLATBOX_API_URL=http://localhost:3100
FLATBOX_API_TOKEN=fbx_demo_integrated_sara_0123456789abcdef

bun run dev, sign in, and the Flatbox nav group lists Sara's projects, review sessions, packages and comments — read-only, scoped by Flatbox itself.

Extending it

  • A new Flatbox view → add a route + a server function that calls another Flatbox endpoint; render the rows read-only, honouring the canEdit flags it returns.
  • A different external service → copy the shape: a *-integration-server.ts that holds the HTTP calls + token, loaders that call it, graceful 502/503 on failure. The seam is the lesson, not Flatbox itself.
  • Writes → only if the remote service exposes them; never reconstruct its permission rules locally — call it and trust its answer.