From 74413df3102619b9da85ebd9af51cf5dd8f24045 Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Fri, 29 May 2026 13:57:51 +0530 Subject: [PATCH] docs(llms.txt): add GET /api/v1/stacks/:slug + canonical browser auth surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes BIZ-FINDING-5/6 content-sync follow-up. - Add GET /api/v1/stacks/{slug} — inspection endpoint already live in openapi.go L2268 but missing from agent-facing llms.txt. - Add the canonical browser auth surface (/auth/email/{start,callback}, /auth/github*, /auth/me, /auth/logout) as a single grouped bullet so agents reading llms.txt don't try to POST a non-existent /auth/login or /auth/refresh. Explicit note: no /auth/refresh equivalent today. - Enrich POST /stacks/new response shape (was just 'requires JWT'). Source of truth: api/internal/router/router.go + CLAUDE.md 'Live API surface' block (also updated this sprint). Follow-up (outside this PR): instanode-web/public/llms.txt is a stale copy of this file. Operator must manually re-sync per CLAUDE.md 'Operator follow-ups' note — content repo has no auto-deploy. Co-Authored-By: Claude Opus 4.7 (1M context) --- llms.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/llms.txt b/llms.txt index 620db4b..9e730b7 100644 --- a/llms.txt +++ b/llms.txt @@ -40,10 +40,19 @@ Pick a descriptive name per resource (e.g. `"prod-db"`, `"sessions-cache"`, `"ev - **`GET /healthz`** — Shallow liveness probe. Returns 200 with `{ok, commit_id, build_time, version}` if the binary is up and can ping its primary platform DB. Wired to the Kubernetes `livenessProbe`. Use `/readyz` for deep upstream checks. - **`GET /readyz`** — Deep readiness probe. Multi-component upstream reachability matrix (platform_db, customer_db, redis, provisioner_grpc, NATS, DO Spaces, Brevo, Razorpay, GeoIP). Per-check criticality: `platform_db` + `provisioner_grpc` are CRITICAL (failure → 503); everything else degrades to `200 + overall=degraded`. Each check runs in parallel behind a 10-15s cache to avoid self-DoS via the k8s `readinessProbe` cycle. Response envelope: `{ok, overall, commit_id, checks: {name: {status, latency_ms, last_checked, message?}}}`. Same shape served by api, worker, and provisioner. - **`POST /deploy/new`** — Container deploy. Multipart form: `tarball=@app.tar.gz` (required, gzipped tar containing Dockerfile + source, ≤50 MB) and `name=my-app` (**required** — same 1–64 char `^[A-Za-z0-9][A-Za-z0-9 _-]*$` rule), plus optional `port=8080`, `env=production` (scope), and `env_vars={"KEY":"VAL"}` (JSON string of env vars injected into the pod). Build runs in-cluster via kaniko (~30–90s); call returns `202` with `status=building`, then `status=healthy` once the URL on `*.deployment.instanode.dev` is live with a Let's Encrypt cert. **Requires a JWT** — `Authorization: Bearer `. -- **`POST /stacks/new`** — Multi-service deploy. Multipart form: an `instant.yaml` manifest plus one tarball per service, and `name=my-stack` (**required** — same 1–64 char `^[A-Za-z0-9][A-Za-z0-9 _-]*$` rule). **Requires a JWT.** +- **`POST /stacks/new`** — Multi-service deploy. Multipart form: an `instant.yaml` manifest plus one tarball per service, and `name=my-stack` (**required** — same 1–64 char `^[A-Za-z0-9][A-Za-z0-9 _-]*$` rule). **Requires a JWT.** Returns `{ok, slug, stack_url, services: [{name, url, status}]}`. Anonymous stacks (no Bearer JWT) are accepted and inherit the 24h TTL. +- **`GET /api/v1/stacks/{slug}`** — Inspect a stack by slug. Returns the manifest, current per-service status, exposed URLs, and the merged env-vars (redacted). Anonymous-tier stacks are readable by anyone holding the slug; authenticated stacks require the owning team's session JWT. - **`PATCH /stacks/{slug}/env`** — Merge env-vars into an existing stack. Body: `{"env_vars": {"KEY": "value"}}`. Setting a key to the empty string deletes it. Keys must match `[A-Z_][A-Z0-9_]*`. Total payload after merge capped at 64KiB. Persisted to `stacks.env_vars` JSONB; the next `POST /stacks/{slug}/redeploy` applies them. Anonymous stacks cannot be mutated post-creation. (Replaced a previously silent-no-op handler on 2026-05-20; do not assume any pre-2026-05-20 PATCH actually persisted.) - **`POST /auth/cli`** — Mint a CLI device-flow auth session. Returns `{session_id, auth_url, expires_at}` where `auth_url` is a dashboard URL the user opens in a browser to approve. **Note:** older builds returned an `instant.dev` host that was incorrect — current builds return the real dashboard host. CLI polls `GET /auth/cli/{id}` until approved or expired (5min). - **`GET /auth/cli/{id}`** — Poll the CLI device-flow session. Response includes `status` (`pending` / `approved` / `expired`) and, once approved, an `api_token` the CLI persists. Non-UUID ids return 404 `session_not_found`. +- **Browser auth surface (dashboard only — agents use `/auth/cli` device-flow above).** The dashboard logs users in via magic-link or GitHub OAuth; both mint a 24h session JWT in a cookie. There is no `/auth/login` aggregator and no `/auth/refresh` — the JWT is single-rotation, re-login on expiry. + - `POST /auth/email/start` — request a magic-link email. Body: `{"email": "..."}`. Returns `{ok}` always (no email-enumeration leak). + - `GET /auth/email/callback?token=...` — consume the link → sets session cookie → redirects to dashboard. + - `GET /auth/github/start` — CSRF-protected redirect to GitHub OAuth. + - `GET /auth/github/callback` — OAuth callback → sets session cookie. + - `POST /auth/github` — body-flow GitHub login (server-to-server; not used by the dashboard). + - `GET /auth/me` — current user/team. Requires session JWT. + - `POST /auth/logout` — `jti`-revocation via Redis set. Requires session JWT. - **`POST /api/v1/billing/promotion/validate`** — Validate a promo code without applying it. Body: `{"code": "EARLYBIRD"}`. Returns `{ok, discount_percent, discount_amount_inr, message}` for valid codes. Promo codes only DISCOUNT at checkout once a corresponding Razorpay Offer exists in the dashboard — validate-result `ok=true` is necessary but not sufficient until then. ## Anonymous tier limits (free, 24-hour TTL)