Documentation
¶
Overview ¶
Package base is managed Hanzo Base: a hosted backend for your app — collections, records, access rules and sign-in.
It serves that engine per org at /v1/base and /v1/collections, plus the platform's public waitlist at /v1/waitlist.
It is the in-binary replacement for the standalone `ghcr.io/hanzoai/superbase` pod, whose whole job was `base.New()` + serve. cloud already links github.com/hanzoai/base, so it runs the SAME engine in-process across TWO orthogonal lanes:
LANE 1 — the viral waitlist (GTM launch surface). ONE platform Base app
carries the waitlist plugin; its /v1/waitlist/* routes are PUBLIC (a signup
surface has no principal to scope by) and platform-owned (one waitlist per
brand, not customer data). console reads it via WAITLIST_URL=…/v1/waitlist.
LANE 2 — managed Base hosting (what superbase/PocketHost provided). ONE Base
app PER ORG, opened lazily and pooled, each on its OWN SQLite under
{DataDir}/base/{orgSegment}/ — the same "prod = SQLite per tenant" model
(HIP-0302) the NewBase leaves (captable/sign/dataroom) use, so an org's
collections/records are PHYSICALLY isolated. Served AUTHENTICATED under
/v1/base/*, the org resolved from the VALIDATED cloud principal (never a
client header). This is the console Bases manager's backend.
The two lanes are deliberately NOT one app: the waitlist is a public, single, brand-level instance; hosted Bases are private, per-org, and many.
A THIRD prefix, /v1/collections, is served by neither engine above: it is a principal-gated forward to the SEPARATE managed Base deployment that owns the cross-instance `tenants` registry (collections.go). It answers the same question the embed lane does — an org's collections and their records — from a different store, so the two are not interchangeable and one of them is eventually redundant.
MOUNT PREFIX. Base's REST router honours BASE_API_PREFIX (default /v1); this package pins it to /v1/base so the per-org engine serves its collections API natively at /v1/base/collections/… (self-generated URLs included) and never collides with cloud's other /v1 routes. The waitlist plugin binds a FIXED /v1/waitlist regardless of the prefix, so the two lanes never overlap.
IAM-NATIVE, ONE AUTH SOURCE. Each per-org app validates bearer tokens against Hanzo IAM's JWKS ({IAMIssuer}/v1/iam/.well-known/jwks) as its EXCLUSIVE auth source (apis.StoreKey{JWKSURL,ExternalAuthOnly}) — the same IAM the cloud edge validates for org routing. The edge selects the org; Base authorises the record; both consume ONE IAM. No second auth path is introduced.
FAIL-CLOSED + STAGED. The embed activates only when CLOUD_BASE_EMBED is truthy. Absent it, Mount is a no-op except the always-on GET /v1/base/health liveness route, so linking this subsystem into every cloud variant changes nothing until a single-writer deployment opts in. Activation is one CR env.
ONE WRITER, DURABLE. Every embedded store is single-open + single-writer: the base deployment is single-replica, strategy Recreate, on the RWO cloud-api-data PVC, so each per-org SQLite is durable across restarts — the property the standalone base pod had with its own PVC.
Index ¶
Constants ¶
const SubmissionsCollection = "submissions"
SubmissionsCollection is the ONE collection every project's Base space carries for generic data collection — the form, forum, and data submissions a deployed site POSTs to /v1/base/collections/submissions/records. Anyone may CREATE (so an anonymous published page can submit out of the box); reads stay superuser-only (submissions are private by default).
Variables ¶
var ErrNotEmbedded = errors.New("base: embed disabled")
ErrNotEmbedded is returned by EnsureSpace when the base embed is disabled (CLOUD_BASE_EMBED off). It is a fail-soft sentinel: a caller provisioning a project's data space treats it as "deferred", never as a failure — the space is re-ensured on the next call once the embed is on.
Functions ¶
func EnsureSpace ¶
EnsureSpace provisions an org's Base data space idempotently and in-process (no HTTP): it opens+migrates the org's per-org Base app so its SQLite exists, then ensures the default submissions collection exists. Safe to call repeatedly — an existing collection is left untouched. Returns ErrNotEmbedded when the embed is off so the caller can fail soft. This is the ONE entrypoint other subsystems (projects) use to wire a project's data space by default.
Types ¶
This section is empty.