Read the story

Architecture

Lists every Hybridge app on one board.On Cloud Run, behind IAP.

Anyone with a Hybridge Google account passes IAP and opens any app from one board of 38 projects grouped by status. Four leaders also see Work and History, and one editor changes the cards, each save writing the project and its history entry in a single Firestore transaction.

78 minutes

from the first commit to a working live board on Oct 22

1 editor

moves or edits a card. Four leaders read Work and History, and everyone else sees Apps

38 projects

on one board in panes by status, 22 of them live

21 edits

logged since launch, each with who, when, and every field's old and new value

New York --:-- simulated

An edit, logged
Hybridge Launchpad Anyone with a Hybridge Google account passes IAP and opens any app from one board of 38 projects grouped by status. Four leaders also see Work and History, and one editor changes the cards, each save writing the project and its history entry in a single Firestore transaction. Four leaders Work and History Apps, Work, History dark glass board Welcome tour 9 to 13 stops by role Hybridge staff Apps tab, view only Google IAP one domain only hybridge-launchpad Cloud Run, Next.js 15 Projects Firestore, 38 cards Change history append only One editor drag, hide, add launchpad-requests same image, no IAP projects.json first start only sign in sign in edits signed JWT one write old and new pages first visit same image seeds once GCP hybridge-dashboard, us-central1

Hover a part to trace what it touches. Click it for its notes.

  • Built by me
  • Managed by Google
  • Outside system
  • Main data path
  • On demand
  • Credentials cross

When it breaks

What each failure does, and what it does not do.

  1. The bundle loses Firestore

    A dynamic import in the Next production bundle exposed the Firestore class only under default, so every page failed with 'b is not a constructor'. The loader takes either shape now, and a test covers both.

    lib/store/index.ts:70

  2. The signed header fails

    No valid IAP assertion means no email. The page still loads with the Apps tab, and Work, History and editing stay hidden.

    lib/viewer.ts:75

  3. Two instances seed at once

    The seed uses create(), which fails when the document exists, so a second instance cannot overwrite an early edit.

    lib/store/firestore.ts:56

What I tuned

Small choices that keep it fast and cheap.

  1. Scale to zero

    No minimum instances, at most two, 1 GiB each. Request time for all three services in the project came to under two cents in October.

    scripts/deploy.ps1:263

  2. One store, two homes

    A JSON file on my laptop, Firestore when deployed, behind one small interface the tests fake.

    lib/store/index.ts:36

  3. History without an index

    One project's history is short, so it is sorted in memory instead of with a composite Firestore index.

    lib/store/firestore.ts:105

Guards

Rules the code enforces, not rules people remember.

  1. Signed header, verified

    The email comes only from IAP's signed assertion, checked against Google's keys and this service's audience. The unsigned header is ignored.

    lib/viewer.ts:75

  2. History is append only

    Each save writes the project and its history entry in one transaction. Entries are only ever created.

    lib/store/firestore.ts:87

  3. Deploy refuses a dirty tree

    Cloud Run builds the folder as it is, so the script stops on uncommitted files or any branch but main, then runs the tests and a build.

    scripts/deploy.ps1:141

What it costs

Measured from the Google Cloud billing export, October 1 to 28, net of credits, for the whole project. It holds Launchpad, its request relay and the June board it replaced, whose daily sync job and secrets make up most of the bill. Firestore does not show up at all.

$0.32in October

  • $0.20 Secret Manager, three secrets
  • $0.04 Scheduler, the June sync job
  • $0.04 Cloud Run, jobs and requests
  • $0.04 Image registry