Phase 4: AI-driven app/database/auth lifecycle

Workspace-owned deploy infra so AI agents can create and destroy
Coolify resources without ever touching the root admin token.

  vibn_workspaces
    + coolify_server_uuid, coolify_destination_uuid
    + coolify_environment_name (default "production")
    + coolify_private_key_uuid, gitea_bot_ssh_key_id

  ensureWorkspaceProvisioned
    + generates an ed25519 keypair per workspace
    + pushes pubkey to the Gitea bot user (read/write scoped by team)
    + registers privkey in Coolify as a reusable deploy key

  New endpoints under /api/workspaces/[slug]/
    apps/                POST (private-deploy-key from Gitea repo)
    apps/[uuid]          PATCH, DELETE?confirm=<name>
    apps/[uuid]/domains  GET, PATCH (policy: *.{ws}.vibnai.com only)
    databases/           GET, POST (8 types incl. postgres, clickhouse, dragonfly)
    databases/[uuid]     GET, PATCH, DELETE?confirm=<name>
    auth/                GET, POST (Pocketbase, Authentik, Keycloak, Pocket-ID, Logto, Supertokens)
    auth/[uuid]          DELETE?confirm=<name>

  MCP (/api/mcp) gains 15 new tools that mirror the REST surface and
  enforce the same workspace tenancy + delete-confirm guard.

  Safety: destructive ops require ?confirm=<exact-resource-name>; volumes
  are kept by default (pass delete_volumes=true to drop).

Made-with: Cursor
This commit is contained in:
2026-04-21 12:04:59 -07:00
parent b51fb6da21
commit 0797717bc1
14 changed files with 2274 additions and 118 deletions

View File

@@ -198,6 +198,23 @@ export async function POST(req: NextRequest) {
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS gitea_bot_username TEXT`,
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS gitea_bot_user_id INT`,
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS gitea_bot_token_encrypted TEXT`,
// ── Phase 4: workspace-owned deploy infra ────────────────────────
// Lets AI agents create Coolify applications/databases/services
// against a Gitea repo the bot can read, routed to the right
// server and Docker destination, and exposed under the workspace's
// own subdomain namespace.
//
// coolify_server_uuid — which Coolify server the workspace deploys to
// coolify_destination_uuid — Docker network / destination on that server
// coolify_environment_name — Coolify environment (default "production")
// coolify_private_key_uuid — workspace-wide SSH deploy key (Coolify-side UUID)
// gitea_bot_ssh_key_id — Gitea key id for the matching public key (for rotation)
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS coolify_server_uuid TEXT`,
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS coolify_destination_uuid TEXT`,
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS coolify_environment_name TEXT NOT NULL DEFAULT 'production'`,
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS coolify_private_key_uuid TEXT`,
`ALTER TABLE vibn_workspaces ADD COLUMN IF NOT EXISTS gitea_bot_ssh_key_id INT`,
];
for (const stmt of statements) {