WORK INDEX
EMAIL ME
OWN PRODUCT  ·  IN BETA  ·  2026

The clientnever signs in.

Give a client one place to check what is done, what happens next and what needs their input.

FOR STUDIOS KEEPING CLIENTS INFORMED

An independent product. My role: design, development and deployment.

View the mvp / product build package · from $7,500 →
PRODUCT
Sightline
ROLE
Design, build & launch
AUTH
Magic link, no passwords
STACK
Next.js 16 · Prisma
DATA
Postgres · Neon
A Sightline client page, showing the decision and the requests waiting on the client
01  THE PROBLEM

A project update should be easy to find.

A client wants to know three things: is it moving, what happens next, and is it waiting on them. Finding those answers across a project board and an email thread takes effort. Sightline puts the current status, decisions and requests together on one page.

The constraint arrived before the design did. The client cannot be asked to make an account. That deletes the obvious answers in one go: no invitations, no seats, no notification settings, no second product for them to learn. Everything else in the system follows from it.

The constraint I set: if the client has to remember anything to read this page, it has already failed. Not a password, not a login, not which tool the project lives in.
02  ARCHITECTURE

Two surfaces, one database, and a password on neither.

The studio side sits behind a magic link. The client side is one server-rendered page at /p/<slug>. The link grants access to that project, so anyone holding it can use the client page. There is no separate API tier. The studio's own pages are server-rendered already, so an HTTP layer in front of Postgres would have been a second place to write the same authorisation check.

That makes authorisation the design. The client can do exactly two things: mark a request done and decide an approval. Both use the project link, and the server scopes each action to that project. On the studio side, each child-row write carries the owning project and user in the same where clause. The permission check and the write are checked together.

The sign-in email links to a page with a button on it, not straight to the verify endpoint. Verification happens after that button is pressed, so simply opening the landing page does not consume the sign-in token. The stored tokens are hashed.

FIG. 02.1 / SYSTEM
CLIENT PAGE
no account
SERVER ACTIONS
slug-scoped
PRISMA
typed
POSTGRES
source of truth
THE CLIENT'S ONLY TWO WRITES TAKE A SLUG AND NEVER A SESSION
EVERY STUDIO WRITE CARRIES ITS OWN AUTHORISATION IN THE WHERE CLAUSE
03  DATA MODEL

Five tables, and the rules worth having are constraints.

A client reads the page as a record of what was agreed. The schema's job is to stop that record and the interface disagreeing. Anything derivable is derived, and anything that has to happen together happens in one transaction.

projects
A unique slug identifies the project and grants access to its client page. Progress is calculated from the milestones, with a nullable override when a different status needs to be shown.
approvals
One row per project, and a unique constraint on the project id is what enforces it, not a check in the app. Two decisions competing for the same answer cannot be stored.
project_updates
The history the client reads. Deciding an approval writes the decision and its history entry in one transaction, so a decision can never exist without the line that explains it.
milestones
Ordered, each with one line of description and a done, active or todo state. Progress scores a complete milestone one and an active one a half, so the percentage cannot disagree with the timeline printed under it.
requests
What the studio is waiting on, marked blocking or when-you-can. Completing one is an update guarded on the done timestamp still being null, so a second tap from the client changes nothing.
04  STACK MANIFEST
CLIENT
Next.js 16 · React 19 · Server Components · Tailwind 4
SERVER
Server Actions · Better Auth · magic link
DATA
Postgres · Prisma 7 · Neon
SERVICES
Vercel · Resend
Need a simpler way to keep clients informed?