|
| 1 | +# common |
| 2 | + |
| 3 | +Shared Go packages for the [InstaNode](https://instanode.dev) platform — the |
| 4 | +zero-friction developer infrastructure that lets agents provision databases, |
| 5 | +caches, queues, object storage, and full application deployments with a single |
| 6 | +HTTP call. |
| 7 | + |
| 8 | +This repo is the **shared substrate** consumed by the three backend services: |
| 9 | + |
| 10 | +- **api** — agent-facing HTTP surface (port 8080) |
| 11 | +- **worker** — River-backed background jobs (expiry, billing, propagation, email) |
| 12 | +- **provisioner** — gRPC service that creates and destroys real databases |
| 13 | + |
| 14 | +Module path: `instant.dev/common` (Go 1.25+). |
| 15 | + |
| 16 | +## Why a separate module? |
| 17 | + |
| 18 | +Every backend service depends on the same tier definitions, the same encryption |
| 19 | +keyring, the same readiness check shape, and the same provider interfaces. We |
| 20 | +factored those out so a change to a tier limit, a new provisioner backend, or a |
| 21 | +new readiness check lands in one place and propagates to every service via a |
| 22 | +single `go mod` bump — instead of three drifting copies. |
| 23 | + |
| 24 | +## Packages |
| 25 | + |
| 26 | +| Package | Purpose | |
| 27 | +|---|---| |
| 28 | +| [`buildinfo`](./buildinfo) | ldflag-stamped `GitSHA` + `BuildTime` + `Version` exposed on every service's `/healthz`. Lets ops verify "is the running pod actually the commit I just pushed?" — see [InstaNode CLAUDE.md rule 14](https://instanode.dev) (Build-SHA gate). | |
| 29 | +| [`crypto`](./crypto) | AES-256-GCM keyring (multi-key with rotation), JWT signing helpers, IP fingerprint hashing (SHA256 over `/24` subnet + ASN), and base32 token generation. Fails open on decrypt errors so a key rotation doesn't break reads. | |
| 30 | +| [`logctx`](./logctx) | `slog.Handler` wrapper that injects `commit_id`, `request_id`, `team_id`, `resource_token` from `context.Context` into every structured log line. Keys are defined once here so api, worker, and provisioner emit consistent JSON. | |
| 31 | +| [`plans`](./plans) | Tier registry loaded from `plans.yaml` — the single source of truth for per-tier limits (storage MB, connection caps, deployment slots, webhook retention, etc.). Iterated by `/api/v1/capabilities` so adding a tier in `plans.yaml` + `rank.go` automatically surfaces to clients. | |
| 32 | +| [`queueprovider`](./queueprovider) | Pluggable factory + `QueueCredentialProvider` interface for NATS / RabbitMQ / Kafka / `legacyopen` backends. NATS impl mints per-tenant account JWTs + user NKeys; RabbitMQ + Kafka are portability skeletons (return `ErrNotImplemented`); `legacyopen` is the cutover shim for pre-isolation tenants. | |
| 33 | +| [`readiness`](./readiness) | Shared `Registry` + `Check` interface for deep `/readyz` endpoints. Reusable check constructors for HTTP/GET, gRPC dial, Postgres ping, Redis ping, Mongo ping, NATS ping. Per-check criticality (critical / degraded) and 10-15s cache TTL. Emits Prometheus + slog. | |
| 34 | +| [`resourcestatus`](./resourcestatus) | Shared enum for resource lifecycle states (`active`, `expired`, `deleting`, `deleted`, …) plus the expiry-warning ladder stages (6h / 2h / 1h imminent). | |
| 35 | +| [`resourcetype`](./resourcetype) | Shared enum for provisioned resource kinds (`postgres`, `redis`, `mongodb`, `queue`, `storage`, `webhook`, `deploy`, …). | |
| 36 | +| [`storageprovider`](./storageprovider) | Pluggable factory + `StorageCredentialProvider` interface for DigitalOcean Spaces / Cloudflare R2 / AWS S3 / MinIO backends. Capability-aware: each backend declares whether it supports prefix-scoped keys, bucket-scoped keys, STS temp credentials, and bucket-per-tenant — the api uses this to decide between `prefix-scoped`, `prefix-scoped-temporary`, `shared-master-key`, and `broker` modes. Live prod uses DO Spaces in `prefix-scoped` mode. | |
| 37 | + |
| 38 | +## Using in a downstream service |
| 39 | + |
| 40 | +```go |
| 41 | +import ( |
| 42 | + "instant.dev/common/buildinfo" |
| 43 | + "instant.dev/common/logctx" |
| 44 | + "instant.dev/common/plans" |
| 45 | + "instant.dev/common/readiness" |
| 46 | +) |
| 47 | +``` |
| 48 | + |
| 49 | +This module is consumed via a `replace` directive in the api / worker / |
| 50 | +provisioner `go.mod` files when developing across the repo bundle locally. In |
| 51 | +prod CI, tagged releases are pulled directly. |
| 52 | + |
| 53 | +## Versioning |
| 54 | + |
| 55 | +`common` follows semantic versioning. **Contract changes** (a new tier in |
| 56 | +`plans.yaml`, a renamed `resourcetype`, a changed `readiness.Status` shape) |
| 57 | +must land in synchronised PRs across `common` + `api` + `worker` + |
| 58 | +`provisioner` — see the [InstaNode handoff doc](https://instanode.dev) |
| 59 | +rule 22 ("Contract changes touch all surfaces in one PR"). |
| 60 | + |
| 61 | +## Testing |
| 62 | + |
| 63 | +```bash |
| 64 | +go test ./... |
| 65 | +``` |
| 66 | + |
| 67 | +Each package ships unit tests; contract tests live alongside the factory in |
| 68 | +`queueprovider/contract_test.go` and `storageprovider/contract_test.go` to |
| 69 | +verify every backend implements the interface consistently. |
| 70 | + |
| 71 | +## Contributing |
| 72 | + |
| 73 | +See [CONTRIBUTING.md](./CONTRIBUTING.md). Issues + PRs on this repo are |
| 74 | +welcome for shared-package bugs; platform-wide bugs (API behaviour, dashboard, |
| 75 | +billing, deploy pipeline) belong on the [api repo](https://github.com/InstaNode-dev). |
| 76 | + |
| 77 | +## Security |
| 78 | + |
| 79 | +See [SECURITY.md](./SECURITY.md). Report vulnerabilities privately to |
| 80 | +**security@instanode.dev** — do not open a public issue. |
| 81 | + |
| 82 | +## License |
| 83 | + |
| 84 | +[MIT](./LICENSE) © 2026 InstaNode. |
0 commit comments