About this site

How it's built

One repository produces two distinct outputs: a static public site and a private layer that is only served after the gate has checked who is asking. Research projects publish into the private layer on their own schedule.

How the public site and the private layer fit togetherThe hub repository builds a public site and, through contract validation, writes private content to a content bucket. Satellite and pulled sources also publish manifests to that bucket. A gate on Cloud Run reads Firestore for the session and access policy before it serves a private object to a signed-in member. Leak checks guard the public build.This repositoryAstro hubContract validationschema · paths · sourceContent bucketprivate objectsSatellitespulled sourcesPublic buildstaticPublic originresearch · CV · writingGateCloud RunSigned-in memberprojects · calendarFirestoresession · groups · rulesPublic guardrailsleak check · allowlist · private-link check
Private content never enters the public output. The same repository builds both sides, but only the gate can serve the private objects.

The hub

The hub is a static Astro site. One build produces the public pages that anyone can read; a second build produces the private pages. The private build is uploaded to a content bucket rather than to the public origin, so a private route has no public object to fetch.

Satellites and pulled sources

Research projects do not have to live in this repository. A satellite repository publishes a versioned manifest and its rendered pages into the content bucket. A pulled source does the same for material that originates elsewhere. In both cases the manifest is validated before anything is uploaded, so a contract break fails the publish instead of producing a half-live project.

The gate

The gate is a small Cloud Run service. It reads the Firebase session, loads the access policy from Firestore, and decides whether the requested object may be served. The same styled not-found response is returned for a missing private page and a forbidden one, so the response cannot be used to discover which private paths exist.

The gate also owns the owner-only Admin area. Admin is never rendered for a non-owner; the route is server-enforced, and every write is audited.

Guardrails

The public build is checked for the titles, summaries, slugs, routes and payload paths of every private item. A publish allowlist limits what may reach the public origin, and a private-link check makes sure every link in the private build resolves under the gate's base. The leak check has its own self-test: a deliberately injected leak must make it fail.