This repository has been archived on 2026-06-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
master-ai/AI_CAPABILITIES_ROADMAP.md
mawkone 2491363b5c docs(path-b): execution plan + vibn-dev image scaffold
- AI_PATH_B_EXECUTION_PLAN.md: add 3 safety nets (auto-push, kill
  switch, hard tool removal), tighten 4 risks (network policy week 1,
  HMR spike day 1, lean image + lazy mise, random preview suffix).
- AI_CAPABILITIES_ROADMAP.md: pointer note already in place.
- vibn-dev/Dockerfile + supervisord.conf + mise.default.toml + README:
  scaffold for the per-project dev container image. Ubuntu 24.04 +
  git + ripgrep + python3 + mise. Toolchains lazy-install on first
  `mise install`. Container runs as uid 1000 vibn (sudo available).

Frontend wiring lives in vibn-frontend (separate commit).

Made-with: Cursor
2026-04-28 12:53:31 -07:00

674 lines
26 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Vibn AI Capability Roadmap
> **⚠ See also:** [`AI_PATH_B_EXECUTION_PLAN.md`](./AI_PATH_B_EXECUTION_PLAN.md)
> — proposed pivot to a Claude-Code-style persistent dev container per
> project. Once approved, that doc supersedes any "code authoring" item
> in this roadmap; this file remains the source of truth for
> infrastructure primitives (P5.x, P6.x, P7.x).
>
> The ordered plan for closing the gap between what the Vibn agent can do
> today and what it needs to do for a real customer to ship, operate, and
> scale a SaaS through it.
>
> **Companion to:** [`AI_CAPABILITIES.md`](./AI_CAPABILITIES.md) (current state).
>
> **Prioritization framing:**
> 1. Does it unblock *shipping a real product* (not a demo)?
> 2. Does it unblock *surviving past the first paying customer*?
> 3. Does it only matter once usage scales?
>
> Tier 1 = (1). Tier 2 = (2). Tier 3 = (3). Tier 4 = revisit when demanded.
>
> **Sequencing rule:** complete Tier 1 before any Tier 2 item. The trap
> is polishing safety rails (audit, scopes, quotas) before the product is
> actually shippable.
---
## 0. Substrate & constraints
Vibn runs on a two-cloud substrate, constrained to Canadian data residency:
| Layer | Provider | Region | Purpose |
|---|---|---|---|
| **App hosting** | Coolify (self-managed) | Montreal VPS | All app / database / auth containers. Current state. |
| **Managed services** | **Google Cloud** | `northamerica-northeast1` (Montreal) | Object storage, cron, queues, logs, backups, monitoring, secrets. |
| **Domain registration** | OpenSRS (Tucows) | Toronto | Wholesale domain API. Canadian company, pre-funded float account. |
| **Authoritative DNS** | Cloud DNS (default) / CIRA D-Zone (strict) | Global anycast / Canadian | Managed DNS for workspace-owned domains. |
| **Transactional email** | Amazon SES | `ca-central-1` (Montreal) | No GCP equivalent; AWS's Canadian region keeps data in-country. |
**Absolute rule: no customer data leaves Canada.** Every workspace-owned
resource (storage bucket, database, log bucket, task queue, scheduler
job, email message body) must be pinned to a Canadian region.
### Why mix clouds?
- **Coolify stays** because we already built the workspace-scoped
provisioning around it (Phase 4). Migrating apps to Cloud Run is a
rewrite we don't need.
- **GCP-CA** fills every managed-service gap Coolify has. Cheaper and
more reliable than self-hosting MinIO/Loki/scheduler.
- **AWS SES for email** because GCP has no first-party transactional
email service and SES `ca-central-1` is the only credible
Canadian-resident managed option.
- **OpenSRS for domains** because it's the wholesale API behind most
Canadian registrars, and we already have the deposit.
### Compliance upgrade path (Tier 4 territory)
For regulated customers (healthcare, financial, public sector):
- **Assured Workloads for Canada** on GCP — enforces Canadian personnel
access + data residency contractually.
- **CIRA D-Zone** instead of Cloud DNS — first-party Canadian managed DNS.
- Keep the SES and OpenSRS pieces as-is (already Canadian-resident).
Document the caveat on a public trust page. Build the Assured-Workloads
variant when a real customer asks.
---
## Current state (Phase 4 + P5.1 verified, Apr 2026)
- Workspace tenancy: Gitea org + Coolify project + SSH deploy key per
workspace.
- Agent can: create repos, create apps, provision 8 database flavors,
deploy 8 vetted auth providers, manage env vars, deploy + poll,
update, delete (with `?confirm=<name>`), set domains under
`*.{slug}.vibnai.com`.
- Control-plane MCP: 24 tools + full REST surface at `/api/mcp`.
API-key scoped per workspace.
- **P5.1 custom apex domains** — OpenSRS + Cloud DNS + Coolify
lifecycle (search / register / attach / inspect) shipped and
verified end-to-end against PROD GCP + OpenSRS sandbox + PROD
Coolify on `v4.0.0-beta.473` (2026-04-22). All 5 sub-systems green
in `smoke-attach-e2e.ts`: register → zone → A records → registrar
NS update → Coolify `fqdn` patch → cleanup. Required a server-side
config fix on `coolify-server-mtl` (proxy.type=TRAEFIK,
is_build_server=false) so `Server::isProxyShouldRun()` returns
true and the controller maps `domains``fqdn` — see
[`AI_CAPABILITIES.md`](./AI_CAPABILITIES.md) § 3.6 for the gory details.
- **Agent-runner stdio MCP bridge** — `vibn-agent-runner` now exposes
its full in-house toolkit (28 tools) outward over 5 stdio MCP
servers so external clients (Cursor, Claude Desktop, Goose) can
drive the same Coolify / Gitea / workspace / memory / search /
sub-agent surface as the internal Coder/PM/Marketing agents, with
shared protected-repo + protected-app guardrails. Every tool now
has a pure `*-api.ts` module, a registry wrapper for the in-process
loop, and an MCP server wrapper — single source of truth, verified
by `scripts/smoke-mcp.js`.
- Enforced: tenant isolation, domain policy, delete confirms,
secrets-at-rest encryption, protected-repo / protected-app guards.
See [`AI_CAPABILITIES.md`](./AI_CAPABILITIES.md) (§ 3.6 for P5.1,
§ 3.7 for the stdio MCP bridge) for the complete current surface.
---
## Tier 1 — Blocks shipping a real product
Without these, anything the agent builds is *demo-shaped*. Ship these
next, in the recommended sequence below.
### P5.1 · Custom apex domains via OpenSRS
**Goal:** agent buys `mysaas.com` on the user's behalf and attaches it
to a Coolify app with automatic TLS.
**Why now:** you already opened an OpenSRS reseller account with a $100
float. Unlocks real branding, DKIM for email (P5.2 depends on this),
and gives you a revenue line (markup on domains).
**Surface:**
| Tool / endpoint | Purpose |
|---|---|
| `domains.search` | Live availability + suggestions via OpenSRS `lookup`. |
| `domains.check_price` | Per-TLD price from OpenSRS + markup. |
| `domains.register` | Debits workspace float, registers via OpenSRS. |
| `domains.list` | Workspace's owned domains. |
| `domains.renew` / `domains.transfer` | Lifecycle. |
| `domains.{name}.attach` | Attach to a Coolify app: DNS records + Coolify `fqdn` + Let's Encrypt. |
| `domains.{name}.detach` | Free a domain from an app, keep registration. |
| `domains.{name}.attach_status` | Polls DNS propagation + cert issuance (async). |
**Infra:**
- **OpenSRS client** (their XML/SOAP or REST API).
- **Cloud DNS** for zone management (default). CIRA D-Zone available as a
workspace-level preference for strict-residency customers.
- **Workspace float ledger** (`vibn_workspace_billing_float`) — a
prepaid balance in CAD, debited on register/renew. Reconciled nightly
against the OpenSRS master deposit.
- `VIBN_OPENSRS_DEPOSIT_ACCOUNT` as the master float handle.
**New columns** on `vibn_workspaces`:
- `preferred_dns_provider TEXT DEFAULT 'cloud_dns'`
- `cloud_dns_zone_name TEXT` ← GCP managed zone for this workspace.
**Risks:**
- DNS propagation is human-scale (minuteshours). Agents need the
async `attach_status` polling loop, not a sync call.
- Cert issuance via Let's Encrypt is rate-limited (50/week per domain).
Abuse-prevent with per-workspace rate caps.
**Estimate:** **2 weeks.**
---
### P5.2 · Transactional email (AWS SES `ca-central-1`)
**Goal:** auth providers can send password-reset emails; agents can
`email.send` from `noreply@mysaas.com`.
**Why now:** every auth provider on the allowlist is broken without
SMTP. Also pairs with P5.1 — per-workspace sender domains need DKIM on
domains you own.
**Why SES ca-central-1 specifically:** GCP has no first-party
transactional email service. All mainstream providers (Postmark,
Resend, Mailgun, SendGrid) are US-primary. SES's Montreal region is the
only credible managed option that keeps message bodies in Canada.
**Two-phase rollout:**
**Phase A — shared-sender MVP (1 week):**
- One SES-verified sender domain `mail.vibnai.com`.
- Every workspace can send from `noreply@mail.vibnai.com` out of the box.
- `email.send` tool + injected `SMTP_*` env vars.
- Bounce / complaint webhooks routed via SNS → a Cloud Run service
that writes per-workspace notifications.
**Phase B — per-workspace sender domains (1 week, depends on P5.1):**
- `email.verify_sender_domain` creates the SPF/DKIM/DMARC records via
the Cloud DNS / CIRA D-Zone client on a workspace-owned domain.
- Polls SES verification; flips `verified=true` when done.
- Workspace can now `email.send from: founder@mysaas.com`.
**Surface:**
| Tool | Purpose |
|---|---|
| `email.send` | Single message; returns SES `message_id`. |
| `email.send_batch` | Up to 100 at a time. |
| `email.list_messages` | Recent sent mail + delivery state (from SES + our log). |
| `email.verify_sender_domain` | Kick off DKIM for a workspace-owned domain. |
| `email.sender_status` | Poll verification state. |
| `email.webhooks.list` | Recent bounces/complaints. |
**Infra:**
- SES identity per workspace-owned sender domain.
- SNS topic → Cloud Run webhook receiver (in `northamerica-northeast1`)
for bounce/complaint ingestion.
- Rate limits: start in SES sandbox (200/day), request production limits
after first real customer.
**Estimate:** **2 weeks total** (1 week Phase A + 1 week Phase B).
---
### P5.3 · Object storage (Google Cloud Storage, `northamerica-northeast1`)
**Goal:** any SaaS the agent builds can take user uploads — avatars,
attachments, exports, images — without the user pasting in third-party
credentials.
**Why now:** "can users upload a file?" is the #1 post-demo question.
Blocks ~half of realistic SaaS ideas.
**GCP collapses this item.** No MinIO container to babysit; GCS provides
managed bucket + signed URLs + lifecycle policies + encryption out of
the box.
**Surface:**
| Tool | Purpose |
|---|---|
| `storage.buckets.list` | Buckets in this workspace (filtered by `workspace={slug}` label). |
| `storage.buckets.create` | New bucket. Optional `public_read`. Enforced region: `northamerica-northeast1`. |
| `storage.buckets.delete` | Destroy bucket. `confirm` gate. |
| `storage.presign_upload` | PUT URL, TTL, content-type constraint. |
| `storage.presign_download` | GET URL, TTL. |
| `storage.list_objects` | Pagination + prefix filter. |
| `storage.delete_object` | Single object. |
| `storage.set_lifecycle` | TTL delete, multipart cleanup, archive tiering. |
**Provisioning additions:**
- Default bucket `vibn-ws-{slug}` created on workspace provision.
- Uniform bucket-level access enabled by default.
- Per-workspace GCP service account `vibn-ws-{slug}@...`, scoped to its
own bucket via `roles/storage.objectAdmin`.
- Keyfile stored encrypted (AES-256-GCM, same `VIBN_SECRETS_KEY`) in
`vibn_workspaces.gcp_service_account_key_encrypted`.
**New columns** on `vibn_workspaces`:
- `gcs_bucket_name TEXT`
- `gcp_service_account_email TEXT`
- `gcp_service_account_key_encrypted BYTEA`
**Env injection:**
- `STORAGE_ENDPOINT=https://storage.googleapis.com`
- `STORAGE_BUCKET={workspace-bucket-name}`
- `STORAGE_ACCESS_KEY`, `STORAGE_SECRET_KEY` (S3-compatible via GCS HMAC keys)
— auto-injected on app creation so agent code uses standard S3 SDKs.
**Estimate:** **3 days.**
---
### P5.4 · Workers, cron, and queues (Cloud Tasks + Cloud Scheduler + Cloud Run Jobs)
**Goal:** agents can declare async workers, scheduled jobs, and queued
tasks. Anything that isn't a single `ports: 3000` web container.
**Why now:** webhooks, retries, nightly cleanup, image processing,
email sending — every real SaaS needs a non-web process. Current
workaround (second Coolify app) is brittle and manual.
**Hybrid approach — Coolify for compute, GCP for orchestration:**
Option evaluated and chosen:
- **Cloud Scheduler** (`northamerica-northeast1`) for cron: fires
HTTP webhooks into the app at the scheduled time.
- **Cloud Tasks** (`northamerica-northeast1`) for queue: agent code
calls `enqueue(task)`, Cloud Tasks dispatches to the app's worker
endpoint with retries, backoff, and at-least-once semantics.
- **Worker process** stays on Coolify as a second app-per-repo with a
different start command, exposed on an internal URL.
Rejected alternative: migrate everything to Cloud Run Jobs. More managed
but splits the "Live" view across two deploy targets and changes the
agent's mental model. Not worth it for MVP.
**Shape — extend `apps.create`:**
```json
{
"repo": "my-site",
"services": {
"web": { "command": "npm start", "ports": "3000" },
"worker": { "command": "npm run worker", "replicas": 2 }
},
"cron": [
{ "name": "nightly-backup", "schedule": "0 3 * * *", "path": "/tasks/backup" },
{ "name": "sync", "schedule": "*/10 * * * *", "path": "/tasks/sync" }
],
"queues": [
{ "name": "emails" },
{ "name": "image-processing" }
]
}
```
Internally creates: two Coolify apps (web + worker), N Cloud Scheduler
jobs labeled `workspace={slug}`, N Cloud Tasks queues.
**Surface additions:**
| Tool | Purpose |
|---|---|
| `apps.services.list` | All processes in an app. |
| `apps.services.update` | Scale replicas, change command. |
| `apps.services.logs` | Per-process logs. |
| `cron.list` | Scheduler jobs in this workspace. |
| `cron.create` / `cron.update` / `cron.delete` | Manage scheduled jobs. |
| `cron.run_now` | Fire a scheduled job immediately (useful for agent testing). |
| `queues.list` | Cloud Tasks queues in this workspace. |
| `queues.create` / `queues.delete` | Manage queues. |
| `queues.enqueue` | (Normally called from app code, but exposed for agent-driven testing.) |
| `queues.pause` / `queues.resume` | Emergency ops. |
**New columns** on `vibn_workspaces`:
- `cloud_scheduler_location TEXT DEFAULT 'northamerica-northeast1'`
- `cloud_tasks_location TEXT DEFAULT 'northamerica-northeast1'`
**Auth to GCP:** per-workspace service account (provisioned in P5.3) is
extended with `roles/cloudscheduler.admin` and `roles/cloudtasks.admin`
*scoped to resources labeled `workspace={slug}`* via IAM conditions.
Agents can only act on their own workspace's jobs/queues.
**Estimate:** **1 week.**
---
### Tier 1 total: ~5 weeks of focused work
After Tier 1 lands, an agent can:
- Buy `mysaas.com`, point it at a Next.js app.
- Deploy Authentik with working password-reset emails from `noreply@mysaas.com`.
- Offer user uploads (avatars, attachments).
- Run `0 3 * * *` nightly cleanup cron.
- Process Stripe webhooks idempotently via a retry queue.
That's a shippable SaaS. Everything after this is about *keeping* it
shipped.
---
## Tier 2 — Blocks surviving past the first real customer
Once users exist, these prevent silent failures.
### P6.1 · Database backups + restore (GCS + wal-g)
**Goal:** nightly backups, on-demand backups, one-call restore. No
"agent ran `DROP TABLE` in a migration" permanent data loss.
**Why:** scariest item on this list. Failure mode is irrecoverable.
**Shape:**
- `databases.{uuid}.backup` — on-demand `pg_dump` / `mongodump` to the
workspace's GCS bucket (depends on P5.3).
- `databases.{uuid}.backups.list` — lists backups with timestamp + size.
- `databases.{uuid}.backups.restore``confirm`-gated restore from a
specific backup uuid.
- Per-database backup policy: daily / hourly / off, retention days.
- Default: every AI-created database gets daily backups + 7-day
retention on.
**Infra:**
- Cron jobs run via P5.4's Cloud Scheduler primitive.
- Stored at `gs://vibn-ws-{slug}/backups/{db-uuid}/{iso-timestamp}.sql.gz`.
- Lifecycle rules auto-delete backups older than retention.
- Object-level retention lock available for "immutable backups" on
request (Tier 3 feature).
**Upgrade path:**
- **Postgres point-in-time recovery** via `wal-g` shipping WAL segments
to the same GCS bucket. Adds RPO < 5 min.
- **ClickHouse**: `clickhouse-backup` to GCS.
- **MongoDB**: `mongodump` incremental.
**Estimate:** **3 days** for MVP (pg_dump + schedule + restore).
**+1 week** for wal-g PITR if/when a customer asks.
---
### P6.2 · Runtime log streaming (Cloud Logging)
**Goal:** agent can see "is the app erroring at 10 req/s right now?",
not just "did the build succeed."
**Why:** today deploy logs are surfaced but container stdout/stderr is
not. An agent that "fixed a bug" can't verify the fix without a human
SSH-ing into Coolify.
**GCP collapses this item** — ship container logs to Cloud Logging with
a workspace label, query via the logs API.
**Shape:**
- Fluent-bit sidecar (or Coolify label) ships container stdout/stderr
to Cloud Logging in `northamerica-northeast1` with labels
`workspace={slug}`, `app={app-uuid}`, `service={web|worker|...}`.
- Per-workspace log bucket for retention isolation.
**Surface:**
| Tool | Purpose |
|---|---|
| `apps.logs` | Last N lines across replicas. Filter by timestamp, severity. |
| `apps.logs.tail` | SSE stream of new log lines. |
| `apps.logs.search` | Thin wrapper on Cloud Logging's query API — grep, severity filter, time window. |
| `apps.services.logs` | Same, scoped to a single service. |
**Retention:** default 30 days in the workspace log bucket; exportable
to the workspace's GCS bucket on request for long-term storage.
**Estimate:** **3 days** (fluent-bit config + thin API wrapper).
---
### P6.3 · Scoped API keys
**Goal:** invite a CI bot or teammate without giving root on the
workspace.
**Why:** solo-builder flow survives without it. Breaks the moment a
second principal enters.
**Shape:**
- Keys gain `scopes: string[]` and optional `expires_at`.
- Scope tokens: `apps:read`, `apps:write`, `apps:delete`,
`databases:*`, `auth:*`, `domains:read`, `domains:write`,
`storage:*`, `email:send`, `cron:*`, `queues:*`, `deploy:*`.
- Per-scope rate limits optional (Tier 3; API shape supports it from
day one).
**Surface changes:**
| Tool | Change |
|---|---|
| `keys.create` | Accepts `scopes`, `expires_at`. |
| `keys.list` | Returns scopes per key. |
| `keys.rotate` | Mints new token, preserves scope set. |
Every MCP/REST handler gets a scope requirement checked in the
principal resolver.
**Estimate:** **1 week.**
---
### Tier 2 total: ~2 weeks
After Tier 2 lands, a SaaS shipped on Vibn can survive without you
dropping into a psql REPL at 3am.
---
## Tier 3 — Matters once usage scales
Don't build these until at least one real customer is hitting them.
Building them pre-market is the classic infra-overinvestment trap.
### P7.1 · Per-workspace quotas + cost caps
Max apps, max dbs, max GCS GB, max egress, max SES messages/month, max
OpenSRS spend/month. Per-plan configurable. Hallucinating agents can't
OOM the cluster or burn your SES reputation.
### P7.2 · Audit log
Append-only per-workspace log of (principal, action, params, timestamp,
result). Cloud Logging with a dedicated `audit-logs` log-bucket, 400-day
retention. Read API for the settings panel. Needed for any
SOC-2-adjacent buyer.
### P7.3 · Preview-per-PR environments
Open a PR → `pr-42.mark.vibnai.com` deploys automatically with a
throw-away database. Teardown on PR close/merge. Unblocks multi-agent
flows.
### P7.4 · Atomic multi-resource operations (`stacks`)
`POST /stacks` takes a full app + db + auth + domain + cron spec;
creates atomically, rolls back on failure. Agent ergonomics win once
demo flow is routine.
### P7.5 · Billing integration
Stripe subscriptions for Vibn itself (workspace billing), plus
per-workspace float top-ups, plus reconciliation to the OpenSRS master
deposit and GCP / SES cost allocation. Only needed when you charge
real dollars.
### P7.6 · Assured Workloads for Canada
GCP policy-enforced Canadian residency + Canadian personnel access.
For regulated customers (healthcare, financial, public sector). Priced
accordingly; ship only when a real customer needs it.
### P7.7 · CIRA D-Zone as a workspace DNS option
Swap Cloud DNS → CIRA D-Zone for a workspace with strict residency
requirements. API-compatible wrapper so nothing agent-facing changes.
---
## Tier 4 — Revisit when demanded
Items to explicitly *not* build until a concrete customer asks.
- **Multi-region** — single-region Canada is fine for B2B SaaS makers
(our early market).
- **Cloud Run migration** — would rewrite most of Coolify-based
capabilities. Revisit if/when Coolify becomes a bottleneck.
- **Managed search / vector DB as first-class types** — agents can
deploy Meilisearch / Typesense / pgvector-Postgres as regular services.
- **mTLS / custom CAs / BYO-cert upload** — enterprise creep.
- **MCP protocol polish** (streaming, resources, prompts, per-tool
schemas) — current JSON-over-HTTP works. Revisit on real friction.
- **Per-app basic auth, IP allowlists, WAF** — Traefik middleware
manually until someone asks.
---
## Roadmap at a glance
| Phase | Items | Est. | Unblocks |
|---|---|---|---|
| **P5 — Real SaaS primitives** | Domains, email, storage, workers/cron/queues | ~5 wk | Shipping a real product |
| **P6 — Keep-it-running** | Backups, runtime logs, scoped keys | ~2 wk | First real customer survives |
| **P7 — Scale** | Quotas, audit, previews, stacks, billing, Assured Workloads, D-Zone | demand-driven | Platform grows past 1st cohort |
| **P8+** | Tier 4 items | never, unless pulled by customer | — |
**Total to "agent ships a SaaS a founder would pay $29/mo for":**
P5 + P6 = **~7 weeks** (was ~11 before GCP-CA; ~40% compression from
managed-service leverage).
---
## Dependency graph
```
P5.1 Domains ──┬──→ P5.2 Email Phase B (per-domain DKIM)
├──→ P7.7 CIRA D-Zone swap
└──→ (future: customer-owned sub-domain routing)
P5.3 Storage ──┬──→ P6.1 Database backups (backups need a bucket)
└──→ P7.2 Audit log export
P5.4 Workers/cron/queues ──┬──→ P6.1 Database backups (run via scheduler)
└──→ most real SaaS patterns
P6.2 Runtime logs — independent, can land anytime
P6.3 Scoped keys — independent, can land anytime
P7.6 Assured Workloads — wraps everything; build once demanded
```
**Parallelizable (three people):**
- Track A: P5.1 → P5.2
- Track B: P5.3 → P6.1
- Track C: P5.4 → P6.2
Track C finishes earliest; use that slack to land P6.3.
---
## Per-workspace GCP provisioning (shared across P5.3, P5.4, P6.1, P6.2)
`ensureWorkspaceProvisioned()` gains a GCP-CA block that runs once per
workspace, idempotently. All resources are created in
`northamerica-northeast1`.
| Resource | Name pattern | Notes |
|---|---|---|
| GCS bucket | `vibn-ws-{slug}` | Uniform bucket-level access. Lifecycle policies off by default. |
| Cloud DNS managed zone | `vibn-ws-{slug}-zone` | Created per workspace-owned domain in P5.1, not on workspace provision. |
| Cloud Logging log bucket | `vibn-ws-{slug}-logs` | 30-day retention default. |
| Cloud Tasks location | `northamerica-northeast1` | Queues created per-app in P5.4, not here. |
| GCP service account | `vibn-ws-{slug}@{project}.iam` | Single SA per workspace, narrow roles. |
| Service account key | stored encrypted in `vibn_workspaces` | AES-256-GCM, same `VIBN_SECRETS_KEY`. |
**New columns** on `vibn_workspaces` (cumulative across P5.1-P6.2):
```sql
-- P5.1
preferred_dns_provider TEXT DEFAULT 'cloud_dns',
cloud_dns_zone_name TEXT,
-- P5.3
gcs_bucket_name TEXT,
gcp_service_account_email TEXT,
gcp_service_account_key_encrypted BYTEA,
-- P5.4
cloud_scheduler_location TEXT DEFAULT 'northamerica-northeast1',
cloud_tasks_location TEXT DEFAULT 'northamerica-northeast1',
-- P6.2
cloud_logging_bucket_name TEXT
```
Three migration steps, one per phase. All guarded by the existing
admin-gated `POST /api/admin/migrate` endpoint.
---
## Non-goals (stated explicitly so they don't creep in)
- **A general-purpose PaaS.** Vibn is an agent-driven SaaS builder, not
a Heroku / Fly clone. Every capability must answer "what does an agent
need to build a SaaS?" — not "what does a dev need to deploy a
container?"
- **Support for non-allowlisted auth providers, databases, services.**
The curated surface is the feature. "Any Coolify service" would blow
up the tenant-safety model and dilute agent decision-making.
- **A consumer-facing OpenSRS UI.** OpenSRS is plumbing for the agent.
Humans should never see an OpenSRS checkout screen — only
`domains.register { name: "mysaas.com" }` from the agent.
- **Multi-cloud abstraction layer.** One Coolify cluster + GCP-CA +
SES-CA + OpenSRS is the contract. If customers want to bring their
own, that's Tier 4.
- **Anything that moves customer data out of Canada.** Even for
performance. If a managed service only has US regions, we self-host
in Canada or we don't offer it.
---
## Recommended execution order (opinionated)
Given dependencies and quick-wins-first philosophy:
**Week 1:**
- P5.3 Storage (GCS wrap, 3 days) → proves the GCP-CA provisioning pattern.
- P5.4 Workers/cron/queues (starts in parallel; depends on P5.3 only for
the service account).
**Week 2:**
- P5.4 completes.
- P5.1 Domains starts (OpenSRS client + Cloud DNS wrapper).
**Week 3:**
- P5.1 completes.
- P5.2 Email Phase A (shared-sender MVP) starts.
**Week 4:**
- P5.2 Phase A completes.
- P5.2 Phase B (per-domain DKIM) starts, now that P5.1 is available.
**Week 5:**
- P5.2 Phase B completes. **P5 / Tier 1 done.**
- P6.1 Database backups starts (3 days).
- P6.2 Runtime logs starts in parallel (3 days).
**Week 6:**
- P6.3 Scoped keys (1 week).
**Week 7:**
- Slack week — hardening, docs (`AI_CAPABILITIES.md` refresh), first
real customer onboarding.
**End state at week 7:** agent can take a founder from "I have an idea"
to "I have `mysaas.com` live, with auth, with user uploads, with email,
with backups, with visible error logs, and a CI bot can deploy it
without root access."
That's the Vibn product.
---
## How to use this doc
- When someone proposes a feature, find its tier. If it's Tier 3 or 4
and we're still shipping Tier 1, say no.
- Before starting a Tier 1 item, re-read its section and make sure
prerequisites shipped. Email-per-domain before domains is wasted code.
- [`AI_CAPABILITIES.md`](./AI_CAPABILITIES.md) is the canonical
reference of *what exists today*. This doc is the canonical reference
of *what comes next*. When an item ships, move it from here to that
doc and delete its section here.
- When a user request implies Canadian residency (they say "PIPEDA",
"healthcare", "public sector", or "our data can't leave Canada"), pin
the answer to this doc's §0 Substrate & constraints. Don't improvise.