diff --git a/.github/actions/setup-test-env/action.yml b/.github/actions/setup-test-env/action.yml index 60c11167d..a7b7e494b 100644 --- a/.github/actions/setup-test-env/action.yml +++ b/.github/actions/setup-test-env/action.yml @@ -14,7 +14,7 @@ inputs: runs: using: composite steps: - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: ${{ inputs.bun-version }} @@ -22,6 +22,10 @@ runs: shell: bash run: bun install --frozen-lockfile + - name: Validate migration journal + shell: bash + run: bun run db:check-migrations + - name: Start postgres and redis if: inputs.setup-db == 'true' shell: bash diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..9520137ed --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,147 @@ +name: CI + +on: + push: + branches: [dev, main] + pull_request: + branches: [dev, main] + +concurrency: + group: ci-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + BUN_VERSION: "1.3.9" + NODE_OPTIONS: --max-old-space-size=4096 + +jobs: + lint: + name: Lint & Format + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: ${{ env.BUN_VERSION }} + + - name: Cache Bun + uses: actions/cache@v4 + with: + path: ~/.bun/install/cache + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} + restore-keys: bun-${{ runner.os }}- + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run lint + run: bun run lint + + typecheck: + name: Type Check + runs-on: ubuntu-latest + timeout-minutes: 15 + continue-on-error: true + steps: + - uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: ${{ env.BUN_VERSION }} + + - name: Cache Bun + uses: actions/cache@v4 + with: + path: ~/.bun/install/cache + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} + restore-keys: bun-${{ runner.os }}- + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run typecheck + run: bun run check-types + + test: + name: Unit Tests + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + NODE_ENV: test + steps: + - uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: ${{ env.BUN_VERSION }} + + - name: Cache Bun + uses: actions/cache@v4 + with: + path: ~/.bun/install/cache + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} + restore-keys: bun-${{ runner.os }}- + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run tests + run: bun run test + + build: + name: Build + runs-on: ubuntu-latest + timeout-minutes: 20 + continue-on-error: true + needs: [lint, typecheck] + env: + NODE_ENV: production + steps: + - uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: ${{ env.BUN_VERSION }} + + - name: Cache Bun + uses: actions/cache@v4 + with: + path: ~/.bun/install/cache + key: bun-${{ runner.os }}-${{ hashFiles('bun.lock') }} + restore-keys: bun-${{ runner.os }}- + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Build + run: bun run build + + notify: + name: Notify + runs-on: ubuntu-latest + needs: [lint, typecheck, test, build] + if: always() && github.event_name == 'push' + steps: + - name: Notify Discord + uses: sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1 + if: ${{ needs.build.result == 'success' }} + with: + webhook: ${{ secrets.DISCORD_WEBHOOK }} + title: "✅ CI Passed" + description: "Branch: ${{ github.ref_name }}\nCommit: ${{ github.sha }}" + color: 0x00ff00 + + - name: Notify Discord (Failure) + uses: sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1 + if: ${{ needs.lint.result == 'failure' || needs.typecheck.result == 'failure' || needs.test.result == 'failure' || needs.build.result == 'failure' }} + with: + webhook: ${{ secrets.DISCORD_WEBHOOK }} + title: "❌ CI Failed" + description: "Branch: ${{ github.ref_name }}\nCommit: ${{ github.sha }}" + color: 0xff0000 diff --git a/.github/workflows/deploy-backend.yml b/.github/workflows/deploy-backend.yml new file mode 100644 index 000000000..d9ae2f2d3 --- /dev/null +++ b/.github/workflows/deploy-backend.yml @@ -0,0 +1,156 @@ +name: Deploy Backend + +on: + push: + branches: [dev, main] + paths: + - 'packages/lib/**' + - 'packages/db/**' + - 'packages/scripts/**' + - 'packages/services/**' + - 'app/api/**' + - 'package.json' + - 'bun.lock' + workflow_dispatch: + inputs: + environment: + description: 'Environment to deploy' + required: true + default: 'staging' + type: choice + options: + - staging + - production + +concurrency: + group: deploy-backend-${{ github.ref }} + cancel-in-progress: false + +env: + BUN_VERSION: "1.3.9" + +jobs: + determine-env: + name: Determine Environment + runs-on: ubuntu-latest + outputs: + environment: ${{ steps.env.outputs.environment }} + branch: ${{ steps.env.outputs.branch }} + steps: + - name: Set environment + id: env + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "environment=${{ github.event.inputs.environment }}" >> $GITHUB_OUTPUT + echo "branch=${{ github.event.inputs.environment == 'production' && 'main' || 'dev' }}" >> $GITHUB_OUTPUT + elif [ "${{ github.ref }}" = "refs/heads/main" ]; then + echo "environment=production" >> $GITHUB_OUTPUT + echo "branch=main" >> $GITHUB_OUTPUT + else + echo "environment=staging" >> $GITHUB_OUTPUT + echo "branch=dev" >> $GITHUB_OUTPUT + fi + + deploy: + name: Deploy to milady VPS + runs-on: ubuntu-latest + needs: determine-env + environment: ${{ needs.determine-env.outputs.environment }} + timeout-minutes: 15 + steps: + - name: Deploy via SSH + uses: appleboy/ssh-action@029f5b4aeeeb58fdfe1410a5d17f967dacf36262 # v1.0.3 + with: + host: ${{ secrets.MILADY_VPS_HOST }} + username: deploy + key: ${{ secrets.MILADY_VPS_SSH_KEY }} + script_stop: true + script: | + set -e + echo "=== Deploying eliza-cloud backend ===" + + cd /opt/eliza-cloud + + # Fetch and checkout + git fetch origin + git checkout ${{ needs.determine-env.outputs.branch }} + git pull origin ${{ needs.determine-env.outputs.branch }} + + # Install and build + export NEXT_DIST_DIR=.next-build + export PORT=3334 + bun install --frozen-lockfile + bun run build + + # Restart the Next.js service + sudo systemctl restart eliza-cloud + + echo "=== Deploy complete ===" + + - name: Health Check + uses: appleboy/ssh-action@029f5b4aeeeb58fdfe1410a5d17f967dacf36262 # v1.0.3 + with: + host: ${{ secrets.MILADY_VPS_HOST }} + username: deploy + key: ${{ secrets.MILADY_VPS_SSH_KEY }} + script: | + sleep 10 + echo "Checking eliza-cloud health..." + curl -sf http://localhost:3334/api/health || exit 1 + echo "Health check passed!" + + - name: Notify Discord (Success) + if: success() + uses: sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1 + with: + webhook: ${{ secrets.DISCORD_WEBHOOK }} + title: "🚀 Backend Deployed" + description: | + Environment: ${{ needs.determine-env.outputs.environment }} + Branch: ${{ needs.determine-env.outputs.branch }} + Commit: ${{ github.sha }} + color: 0x00ff00 + + - name: Notify Discord (Failure) + if: failure() + uses: sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1 + with: + webhook: ${{ secrets.DISCORD_WEBHOOK }} + title: "❌ Backend Deploy Failed" + description: | + Environment: ${{ needs.determine-env.outputs.environment }} + Branch: ${{ needs.determine-env.outputs.branch }} + Commit: ${{ github.sha }} + color: 0xff0000 + + migrate-db: + name: Run Database Migrations + runs-on: ubuntu-latest + needs: [determine-env, deploy] + if: needs.determine-env.outputs.environment == 'production' + environment: production + timeout-minutes: 10 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + with: + bun-version: ${{ env.BUN_VERSION }} + + - name: Install dependencies + run: bun install --frozen-lockfile + + - name: Run migrations + env: + DATABASE_URL: ${{ secrets.NEON_DATABASE_URL }} + run: bun run db:migrate + + - name: Notify Discord + if: success() + uses: sarisia/actions-status-discord@eb045afee445dc055c18d3d90bd0f244fd062708 # v1 + with: + webhook: ${{ secrets.DISCORD_WEBHOOK }} + title: "🗄️ Database Migrated" + description: "Production database migrations applied" + color: 0x00ff00 diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c4b59fa29..ab689538a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,6 +28,7 @@ jobs: run: bun run lint - name: Run typecheck run: bun run check-types + continue-on-error: true unit-tests: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 8625dbcfa..cd12e9515 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,5 @@ modelcontextprotocol/ *storybook.log storybook-static .next-dev/ +DEV_TO_PROD_AUDIT.md +TRIAGE_NOTES.md diff --git a/app/api/agents/[id]/headscale-ip/route.ts b/app/api/agents/[id]/headscale-ip/route.ts index 859257da7..abc0f00e9 100644 --- a/app/api/agents/[id]/headscale-ip/route.ts +++ b/app/api/agents/[id]/headscale-ip/route.ts @@ -1,3 +1,4 @@ +import { timingSafeEqual } from "node:crypto"; import { NextRequest, NextResponse } from "next/server"; import { miladySandboxesRepository } from "@/db/repositories/milady-sandboxes"; @@ -38,7 +39,11 @@ export async function GET(request: NextRequest, { params }: { params: Promise<{ return NextResponse.json({ error: "internal auth not configured" }, { status: 503 }); } - if (getInternalToken(request) !== expectedToken) { + const providedToken = getInternalToken(request) ?? ""; + const tokensMatch = + providedToken.length === expectedToken.length && + timingSafeEqual(Buffer.from(providedToken), Buffer.from(expectedToken)); + if (!tokensMatch) { console.warn(`[headscale-ip] blocked unauthorized lookup for ${agentId}`); return NextResponse.json({ error: "forbidden" }, { status: 403 }); } diff --git a/app/api/auth/pair/route.ts b/app/api/auth/pair/route.ts index 64851d86b..34f313cd1 100644 --- a/app/api/auth/pair/route.ts +++ b/app/api/auth/pair/route.ts @@ -1,5 +1,6 @@ import { NextRequest, NextResponse } from "next/server"; import { miladySandboxesRepository } from "@/db/repositories/milady-sandboxes"; +import { RateLimitPresets, withRateLimit } from "@/lib/middleware/rate-limit"; import { getPairingTokenService } from "@/lib/services/pairing-token"; export const dynamic = "force-dynamic"; @@ -15,7 +16,7 @@ export const dynamic = "force-dynamic"; * endpoint directly at /api/auth/pair (when nginx is configured to * fall through to port 3334). */ -export async function POST(request: NextRequest) { +async function handler(request: NextRequest) { try { const body = await request.json().catch(() => null); const token = body?.token; @@ -36,8 +37,11 @@ export async function POST(request: NextRequest) { return NextResponse.json({ error: "Invalid or expired pairing code" }, { status: 401 }); } - // Look up the sandbox to get container details - const sandbox = await miladySandboxesRepository.findById(pairingToken.agentId); + // Look up the sandbox scoped to the org to prevent cross-org access + const sandbox = await miladySandboxesRepository.findByIdAndOrg( + pairingToken.agentId, + pairingToken.orgId, + ); if (!sandbox) { return NextResponse.json({ error: "Agent not found" }, { status: 404 }); @@ -66,3 +70,5 @@ export async function POST(request: NextRequest) { return NextResponse.json({ error: "Pairing failed" }, { status: 500 }); } } + +export const POST = withRateLimit(handler, RateLimitPresets.STRICT); diff --git a/app/api/compat/agents/[id]/logs/route.ts b/app/api/compat/agents/[id]/logs/route.ts index 6539f5273..8ba2a5f5b 100644 --- a/app/api/compat/agents/[id]/logs/route.ts +++ b/app/api/compat/agents/[id]/logs/route.ts @@ -8,7 +8,7 @@ import { NextRequest, NextResponse } from "next/server"; import { envelope, errorEnvelope } from "@/lib/api/compat-envelope"; import { logger } from "@/lib/utils/logger"; -import { miladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { assertSafeOutboundUrl } from "@/lib/security/outbound-url"; import { handleCompatCorsOptions, withCompatCors } from "../../../_lib/cors"; import { requireCompatAuth } from "../../../_lib/auth"; diff --git a/app/api/compat/agents/[id]/route.ts b/app/api/compat/agents/[id]/route.ts index 9f6e1be64..cf9df9d8e 100644 --- a/app/api/compat/agents/[id]/route.ts +++ b/app/api/compat/agents/[id]/route.ts @@ -11,7 +11,7 @@ import { toCompatOpResult, } from "@/lib/api/compat-envelope"; import { reusesExistingMiladyCharacter } from "@/lib/services/milady-agent-config"; -import { miladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { logger } from "@/lib/utils/logger"; import { requireCompatAuth } from "../../_lib/auth"; import { handleCompatCorsOptions, withCompatCors } from "../../_lib/cors"; diff --git a/app/api/compat/agents/[id]/suspend/route.ts b/app/api/compat/agents/[id]/suspend/route.ts index db0454ec4..f03d6f069 100644 --- a/app/api/compat/agents/[id]/suspend/route.ts +++ b/app/api/compat/agents/[id]/suspend/route.ts @@ -5,7 +5,7 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { envelope, errorEnvelope, toCompatOpResult } from "@/lib/api/compat-envelope"; -import { miladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { logger } from "@/lib/utils/logger"; import { requireCompatAuth } from "../../../_lib/auth"; import { handleCompatCorsOptions, withCompatCors } from "../../../_lib/cors"; diff --git a/app/api/compat/agents/route.ts b/app/api/compat/agents/route.ts index f888110de..782b394a0 100644 --- a/app/api/compat/agents/route.ts +++ b/app/api/compat/agents/route.ts @@ -6,7 +6,7 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { envelope, toCompatAgent, toCompatCreateResult } from "@/lib/api/compat-envelope"; import { stripReservedMiladyConfigKeys } from "@/lib/services/milady-agent-config"; -import { miladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { logger } from "@/lib/utils/logger"; import { requireCompatAuth } from "../_lib/auth"; import { handleCompatCorsOptions, withCompatCors } from "../_lib/cors"; diff --git a/app/api/cron/milady-billing/route.ts b/app/api/cron/milady-billing/route.ts index 645ca6dd3..ff01ef1ad 100644 --- a/app/api/cron/milady-billing/route.ts +++ b/app/api/cron/milady-billing/route.ts @@ -578,8 +578,14 @@ async function handleMiladyBilling(request: NextRequest): Promise org.credit_balance = String(result.newBalance); } else if (result.action === "warning_sent") { warningsSent++; + // Refresh in-memory balance after warning (balance may have changed) + const freshBalance = await getOrgBalance(org.id); + if (freshBalance !== null) org.credit_balance = String(freshBalance); } else if (result.action === "shutdown") { sandboxesShutdown++; + // Refresh in-memory balance after shutdown action + const freshBalance = await getOrgBalance(org.id); + if (freshBalance !== null) org.credit_balance = String(freshBalance); } else if (result.action === "error") { errors++; } diff --git a/app/api/v1/agents/[agentId]/logs/route.ts b/app/api/v1/agents/[agentId]/logs/route.ts index 198e1b128..93212748e 100644 --- a/app/api/v1/agents/[agentId]/logs/route.ts +++ b/app/api/v1/agents/[agentId]/logs/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { logger } from "@/lib/utils/logger"; import { requireServiceKey, ServiceKeyAuthError } from "@/lib/auth/service-key"; -import { miladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { assertSafeOutboundUrl } from "@/lib/security/outbound-url"; export const dynamic = "force-dynamic"; diff --git a/app/api/v1/billing/settings/route.ts b/app/api/v1/billing/settings/route.ts index d705b9ec8..4adb0e7af 100644 --- a/app/api/v1/billing/settings/route.ts +++ b/app/api/v1/billing/settings/route.ts @@ -50,20 +50,21 @@ const UpdateSettingsSchema = z.object({ .optional(), }); -function isAuthenticationError(message: string): boolean { - return ( - message.includes("Unauthorized") || - message.includes("Authentication required") || - message.includes("Forbidden") || - message.includes("Invalid or expired API key") || - message.includes("API key is inactive") || - message.includes("API key has expired") || - message.includes("Invalid or expired token") - ); -} - -function getErrorMessage(error: unknown, fallbackMessage: string): string { - return error instanceof Error ? error.message : fallbackMessage; +/** + * Detect authentication/authorization errors by status code rather than + * fragile string matching on error messages. + */ +function isAuthenticationError(error: unknown): boolean { + if (error != null && typeof error === "object") { + const status = (error as { status?: number }).status; + if (status === 401 || status === 403) return true; + } + // ApiError (from @/lib/api/errors) carries .status + if (error instanceof Error && "status" in error) { + const status = (error as Error & { status?: number }).status; + if (status === 401 || status === 403) return true; + } + return false; } /** @@ -100,12 +101,13 @@ async function handleGET(req: NextRequest) { } catch (error) { logger.error("[Billing Settings API] Error getting settings:", error); - const errorMessage = getErrorMessage(error, "Failed to get billing settings"); - const isAuthError = isAuthenticationError(errorMessage); + if (isAuthenticationError(error)) { + return NextResponse.json({ success: false, error: "Unauthorized" }, { status: 401 }); + } return NextResponse.json( - { success: false, error: isAuthError ? "Unauthorized" : errorMessage }, - { status: isAuthError ? 401 : 500 }, + { success: false, error: "Failed to get billing settings" }, + { status: 500 }, ); } } @@ -175,17 +177,21 @@ async function handlePUT(req: NextRequest) { } catch (error) { logger.error("[Billing Settings API] Error updating settings:", error); - const errorMessage = getErrorMessage(error, "Failed to update billing settings"); - const isAuthError = isAuthenticationError(errorMessage); + if (isAuthenticationError(error)) { + return NextResponse.json({ success: false, error: "Unauthorized" }, { status: 401 }); + } + // Allow domain-specific validation messages through (e.g. "Cannot enable + // auto-top-up without a payment method") since they don't leak internals. + const message = error instanceof Error ? error.message : ""; const isValidationError = - errorMessage.includes("Cannot enable") || - errorMessage.includes("must be") || - errorMessage.includes("cannot exceed"); + message.includes("Cannot enable") || + message.includes("must be") || + message.includes("cannot exceed"); return NextResponse.json( - { success: false, error: errorMessage }, - { status: isAuthError ? 401 : isValidationError ? 400 : 500 }, + { success: false, error: isValidationError ? message : "Failed to update billing settings" }, + { status: isValidationError ? 400 : 500 }, ); } } diff --git a/app/api/v1/milady/agents/[agentId]/backups/route.ts b/app/api/v1/milady/agents/[agentId]/backups/route.ts index a45558794..4e5bd0c62 100644 --- a/app/api/v1/milady/agents/[agentId]/backups/route.ts +++ b/app/api/v1/milady/agents/[agentId]/backups/route.ts @@ -1,9 +1,17 @@ import { NextRequest, NextResponse } from "next/server"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; export const dynamic = "force-dynamic"; +const CORS_METHODS = "GET, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + /** * GET /api/v1/milady/agents/[agentId]/backups * List state backups for a Milady cloud agent. @@ -12,19 +20,26 @@ export async function GET( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; - const backups = await miladySandboxService.listBackups(agentId, user.organization_id); + const backups = await miladySandboxService.listBackups(agentId, user.organization_id); - return NextResponse.json({ - success: true, - data: backups.map((b) => ({ - id: b.id, - snapshotType: b.snapshot_type, - sizeBytes: b.size_bytes, - vercelSnapshotId: b.vercel_snapshot_id, - createdAt: b.created_at, - })), - }); + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: backups.map((b) => ({ + id: b.id, + snapshotType: b.snapshot_type, + sizeBytes: b.size_bytes, + vercelSnapshotId: b.vercel_snapshot_id, + createdAt: b.created_at, + })), + }), + CORS_METHODS, + ); + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } diff --git a/app/api/v1/milady/agents/[agentId]/bridge/route.ts b/app/api/v1/milady/agents/[agentId]/bridge/route.ts index a5caf6602..a838ac31c 100644 --- a/app/api/v1/milady/agents/[agentId]/bridge/route.ts +++ b/app/api/v1/milady/agents/[agentId]/bridge/route.ts @@ -1,11 +1,19 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import type { BridgeRequest } from "@/lib/services/milady-sandbox"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; export const dynamic = "force-dynamic"; +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + const bridgeRequestSchema = z.object({ jsonrpc: z.literal("2.0"), id: z.union([z.string(), z.number()]).optional(), @@ -26,20 +34,27 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - const body = await request.json(); - - const parsed = bridgeRequestSchema.safeParse(body); - if (!parsed.success) { - return NextResponse.json( - { success: false, error: "Invalid JSON-RPC request", details: parsed.error.issues }, - { status: 400 }, - ); - } + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; + const body = await request.json(); + + const parsed = bridgeRequestSchema.safeParse(body); + if (!parsed.success) { + return applyCorsHeaders( + NextResponse.json( + { success: false, error: "Invalid JSON-RPC request", details: parsed.error.issues }, + { status: 400 }, + ), + CORS_METHODS, + ); + } - const rpcRequest = parsed.data as BridgeRequest; - const response = await miladySandboxService.bridge(agentId, user.organization_id, rpcRequest); + const rpcRequest = parsed.data as BridgeRequest; + const response = await miladySandboxService.bridge(agentId, user.organization_id, rpcRequest); - return NextResponse.json(response); + return applyCorsHeaders(NextResponse.json(response), CORS_METHODS); + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } diff --git a/app/api/v1/milady/agents/[agentId]/pairing-token/route.ts b/app/api/v1/milady/agents/[agentId]/pairing-token/route.ts index c582dad39..74f3f7bb6 100644 --- a/app/api/v1/milady/agents/[agentId]/pairing-token/route.ts +++ b/app/api/v1/milady/agents/[agentId]/pairing-token/route.ts @@ -1,11 +1,19 @@ import { NextRequest, NextResponse } from "next/server"; import { miladySandboxesRepository } from "@/db/repositories/milady-sandboxes"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { getMiladyAgentPublicWebUiUrl } from "@/lib/milady-web-ui"; import { getPairingTokenService } from "@/lib/services/pairing-token"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; export const dynamic = "force-dynamic"; +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + /** * POST /api/v1/milady/agents/[agentId]/pairing-token * @@ -17,50 +25,66 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; - const sandbox = await miladySandboxesRepository.findByIdAndOrg(agentId, user.organization_id); + const sandbox = await miladySandboxesRepository.findByIdAndOrg(agentId, user.organization_id); - if (!sandbox) { - return NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }); - } + if (!sandbox) { + return applyCorsHeaders( + NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }), + CORS_METHODS, + ); + } - if (sandbox.status !== "running") { - return NextResponse.json( - { success: false, error: "Agent must be running to generate pairing token" }, - { status: 400 }, - ); - } + if (sandbox.status !== "running") { + return applyCorsHeaders( + NextResponse.json( + { success: false, error: "Agent must be running to generate pairing token" }, + { status: 400 }, + ), + CORS_METHODS, + ); + } - const webUiUrl = getMiladyAgentPublicWebUiUrl(sandbox); - if (!webUiUrl) { - return NextResponse.json( - { success: false, error: "Agent Web UI URL is not configured" }, - { status: 500 }, - ); - } + const webUiUrl = getMiladyAgentPublicWebUiUrl(sandbox); + if (!webUiUrl) { + return applyCorsHeaders( + NextResponse.json( + { success: false, error: "Agent Web UI URL is not configured" }, + { status: 500 }, + ), + CORS_METHODS, + ); + } - const tokenService = getPairingTokenService(); - const pairingToken = await tokenService.generateToken( - user.id, - user.organization_id, - agentId, - webUiUrl, - ); + const tokenService = getPairingTokenService(); + const pairingToken = await tokenService.generateToken( + user.id, + user.organization_id, + agentId, + webUiUrl, + ); - const response = NextResponse.json({ - success: true, - data: { - token: pairingToken, - redirectUrl: `${webUiUrl}/pair?token=${pairingToken}`, - expiresIn: 60, - }, - }); + const response = applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + token: pairingToken, + redirectUrl: `${webUiUrl}/pair?token=${pairingToken}`, + expiresIn: 60, + }, + }), + CORS_METHODS, + ); - response.headers.set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate"); - response.headers.set("Pragma", "no-cache"); - response.headers.set("Expires", "0"); + response.headers.set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate"); + response.headers.set("Pragma", "no-cache"); + response.headers.set("Expires", "0"); - return response; + return response; + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } diff --git a/app/api/v1/milady/agents/[agentId]/provision/route.ts b/app/api/v1/milady/agents/[agentId]/provision/route.ts index 6c39600ae..fd2cc6bf1 100644 --- a/app/api/v1/milady/agents/[agentId]/provision/route.ts +++ b/app/api/v1/milady/agents/[agentId]/provision/route.ts @@ -1,10 +1,12 @@ import { NextRequest, NextResponse } from "next/server"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { MILADY_PRICING } from "@/lib/constants/milady-pricing"; import { assertSafeOutboundUrl } from "@/lib/security/outbound-url"; import { checkMiladyCreditGate } from "@/lib/services/milady-billing-gate"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { provisioningJobService } from "@/lib/services/provisioning-jobs"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; import { logger } from "@/lib/utils/logger"; export const dynamic = "force-dynamic"; @@ -12,6 +14,12 @@ export const dynamic = "force-dynamic"; // Sync fallback (?sync=true) still needs headroom for legacy callers. export const maxDuration = 120; +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + function getProvisionFailureStatus(error?: string): 404 | 409 | 500 { if (error === "Agent not found") return 404; if (error === "Agent is already being provisioned") return 409; @@ -55,160 +63,188 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - const sync = request.nextUrl.searchParams.get("sync") === "true"; - - logger.info("[milady-api] Provision requested", { - agentId, - orgId: user.organization_id, - async: !sync, - }); - - // Fast path: check if already running (no job needed) - const existing = await miladySandboxService.getAgentForWrite(agentId, user.organization_id!); - if (!existing) { - return NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }); - } - - if (existing.status === "running" && existing.bridge_url && existing.health_url) { - return NextResponse.json({ - success: true, - data: { - id: existing.id, - agentName: existing.agent_name, - status: existing.status, - bridgeUrl: existing.bridge_url, - healthUrl: existing.health_url, - }, - }); - } + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; + const sync = request.nextUrl.searchParams.get("sync") === "true"; - // ── Credit gate: require minimum deposit before provisioning ────── - const creditCheck = await checkMiladyCreditGate(user.organization_id); - if (!creditCheck.allowed) { - logger.warn("[milady-api] Provision blocked: insufficient credits", { + logger.info("[milady-api] Provision requested", { agentId, orgId: user.organization_id, - balance: creditCheck.balance, - required: MILADY_PRICING.MINIMUM_DEPOSIT, + async: !sync, }); - return NextResponse.json( - { - success: false, - error: creditCheck.error, - requiredBalance: MILADY_PRICING.MINIMUM_DEPOSIT, - currentBalance: creditCheck.balance, - }, - { status: 402 }, - ); - } - // ── Sync fallback (legacy) ──────────────────────────────────────── - if (sync) { - const result = await miladySandboxService.provision(agentId, user.organization_id!); + // Fast path: check if already running (no job needed) + const existing = await miladySandboxService.getAgentForWrite(agentId, user.organization_id!); + if (!existing) { + return applyCorsHeaders( + NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }), + CORS_METHODS, + ); + } - if (!result.success) { - const status = getProvisionFailureStatus(result.error); - const clientError = sanitizeProvisionFailureMessage(result.error, status); + if (existing.status === "running" && existing.bridge_url && existing.health_url) { + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + id: existing.id, + agentName: existing.agent_name, + status: existing.status, + bridgeUrl: existing.bridge_url, + healthUrl: existing.health_url, + }, + }), + CORS_METHODS, + ); + } - if (status === 500) { - logger.error("[milady-api] Sync provision failed", { - agentId, - orgId: user.organization_id, - error: result.error, - }); + // ── Credit gate: require minimum deposit before provisioning ────── + const creditCheck = await checkMiladyCreditGate(user.organization_id); + if (!creditCheck.allowed) { + logger.warn("[milady-api] Provision blocked: insufficient credits", { + agentId, + orgId: user.organization_id, + balance: creditCheck.balance, + required: MILADY_PRICING.MINIMUM_DEPOSIT, + }); + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: creditCheck.error, + requiredBalance: MILADY_PRICING.MINIMUM_DEPOSIT, + currentBalance: creditCheck.balance, + }, + { status: 402 }, + ), + CORS_METHODS, + ); + } + + // ── Sync fallback (legacy) ──────────────────────────────────────── + if (sync) { + const result = await miladySandboxService.provision(agentId, user.organization_id!); + + if (!result.success) { + const status = getProvisionFailureStatus(result.error); + const clientError = sanitizeProvisionFailureMessage(result.error, status); + + if (status === 500) { + logger.error("[milady-api] Sync provision failed", { + agentId, + orgId: user.organization_id, + error: result.error, + }); + } + + return applyCorsHeaders( + NextResponse.json({ success: false, error: clientError }, { status }), + CORS_METHODS, + ); } - return NextResponse.json({ success: false, error: clientError }, { status }); + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + id: result.sandboxRecord.id, + agentName: result.sandboxRecord.agent_name, + status: result.sandboxRecord.status, + bridgeUrl: result.bridgeUrl, + healthUrl: result.healthUrl, + }, + }), + CORS_METHODS, + ); } - return NextResponse.json({ - success: true, - data: { - id: result.sandboxRecord.id, - agentName: result.sandboxRecord.agent_name, - status: result.sandboxRecord.status, - bridgeUrl: result.bridgeUrl, - healthUrl: result.healthUrl, - }, - }); - } + // ── Async path (default) ────────────────────────────────────────── + const webhookUrl = request.headers.get("x-webhook-url") ?? undefined; + if (webhookUrl) { + try { + await assertSafeOutboundUrl(webhookUrl); + } catch (error) { + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : "Invalid webhook URL", + }, + { status: 400 }, + ), + CORS_METHODS, + ); + } + } - // ── Async path (default) ────────────────────────────────────────── - const webhookUrl = request.headers.get("x-webhook-url") ?? undefined; - if (webhookUrl) { + let enqueueResult; try { - await assertSafeOutboundUrl(webhookUrl); + enqueueResult = await provisioningJobService.enqueueMiladyProvisionOnce({ + agentId, + organizationId: user.organization_id!, + userId: user.id, + agentName: existing.agent_name ?? agentId, + webhookUrl, + expectedUpdatedAt: existing.updated_at, + }); } catch (error) { - return NextResponse.json( - { - success: false, - error: error instanceof Error ? error.message : "Invalid webhook URL", - }, - { status: 400 }, + const message = error instanceof Error ? error.message : String(error); + const status = + message === "Agent not found" + ? 404 + : message === "Agent state changed while starting" + ? 409 + : 500; + + if (status === 500) { + logger.error("[milady-api] Failed to enqueue provisioning job", { + agentId, + orgId: user.organization_id, + error: message, + }); + } + + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: sanitizeEnqueueFailureMessage(message, status), + }, + { status }, + ), + CORS_METHODS, ); } - } - let enqueueResult; - try { - enqueueResult = await provisioningJobService.enqueueMiladyProvisionOnce({ - agentId, - organizationId: user.organization_id!, - userId: user.id, - agentName: existing.agent_name ?? agentId, - webhookUrl, - expectedUpdatedAt: existing.updated_at, - }); - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - const status = - message === "Agent not found" - ? 404 - : message === "Agent state changed while starting" - ? 409 - : 500; - - if (status === 500) { - logger.error("[milady-api] Failed to enqueue provisioning job", { - agentId, - orgId: user.organization_id, - error: message, - }); - } + const { job, created } = enqueueResult; - return NextResponse.json( - { - success: false, - error: sanitizeEnqueueFailureMessage(message, status), - }, - { status }, + return applyCorsHeaders( + NextResponse.json( + { + success: true, + created, + alreadyInProgress: !created, + message: created + ? "Provisioning job created. Poll the job endpoint for status." + : "Provisioning is already in progress. Poll the existing job for status.", + data: { + jobId: job.id, + agentId, + status: job.status, + estimatedCompletionAt: job.estimated_completion_at, + }, + polling: { + endpoint: `/api/v1/jobs/${job.id}`, + intervalMs: 5000, + expectedDurationMs: 90000, + }, + }, + { status: created ? 202 : 409 }, + ), + CORS_METHODS, ); + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); } - - const { job, created } = enqueueResult; - - return NextResponse.json( - { - success: true, - created, - alreadyInProgress: !created, - message: created - ? "Provisioning job created. Poll the job endpoint for status." - : "Provisioning is already in progress. Poll the existing job for status.", - data: { - jobId: job.id, - agentId, - status: job.status, - estimatedCompletionAt: job.estimated_completion_at, - }, - polling: { - endpoint: `/api/v1/jobs/${job.id}`, - intervalMs: 5000, - expectedDurationMs: 90000, - }, - }, - { status: created ? 202 : 409 }, - ); } diff --git a/app/api/v1/milady/agents/[agentId]/restore/route.ts b/app/api/v1/milady/agents/[agentId]/restore/route.ts index 897c22c64..8e2f14f04 100644 --- a/app/api/v1/milady/agents/[agentId]/restore/route.ts +++ b/app/api/v1/milady/agents/[agentId]/restore/route.ts @@ -1,11 +1,19 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; export const dynamic = "force-dynamic"; export const maxDuration = 120; // Restore may trigger re-provision +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + const restoreSchema = z.object({ backupId: z.string().uuid().optional(), }); @@ -21,47 +29,60 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - const body = await request.json(); + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; + const body = await request.json(); - const parsed = restoreSchema.safeParse(body); - if (!parsed.success) { - return NextResponse.json( - { - success: false, - error: "Invalid request", - details: parsed.error.issues, - }, - { status: 400 }, - ); - } + const parsed = restoreSchema.safeParse(body); + if (!parsed.success) { + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: "Invalid request", + details: parsed.error.issues, + }, + { status: 400 }, + ), + CORS_METHODS, + ); + } - const result = await miladySandboxService.restore( - agentId, - user.organization_id, - parsed.data.backupId, - ); + const result = await miladySandboxService.restore( + agentId, + user.organization_id, + parsed.data.backupId, + ); - if (!result.success) { - const status = - result.error === "Agent not found" - ? 404 - : result.error === "No backup found" + if (!result.success) { + const status = + result.error === "Agent not found" ? 404 - : result.error === "Stopped agents can only restore the latest backup" - ? 409 - : 500; + : result.error === "No backup found" + ? 404 + : result.error === "Stopped agents can only restore the latest backup" + ? 409 + : 500; - return NextResponse.json({ success: false, error: result.error }, { status }); - } + return applyCorsHeaders( + NextResponse.json({ success: false, error: result.error }, { status }), + CORS_METHODS, + ); + } - return NextResponse.json({ - success: true, - data: { - restoredFromBackupId: result.backup!.id, - snapshotType: result.backup!.snapshot_type, - createdAt: result.backup!.created_at, - }, - }); + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + restoredFromBackupId: result.backup!.id, + snapshotType: result.backup!.snapshot_type, + createdAt: result.backup!.created_at, + }, + }), + CORS_METHODS, + ); + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } diff --git a/app/api/v1/milady/agents/[agentId]/resume/route.ts b/app/api/v1/milady/agents/[agentId]/resume/route.ts index 399c8c765..28fe6ed88 100644 --- a/app/api/v1/milady/agents/[agentId]/resume/route.ts +++ b/app/api/v1/milady/agents/[agentId]/resume/route.ts @@ -1,15 +1,23 @@ import { NextRequest, NextResponse } from "next/server"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { MILADY_PRICING } from "@/lib/constants/milady-pricing"; import { assertSafeOutboundUrl } from "@/lib/security/outbound-url"; import { checkMiladyCreditGate } from "@/lib/services/milady-billing-gate"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { provisioningJobService } from "@/lib/services/provisioning-jobs"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; import { logger } from "@/lib/utils/logger"; export const dynamic = "force-dynamic"; export const maxDuration = 120; +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + /** * POST /api/v1/milady/agents/[agentId]/resume * @@ -28,140 +36,165 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - const sync = request.nextUrl.searchParams.get("sync") === "true"; - - logger.info("[milady-api] Resume requested", { - agentId, - orgId: user.organization_id, - async: !sync, - }); - - const agent = await miladySandboxService.getAgentForWrite(agentId, user.organization_id); - if (!agent) { - return NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }); - } - - if (agent.status === "running" && agent.bridge_url && agent.health_url) { - return NextResponse.json({ - success: true, - data: { - agentId, - action: "resume", - message: "Agent is already running", - status: agent.status, - }, - }); - } + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; + const sync = request.nextUrl.searchParams.get("sync") === "true"; - // ── Credit gate: require minimum deposit before resuming ────────── - const creditCheck = await checkMiladyCreditGate(user.organization_id); - if (!creditCheck.allowed) { - logger.warn("[milady-api] Resume blocked: insufficient credits", { + logger.info("[milady-api] Resume requested", { agentId, orgId: user.organization_id, - balance: creditCheck.balance, - required: MILADY_PRICING.MINIMUM_DEPOSIT, + async: !sync, }); - return NextResponse.json( - { - success: false, - error: creditCheck.error, - requiredBalance: MILADY_PRICING.MINIMUM_DEPOSIT, - currentBalance: creditCheck.balance, - }, - { status: 402 }, - ); - } - if (sync) { - const result = await miladySandboxService.provision(agentId, user.organization_id); + const agent = await miladySandboxService.getAgentForWrite(agentId, user.organization_id); + if (!agent) { + return applyCorsHeaders( + NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }), + CORS_METHODS, + ); + } - if (!result.success) { - const status = - result.error === "Agent not found" - ? 404 - : result.error === "Agent is already being provisioned" - ? 409 - : 500; - return NextResponse.json( - { success: false, error: result.error ?? "Resume failed" }, - { status }, + if (agent.status === "running" && agent.bridge_url && agent.health_url) { + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + agentId, + action: "resume", + message: "Agent is already running", + status: agent.status, + }, + }), + CORS_METHODS, ); } - return NextResponse.json({ - success: true, - data: { + // ── Credit gate: require minimum deposit before resuming ────────── + const creditCheck = await checkMiladyCreditGate(user.organization_id); + if (!creditCheck.allowed) { + logger.warn("[milady-api] Resume blocked: insufficient credits", { agentId, - action: "resume", - message: "Agent resumed from latest snapshot", - status: "running", - bridgeUrl: result.bridgeUrl, - healthUrl: result.healthUrl, - }, - }); - } + orgId: user.organization_id, + balance: creditCheck.balance, + required: MILADY_PRICING.MINIMUM_DEPOSIT, + }); + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: creditCheck.error, + requiredBalance: MILADY_PRICING.MINIMUM_DEPOSIT, + currentBalance: creditCheck.balance, + }, + { status: 402 }, + ), + CORS_METHODS, + ); + } - const webhookUrl = request.headers.get("x-webhook-url") ?? undefined; - if (webhookUrl) { - try { - await assertSafeOutboundUrl(webhookUrl); - } catch (error) { - return NextResponse.json( - { - success: false, - error: error instanceof Error ? error.message : "Invalid webhook URL", - }, - { status: 400 }, + if (sync) { + const result = await miladySandboxService.provision(agentId, user.organization_id); + + if (!result.success) { + const status = + result.error === "Agent not found" + ? 404 + : result.error === "Agent is already being provisioned" + ? 409 + : 500; + return applyCorsHeaders( + NextResponse.json({ success: false, error: result.error ?? "Resume failed" }, { status }), + CORS_METHODS, + ); + } + + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + agentId, + action: "resume", + message: "Agent resumed from latest snapshot", + status: "running", + bridgeUrl: result.bridgeUrl, + healthUrl: result.healthUrl, + }, + }), + CORS_METHODS, ); } - } - try { - const { job, created } = await provisioningJobService.enqueueMiladyProvisionOnce({ - agentId, - organizationId: user.organization_id, - userId: user.id, - agentName: agent.agent_name ?? agentId, - webhookUrl, - expectedUpdatedAt: agent.updated_at, - }); + const webhookUrl = request.headers.get("x-webhook-url") ?? undefined; + if (webhookUrl) { + try { + await assertSafeOutboundUrl(webhookUrl); + } catch (error) { + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: error instanceof Error ? error.message : "Invalid webhook URL", + }, + { status: 400 }, + ), + CORS_METHODS, + ); + } + } - return NextResponse.json( - { - success: true, - created, - alreadyInProgress: !created, - data: { - agentId, - action: "resume", - jobId: job.id, - status: job.status, - message: created - ? "Resume job created. Agent will restore from latest snapshot." - : "Resume is already in progress.", - }, - polling: { - endpoint: `/api/v1/jobs/${job.id}`, - intervalMs: 5000, - expectedDurationMs: 90000, - }, - }, - { status: created ? 202 : 409 }, - ); + try { + const { job, created } = await provisioningJobService.enqueueMiladyProvisionOnce({ + agentId, + organizationId: user.organization_id, + userId: user.id, + agentName: agent.agent_name ?? agentId, + webhookUrl, + expectedUpdatedAt: agent.updated_at, + }); + + return applyCorsHeaders( + NextResponse.json( + { + success: true, + created, + alreadyInProgress: !created, + data: { + agentId, + action: "resume", + jobId: job.id, + status: job.status, + message: created + ? "Resume job created. Agent will restore from latest snapshot." + : "Resume is already in progress.", + }, + polling: { + endpoint: `/api/v1/jobs/${job.id}`, + intervalMs: 5000, + expectedDurationMs: 90000, + }, + }, + { status: created ? 202 : 409 }, + ), + CORS_METHODS, + ); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + const status = + message === "Agent not found" + ? 404 + : message === "Agent state changed while starting" + ? 409 + : 500; + return applyCorsHeaders( + NextResponse.json( + { success: false, error: status === 500 ? "Failed to resume agent" : message }, + { status }, + ), + CORS_METHODS, + ); + } } catch (error) { - const message = error instanceof Error ? error.message : String(error); - const status = - message === "Agent not found" - ? 404 - : message === "Agent state changed while starting" - ? 409 - : 500; - return NextResponse.json( - { success: false, error: status === 500 ? "Failed to resume agent" : message }, - { status }, - ); + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); } } diff --git a/app/api/v1/milady/agents/[agentId]/route.ts b/app/api/v1/milady/agents/[agentId]/route.ts index cda3bf845..8b2913d01 100644 --- a/app/api/v1/milady/agents/[agentId]/route.ts +++ b/app/api/v1/milady/agents/[agentId]/route.ts @@ -1,13 +1,21 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { userCharactersRepository } from "@/db/repositories/characters"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { reusesExistingMiladyCharacter } from "@/lib/services/milady-agent-config"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; import { logger } from "@/lib/utils/logger"; export const dynamic = "force-dynamic"; +const CORS_METHODS = "GET, PATCH, DELETE, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + const patchAgentSchema = z.object({ action: z.enum(["shutdown", "suspend"]), }); @@ -20,64 +28,76 @@ export async function GET( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; - const agent = await miladySandboxService.getAgent(agentId, user.organization_id); - if (!agent) { - return NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }); - } + const agent = await miladySandboxService.getAgent(agentId, user.organization_id); + if (!agent) { + return applyCorsHeaders( + NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }), + CORS_METHODS, + ); + } - // Resolve token linkage from associated character or JSONB fallback - let tokenAddress: string | null = null; - let tokenChain: string | null = null; - let tokenName: string | null = null; - let tokenTicker: string | null = null; + // Resolve token linkage from associated character or JSONB fallback + let tokenAddress: string | null = null; + let tokenChain: string | null = null; + let tokenName: string | null = null; + let tokenTicker: string | null = null; - if (agent.character_id) { - const char = await userCharactersRepository.findByIdInOrganization( - agent.character_id, - user.organization_id, - ); - if (char) { - tokenAddress = char.token_address ?? null; - tokenChain = char.token_chain ?? null; - tokenName = char.token_name ?? null; - tokenTicker = char.token_ticker ?? null; + if (agent.character_id) { + const char = await userCharactersRepository.findByIdInOrganization( + agent.character_id, + user.organization_id, + ); + if (char) { + tokenAddress = char.token_address ?? null; + tokenChain = char.token_chain ?? null; + tokenName = char.token_name ?? null; + tokenTicker = char.token_ticker ?? null; + } } - } - // Fallback to agent_config JSONB — use typeof guards since JSONB - // values are untyped and could be numbers, objects, etc. - if (!tokenAddress) { - const cfg = agent.agent_config as Record | null; - tokenAddress = typeof cfg?.tokenContractAddress === "string" ? cfg.tokenContractAddress : null; - tokenChain = typeof cfg?.chain === "string" ? cfg.chain : null; - tokenName = typeof cfg?.tokenName === "string" ? cfg.tokenName : null; - tokenTicker = typeof cfg?.tokenTicker === "string" ? cfg.tokenTicker : null; - } + // Fallback to agent_config JSONB — use typeof guards since JSONB + // values are untyped and could be numbers, objects, etc. + if (!tokenAddress) { + const cfg = agent.agent_config as Record | null; + tokenAddress = + typeof cfg?.tokenContractAddress === "string" ? cfg.tokenContractAddress : null; + tokenChain = typeof cfg?.chain === "string" ? cfg.chain : null; + tokenName = typeof cfg?.tokenName === "string" ? cfg.tokenName : null; + tokenTicker = typeof cfg?.tokenTicker === "string" ? cfg.tokenTicker : null; + } - return NextResponse.json({ - success: true, - data: { - id: agent.id, - agentName: agent.agent_name, - status: agent.status, - databaseStatus: agent.database_status, - bridgeUrl: agent.bridge_url, - lastBackupAt: agent.last_backup_at, - lastHeartbeatAt: agent.last_heartbeat_at, - errorMessage: agent.error_message, - errorCount: agent.error_count, - createdAt: agent.created_at, - updatedAt: agent.updated_at, - // Canonical token linkage - token_address: tokenAddress, - token_chain: tokenChain, - token_name: tokenName, - token_ticker: tokenTicker, - }, - }); + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + id: agent.id, + agentName: agent.agent_name, + status: agent.status, + databaseStatus: agent.database_status, + bridgeUrl: agent.bridge_url, + lastBackupAt: agent.last_backup_at, + lastHeartbeatAt: agent.last_heartbeat_at, + errorMessage: agent.error_message, + errorCount: agent.error_count, + createdAt: agent.created_at, + updatedAt: agent.updated_at, + // Canonical token linkage + token_address: tokenAddress, + token_chain: tokenChain, + token_name: tokenName, + token_ticker: tokenTicker, + }, + }), + CORS_METHODS, + ); + } catch (error) { + logger.error("[milady-api] GET /agents/[agentId] error", { error }); + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } /** @@ -88,80 +108,103 @@ export async function PATCH( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - const body = await request.json().catch(() => null); - - const parsed = patchAgentSchema.safeParse(body); - if (!parsed.success) { - return NextResponse.json( - { - success: false, - error: "Invalid request data", - details: parsed.error.issues, - }, - { status: 400 }, - ); - } + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; + const body = await request.json().catch(() => null); - if (parsed.data.action === "shutdown" || parsed.data.action === "suspend") { - const agent = await miladySandboxService.getAgentForWrite(agentId, user.organization_id); - if (!agent) { - return NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }); + const parsed = patchAgentSchema.safeParse(body); + if (!parsed.success) { + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: "Invalid request data", + details: parsed.error.issues, + }, + { status: 400 }, + ), + CORS_METHODS, + ); } - if (agent.status === "stopped") { - return NextResponse.json({ - success: true, - data: { - agentId, - action: parsed.data.action, - message: - parsed.data.action === "shutdown" - ? "Agent is already stopped" - : "Agent is already suspended", - previousStatus: agent.status, - }, + if (parsed.data.action === "shutdown" || parsed.data.action === "suspend") { + const agent = await miladySandboxService.getAgentForWrite(agentId, user.organization_id); + if (!agent) { + return applyCorsHeaders( + NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }), + CORS_METHODS, + ); + } + + if (agent.status === "stopped") { + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + agentId, + action: parsed.data.action, + message: + parsed.data.action === "shutdown" + ? "Agent is already stopped" + : "Agent is already suspended", + previousStatus: agent.status, + }, + }), + CORS_METHODS, + ); + } + + const result = await miladySandboxService.shutdown(agentId, user.organization_id); + if (!result.success) { + const status = + result.error === "Agent not found" + ? 404 + : result.error === "Agent provisioning is in progress" + ? 409 + : 400; + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: result.error ?? `${parsed.data.action} failed`, + }, + { status }, + ), + CORS_METHODS, + ); + } + + logger.info(`[milady-api] Agent ${parsed.data.action} complete`, { + agentId, + orgId: user.organization_id, }); - } - const result = await miladySandboxService.shutdown(agentId, user.organization_id); - if (!result.success) { - const status = - result.error === "Agent not found" - ? 404 - : result.error === "Agent provisioning is in progress" - ? 409 - : 400; - return NextResponse.json( - { - success: false, - error: result.error ?? `${parsed.data.action} failed`, - }, - { status }, + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + agentId, + action: parsed.data.action, + message: + parsed.data.action === "shutdown" + ? "Agent shutdown complete" + : "Agent suspended with snapshot. Use resume or provision to restart.", + previousStatus: agent.status, + }, + }), + CORS_METHODS, ); } - logger.info(`[milady-api] Agent ${parsed.data.action} complete`, { - agentId, - orgId: user.organization_id, - }); - - return NextResponse.json({ - success: true, - data: { - agentId, - action: parsed.data.action, - message: - parsed.data.action === "shutdown" - ? "Agent shutdown complete" - : "Agent suspended with snapshot. Use resume or provision to restart.", - previousStatus: agent.status, - }, - }); + return applyCorsHeaders( + NextResponse.json({ success: false, error: "Unsupported action" }, { status: 400 }), + CORS_METHODS, + ); + } catch (error) { + logger.error("[milady-api] PATCH /agents/[agentId] error", { error }); + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); } - - return NextResponse.json({ success: false, error: "Unsupported action" }, { status: 400 }); } /** @@ -172,44 +215,52 @@ export async function DELETE( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - - const deleted = await miladySandboxService.deleteAgent(agentId, user.organization_id); - if (!deleted.success) { - const status = - deleted.error === "Agent not found" - ? 404 - : deleted.error === "Agent provisioning is in progress" - ? 409 - : 500; - return NextResponse.json({ success: false, error: deleted.error }, { status }); - } + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; + + const deleted = await miladySandboxService.deleteAgent(agentId, user.organization_id); + if (!deleted.success) { + const status = + deleted.error === "Agent not found" + ? 404 + : deleted.error === "Agent provisioning is in progress" + ? 409 + : 500; + return applyCorsHeaders( + NextResponse.json({ success: false, error: deleted.error }, { status }), + CORS_METHODS, + ); + } - const characterId = deleted.deletedSandbox.character_id; - const sandboxConfig = deleted.deletedSandbox.agent_config as Record | null; - const reusesExistingCharacter = reusesExistingMiladyCharacter(sandboxConfig); + const characterId = deleted.deletedSandbox.character_id; + const sandboxConfig = deleted.deletedSandbox.agent_config as Record | null; + const reusesExistingCharacter = reusesExistingMiladyCharacter(sandboxConfig); - if (characterId && !reusesExistingCharacter) { - try { - await userCharactersRepository.delete(characterId); - logger.info("[milady-api] Cleaned up linked character after delete", { - agentId, - characterId, - }); - } catch (characterErr) { - logger.warn("[milady-api] Failed to clean up linked character after delete", { - agentId, - characterId, - error: characterErr instanceof Error ? characterErr.message : String(characterErr), - }); + if (characterId && !reusesExistingCharacter) { + try { + await userCharactersRepository.delete(characterId); + logger.info("[milady-api] Cleaned up linked character after delete", { + agentId, + characterId, + }); + } catch (characterErr) { + logger.warn("[milady-api] Failed to clean up linked character after delete", { + agentId, + characterId, + error: characterErr instanceof Error ? characterErr.message : String(characterErr), + }); + } } - } - logger.info("[milady-api] Agent deleted", { - agentId, - orgId: user.organization_id, - }); + logger.info("[milady-api] Agent deleted", { + agentId, + orgId: user.organization_id, + }); - return NextResponse.json({ success: true }); + return applyCorsHeaders(NextResponse.json({ success: true }), CORS_METHODS); + } catch (error) { + logger.error("[milady-api] DELETE /agents/[agentId] error", { error }); + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } diff --git a/app/api/v1/milady/agents/[agentId]/snapshot/route.ts b/app/api/v1/milady/agents/[agentId]/snapshot/route.ts index 3eee32144..e5d31abb5 100644 --- a/app/api/v1/milady/agents/[agentId]/snapshot/route.ts +++ b/app/api/v1/milady/agents/[agentId]/snapshot/route.ts @@ -1,9 +1,17 @@ import { NextRequest, NextResponse } from "next/server"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; export const dynamic = "force-dynamic"; +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + /** * POST /api/v1/milady/agents/[agentId]/snapshot * Trigger a manual state backup of the running sandbox. @@ -12,25 +20,35 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; - const result = await miladySandboxService.snapshot(agentId, user.organization_id, "manual"); + const result = await miladySandboxService.snapshot(agentId, user.organization_id, "manual"); - if (!result.success) { - return NextResponse.json( - { success: false, error: result.error }, - { status: result.error === "Sandbox is not running" ? 409 : 500 }, + if (!result.success) { + return applyCorsHeaders( + NextResponse.json( + { success: false, error: result.error }, + { status: result.error === "Sandbox is not running" ? 409 : 500 }, + ), + CORS_METHODS, + ); + } + + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + backupId: result.backup!.id, + snapshotType: result.backup!.snapshot_type, + sizeBytes: result.backup!.size_bytes, + createdAt: result.backup!.created_at, + }, + }), + CORS_METHODS, ); + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); } - - return NextResponse.json({ - success: true, - data: { - backupId: result.backup!.id, - snapshotType: result.backup!.snapshot_type, - sizeBytes: result.backup!.size_bytes, - createdAt: result.backup!.created_at, - }, - }); } diff --git a/app/api/v1/milady/agents/[agentId]/stream/route.ts b/app/api/v1/milady/agents/[agentId]/stream/route.ts index 734b78e56..1450401b2 100644 --- a/app/api/v1/milady/agents/[agentId]/stream/route.ts +++ b/app/api/v1/milady/agents/[agentId]/stream/route.ts @@ -1,13 +1,21 @@ import { NextRequest } from "next/server"; import { z } from "zod"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import type { BridgeRequest } from "@/lib/services/milady-sandbox"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; export const dynamic = "force-dynamic"; // Streaming responses can be long-running export const maxDuration = 120; +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + const streamRequestSchema = z.object({ jsonrpc: z.literal("2.0"), id: z.union([z.string(), z.number()]).optional(), @@ -32,61 +40,74 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - const body = await request.json(); + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; + const body = await request.json(); - const parsed = streamRequestSchema.safeParse(body); - if (!parsed.success) { - return new Response( - JSON.stringify({ error: "Invalid request", details: parsed.error.issues }), - { status: 400, headers: { "Content-Type": "application/json" } }, - ); - } + const parsed = streamRequestSchema.safeParse(body); + if (!parsed.success) { + return applyCorsHeaders( + new Response(JSON.stringify({ error: "Invalid request", details: parsed.error.issues }), { + status: 400, + headers: { "Content-Type": "application/json" }, + }), + CORS_METHODS, + ); + } + + const rpcRequest = parsed.data as BridgeRequest; - const rpcRequest = parsed.data as BridgeRequest; + // Get the raw SSE stream from the sandbox + const upstreamResponse = await miladySandboxService.bridgeStream( + agentId, + user.organization_id, + rpcRequest, + ); - // Get the raw SSE stream from the sandbox - const upstreamResponse = await miladySandboxService.bridgeStream( - agentId, - user.organization_id, - rpcRequest, - ); + if (!upstreamResponse || !upstreamResponse.body) { + const { readable, writable } = new TransformStream(); + const writer = writable.getWriter(); + const encoder = new TextEncoder(); - if (!upstreamResponse || !upstreamResponse.body) { - const { readable, writable } = new TransformStream(); - const writer = writable.getWriter(); - const encoder = new TextEncoder(); + // Send error as SSE then close + (async () => { + await writer.write( + encoder.encode( + `event: error\ndata: ${JSON.stringify({ message: "Sandbox is not running or unreachable" })}\n\n`, + ), + ); + await writer.close(); + })(); - // Send error as SSE then close - (async () => { - await writer.write( - encoder.encode( - `event: error\ndata: ${JSON.stringify({ message: "Sandbox is not running or unreachable" })}\n\n`, - ), + return applyCorsHeaders( + new Response(readable, { + headers: { + "Content-Type": "text/event-stream", + "Cache-Control": "no-cache, no-transform", + Connection: "keep-alive", + "X-Accel-Buffering": "no", + }, + }), + CORS_METHODS, ); - await writer.close(); - })(); + } - return new Response(readable, { - headers: { - "Content-Type": "text/event-stream", - "Cache-Control": "no-cache, no-transform", - Connection: "keep-alive", - "X-Accel-Buffering": "no", - }, - }); + // Proxy the upstream SSE stream directly to the client. + // The sandbox bridge/stream endpoint already emits proper SSE events + // (connected, chunk, done), so we just pipe the body through. + return applyCorsHeaders( + new Response(upstreamResponse.body, { + headers: { + "Content-Type": "text/event-stream", + "Cache-Control": "no-cache, no-transform", + Connection: "keep-alive", + "X-Accel-Buffering": "no", + }, + }), + CORS_METHODS, + ); + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); } - - // Proxy the upstream SSE stream directly to the client. - // The sandbox bridge/stream endpoint already emits proper SSE events - // (connected, chunk, done), so we just pipe the body through. - return new Response(upstreamResponse.body, { - headers: { - "Content-Type": "text/event-stream", - "Cache-Control": "no-cache, no-transform", - Connection: "keep-alive", - "X-Accel-Buffering": "no", - }, - }); } diff --git a/app/api/v1/milady/agents/[agentId]/suspend/route.ts b/app/api/v1/milady/agents/[agentId]/suspend/route.ts index af91cff2f..bfb0293cf 100644 --- a/app/api/v1/milady/agents/[agentId]/suspend/route.ts +++ b/app/api/v1/milady/agents/[agentId]/suspend/route.ts @@ -1,10 +1,18 @@ import { NextRequest, NextResponse } from "next/server"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; import { logger } from "@/lib/utils/logger"; export const dynamic = "force-dynamic"; +const CORS_METHODS = "POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + /** * POST /api/v1/milady/agents/[agentId]/suspend * @@ -21,58 +29,71 @@ export async function POST( request: NextRequest, { params }: { params: Promise<{ agentId: string }> }, ) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const { agentId } = await params; - - logger.info("[milady-api] Suspend requested", { - agentId, - orgId: user.organization_id, - }); + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const { agentId } = await params; - const agent = await miladySandboxService.getAgentForWrite(agentId, user.organization_id); - if (!agent) { - return NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }); - } - - if (agent.status === "stopped") { - return NextResponse.json({ - success: true, - data: { - agentId, - action: "suspend", - message: "Agent is already suspended", - previousStatus: agent.status, - }, + logger.info("[milady-api] Suspend requested", { + agentId, + orgId: user.organization_id, }); - } - const result = await miladySandboxService.shutdown(agentId, user.organization_id); + const agent = await miladySandboxService.getAgentForWrite(agentId, user.organization_id); + if (!agent) { + return applyCorsHeaders( + NextResponse.json({ success: false, error: "Agent not found" }, { status: 404 }), + CORS_METHODS, + ); + } - if (!result.success) { - const status = - result.error === "Agent not found" - ? 404 - : result.error === "Agent provisioning is in progress" - ? 409 - : 500; - return NextResponse.json( - { success: false, error: result.error ?? "Suspend failed" }, - { status }, - ); - } + if (agent.status === "stopped") { + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + agentId, + action: "suspend", + message: "Agent is already suspended", + previousStatus: agent.status, + }, + }), + CORS_METHODS, + ); + } - logger.info("[milady-api] Agent suspended", { - agentId, - orgId: user.organization_id, - }); + const result = await miladySandboxService.shutdown(agentId, user.organization_id); - return NextResponse.json({ - success: true, - data: { + if (!result.success) { + const status = + result.error === "Agent not found" + ? 404 + : result.error === "Agent provisioning is in progress" + ? 409 + : 500; + return applyCorsHeaders( + NextResponse.json({ success: false, error: result.error ?? "Suspend failed" }, { status }), + CORS_METHODS, + ); + } + + logger.info("[milady-api] Agent suspended", { agentId, - action: "suspend", - message: "Agent suspended with snapshot. Use resume or provision to restart.", - previousStatus: agent.status, - }, - }); + orgId: user.organization_id, + }); + + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: { + agentId, + action: "suspend", + message: "Agent suspended with snapshot. Use resume or provision to restart.", + previousStatus: agent.status, + }, + }), + CORS_METHODS, + ); + } catch (error) { + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } diff --git a/app/api/v1/milady/agents/route.ts b/app/api/v1/milady/agents/route.ts index c19e7ea5d..a972dcae1 100644 --- a/app/api/v1/milady/agents/route.ts +++ b/app/api/v1/milady/agents/route.ts @@ -1,6 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { z } from "zod"; import { userCharactersRepository } from "@/db/repositories/characters"; +import { errorToResponse } from "@/lib/api/errors"; import { requireAuthOrApiKeyWithOrg } from "@/lib/auth"; import { MILADY_PRICING } from "@/lib/constants/milady-pricing"; import { @@ -10,10 +11,17 @@ import { import { checkMiladyCreditGate } from "@/lib/services/milady-billing-gate"; import { prepareManagedMiladyEnvironment } from "@/lib/services/milady-managed-launch"; import { miladySandboxService } from "@/lib/services/milady-sandbox"; +import { applyCorsHeaders, handleCorsOptions } from "@/lib/services/proxy/cors"; import { logger } from "@/lib/utils/logger"; export const dynamic = "force-dynamic"; +const CORS_METHODS = "GET, POST, OPTIONS"; + +export function OPTIONS() { + return handleCorsOptions(CORS_METHODS); +} + const createAgentSchema = z.object({ agentName: z.string().min(1).max(100), characterId: z.string().uuid().optional(), @@ -26,43 +34,51 @@ const createAgentSchema = z.object({ * List all Milady cloud agents for the authenticated user's organization. */ export async function GET(request: NextRequest) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const agents = await miladySandboxService.listAgents(user.organization_id); - - const characterIds = Array.from( - new Set(agents.map((a) => a.character_id).filter((id): id is string => id != null)), - ); - const characters = - characterIds.length > 0 - ? await userCharactersRepository.findByIdsInOrganization(characterIds, user.organization_id) - : []; - const charMap = new Map(characters.map((c) => [c.id, c])); - - return NextResponse.json({ - success: true, - data: agents.map((a) => { - const char = a.character_id ? charMap.get(a.character_id) : undefined; - // Fallback: extract from agent_config JSONB if character record not linked - const cfg = a.agent_config as Record | null; - return { - id: a.id, - agentName: a.agent_name, - status: a.status, - databaseStatus: a.database_status, - lastBackupAt: a.last_backup_at, - lastHeartbeatAt: a.last_heartbeat_at, - errorMessage: a.error_message, - createdAt: a.created_at, - updatedAt: a.updated_at, - // Canonical token linkage - token_address: - char?.token_address ?? (cfg?.tokenContractAddress as string | undefined) ?? null, - token_chain: char?.token_chain ?? (cfg?.chain as string | undefined) ?? null, - token_name: char?.token_name ?? (cfg?.tokenName as string | undefined) ?? null, - token_ticker: char?.token_ticker ?? (cfg?.tokenTicker as string | undefined) ?? null, - }; - }), - }); + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const agents = await miladySandboxService.listAgents(user.organization_id); + + const characterIds = Array.from( + new Set(agents.map((a) => a.character_id).filter((id): id is string => id != null)), + ); + const characters = + characterIds.length > 0 + ? await userCharactersRepository.findByIdsInOrganization(characterIds, user.organization_id) + : []; + const charMap = new Map(characters.map((c) => [c.id, c])); + + return applyCorsHeaders( + NextResponse.json({ + success: true, + data: agents.map((a) => { + const char = a.character_id ? charMap.get(a.character_id) : undefined; + // Fallback: extract from agent_config JSONB if character record not linked + const cfg = a.agent_config as Record | null; + return { + id: a.id, + agentName: a.agent_name, + status: a.status, + databaseStatus: a.database_status, + lastBackupAt: a.last_backup_at, + lastHeartbeatAt: a.last_heartbeat_at, + errorMessage: a.error_message, + createdAt: a.created_at, + updatedAt: a.updated_at, + // Canonical token linkage + token_address: + char?.token_address ?? (cfg?.tokenContractAddress as string | undefined) ?? null, + token_chain: char?.token_chain ?? (cfg?.chain as string | undefined) ?? null, + token_name: char?.token_name ?? (cfg?.tokenName as string | undefined) ?? null, + token_ticker: char?.token_ticker ?? (cfg?.tokenTicker as string | undefined) ?? null, + }; + }), + }), + CORS_METHODS, + ); + } catch (error) { + logger.error("[milady-api] GET /agents error", { error }); + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); + } } /** @@ -70,92 +86,109 @@ export async function GET(request: NextRequest) { * Create a new Milady cloud agent. */ export async function POST(request: NextRequest) { - const { user } = await requireAuthOrApiKeyWithOrg(request); - const body = await request.json(); - - const parsed = createAgentSchema.safeParse(body); - if (!parsed.success) { - return NextResponse.json( - { - success: false, - error: "Invalid request data", - details: parsed.error.issues, - }, - { status: 400 }, - ); - } + try { + const { user } = await requireAuthOrApiKeyWithOrg(request); + const body = await request.json(); - // ── Credit gate: require minimum deposit before creating an agent ── - const creditCheck = await checkMiladyCreditGate(user.organization_id); - if (!creditCheck.allowed) { - logger.warn("[milady-api] Agent creation blocked: insufficient credits", { - orgId: user.organization_id, - balance: creditCheck.balance, - required: MILADY_PRICING.MINIMUM_DEPOSIT, + const parsed = createAgentSchema.safeParse(body); + if (!parsed.success) { + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: "Invalid request data", + details: parsed.error.issues, + }, + { status: 400 }, + ), + CORS_METHODS, + ); + } + + // ── Credit gate: require minimum deposit before creating an agent ── + const creditCheck = await checkMiladyCreditGate(user.organization_id); + if (!creditCheck.allowed) { + logger.warn("[milady-api] Agent creation blocked: insufficient credits", { + orgId: user.organization_id, + balance: creditCheck.balance, + required: MILADY_PRICING.MINIMUM_DEPOSIT, + }); + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: creditCheck.error, + requiredBalance: MILADY_PRICING.MINIMUM_DEPOSIT, + currentBalance: creditCheck.balance, + }, + { status: 402 }, + ), + CORS_METHODS, + ); + } + + if (parsed.data.characterId) { + const character = await userCharactersRepository.findByIdInOrganizationForWrite( + parsed.data.characterId, + user.organization_id, + ); + + if (!character) { + return applyCorsHeaders( + NextResponse.json( + { + success: false, + error: "Character not found", + }, + { status: 404 }, + ), + CORS_METHODS, + ); + } + } + + // Strip reserved __milady* keys from user-supplied agentConfig to prevent + // callers from spoofing internal lifecycle flags. + const sanitizedConfig = stripReservedMiladyConfigKeys(parsed.data.agentConfig); + const managedEnvironment = await prepareManagedMiladyEnvironment({ + existingEnv: parsed.data.environmentVars, + organizationId: user.organization_id, + userId: user.id, }); - return NextResponse.json( - { - success: false, - error: creditCheck.error, - requiredBalance: MILADY_PRICING.MINIMUM_DEPOSIT, - currentBalance: creditCheck.balance, - }, - { status: 402 }, - ); - } - if (parsed.data.characterId) { - const character = await userCharactersRepository.findByIdInOrganizationForWrite( - parsed.data.characterId, - user.organization_id, - ); + const agent = await miladySandboxService.createAgent({ + organizationId: user.organization_id, + userId: user.id, + agentName: parsed.data.agentName, + characterId: parsed.data.characterId, + agentConfig: parsed.data.characterId + ? withReusedMiladyCharacterOwnership(sanitizedConfig) + : sanitizedConfig, + environmentVars: managedEnvironment.environmentVars, + }); + + logger.info("[milady-api] Agent created", { + agentId: agent.id, + orgId: user.organization_id, + }); - if (!character) { - return NextResponse.json( + return applyCorsHeaders( + NextResponse.json( { - success: false, - error: "Character not found", + success: true, + data: { + id: agent.id, + agentName: agent.agent_name, + status: agent.status, + createdAt: agent.created_at, + }, }, - { status: 404 }, - ); - } + { status: 201 }, + ), + CORS_METHODS, + ); + } catch (error) { + logger.error("[milady-api] POST /agents error", { error }); + return applyCorsHeaders(errorToResponse(error), CORS_METHODS); } - - // Strip reserved __milady* keys from user-supplied agentConfig to prevent - // callers from spoofing internal lifecycle flags. - const sanitizedConfig = stripReservedMiladyConfigKeys(parsed.data.agentConfig); - const managedEnvironment = await prepareManagedMiladyEnvironment({ - existingEnv: parsed.data.environmentVars, - organizationId: user.organization_id, - userId: user.id, - }); - - const agent = await miladySandboxService.createAgent({ - organizationId: user.organization_id, - userId: user.id, - agentName: parsed.data.agentName, - characterId: parsed.data.characterId, - agentConfig: parsed.data.characterId - ? withReusedMiladyCharacterOwnership(sanitizedConfig) - : sanitizedConfig, - environmentVars: managedEnvironment.environmentVars, - }); - - logger.info("[milady-api] Agent created", { - agentId: agent.id, - orgId: user.organization_id, - }); - - return NextResponse.json( - { - success: true, - data: { - id: agent.id, - agentName: agent.agent_name, - status: agent.status, - createdAt: agent.created_at, - }, - }, - { status: 201 }, - ); } diff --git a/app/dashboard/containers/agents/[id]/page.tsx b/app/dashboard/containers/agents/[id]/page.tsx index 725afabe4..edc58604d 100644 --- a/app/dashboard/containers/agents/[id]/page.tsx +++ b/app/dashboard/containers/agents/[id]/page.tsx @@ -16,7 +16,7 @@ import { requireAuthWithOrg } from "@/lib/auth"; import { statusBadgeColor, statusDotColor } from "@/lib/constants/sandbox-status"; import { getPreferredMiladyAgentWebUiUrl } from "@/lib/milady-web-ui"; import { adminService } from "@/lib/services/admin"; -import { miladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { MiladyAgentActions } from "@/packages/ui/src/components/containers/agent-actions"; import { DockerLogsViewer } from "@/packages/ui/src/components/containers/docker-logs-viewer"; import { MiladyBackupsPanel } from "@/packages/ui/src/components/containers/milady-backups-panel"; diff --git a/docs/steward-container-provisioning.md b/docs/steward-container-provisioning.md new file mode 100644 index 000000000..20864252e --- /dev/null +++ b/docs/steward-container-provisioning.md @@ -0,0 +1,23 @@ +# Steward-aware container provisioning + +Updated the Docker sandbox orchestrator so newly provisioned Milady containers are created with Steward integration by default. + +## What changed + +- Default Docker image now falls back to `milady/agent:v2.0.0-steward-2` + - Overrideable with `MILADY_DOCKER_IMAGE` +- New containers now receive these env vars automatically: + - `MILADY_CLOUD_PROVISIONED=1` + - `STEWARD_API_URL=http://localhost:3200` + - `STEWARD_AGENT_ID=` + - `STEWARD_AGENT_TOKEN=` +- Provisioning now registers the agent in Steward on the target node before container start: + - `POST /agents` + - `POST /agents/:agentId/token` +- New containers are attached to `milady-isolated` by default + - Overrideable with `MILADY_DOCKER_NETWORK` +- Docker healthcheck now targets `MILADY_PORT` instead of legacy `ELIZA_PORT` + +## Scope + +These changes only affect newly created Docker sandboxes. Running containers are not modified. diff --git a/package.json b/package.json index 6a623388a..07f887410 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,8 @@ "db:local:logs": "docker-compose logs -f postgres", "db:local:seed": "tsx packages/scripts/seed-local-dev.ts", "db:audit": "bun run packages/scripts/audit-migrations.ts", + "db:check-migrations": "bun run packages/scripts/check-migration-journal.ts", + "db:repair-journal": "bun run packages/scripts/repair-drizzle-journal.ts", "seed:credit-packs": "tsx packages/scripts/seed-credit-packs.ts", "stripe:webhook": "stripe listen --forward-to localhost:3000/api/stripe/webhook", "cron:auto-top-up": "tsx packages/scripts/trigger-auto-top-up.ts", diff --git a/packages/db/migrations/0043_seed_chain_data_pricing.sql b/packages/db/migrations/0044_seed_chain_data_pricing.sql similarity index 100% rename from packages/db/migrations/0043_seed_chain_data_pricing.sql rename to packages/db/migrations/0044_seed_chain_data_pricing.sql diff --git a/packages/db/migrations/0044_add_whatsapp_identity_columns.sql b/packages/db/migrations/0045_add_whatsapp_identity_columns.sql similarity index 100% rename from packages/db/migrations/0044_add_whatsapp_identity_columns.sql rename to packages/db/migrations/0045_add_whatsapp_identity_columns.sql diff --git a/packages/db/migrations/0045_add_redeemable_earnings_breakdown_columns.sql b/packages/db/migrations/0046_add_redeemable_earnings_breakdown_columns.sql similarity index 100% rename from packages/db/migrations/0045_add_redeemable_earnings_breakdown_columns.sql rename to packages/db/migrations/0046_add_redeemable_earnings_breakdown_columns.sql diff --git a/packages/db/migrations/0046_docker_nodes.sql b/packages/db/migrations/0047_docker_nodes.sql similarity index 100% rename from packages/db/migrations/0046_docker_nodes.sql rename to packages/db/migrations/0047_docker_nodes.sql diff --git a/packages/db/migrations/0048_00_elite_rumiko_fujikawa_drops.sql b/packages/db/migrations/0048_00_elite_rumiko_fujikawa_drops.sql new file mode 100644 index 000000000..251cbc965 --- /dev/null +++ b/packages/db/migrations/0048_00_elite_rumiko_fujikawa_drops.sql @@ -0,0 +1,62 @@ +ALTER TABLE "org_feed_configs" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "pending_reply_confirmations" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "social_engagement_events" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "social_notification_messages" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "domain_moderation_events" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "org_checkin_responses" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "org_checkin_schedules" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "org_platform_connections" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "org_platform_servers" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "org_team_members" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "org_todos" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +ALTER TABLE "n8n_workflow"."credential_mappings" DISABLE ROW LEVEL SECURITY;--> statement-breakpoint +DROP TABLE IF EXISTS "org_feed_configs" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "pending_reply_confirmations" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "social_engagement_events" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "social_notification_messages" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "domain_moderation_events" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "org_checkin_responses" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "org_checkin_schedules" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "org_platform_connections" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "org_platform_servers" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "org_team_members" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "org_todos" CASCADE;--> statement-breakpoint +DROP TABLE IF EXISTS "n8n_workflow"."credential_mappings" CASCADE;--> statement-breakpoint +ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "users_anonymous_session_id_unique";--> statement-breakpoint +DROP INDEX IF EXISTS "organizations_stripe_customer_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "organizations_auto_top_up_enabled_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "users_privy_user_id_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "users_anonymous_session_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "users_expires_at_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "users_work_function_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "users_telegram_id_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "users_phone_number_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "users_discord_id_idx";--> statement-breakpoint +DROP INDEX IF EXISTS "apps_user_database_status_idx";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "webhook_url";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "webhook_secret";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "tax_id_type";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "tax_id_value";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "billing_address";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "auto_top_up_subscription_id";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "max_api_requests";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "max_tokens_per_request";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "allowed_models";--> statement-breakpoint +ALTER TABLE "organizations" DROP COLUMN IF EXISTS "allowed_providers";--> statement-breakpoint +ALTER TABLE "apps" DROP COLUMN IF EXISTS "features_enabled";--> statement-breakpoint +ALTER TABLE "apps" DROP COLUMN IF EXISTS "rate_limit_per_minute";--> statement-breakpoint +ALTER TABLE "apps" DROP COLUMN IF EXISTS "rate_limit_per_hour";--> statement-breakpoint + +DROP TYPE IF EXISTS "public"."reply_confirmation_status";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."social_engagement_type";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."domain_event_detected_by";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."domain_event_severity";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."domain_event_type";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."org_agent_type";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."org_checkin_frequency";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."org_checkin_type";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."org_platform_status";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."org_platform_type";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."org_todo_priority";--> statement-breakpoint +DROP TYPE IF EXISTS "public"."org_todo_status";--> statement-breakpoint +DROP SCHEMA IF EXISTS "n8n_workflow"; diff --git a/packages/db/migrations/0048_01_elite_rumiko_fujikawa_creates.sql b/packages/db/migrations/0048_01_elite_rumiko_fujikawa_creates.sql new file mode 100644 index 000000000..177a68957 --- /dev/null +++ b/packages/db/migrations/0048_01_elite_rumiko_fujikawa_creates.sql @@ -0,0 +1,136 @@ + +CREATE TABLE IF NOT EXISTS "organization_billing" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "organization_id" uuid NOT NULL, + "stripe_customer_id" text, + "billing_email" text, + "tax_id_type" text, + "tax_id_value" text, + "billing_address" jsonb, + "stripe_payment_method_id" text, + "stripe_default_payment_method" text, + "auto_top_up_enabled" boolean DEFAULT false NOT NULL, + "auto_top_up_amount" numeric(12, 6), + "auto_top_up_threshold" numeric(12, 6) DEFAULT '0.000000', + "auto_top_up_subscription_id" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "organization_billing_organization_id_unique" UNIQUE("organization_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "organization_config" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "organization_id" uuid NOT NULL, + "webhook_url" text, + "webhook_secret" text, + "max_api_requests" integer DEFAULT 1000, + "max_tokens_per_request" integer, + "allowed_models" jsonb DEFAULT '[]'::jsonb NOT NULL, + "allowed_providers" jsonb DEFAULT '[]'::jsonb NOT NULL, + "settings" jsonb DEFAULT '{}'::jsonb NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "organization_config_organization_id_unique" UNIQUE("organization_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "organization_encryption_keys" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "organization_id" uuid NOT NULL, + "encrypted_dek" text NOT NULL, + "key_version" integer DEFAULT 1 NOT NULL, + "algorithm" text DEFAULT 'aes-256-gcm' NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "rotated_at" timestamp, + CONSTRAINT "organization_encryption_keys_org_unique" UNIQUE("organization_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user_identities" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" uuid NOT NULL, + "privy_user_id" text, + "is_anonymous" boolean DEFAULT false NOT NULL, + "anonymous_session_id" text, + "expires_at" timestamp, + "telegram_id" text, + "telegram_username" text, + "telegram_first_name" text, + "telegram_photo_url" text, + "phone_number" text, + "phone_verified" boolean DEFAULT false, + "discord_id" text, + "discord_username" text, + "discord_global_name" text, + "discord_avatar_url" text, + "whatsapp_id" text, + "whatsapp_name" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "user_identities_user_id_unique" UNIQUE("user_id"), + CONSTRAINT "user_identities_privy_user_id_unique" UNIQUE("privy_user_id"), + CONSTRAINT "user_identities_anonymous_session_id_unique" UNIQUE("anonymous_session_id"), + CONSTRAINT "user_identities_telegram_id_unique" UNIQUE("telegram_id"), + CONSTRAINT "user_identities_phone_number_unique" UNIQUE("phone_number"), + CONSTRAINT "user_identities_discord_id_unique" UNIQUE("discord_id"), + CONSTRAINT "user_identities_whatsapp_id_unique" UNIQUE("whatsapp_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "user_preferences" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" uuid NOT NULL, + "nickname" text, + "work_function" text, + "preferences" text, + "response_notifications" boolean DEFAULT true, + "email_notifications" boolean DEFAULT true, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "user_preferences_user_id_unique" UNIQUE("user_id") +); +--> statement-breakpoint + +CREATE TABLE IF NOT EXISTS "app_config" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "app_id" uuid NOT NULL, + "features_enabled" jsonb DEFAULT '{"chat":true,"image":false,"video":false,"voice":false,"agents":false,"embedding":false}'::jsonb NOT NULL, + "twitter_automation" jsonb DEFAULT '{"enabled":false,"autoPost":false,"autoReply":false,"autoEngage":false,"discovery":false,"postIntervalMin":90,"postIntervalMax":150}'::jsonb, + "telegram_automation" jsonb DEFAULT '{"enabled":false,"autoReply":true,"autoAnnounce":false,"announceIntervalMin":120,"announceIntervalMax":240}'::jsonb, + "discord_automation" jsonb DEFAULT '{"enabled":false,"autoAnnounce":false,"announceIntervalMin":120,"announceIntervalMax":240}'::jsonb, + "promotional_assets" jsonb DEFAULT '[]'::jsonb, + "linked_character_ids" jsonb DEFAULT '[]'::jsonb NOT NULL, + "github_repo" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "app_config_app_id_unique" UNIQUE("app_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "app_billing" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "app_id" uuid NOT NULL, + "custom_pricing_enabled" boolean DEFAULT false NOT NULL, + "monetization_enabled" boolean DEFAULT false NOT NULL, + "inference_markup_percentage" numeric(7, 2) DEFAULT '0.00' NOT NULL, + "purchase_share_percentage" numeric(5, 2) DEFAULT '10.00' NOT NULL, + "platform_offset_amount" numeric(10, 2) DEFAULT '1.00' NOT NULL, + "total_creator_earnings" numeric(12, 6) DEFAULT '0.000000' NOT NULL, + "total_platform_revenue" numeric(12, 6) DEFAULT '0.000000' NOT NULL, + "rate_limit_per_minute" integer DEFAULT 60, + "rate_limit_per_hour" integer DEFAULT 1000, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "app_billing_app_id_unique" UNIQUE("app_id") +); +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "app_databases" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "app_id" uuid NOT NULL, + "user_database_uri" text, + "user_database_project_id" text, + "user_database_branch_id" text, + "user_database_region" text DEFAULT 'aws-us-east-1', + "user_database_status" "user_database_status" DEFAULT 'none' NOT NULL, + "user_database_error" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL, + CONSTRAINT "app_databases_app_id_unique" UNIQUE("app_id") +); +--> statement-breakpoint \ No newline at end of file diff --git a/packages/db/migrations/0048_02_elite_rumiko_fujikawa_alters.sql b/packages/db/migrations/0048_02_elite_rumiko_fujikawa_alters.sql new file mode 100644 index 000000000..4e325ca2e --- /dev/null +++ b/packages/db/migrations/0048_02_elite_rumiko_fujikawa_alters.sql @@ -0,0 +1,36 @@ +ALTER TABLE "organizations" ALTER COLUMN "credit_balance" SET DATA TYPE numeric(16, 6);--> statement-breakpoint +ALTER TABLE "organizations" ALTER COLUMN "credit_balance" SET DEFAULT '100.000000';--> statement-breakpoint +ALTER TABLE "organizations" ALTER COLUMN "auto_top_up_enabled" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "organizations" ALTER COLUMN "auto_top_up_threshold" DROP DEFAULT;--> statement-breakpoint +ALTER TABLE "organizations" ALTER COLUMN "settings" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "usage_records" ALTER COLUMN "input_cost" SET DATA TYPE numeric(16, 6);--> statement-breakpoint +ALTER TABLE "usage_records" ALTER COLUMN "input_cost" SET DEFAULT '0.000000';--> statement-breakpoint +ALTER TABLE "usage_records" ALTER COLUMN "output_cost" SET DATA TYPE numeric(16, 6);--> statement-breakpoint +ALTER TABLE "usage_records" ALTER COLUMN "output_cost" SET DEFAULT '0.000000';--> statement-breakpoint +ALTER TABLE "usage_records" ALTER COLUMN "markup" SET DATA TYPE numeric(16, 6);--> statement-breakpoint +ALTER TABLE "usage_records" ALTER COLUMN "markup" SET DEFAULT '0.000000';--> statement-breakpoint +ALTER TABLE "credit_transactions" ALTER COLUMN "amount" SET DATA TYPE numeric(16, 6);--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "custom_pricing_enabled" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "inference_markup_percentage" SET DATA TYPE real;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "inference_markup_percentage" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "purchase_share_percentage" SET DATA TYPE real;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "purchase_share_percentage" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "platform_offset_amount" SET DATA TYPE real;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "platform_offset_amount" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "total_creator_earnings" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "total_platform_revenue" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "linked_character_ids" DROP NOT NULL;--> statement-breakpoint +ALTER TABLE "apps" ALTER COLUMN "user_database_region" DROP DEFAULT;--> statement-breakpoint + + +ALTER TABLE "apps" ADD COLUMN "email_notifications" boolean DEFAULT true;--> statement-breakpoint +ALTER TABLE "apps" ADD COLUMN "response_notifications" boolean DEFAULT true;--> statement-breakpoint +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'organization_billing_organization_id_organizations_id_fk') THEN ALTER TABLE "organization_billing" ADD CONSTRAINT "organization_billing_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'organization_config_organization_id_organizations_id_fk') THEN ALTER TABLE "organization_config" ADD CONSTRAINT "organization_config_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'organization_encryption_keys_organization_id_organizations_id_fk') THEN ALTER TABLE "organization_encryption_keys" ADD CONSTRAINT "organization_encryption_keys_organization_id_organizations_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'user_identities_user_id_users_id_fk') THEN ALTER TABLE "user_identities" ADD CONSTRAINT "user_identities_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'user_preferences_user_id_users_id_fk') THEN ALTER TABLE "user_preferences" ADD CONSTRAINT "user_preferences_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; + +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'app_config_app_id_apps_id_fk') THEN ALTER TABLE "app_config" ADD CONSTRAINT "app_config_app_id_apps_id_fk" FOREIGN KEY ("app_id") REFERENCES "public"."apps"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'app_billing_app_id_apps_id_fk') THEN ALTER TABLE "app_billing" ADD CONSTRAINT "app_billing_app_id_apps_id_fk" FOREIGN KEY ("app_id") REFERENCES "public"."apps"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; +DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'app_databases_app_id_apps_id_fk') THEN ALTER TABLE "app_databases" ADD CONSTRAINT "app_databases_app_id_apps_id_fk" FOREIGN KEY ("app_id") REFERENCES "public"."apps"("id") ON DELETE cascade ON UPDATE no action; END IF; END $$; \ No newline at end of file diff --git a/packages/db/migrations/0048_03_elite_rumiko_fujikawa_indexes.sql b/packages/db/migrations/0048_03_elite_rumiko_fujikawa_indexes.sql new file mode 100644 index 000000000..3f7136683 --- /dev/null +++ b/packages/db/migrations/0048_03_elite_rumiko_fujikawa_indexes.sql @@ -0,0 +1,25 @@ +CREATE INDEX IF NOT EXISTS "org_billing_organization_idx" ON "organization_billing" USING btree ("organization_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "org_billing_stripe_customer_idx" ON "organization_billing" USING btree ("stripe_customer_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "org_billing_auto_top_up_enabled_idx" ON "organization_billing" USING btree ("auto_top_up_enabled");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "org_config_organization_idx" ON "organization_config" USING btree ("organization_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "org_encryption_keys_org_idx" ON "organization_encryption_keys" USING btree ("organization_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_user_idx" ON "user_identities" USING btree ("user_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_privy_user_id_idx" ON "user_identities" USING btree ("privy_user_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_is_anonymous_idx" ON "user_identities" USING btree ("is_anonymous");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_anonymous_session_idx" ON "user_identities" USING btree ("anonymous_session_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_expires_at_idx" ON "user_identities" USING btree ("expires_at");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_telegram_id_idx" ON "user_identities" USING btree ("telegram_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_phone_number_idx" ON "user_identities" USING btree ("phone_number");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_discord_id_idx" ON "user_identities" USING btree ("discord_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_identities_whatsapp_id_idx" ON "user_identities" USING btree ("whatsapp_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_preferences_user_idx" ON "user_preferences" USING btree ("user_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "user_preferences_work_function_idx" ON "user_preferences" USING btree ("work_function");--> statement-breakpoint + +CREATE INDEX IF NOT EXISTS "app_config_app_idx" ON "app_config" USING btree ("app_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "app_billing_app_idx" ON "app_billing" USING btree ("app_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "app_databases_app_idx" ON "app_databases" USING btree ("app_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "app_databases_status_idx" ON "app_databases" USING btree ("user_database_status");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "users_privy_idx" ON "users" USING btree ("privy_user_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "users_telegram_idx" ON "users" USING btree ("telegram_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "users_discord_idx" ON "users" USING btree ("discord_id");--> statement-breakpoint +CREATE INDEX IF NOT EXISTS "users_phone_idx" ON "users" USING btree ("phone_number");--> statement-breakpoint diff --git a/packages/db/migrations/0047_add_token_agent_linkage.sql b/packages/db/migrations/0048_add_token_agent_linkage.sql similarity index 100% rename from packages/db/migrations/0047_add_token_agent_linkage.sql rename to packages/db/migrations/0048_add_token_agent_linkage.sql diff --git a/packages/db/migrations/0048_elite_rumiko_fujikawa.sql b/packages/db/migrations/0049_elite_rumiko_fujikawa.sql similarity index 100% rename from packages/db/migrations/0048_elite_rumiko_fujikawa.sql rename to packages/db/migrations/0049_elite_rumiko_fujikawa.sql diff --git a/packages/db/migrations/0049_repair_existing_user_identity_privy_claims.sql b/packages/db/migrations/0050_repair_existing_user_identity_privy_claims.sql similarity index 100% rename from packages/db/migrations/0049_repair_existing_user_identity_privy_claims.sql rename to packages/db/migrations/0050_repair_existing_user_identity_privy_claims.sql diff --git a/packages/db/migrations/0050_backfill_user_identities_from_users.sql b/packages/db/migrations/0051_backfill_user_identities_from_users.sql similarity index 100% rename from packages/db/migrations/0050_backfill_user_identities_from_users.sql rename to packages/db/migrations/0051_backfill_user_identities_from_users.sql diff --git a/packages/db/migrations/0051_add_milady_pairing_tokens.sql b/packages/db/migrations/0052_add_milady_pairing_tokens.sql similarity index 100% rename from packages/db/migrations/0051_add_milady_pairing_tokens.sql rename to packages/db/migrations/0052_add_milady_pairing_tokens.sql diff --git a/packages/db/migrations/0052_add_milady_billing_columns.sql b/packages/db/migrations/0053_add_milady_billing_columns.sql similarity index 100% rename from packages/db/migrations/0052_add_milady_billing_columns.sql rename to packages/db/migrations/0053_add_milady_billing_columns.sql diff --git a/packages/db/migrations/0056_add_billing_status_check.sql b/packages/db/migrations/0056_add_billing_status_check.sql new file mode 100644 index 000000000..9299d40db --- /dev/null +++ b/packages/db/migrations/0056_add_billing_status_check.sql @@ -0,0 +1 @@ +ALTER TABLE "milady_sandboxes" ADD CONSTRAINT "billing_status_check" CHECK (billing_status IN ('active', 'warning', 'shutdown_pending', 'suspended')); \ No newline at end of file diff --git a/packages/db/migrations/meta/0056_snapshot.json b/packages/db/migrations/meta/0056_snapshot.json new file mode 100644 index 000000000..7a0414041 --- /dev/null +++ b/packages/db/migrations/meta/0056_snapshot.json @@ -0,0 +1,23077 @@ +{ + "id": "92e26fa8-b9ca-45f6-8baf-48cb52a08d56", + "prevId": "85d26801-2f7a-4e8a-be16-1bd911bd0cfd", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.organizations": { + "name": "organizations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'100.000000'" + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_email": { + "name": "billing_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_payment_method_id": { + "name": "stripe_payment_method_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_default_payment_method": { + "name": "stripe_default_payment_method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auto_top_up_enabled": { + "name": "auto_top_up_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "auto_top_up_threshold": { + "name": "auto_top_up_threshold", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "auto_top_up_amount": { + "name": "auto_top_up_amount", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "organizations_slug_idx": { + "name": "organizations_slug_idx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organizations_slug_unique": { + "name": "organizations_slug_unique", + "columns": [ + "slug" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": { + "credit_balance_non_negative": { + "name": "credit_balance_non_negative", + "value": "\"organizations\".\"credit_balance\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.organization_billing": { + "name": "organization_billing", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_email": { + "name": "billing_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tax_id_type": { + "name": "tax_id_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tax_id_value": { + "name": "tax_id_value", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_address": { + "name": "billing_address", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "stripe_payment_method_id": { + "name": "stripe_payment_method_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_default_payment_method": { + "name": "stripe_default_payment_method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auto_top_up_enabled": { + "name": "auto_top_up_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_top_up_amount": { + "name": "auto_top_up_amount", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false + }, + "auto_top_up_threshold": { + "name": "auto_top_up_threshold", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "auto_top_up_subscription_id": { + "name": "auto_top_up_subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "org_billing_organization_idx": { + "name": "org_billing_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "org_billing_stripe_customer_idx": { + "name": "org_billing_stripe_customer_idx", + "columns": [ + { + "expression": "stripe_customer_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "org_billing_auto_top_up_enabled_idx": { + "name": "org_billing_auto_top_up_enabled_idx", + "columns": [ + { + "expression": "auto_top_up_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "organization_billing_organization_id_organizations_id_fk": { + "name": "organization_billing_organization_id_organizations_id_fk", + "tableFrom": "organization_billing", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_billing_organization_id_unique": { + "name": "organization_billing_organization_id_unique", + "columns": [ + "organization_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_config": { + "name": "organization_config", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "webhook_url": { + "name": "webhook_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "webhook_secret": { + "name": "webhook_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_api_requests": { + "name": "max_api_requests", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 1000 + }, + "max_tokens_per_request": { + "name": "max_tokens_per_request", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "allowed_models": { + "name": "allowed_models", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "allowed_providers": { + "name": "allowed_providers", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "org_config_organization_idx": { + "name": "org_config_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "organization_config_organization_id_organizations_id_fk": { + "name": "organization_config_organization_id_organizations_id_fk", + "tableFrom": "organization_config", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_config_organization_id_unique": { + "name": "organization_config_organization_id_unique", + "columns": [ + "organization_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_invites": { + "name": "organization_invites", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "inviter_user_id": { + "name": "inviter_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "invited_email": { + "name": "invited_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invited_role": { + "name": "invited_role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "accepted_at": { + "name": "accepted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "accepted_by_user_id": { + "name": "accepted_by_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "organization_invites_org_id_idx": { + "name": "organization_invites_org_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "organization_invites_email_idx": { + "name": "organization_invites_email_idx", + "columns": [ + { + "expression": "invited_email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "organization_invites_token_idx": { + "name": "organization_invites_token_idx", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "organization_invites_status_idx": { + "name": "organization_invites_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "organization_invites_organization_id_organizations_id_fk": { + "name": "organization_invites_organization_id_organizations_id_fk", + "tableFrom": "organization_invites", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "organization_invites_inviter_user_id_users_id_fk": { + "name": "organization_invites_inviter_user_id_users_id_fk", + "tableFrom": "organization_invites", + "columnsFrom": [ + "inviter_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "organization_invites_accepted_by_user_id_users_id_fk": { + "name": "organization_invites_accepted_by_user_id_users_id_fk", + "tableFrom": "organization_invites", + "columnsFrom": [ + "accepted_by_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_invites_token_hash_unique": { + "name": "organization_invites_token_hash_unique", + "columns": [ + "token_hash" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_encryption_keys": { + "name": "organization_encryption_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "encrypted_dek": { + "name": "encrypted_dek", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_version": { + "name": "key_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "algorithm": { + "name": "algorithm", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'aes-256-gcm'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "rotated_at": { + "name": "rotated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "org_encryption_keys_org_idx": { + "name": "org_encryption_keys_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "organization_encryption_keys_organization_id_organizations_id_fk": { + "name": "organization_encryption_keys_organization_id_organizations_id_fk", + "tableFrom": "organization_encryption_keys", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "organization_encryption_keys_org_unique": { + "name": "organization_encryption_keys_org_unique", + "columns": [ + "organization_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "wallet_address": { + "name": "wallet_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wallet_chain_type": { + "name": "wallet_chain_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wallet_verified": { + "name": "wallet_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "privy_user_id": { + "name": "privy_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram_id": { + "name": "telegram_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram_username": { + "name": "telegram_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram_first_name": { + "name": "telegram_first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram_photo_url": { + "name": "telegram_photo_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_username": { + "name": "discord_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_global_name": { + "name": "discord_global_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_avatar_url": { + "name": "discord_avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "whatsapp_id": { + "name": "whatsapp_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "whatsapp_name": { + "name": "whatsapp_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phone_number": { + "name": "phone_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phone_verified": { + "name": "phone_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "is_anonymous": { + "name": "is_anonymous", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "anonymous_session_id": { + "name": "anonymous_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "nickname": { + "name": "nickname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "work_function": { + "name": "work_function", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preferences": { + "name": "preferences", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_notifications": { + "name": "email_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "response_notifications": { + "name": "response_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "users_email_idx": { + "name": "users_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_wallet_address_idx": { + "name": "users_wallet_address_idx", + "columns": [ + { + "expression": "wallet_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_wallet_chain_type_idx": { + "name": "users_wallet_chain_type_idx", + "columns": [ + { + "expression": "wallet_chain_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_organization_idx": { + "name": "users_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_is_active_idx": { + "name": "users_is_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_privy_idx": { + "name": "users_privy_idx", + "columns": [ + { + "expression": "privy_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_telegram_idx": { + "name": "users_telegram_idx", + "columns": [ + { + "expression": "telegram_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_discord_idx": { + "name": "users_discord_idx", + "columns": [ + { + "expression": "discord_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_phone_idx": { + "name": "users_phone_idx", + "columns": [ + { + "expression": "phone_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "users_is_anonymous_idx": { + "name": "users_is_anonymous_idx", + "columns": [ + { + "expression": "is_anonymous", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "users_organization_id_organizations_id_fk": { + "name": "users_organization_id_organizations_id_fk", + "tableFrom": "users", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "columns": [ + "email" + ], + "nullsNotDistinct": false + }, + "users_wallet_address_unique": { + "name": "users_wallet_address_unique", + "columns": [ + "wallet_address" + ], + "nullsNotDistinct": false + }, + "users_privy_user_id_unique": { + "name": "users_privy_user_id_unique", + "columns": [ + "privy_user_id" + ], + "nullsNotDistinct": false + }, + "users_telegram_id_unique": { + "name": "users_telegram_id_unique", + "columns": [ + "telegram_id" + ], + "nullsNotDistinct": false + }, + "users_discord_id_unique": { + "name": "users_discord_id_unique", + "columns": [ + "discord_id" + ], + "nullsNotDistinct": false + }, + "users_whatsapp_id_unique": { + "name": "users_whatsapp_id_unique", + "columns": [ + "whatsapp_id" + ], + "nullsNotDistinct": false + }, + "users_phone_number_unique": { + "name": "users_phone_number_unique", + "columns": [ + "phone_number" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_identities": { + "name": "user_identities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "privy_user_id": { + "name": "privy_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_anonymous": { + "name": "is_anonymous", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "anonymous_session_id": { + "name": "anonymous_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "telegram_id": { + "name": "telegram_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram_username": { + "name": "telegram_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram_first_name": { + "name": "telegram_first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telegram_photo_url": { + "name": "telegram_photo_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phone_number": { + "name": "phone_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "phone_verified": { + "name": "phone_verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "discord_id": { + "name": "discord_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_username": { + "name": "discord_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_global_name": { + "name": "discord_global_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "discord_avatar_url": { + "name": "discord_avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "whatsapp_id": { + "name": "whatsapp_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "whatsapp_name": { + "name": "whatsapp_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_identities_user_idx": { + "name": "user_identities_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_privy_user_id_idx": { + "name": "user_identities_privy_user_id_idx", + "columns": [ + { + "expression": "privy_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_is_anonymous_idx": { + "name": "user_identities_is_anonymous_idx", + "columns": [ + { + "expression": "is_anonymous", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_anonymous_session_idx": { + "name": "user_identities_anonymous_session_idx", + "columns": [ + { + "expression": "anonymous_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_expires_at_idx": { + "name": "user_identities_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_telegram_id_idx": { + "name": "user_identities_telegram_id_idx", + "columns": [ + { + "expression": "telegram_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_phone_number_idx": { + "name": "user_identities_phone_number_idx", + "columns": [ + { + "expression": "phone_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_discord_id_idx": { + "name": "user_identities_discord_id_idx", + "columns": [ + { + "expression": "discord_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_identities_whatsapp_id_idx": { + "name": "user_identities_whatsapp_id_idx", + "columns": [ + { + "expression": "whatsapp_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_identities_user_id_users_id_fk": { + "name": "user_identities_user_id_users_id_fk", + "tableFrom": "user_identities", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_identities_user_id_unique": { + "name": "user_identities_user_id_unique", + "columns": [ + "user_id" + ], + "nullsNotDistinct": false + }, + "user_identities_privy_user_id_unique": { + "name": "user_identities_privy_user_id_unique", + "columns": [ + "privy_user_id" + ], + "nullsNotDistinct": false + }, + "user_identities_anonymous_session_id_unique": { + "name": "user_identities_anonymous_session_id_unique", + "columns": [ + "anonymous_session_id" + ], + "nullsNotDistinct": false + }, + "user_identities_telegram_id_unique": { + "name": "user_identities_telegram_id_unique", + "columns": [ + "telegram_id" + ], + "nullsNotDistinct": false + }, + "user_identities_phone_number_unique": { + "name": "user_identities_phone_number_unique", + "columns": [ + "phone_number" + ], + "nullsNotDistinct": false + }, + "user_identities_discord_id_unique": { + "name": "user_identities_discord_id_unique", + "columns": [ + "discord_id" + ], + "nullsNotDistinct": false + }, + "user_identities_whatsapp_id_unique": { + "name": "user_identities_whatsapp_id_unique", + "columns": [ + "whatsapp_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_preferences": { + "name": "user_preferences", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "nickname": { + "name": "nickname", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "work_function": { + "name": "work_function", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "preferences": { + "name": "preferences", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "response_notifications": { + "name": "response_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "email_notifications": { + "name": "email_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_preferences_user_idx": { + "name": "user_preferences_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_preferences_work_function_idx": { + "name": "user_preferences_work_function_idx", + "columns": [ + { + "expression": "work_function", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_preferences_user_id_users_id_fk": { + "name": "user_preferences_user_id_users_id_fk", + "tableFrom": "user_preferences", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_preferences_user_id_unique": { + "name": "user_preferences_user_id_unique", + "columns": [ + "user_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_sessions": { + "name": "user_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credits_used": { + "name": "credits_used", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "requests_made": { + "name": "requests_made", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "tokens_consumed": { + "name": "tokens_consumed", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_activity_at": { + "name": "last_activity_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "device_info": { + "name": "device_info", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_sessions_user_id_idx": { + "name": "user_sessions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_sessions_org_id_idx": { + "name": "user_sessions_org_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_sessions_token_idx": { + "name": "user_sessions_token_idx", + "columns": [ + { + "expression": "session_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_sessions_started_at_idx": { + "name": "user_sessions_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_sessions_active_idx": { + "name": "user_sessions_active_idx", + "columns": [ + { + "expression": "ended_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_sessions_user_id_users_id_fk": { + "name": "user_sessions_user_id_users_id_fk", + "tableFrom": "user_sessions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_sessions_organization_id_organizations_id_fk": { + "name": "user_sessions_organization_id_organizations_id_fk", + "tableFrom": "user_sessions", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_sessions_session_token_unique": { + "name": "user_sessions_session_token_unique", + "columns": [ + "session_token" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.anonymous_sessions": { + "name": "anonymous_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_token": { + "name": "session_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_count": { + "name": "message_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "messages_limit": { + "name": "messages_limit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10 + }, + "total_tokens_used": { + "name": "total_tokens_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_message_at": { + "name": "last_message_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "hourly_message_count": { + "name": "hourly_message_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "hourly_reset_at": { + "name": "hourly_reset_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "fingerprint": { + "name": "fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "signup_prompted_at": { + "name": "signup_prompted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "signup_prompt_count": { + "name": "signup_prompt_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "converted_at": { + "name": "converted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "anon_sessions_token_idx": { + "name": "anon_sessions_token_idx", + "columns": [ + { + "expression": "session_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "anon_sessions_user_id_idx": { + "name": "anon_sessions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "anon_sessions_expires_at_idx": { + "name": "anon_sessions_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "anon_sessions_ip_address_idx": { + "name": "anon_sessions_ip_address_idx", + "columns": [ + { + "expression": "ip_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "anon_sessions_is_active_idx": { + "name": "anon_sessions_is_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "anonymous_sessions_user_id_users_id_fk": { + "name": "anonymous_sessions_user_id_users_id_fk", + "tableFrom": "anonymous_sessions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "anonymous_sessions_session_token_unique": { + "name": "anonymous_sessions_session_token_unique", + "columns": [ + "session_token" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_keys": { + "name": "api_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_prefix": { + "name": "key_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "rate_limit": { + "name": "rate_limit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1000 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "usage_count": { + "name": "usage_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "api_keys_key_idx": { + "name": "api_keys_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "api_keys_key_hash_idx": { + "name": "api_keys_key_hash_idx", + "columns": [ + { + "expression": "key_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "api_keys_key_prefix_idx": { + "name": "api_keys_key_prefix_idx", + "columns": [ + { + "expression": "key_prefix", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "api_keys_organization_idx": { + "name": "api_keys_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "api_keys_user_idx": { + "name": "api_keys_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "api_keys_organization_id_organizations_id_fk": { + "name": "api_keys_organization_id_organizations_id_fk", + "tableFrom": "api_keys", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "columns": [ + "key" + ], + "nullsNotDistinct": false + }, + "api_keys_key_hash_unique": { + "name": "api_keys_key_hash_unique", + "columns": [ + "key_hash" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.cli_auth_sessions": { + "name": "cli_auth_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "api_key_plain": { + "name": "api_key_plain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "authenticated_at": { + "name": "authenticated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "cli_auth_sessions_session_id_idx": { + "name": "cli_auth_sessions_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "cli_auth_sessions_status_idx": { + "name": "cli_auth_sessions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "cli_auth_sessions_user_id_idx": { + "name": "cli_auth_sessions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "cli_auth_sessions_expires_at_idx": { + "name": "cli_auth_sessions_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "cli_auth_sessions_user_id_users_id_fk": { + "name": "cli_auth_sessions_user_id_users_id_fk", + "tableFrom": "cli_auth_sessions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "cli_auth_sessions_session_id_unique": { + "name": "cli_auth_sessions_session_id_unique", + "columns": [ + "session_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_records": { + "name": "usage_records", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "input_tokens": { + "name": "input_tokens", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "output_tokens": { + "name": "output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "input_cost": { + "name": "input_cost", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "output_cost": { + "name": "output_cost", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "markup": { + "name": "markup", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_successful": { + "name": "is_successful", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "usage_records_organization_idx": { + "name": "usage_records_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_records_user_idx": { + "name": "usage_records_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_records_api_key_idx": { + "name": "usage_records_api_key_idx", + "columns": [ + { + "expression": "api_key_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_records_type_idx": { + "name": "usage_records_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_records_provider_idx": { + "name": "usage_records_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_records_created_at_idx": { + "name": "usage_records_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_records_org_created_idx": { + "name": "usage_records_org_created_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_records_org_type_created_idx": { + "name": "usage_records_org_type_created_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "usage_records_organization_id_organizations_id_fk": { + "name": "usage_records_organization_id_organizations_id_fk", + "tableFrom": "usage_records", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "usage_records_user_id_users_id_fk": { + "name": "usage_records_user_id_users_id_fk", + "tableFrom": "usage_records", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "usage_records_api_key_id_api_keys_id_fk": { + "name": "usage_records_api_key_id_api_keys_id_fk", + "tableFrom": "usage_records", + "columnsFrom": [ + "api_key_id" + ], + "tableTo": "api_keys", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_quotas": { + "name": "usage_quotas", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "quota_type": { + "name": "quota_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model_name": { + "name": "model_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "period_type": { + "name": "period_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'weekly'" + }, + "credits_limit": { + "name": "credits_limit", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "current_usage": { + "name": "current_usage", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "period_start": { + "name": "period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "period_end": { + "name": "period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "usage_quotas_org_id_idx": { + "name": "usage_quotas_org_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_quotas_quota_type_idx": { + "name": "usage_quotas_quota_type_idx", + "columns": [ + { + "expression": "quota_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_quotas_period_idx": { + "name": "usage_quotas_period_idx", + "columns": [ + { + "expression": "period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "period_end", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "usage_quotas_active_idx": { + "name": "usage_quotas_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "usage_quotas_organization_id_organizations_id_fk": { + "name": "usage_quotas_organization_id_organizations_id_fk", + "tableFrom": "usage_quotas", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credit_transactions": { + "name": "credit_transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "amount": { + "name": "amount", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "stripe_payment_intent_id": { + "name": "stripe_payment_intent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credit_transactions_organization_idx": { + "name": "credit_transactions_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "credit_transactions_user_idx": { + "name": "credit_transactions_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "credit_transactions_type_idx": { + "name": "credit_transactions_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "credit_transactions_created_at_idx": { + "name": "credit_transactions_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "credit_transactions_stripe_payment_intent_idx": { + "name": "credit_transactions_stripe_payment_intent_idx", + "columns": [ + { + "expression": "stripe_payment_intent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "credit_transactions_organization_id_organizations_id_fk": { + "name": "credit_transactions_organization_id_organizations_id_fk", + "tableFrom": "credit_transactions", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "credit_transactions_user_id_users_id_fk": { + "name": "credit_transactions_user_id_users_id_fk", + "tableFrom": "credit_transactions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credit_packs": { + "name": "credit_packs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credits": { + "name": "credits", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "price_cents": { + "name": "price_cents", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "stripe_price_id": { + "name": "stripe_price_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_product_id": { + "name": "stripe_product_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credit_packs_stripe_price_idx": { + "name": "credit_packs_stripe_price_idx", + "columns": [ + { + "expression": "stripe_price_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "credit_packs_active_idx": { + "name": "credit_packs_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "credit_packs_sort_idx": { + "name": "credit_packs_sort_idx", + "columns": [ + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "credit_packs_stripe_price_id_unique": { + "name": "credit_packs_stripe_price_id_unique", + "columns": [ + "stripe_price_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invoices": { + "name": "invoices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "stripe_invoice_id": { + "name": "stripe_invoice_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_payment_intent_id": { + "name": "stripe_payment_intent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "amount_due": { + "name": "amount_due", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "amount_paid": { + "name": "amount_paid", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'usd'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invoice_type": { + "name": "invoice_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invoice_number": { + "name": "invoice_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "invoice_pdf": { + "name": "invoice_pdf", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hosted_invoice_url": { + "name": "hosted_invoice_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credits_added": { + "name": "credits_added", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "due_date": { + "name": "due_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "paid_at": { + "name": "paid_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "invoices_organization_idx": { + "name": "invoices_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "invoices_stripe_invoice_idx": { + "name": "invoices_stripe_invoice_idx", + "columns": [ + { + "expression": "stripe_invoice_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "invoices_status_idx": { + "name": "invoices_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "invoices_stripe_invoice_id_unique": { + "name": "invoices_stripe_invoice_id_unique", + "columns": [ + "stripe_invoice_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.generations": { + "name": "generations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "negative_prompt": { + "name": "negative_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result": { + "name": "result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "storage_url": { + "name": "storage_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "thumbnail_url": { + "name": "thumbnail_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parameters": { + "name": "parameters", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "dimensions": { + "name": "dimensions", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "tokens": { + "name": "tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "credits": { + "name": "credits", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "usage_record_id": { + "name": "usage_record_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "job_id": { + "name": "job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "generations_organization_idx": { + "name": "generations_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "generations_user_idx": { + "name": "generations_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "generations_api_key_idx": { + "name": "generations_api_key_idx", + "columns": [ + { + "expression": "api_key_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "generations_type_idx": { + "name": "generations_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "generations_status_idx": { + "name": "generations_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "generations_created_at_idx": { + "name": "generations_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "generations_org_type_status_idx": { + "name": "generations_org_type_status_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "generations_org_status_user_created_idx": { + "name": "generations_org_status_user_created_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "generations_organization_id_organizations_id_fk": { + "name": "generations_organization_id_organizations_id_fk", + "tableFrom": "generations", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "generations_user_id_users_id_fk": { + "name": "generations_user_id_users_id_fk", + "tableFrom": "generations", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "generations_api_key_id_api_keys_id_fk": { + "name": "generations_api_key_id_api_keys_id_fk", + "tableFrom": "generations", + "columnsFrom": [ + "api_key_id" + ], + "tableTo": "api_keys", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "generations_usage_record_id_usage_records_id_fk": { + "name": "generations_usage_record_id_usage_records_id_fk", + "tableFrom": "generations", + "columnsFrom": [ + "usage_record_id" + ], + "tableTo": "usage_records", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.jobs": { + "name": "jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "result": { + "name": "result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "generation_id": { + "name": "generation_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "webhook_url": { + "name": "webhook_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "webhook_status": { + "name": "webhook_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "estimated_completion_at": { + "name": "estimated_completion_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scheduled_for": { + "name": "scheduled_for", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "jobs_type_idx": { + "name": "jobs_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "jobs_status_idx": { + "name": "jobs_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "jobs_scheduled_for_idx": { + "name": "jobs_scheduled_for_idx", + "columns": [ + { + "expression": "scheduled_for", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "jobs_organization_idx": { + "name": "jobs_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "jobs_organization_id_organizations_id_fk": { + "name": "jobs_organization_id_organizations_id_fk", + "tableFrom": "jobs", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "jobs_user_id_users_id_fk": { + "name": "jobs_user_id_users_id_fk", + "tableFrom": "jobs", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "jobs_api_key_id_api_keys_id_fk": { + "name": "jobs_api_key_id_api_keys_id_fk", + "tableFrom": "jobs", + "columnsFrom": [ + "api_key_id" + ], + "tableTo": "api_keys", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + }, + "jobs_generation_id_generations_id_fk": { + "name": "jobs_generation_id_generations_id_fk", + "tableFrom": "jobs", + "columnsFrom": [ + "generation_id" + ], + "tableTo": "generations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.model_pricing": { + "name": "model_pricing", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "input_cost_per_1k": { + "name": "input_cost_per_1k", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": true + }, + "output_cost_per_1k": { + "name": "output_cost_per_1k", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": true + }, + "input_cost_per_token": { + "name": "input_cost_per_token", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": false + }, + "output_cost_per_token": { + "name": "output_cost_per_token", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "effective_from": { + "name": "effective_from", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "effective_until": { + "name": "effective_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "model_pricing_provider_model_idx": { + "name": "model_pricing_provider_model_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "model_pricing_active_idx": { + "name": "model_pricing_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.service_pricing": { + "name": "service_pricing", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "service_id": { + "name": "service_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "cost": { + "name": "cost", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "service_pricing_service_method_idx": { + "name": "service_pricing_service_method_idx", + "columns": [ + { + "expression": "service_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "method", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.service_pricing_audit": { + "name": "service_pricing_audit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "service_pricing_id": { + "name": "service_pricing_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "service_id": { + "name": "service_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "old_cost": { + "name": "old_cost", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false + }, + "new_cost": { + "name": "new_cost", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true + }, + "change_type": { + "name": "change_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "changed_by": { + "name": "changed_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "service_pricing_audit_service_idx": { + "name": "service_pricing_audit_service_idx", + "columns": [ + { + "expression": "service_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "service_pricing_audit_pricing_created_idx": { + "name": "service_pricing_audit_pricing_created_idx", + "columns": [ + { + "expression": "service_pricing_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "service_pricing_audit_service_pricing_id_service_pricing_id_fk": { + "name": "service_pricing_audit_service_pricing_id_service_pricing_id_fk", + "tableFrom": "service_pricing_audit", + "columnsFrom": [ + "service_pricing_id" + ], + "tableTo": "service_pricing", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.provider_health": { + "name": "provider_health", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'healthy'" + }, + "last_checked": { + "name": "last_checked", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "response_time": { + "name": "response_time", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "error_rate": { + "name": "error_rate", + "type": "numeric(5, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "provider_health_provider_idx": { + "name": "provider_health_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "provider_health_status_idx": { + "name": "provider_health_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.conversation_messages": { + "name": "conversation_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "conversation_id": { + "name": "conversation_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sequence_number": { + "name": "sequence_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens": { + "name": "tokens", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "usage_record_id": { + "name": "usage_record_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "api_request": { + "name": "api_request", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "api_response": { + "name": "api_response", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "processing_time": { + "name": "processing_time", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "conv_messages_conversation_idx": { + "name": "conv_messages_conversation_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "conv_messages_sequence_idx": { + "name": "conv_messages_sequence_idx", + "columns": [ + { + "expression": "conversation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sequence_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "conv_messages_created_idx": { + "name": "conv_messages_created_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "conversation_messages_conversation_id_conversations_id_fk": { + "name": "conversation_messages_conversation_id_conversations_id_fk", + "tableFrom": "conversation_messages", + "columnsFrom": [ + "conversation_id" + ], + "tableTo": "conversations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "conversation_messages_usage_record_id_usage_records_id_fk": { + "name": "conversation_messages_usage_record_id_usage_records_id_fk", + "tableFrom": "conversation_messages", + "columnsFrom": [ + "usage_record_id" + ], + "tableTo": "usage_records", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.conversations": { + "name": "conversations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"temperature\":0.7,\"maxTokens\":2000,\"topP\":1,\"frequencyPenalty\":0,\"presencePenalty\":0,\"systemPrompt\":\"You are a helpful AI assistant.\"}'::jsonb" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "message_count": { + "name": "message_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "last_message_at": { + "name": "last_message_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "conversations_organization_idx": { + "name": "conversations_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "conversations_user_idx": { + "name": "conversations_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "conversations_updated_idx": { + "name": "conversations_updated_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "conversations_status_idx": { + "name": "conversations_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "conversations_organization_id_organizations_id_fk": { + "name": "conversations_organization_id_organizations_id_fk", + "tableFrom": "conversations", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "conversations_user_id_users_id_fk": { + "name": "conversations_user_id_users_id_fk", + "tableFrom": "conversations", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_characters": { + "name": "user_characters", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "system": { + "name": "system", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "message_examples": { + "name": "message_examples", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "post_examples": { + "name": "post_examples", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "topics": { + "name": "topics", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "adjectives": { + "name": "adjectives", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "knowledge": { + "name": "knowledge", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "plugins": { + "name": "plugins", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "secrets": { + "name": "secrets", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "style": { + "name": "style", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "character_data": { + "name": "character_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "is_template": { + "name": "is_template", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "avatar_url": { + "name": "avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tags": { + "name": "tags", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "featured": { + "name": "featured", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "view_count": { + "name": "view_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "interaction_count": { + "name": "interaction_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "popularity_score": { + "name": "popularity_score", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'cloud'" + }, + "token_address": { + "name": "token_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_chain": { + "name": "token_chain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_name": { + "name": "token_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_ticker": { + "name": "token_ticker", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "erc8004_registered": { + "name": "erc8004_registered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "erc8004_network": { + "name": "erc8004_network", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "erc8004_agent_id": { + "name": "erc8004_agent_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "erc8004_agent_uri": { + "name": "erc8004_agent_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "erc8004_tx_hash": { + "name": "erc8004_tx_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "erc8004_registered_at": { + "name": "erc8004_registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "monetization_enabled": { + "name": "monetization_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inference_markup_percentage": { + "name": "inference_markup_percentage", + "type": "numeric(7, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "payout_wallet_address": { + "name": "payout_wallet_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "total_inference_requests": { + "name": "total_inference_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_creator_earnings": { + "name": "total_creator_earnings", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "total_platform_revenue": { + "name": "total_platform_revenue", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "a2a_enabled": { + "name": "a2a_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "mcp_enabled": { + "name": "mcp_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_characters_organization_idx": { + "name": "user_characters_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_user_idx": { + "name": "user_characters_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_name_idx": { + "name": "user_characters_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_username_idx": { + "name": "user_characters_username_idx", + "columns": [ + { + "expression": "username", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_category_idx": { + "name": "user_characters_category_idx", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_featured_idx": { + "name": "user_characters_featured_idx", + "columns": [ + { + "expression": "featured", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_is_template_idx": { + "name": "user_characters_is_template_idx", + "columns": [ + { + "expression": "is_template", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_is_public_idx": { + "name": "user_characters_is_public_idx", + "columns": [ + { + "expression": "is_public", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_popularity_idx": { + "name": "user_characters_popularity_idx", + "columns": [ + { + "expression": "popularity_score", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_source_idx": { + "name": "user_characters_source_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_erc8004_idx": { + "name": "user_characters_erc8004_idx", + "columns": [ + { + "expression": "erc8004_registered", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_erc8004_agent_idx": { + "name": "user_characters_erc8004_agent_idx", + "columns": [ + { + "expression": "erc8004_network", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "erc8004_agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_monetization_idx": { + "name": "user_characters_monetization_idx", + "columns": [ + { + "expression": "monetization_enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_characters_token_address_idx": { + "name": "user_characters_token_address_idx", + "columns": [ + { + "expression": "token_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_characters_organization_id_organizations_id_fk": { + "name": "user_characters_organization_id_organizations_id_fk", + "tableFrom": "user_characters", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_characters_user_id_users_id_fk": { + "name": "user_characters_user_id_users_id_fk", + "tableFrom": "user_characters", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_characters_username_unique": { + "name": "user_characters_username_unique", + "columns": [ + "username" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_voices": { + "name": "user_voices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "elevenlabs_voice_id": { + "name": "elevenlabs_voice_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "clone_type": { + "name": "clone_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "sample_count": { + "name": "sample_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_audio_duration_seconds": { + "name": "total_audio_duration_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "audio_quality_score": { + "name": "audio_quality_score", + "type": "numeric(3, 2)", + "primaryKey": false, + "notNull": false + }, + "usage_count": { + "name": "usage_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "creation_cost": { + "name": "creation_cost", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_voices_organization_idx": { + "name": "user_voices_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_voices_user_idx": { + "name": "user_voices_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_voices_org_type_idx": { + "name": "user_voices_org_type_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "clone_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_voices_org_usage_idx": { + "name": "user_voices_org_usage_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "usage_count", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_used_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_voices_organization_id_organizations_id_fk": { + "name": "user_voices_organization_id_organizations_id_fk", + "tableFrom": "user_voices", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_voices_user_id_users_id_fk": { + "name": "user_voices_user_id_users_id_fk", + "tableFrom": "user_voices", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_voices_elevenlabs_voice_id_unique": { + "name": "user_voices_elevenlabs_voice_id_unique", + "columns": [ + "elevenlabs_voice_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.voice_cloning_jobs": { + "name": "voice_cloning_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "job_type": { + "name": "job_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "voice_name": { + "name": "voice_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "voice_description": { + "name": "voice_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "progress": { + "name": "progress", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "user_voice_id": { + "name": "user_voice_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "elevenlabs_voice_id": { + "name": "elevenlabs_voice_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "retry_count": { + "name": "retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "voice_cloning_jobs_organization_id_organizations_id_fk": { + "name": "voice_cloning_jobs_organization_id_organizations_id_fk", + "tableFrom": "voice_cloning_jobs", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "voice_cloning_jobs_user_id_users_id_fk": { + "name": "voice_cloning_jobs_user_id_users_id_fk", + "tableFrom": "voice_cloning_jobs", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "voice_cloning_jobs_user_voice_id_user_voices_id_fk": { + "name": "voice_cloning_jobs_user_voice_id_user_voices_id_fk", + "tableFrom": "voice_cloning_jobs", + "columnsFrom": [ + "user_voice_id" + ], + "tableTo": "user_voices", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.voice_samples": { + "name": "voice_samples", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_voice_id": { + "name": "user_voice_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "job_id": { + "name": "job_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "file_name": { + "name": "file_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "file_type": { + "name": "file_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "blob_url": { + "name": "blob_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "duration_seconds": { + "name": "duration_seconds", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false + }, + "sample_rate": { + "name": "sample_rate", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "channels": { + "name": "channels", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "quality_score": { + "name": "quality_score", + "type": "numeric(3, 2)", + "primaryKey": false, + "notNull": false + }, + "is_processed": { + "name": "is_processed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "transcription": { + "name": "transcription", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "voice_samples_user_voice_id_user_voices_id_fk": { + "name": "voice_samples_user_voice_id_user_voices_id_fk", + "tableFrom": "voice_samples", + "columnsFrom": [ + "user_voice_id" + ], + "tableTo": "user_voices", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "voice_samples_job_id_voice_cloning_jobs_id_fk": { + "name": "voice_samples_job_id_voice_cloning_jobs_id_fk", + "tableFrom": "voice_samples", + "columnsFrom": [ + "job_id" + ], + "tableTo": "voice_cloning_jobs", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "voice_samples_organization_id_organizations_id_fk": { + "name": "voice_samples_organization_id_organizations_id_fk", + "tableFrom": "voice_samples", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "voice_samples_user_id_users_id_fk": { + "name": "voice_samples_user_id_users_id_fk", + "tableFrom": "voice_samples", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.container_billing_records": { + "name": "container_billing_records", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "container_id": { + "name": "container_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true + }, + "billing_period_start": { + "name": "billing_period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "billing_period_end": { + "name": "billing_period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'success'" + }, + "credit_transaction_id": { + "name": "credit_transaction_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "container_billing_records_container_idx": { + "name": "container_billing_records_container_idx", + "columns": [ + { + "expression": "container_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "container_billing_records_org_idx": { + "name": "container_billing_records_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "container_billing_records_created_idx": { + "name": "container_billing_records_created_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "container_billing_records_status_idx": { + "name": "container_billing_records_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "container_billing_records_container_id_containers_id_fk": { + "name": "container_billing_records_container_id_containers_id_fk", + "tableFrom": "container_billing_records", + "columnsFrom": [ + "container_id" + ], + "tableTo": "containers", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "container_billing_records_organization_id_organizations_id_fk": { + "name": "container_billing_records_organization_id_organizations_id_fk", + "tableFrom": "container_billing_records", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "container_billing_records_credit_transaction_id_credit_transactions_id_fk": { + "name": "container_billing_records_credit_transaction_id_credit_transactions_id_fk", + "tableFrom": "container_billing_records", + "columnsFrom": [ + "credit_transaction_id" + ], + "tableTo": "credit_transactions", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.containers": { + "name": "containers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_name": { + "name": "project_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "character_id": { + "name": "character_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "cloudformation_stack_name": { + "name": "cloudformation_stack_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ecr_repository_uri": { + "name": "ecr_repository_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ecr_image_tag": { + "name": "ecr_image_tag", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ecs_cluster_arn": { + "name": "ecs_cluster_arn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ecs_service_arn": { + "name": "ecs_service_arn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ecs_task_definition_arn": { + "name": "ecs_task_definition_arn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ecs_task_arn": { + "name": "ecs_task_arn", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "load_balancer_url": { + "name": "load_balancer_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_update": { + "name": "is_update", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'false'" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "image_tag": { + "name": "image_tag", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dockerfile_path": { + "name": "dockerfile_path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environment_vars": { + "name": "environment_vars", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "desired_count": { + "name": "desired_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "cpu": { + "name": "cpu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1792 + }, + "memory": { + "name": "memory", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1792 + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3000 + }, + "health_check_path": { + "name": "health_check_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/health'" + }, + "architecture": { + "name": "architecture", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'arm64'" + }, + "last_deployed_at": { + "name": "last_deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_health_check": { + "name": "last_health_check", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deployment_log": { + "name": "deployment_log", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "last_billed_at": { + "name": "last_billed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_billing_at": { + "name": "next_billing_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "billing_status": { + "name": "billing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "shutdown_warning_sent_at": { + "name": "shutdown_warning_sent_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scheduled_shutdown_at": { + "name": "scheduled_shutdown_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_billed": { + "name": "total_billed", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "containers_organization_idx": { + "name": "containers_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_user_idx": { + "name": "containers_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_status_idx": { + "name": "containers_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_character_idx": { + "name": "containers_character_idx", + "columns": [ + { + "expression": "character_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_ecs_service_idx": { + "name": "containers_ecs_service_idx", + "columns": [ + { + "expression": "ecs_service_arn", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_ecr_repository_idx": { + "name": "containers_ecr_repository_idx", + "columns": [ + { + "expression": "ecr_repository_uri", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_project_name_idx": { + "name": "containers_project_name_idx", + "columns": [ + { + "expression": "project_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_user_project_idx": { + "name": "containers_user_project_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_billing_status_idx": { + "name": "containers_billing_status_idx", + "columns": [ + { + "expression": "billing_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_next_billing_idx": { + "name": "containers_next_billing_idx", + "columns": [ + { + "expression": "next_billing_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "containers_scheduled_shutdown_idx": { + "name": "containers_scheduled_shutdown_idx", + "columns": [ + { + "expression": "scheduled_shutdown_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "containers_organization_id_organizations_id_fk": { + "name": "containers_organization_id_organizations_id_fk", + "tableFrom": "containers", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "containers_user_id_users_id_fk": { + "name": "containers_user_id_users_id_fk", + "tableFrom": "containers", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "containers_api_key_id_api_keys_id_fk": { + "name": "containers_api_key_id_api_keys_id_fk", + "tableFrom": "containers", + "columnsFrom": [ + "api_key_id" + ], + "tableTo": "api_keys", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "containers_character_id_user_characters_id_fk": { + "name": "containers_character_id_user_characters_id_fk", + "tableFrom": "containers", + "columnsFrom": [ + "character_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.alb_priorities": { + "name": "alb_priorities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "project_name": { + "name": "project_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "priority": { + "name": "priority", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "alb_priorities_user_project_idx": { + "name": "alb_priorities_user_project_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "alb_priorities_priority_unique": { + "name": "alb_priorities_priority_unique", + "columns": [ + "priority" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_analytics": { + "name": "app_analytics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "period_start": { + "name": "period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "period_end": { + "name": "period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "period_type": { + "name": "period_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "successful_requests": { + "name": "successful_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "failed_requests": { + "name": "failed_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "unique_users": { + "name": "unique_users", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "new_users": { + "name": "new_users", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_input_tokens": { + "name": "total_input_tokens", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_output_tokens": { + "name": "total_output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "total_credits_used": { + "name": "total_credits_used", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "chat_requests": { + "name": "chat_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "image_requests": { + "name": "image_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "video_requests": { + "name": "video_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "voice_requests": { + "name": "voice_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "agent_requests": { + "name": "agent_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "avg_response_time_ms": { + "name": "avg_response_time_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_analytics_app_id_idx": { + "name": "app_analytics_app_id_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_analytics_period_idx": { + "name": "app_analytics_period_idx", + "columns": [ + { + "expression": "period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "period_end", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_analytics_period_type_idx": { + "name": "app_analytics_period_type_idx", + "columns": [ + { + "expression": "period_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_analytics_app_period_idx": { + "name": "app_analytics_app_period_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_analytics_app_id_apps_id_fk": { + "name": "app_analytics_app_id_apps_id_fk", + "tableFrom": "app_analytics", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_requests": { + "name": "app_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "request_type": { + "name": "request_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'api_key'" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country": { + "name": "country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "city": { + "name": "city", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "input_tokens": { + "name": "input_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "output_tokens": { + "name": "output_tokens", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "credits_used": { + "name": "credits_used", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "response_time_ms": { + "name": "response_time_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'success'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_requests_app_id_idx": { + "name": "app_requests_app_id_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_requests_created_at_idx": { + "name": "app_requests_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_requests_type_idx": { + "name": "app_requests_type_idx", + "columns": [ + { + "expression": "request_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_requests_source_idx": { + "name": "app_requests_source_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_requests_ip_idx": { + "name": "app_requests_ip_idx", + "columns": [ + { + "expression": "ip_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_requests_app_created_idx": { + "name": "app_requests_app_created_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_requests_app_id_apps_id_fk": { + "name": "app_requests_app_id_apps_id_fk", + "tableFrom": "app_requests", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_requests_user_id_users_id_fk": { + "name": "app_requests_user_id_users_id_fk", + "tableFrom": "app_requests", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_users": { + "name": "app_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "signup_source": { + "name": "signup_source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "referral_code_used": { + "name": "referral_code_used", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_credits_used": { + "name": "total_credits_used", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "first_seen_at": { + "name": "first_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": { + "app_users_app_user_idx": { + "name": "app_users_app_user_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_users_app_id_idx": { + "name": "app_users_app_id_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_users_user_id_idx": { + "name": "app_users_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_users_first_seen_idx": { + "name": "app_users_first_seen_idx", + "columns": [ + { + "expression": "first_seen_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_users_app_id_apps_id_fk": { + "name": "app_users_app_id_apps_id_fk", + "tableFrom": "app_users", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_users_user_id_users_id_fk": { + "name": "app_users_user_id_users_id_fk", + "tableFrom": "app_users", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.apps": { + "name": "apps", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "app_url": { + "name": "app_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "allowed_origins": { + "name": "allowed_origins", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "affiliate_code": { + "name": "affiliate_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "referral_bonus_credits": { + "name": "referral_bonus_credits", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_users": { + "name": "total_users", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_credits_used": { + "name": "total_credits_used", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "logo_url": { + "name": "logo_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website_url": { + "name": "website_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contact_email": { + "name": "contact_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "deployment_status": { + "name": "deployment_status", + "type": "app_deployment_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'draft'" + }, + "production_url": { + "name": "production_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_deployed_at": { + "name": "last_deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "github_repo": { + "name": "github_repo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linked_character_ids": { + "name": "linked_character_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "monetization_enabled": { + "name": "monetization_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inference_markup_percentage": { + "name": "inference_markup_percentage", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "purchase_share_percentage": { + "name": "purchase_share_percentage", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "platform_offset_amount": { + "name": "platform_offset_amount", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "custom_pricing_enabled": { + "name": "custom_pricing_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "total_creator_earnings": { + "name": "total_creator_earnings", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "total_platform_revenue": { + "name": "total_platform_revenue", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "discord_automation": { + "name": "discord_automation", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"enabled\":false,\"autoAnnounce\":false,\"announceIntervalMin\":120,\"announceIntervalMax\":240}'::jsonb" + }, + "telegram_automation": { + "name": "telegram_automation", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"enabled\":false,\"autoReply\":true,\"autoAnnounce\":false,\"announceIntervalMin\":120,\"announceIntervalMax\":240}'::jsonb" + }, + "twitter_automation": { + "name": "twitter_automation", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"enabled\":false,\"autoPost\":false,\"autoReply\":false,\"autoEngage\":false,\"discovery\":false,\"postIntervalMin\":90,\"postIntervalMax\":150}'::jsonb" + }, + "promotional_assets": { + "name": "promotional_assets", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "user_database_status": { + "name": "user_database_status", + "type": "user_database_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "user_database_uri": { + "name": "user_database_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_database_project_id": { + "name": "user_database_project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_database_branch_id": { + "name": "user_database_branch_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_database_region": { + "name": "user_database_region", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_database_error": { + "name": "user_database_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_notifications": { + "name": "email_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "response_notifications": { + "name": "response_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_approved": { + "name": "is_approved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "apps_slug_idx": { + "name": "apps_slug_idx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "apps_organization_idx": { + "name": "apps_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "apps_created_by_idx": { + "name": "apps_created_by_idx", + "columns": [ + { + "expression": "created_by_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "apps_affiliate_code_idx": { + "name": "apps_affiliate_code_idx", + "columns": [ + { + "expression": "affiliate_code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "apps_is_active_idx": { + "name": "apps_is_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "apps_created_at_idx": { + "name": "apps_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "apps_organization_id_organizations_id_fk": { + "name": "apps_organization_id_organizations_id_fk", + "tableFrom": "apps", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "apps_created_by_user_id_users_id_fk": { + "name": "apps_created_by_user_id_users_id_fk", + "tableFrom": "apps", + "columnsFrom": [ + "created_by_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "apps_slug_unique": { + "name": "apps_slug_unique", + "columns": [ + "slug" + ], + "nullsNotDistinct": false + }, + "apps_api_key_id_unique": { + "name": "apps_api_key_id_unique", + "columns": [ + "api_key_id" + ], + "nullsNotDistinct": false + }, + "apps_affiliate_code_unique": { + "name": "apps_affiliate_code_unique", + "columns": [ + "affiliate_code" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_config": { + "name": "app_config", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "features_enabled": { + "name": "features_enabled", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{\"chat\":true,\"image\":false,\"video\":false,\"voice\":false,\"agents\":false,\"embedding\":false}'::jsonb" + }, + "twitter_automation": { + "name": "twitter_automation", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"enabled\":false,\"autoPost\":false,\"autoReply\":false,\"autoEngage\":false,\"discovery\":false,\"postIntervalMin\":90,\"postIntervalMax\":150}'::jsonb" + }, + "telegram_automation": { + "name": "telegram_automation", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"enabled\":false,\"autoReply\":true,\"autoAnnounce\":false,\"announceIntervalMin\":120,\"announceIntervalMax\":240}'::jsonb" + }, + "discord_automation": { + "name": "discord_automation", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{\"enabled\":false,\"autoAnnounce\":false,\"announceIntervalMin\":120,\"announceIntervalMax\":240}'::jsonb" + }, + "promotional_assets": { + "name": "promotional_assets", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "linked_character_ids": { + "name": "linked_character_ids", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "github_repo": { + "name": "github_repo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_config_app_idx": { + "name": "app_config_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_config_app_id_apps_id_fk": { + "name": "app_config_app_id_apps_id_fk", + "tableFrom": "app_config", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "app_config_app_id_unique": { + "name": "app_config_app_id_unique", + "columns": [ + "app_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_billing": { + "name": "app_billing", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "custom_pricing_enabled": { + "name": "custom_pricing_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "monetization_enabled": { + "name": "monetization_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inference_markup_percentage": { + "name": "inference_markup_percentage", + "type": "numeric(7, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "purchase_share_percentage": { + "name": "purchase_share_percentage", + "type": "numeric(5, 2)", + "primaryKey": false, + "notNull": true, + "default": "'10.00'" + }, + "platform_offset_amount": { + "name": "platform_offset_amount", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'1.00'" + }, + "total_creator_earnings": { + "name": "total_creator_earnings", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "total_platform_revenue": { + "name": "total_platform_revenue", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "rate_limit_per_minute": { + "name": "rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 60 + }, + "rate_limit_per_hour": { + "name": "rate_limit_per_hour", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 1000 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_billing_app_idx": { + "name": "app_billing_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_billing_app_id_apps_id_fk": { + "name": "app_billing_app_id_apps_id_fk", + "tableFrom": "app_billing", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "app_billing_app_id_unique": { + "name": "app_billing_app_id_unique", + "columns": [ + "app_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_databases": { + "name": "app_databases", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_database_uri": { + "name": "user_database_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_database_project_id": { + "name": "user_database_project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_database_branch_id": { + "name": "user_database_branch_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_database_region": { + "name": "user_database_region", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'aws-us-east-1'" + }, + "user_database_status": { + "name": "user_database_status", + "type": "user_database_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "user_database_error": { + "name": "user_database_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_databases_app_idx": { + "name": "app_databases_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_databases_status_idx": { + "name": "app_databases_status_idx", + "columns": [ + { + "expression": "user_database_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_databases_app_id_apps_id_fk": { + "name": "app_databases_app_id_apps_id_fk", + "tableFrom": "app_databases", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "app_databases_app_id_unique": { + "name": "app_databases_app_id_unique", + "columns": [ + "app_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_credit_balances": { + "name": "app_credit_balances", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "total_purchased": { + "name": "total_purchased", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "total_spent": { + "name": "total_spent", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_credit_balances_app_user_idx": { + "name": "app_credit_balances_app_user_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_credit_balances_app_idx": { + "name": "app_credit_balances_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_credit_balances_user_idx": { + "name": "app_credit_balances_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_credit_balances_org_idx": { + "name": "app_credit_balances_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_credit_balances_app_id_apps_id_fk": { + "name": "app_credit_balances_app_id_apps_id_fk", + "tableFrom": "app_credit_balances", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_credit_balances_user_id_users_id_fk": { + "name": "app_credit_balances_user_id_users_id_fk", + "tableFrom": "app_credit_balances", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_credit_balances_organization_id_organizations_id_fk": { + "name": "app_credit_balances_organization_id_organizations_id_fk", + "tableFrom": "app_credit_balances", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_earnings": { + "name": "app_earnings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "total_lifetime_earnings": { + "name": "total_lifetime_earnings", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "total_inference_earnings": { + "name": "total_inference_earnings", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "total_purchase_earnings": { + "name": "total_purchase_earnings", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "pending_balance": { + "name": "pending_balance", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "withdrawable_balance": { + "name": "withdrawable_balance", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "total_withdrawn": { + "name": "total_withdrawn", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": true, + "default": "'0.000000'" + }, + "last_withdrawal_at": { + "name": "last_withdrawal_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "payout_threshold": { + "name": "payout_threshold", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'25.00'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_earnings_app_idx": { + "name": "app_earnings_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_earnings_app_id_apps_id_fk": { + "name": "app_earnings_app_id_apps_id_fk", + "tableFrom": "app_earnings", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_earnings_transactions": { + "name": "app_earnings_transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_earnings_transactions_app_idx": { + "name": "app_earnings_transactions_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_earnings_transactions_app_created_idx": { + "name": "app_earnings_transactions_app_created_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_earnings_transactions_user_idx": { + "name": "app_earnings_transactions_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_earnings_transactions_type_idx": { + "name": "app_earnings_transactions_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_earnings_transactions_app_id_apps_id_fk": { + "name": "app_earnings_transactions_app_id_apps_id_fk", + "tableFrom": "app_earnings_transactions", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_earnings_transactions_user_id_users_id_fk": { + "name": "app_earnings_transactions_user_id_users_id_fk", + "tableFrom": "app_earnings_transactions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.referral_codes": { + "name": "referral_codes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_referral_id": { + "name": "parent_referral_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "total_referrals": { + "name": "total_referrals", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_signup_earnings": { + "name": "total_signup_earnings", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "total_qualified_earnings": { + "name": "total_qualified_earnings", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "total_commission_earnings": { + "name": "total_commission_earnings", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "referral_codes_user_idx": { + "name": "referral_codes_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "referral_codes_code_idx": { + "name": "referral_codes_code_idx", + "columns": [ + { + "expression": "code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "referral_codes_user_id_users_id_fk": { + "name": "referral_codes_user_id_users_id_fk", + "tableFrom": "referral_codes", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "referral_codes_code_unique": { + "name": "referral_codes_code_unique", + "columns": [ + "code" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.referral_signups": { + "name": "referral_signups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "referral_code_id": { + "name": "referral_code_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "referrer_user_id": { + "name": "referrer_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "referred_user_id": { + "name": "referred_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "app_owner_id": { + "name": "app_owner_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "creator_id": { + "name": "creator_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "signup_bonus_credited": { + "name": "signup_bonus_credited", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "signup_bonus_amount": { + "name": "signup_bonus_amount", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "qualified_at": { + "name": "qualified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "qualified_bonus_credited": { + "name": "qualified_bonus_credited", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "qualified_bonus_amount": { + "name": "qualified_bonus_amount", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0.00'" + }, + "total_commission_earned": { + "name": "total_commission_earned", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "referral_signups_referred_user_idx": { + "name": "referral_signups_referred_user_idx", + "columns": [ + { + "expression": "referred_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "referral_signups_referrer_idx": { + "name": "referral_signups_referrer_idx", + "columns": [ + { + "expression": "referrer_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "referral_signups_code_idx": { + "name": "referral_signups_code_idx", + "columns": [ + { + "expression": "referral_code_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "referral_signups_referral_code_id_referral_codes_id_fk": { + "name": "referral_signups_referral_code_id_referral_codes_id_fk", + "tableFrom": "referral_signups", + "columnsFrom": [ + "referral_code_id" + ], + "tableTo": "referral_codes", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "referral_signups_referrer_user_id_users_id_fk": { + "name": "referral_signups_referrer_user_id_users_id_fk", + "tableFrom": "referral_signups", + "columnsFrom": [ + "referrer_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "referral_signups_referred_user_id_users_id_fk": { + "name": "referral_signups_referred_user_id_users_id_fk", + "tableFrom": "referral_signups", + "columnsFrom": [ + "referred_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "referral_signups_app_owner_id_users_id_fk": { + "name": "referral_signups_app_owner_id_users_id_fk", + "tableFrom": "referral_signups", + "columnsFrom": [ + "app_owner_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "referral_signups_creator_id_users_id_fk": { + "name": "referral_signups_creator_id_users_id_fk", + "tableFrom": "referral_signups", + "columnsFrom": [ + "creator_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.social_share_rewards": { + "name": "social_share_rewards", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "platform": { + "name": "platform", + "type": "social_platform", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "share_type": { + "name": "share_type", + "type": "share_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "share_url": { + "name": "share_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "share_intent_at": { + "name": "share_intent_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "credits_awarded": { + "name": "credits_awarded", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "social_share_rewards_user_idx": { + "name": "social_share_rewards_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "social_share_rewards_platform_idx": { + "name": "social_share_rewards_platform_idx", + "columns": [ + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "social_share_rewards_user_platform_date_idx": { + "name": "social_share_rewards_user_platform_date_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "social_share_rewards_user_id_users_id_fk": { + "name": "social_share_rewards_user_id_users_id_fk", + "tableFrom": "social_share_rewards", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agents": { + "name": "agents", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "server_id": { + "name": "server_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "system": { + "name": "system", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "bio": { + "name": "bio", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "message_examples": { + "name": "message_examples", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "post_examples": { + "name": "post_examples", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "topics": { + "name": "topics", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "adjectives": { + "name": "adjectives", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "knowledge": { + "name": "knowledge", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "plugins": { + "name": "plugins", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "style": { + "name": "style", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.cache": { + "name": "cache", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "cache_agent_id_agents_id_fk": { + "name": "cache_agent_id_agents_id_fk", + "tableFrom": "cache", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": { + "cache_key_agent_id_pk": { + "name": "cache_key_agent_id_pk", + "columns": [ + "key", + "agent_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.channel_participants": { + "name": "channel_participants", + "schema": "", + "columns": { + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "channel_participants_channel_id_channels_id_fk": { + "name": "channel_participants_channel_id_channels_id_fk", + "tableFrom": "channel_participants", + "columnsFrom": [ + "channel_id" + ], + "tableTo": "channels", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": { + "channel_participants_channel_id_entity_id_pk": { + "name": "channel_participants_channel_id_entity_id_pk", + "columns": [ + "channel_id", + "entity_id" + ] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.channels": { + "name": "channels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "message_server_id": { + "name": "message_server_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "topic": { + "name": "topic", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": { + "channels_message_server_id_message_servers_id_fk": { + "name": "channels_message_server_id_message_servers_id_fk", + "tableFrom": "channels", + "columnsFrom": [ + "message_server_id" + ], + "tableTo": "message_servers", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.components": { + "name": "components", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "entity_id": { + "name": "entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "room_id": { + "name": "room_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "world_id": { + "name": "world_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "source_entity_id": { + "name": "source_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "components_entity_id_entities_id_fk": { + "name": "components_entity_id_entities_id_fk", + "tableFrom": "components", + "columnsFrom": [ + "entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "components_agent_id_agents_id_fk": { + "name": "components_agent_id_agents_id_fk", + "tableFrom": "components", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "components_room_id_rooms_id_fk": { + "name": "components_room_id_rooms_id_fk", + "tableFrom": "components", + "columnsFrom": [ + "room_id" + ], + "tableTo": "rooms", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "components_world_id_worlds_id_fk": { + "name": "components_world_id_worlds_id_fk", + "tableFrom": "components", + "columnsFrom": [ + "world_id" + ], + "tableTo": "worlds", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "components_source_entity_id_entities_id_fk": { + "name": "components_source_entity_id_entities_id_fk", + "tableFrom": "components", + "columnsFrom": [ + "source_entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.embeddings": { + "name": "embeddings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "memory_id": { + "name": "memory_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "dim_384": { + "name": "dim_384", + "type": "vector(384)", + "primaryKey": false, + "notNull": false + }, + "dim_512": { + "name": "dim_512", + "type": "vector(512)", + "primaryKey": false, + "notNull": false + }, + "dim_768": { + "name": "dim_768", + "type": "vector(768)", + "primaryKey": false, + "notNull": false + }, + "dim_1024": { + "name": "dim_1024", + "type": "vector(1024)", + "primaryKey": false, + "notNull": false + }, + "dim_1536": { + "name": "dim_1536", + "type": "vector(1536)", + "primaryKey": false, + "notNull": false + }, + "dim_3072": { + "name": "dim_3072", + "type": "vector(3072)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_embedding_memory": { + "name": "idx_embedding_memory", + "columns": [ + { + "expression": "memory_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "embeddings_memory_id_memories_id_fk": { + "name": "embeddings_memory_id_memories_id_fk", + "tableFrom": "embeddings", + "columnsFrom": [ + "memory_id" + ], + "tableTo": "memories", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_embedding_memory": { + "name": "fk_embedding_memory", + "tableFrom": "embeddings", + "columnsFrom": [ + "memory_id" + ], + "tableTo": "memories", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "embedding_source_check": { + "name": "embedding_source_check", + "value": "\"memory_id\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.entities": { + "name": "entities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "names": { + "name": "names", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": { + "entities_agent_id_agents_id_fk": { + "name": "entities_agent_id_agents_id_fk", + "tableFrom": "entities", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "id_agent_id_unique": { + "name": "id_agent_id_unique", + "columns": [ + "id", + "agent_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.logs": { + "name": "logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "entity_id": { + "name": "entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "body": { + "name": "body", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "room_id": { + "name": "room_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "logs_entity_id_entities_id_fk": { + "name": "logs_entity_id_entities_id_fk", + "tableFrom": "logs", + "columnsFrom": [ + "entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "logs_room_id_rooms_id_fk": { + "name": "logs_room_id_rooms_id_fk", + "tableFrom": "logs", + "columnsFrom": [ + "room_id" + ], + "tableTo": "rooms", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_room": { + "name": "fk_room", + "tableFrom": "logs", + "columnsFrom": [ + "room_id" + ], + "tableTo": "rooms", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_user": { + "name": "fk_user", + "tableFrom": "logs", + "columnsFrom": [ + "entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.long_term_memories": { + "name": "long_term_memories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": true, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "embedding": { + "name": "embedding", + "type": "real[]", + "primaryKey": false, + "notNull": false + }, + "confidence": { + "name": "confidence", + "type": "real", + "primaryKey": false, + "notNull": false, + "default": 1 + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + } + }, + "indexes": { + "long_term_memories_agent_entity_idx": { + "name": "long_term_memories_agent_entity_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "long_term_memories_category_idx": { + "name": "long_term_memories_category_idx", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "long_term_memories_confidence_idx": { + "name": "long_term_memories_confidence_idx", + "columns": [ + { + "expression": "confidence", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "long_term_memories_created_at_idx": { + "name": "long_term_memories_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory_access_logs": { + "name": "memory_access_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": true, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true + }, + "memory_id": { + "name": "memory_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true + }, + "memory_type": { + "name": "memory_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "accessed_at": { + "name": "accessed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "room_id": { + "name": "room_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": false + }, + "relevance_score": { + "name": "relevance_score", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "was_useful": { + "name": "was_useful", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "memory_access_logs_memory_idx": { + "name": "memory_access_logs_memory_idx", + "columns": [ + { + "expression": "memory_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "memory_access_logs_agent_idx": { + "name": "memory_access_logs_agent_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "memory_access_logs_accessed_at_idx": { + "name": "memory_access_logs_accessed_at_idx", + "columns": [ + { + "expression": "accessed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memories": { + "name": "memories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "room_id": { + "name": "room_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "world_id": { + "name": "world_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "unique": { + "name": "unique", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": { + "idx_memories_type_room": { + "name": "idx_memories_type_room", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "idx_memories_world_id": { + "name": "idx_memories_world_id", + "columns": [ + { + "expression": "world_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "idx_memories_metadata_type": { + "name": "idx_memories_metadata_type", + "columns": [ + { + "expression": "((metadata->>'type'))", + "isExpression": true, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "idx_memories_document_id": { + "name": "idx_memories_document_id", + "columns": [ + { + "expression": "((metadata->>'documentId'))", + "isExpression": true, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "idx_fragments_order": { + "name": "idx_fragments_order", + "columns": [ + { + "expression": "((metadata->>'documentId'))", + "isExpression": true, + "asc": true, + "nulls": "last" + }, + { + "expression": "((metadata->>'position'))", + "isExpression": true, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "memories_entity_id_entities_id_fk": { + "name": "memories_entity_id_entities_id_fk", + "tableFrom": "memories", + "columnsFrom": [ + "entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "memories_agent_id_agents_id_fk": { + "name": "memories_agent_id_agents_id_fk", + "tableFrom": "memories", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "memories_room_id_rooms_id_fk": { + "name": "memories_room_id_rooms_id_fk", + "tableFrom": "memories", + "columnsFrom": [ + "room_id" + ], + "tableTo": "rooms", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_room": { + "name": "fk_room", + "tableFrom": "memories", + "columnsFrom": [ + "room_id" + ], + "tableTo": "rooms", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_user": { + "name": "fk_user", + "tableFrom": "memories", + "columnsFrom": [ + "entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_agent": { + "name": "fk_agent", + "tableFrom": "memories", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "fragment_metadata_check": { + "name": "fragment_metadata_check", + "value": "\n CASE \n WHEN metadata->>'type' = 'fragment' THEN\n metadata ? 'documentId' AND \n metadata ? 'position'\n ELSE true\n END\n " + }, + "document_metadata_check": { + "name": "document_metadata_check", + "value": "\n CASE \n WHEN metadata->>'type' = 'document' THEN\n metadata ? 'timestamp'\n ELSE true\n END\n " + } + }, + "isRLSEnabled": false + }, + "public.message_servers": { + "name": "message_servers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.central_messages": { + "name": "central_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "author_id": { + "name": "author_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "raw_message": { + "name": "raw_message", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "in_reply_to_root_message_id": { + "name": "in_reply_to_root_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "CURRENT_TIMESTAMP" + } + }, + "indexes": {}, + "foreignKeys": { + "central_messages_channel_id_channels_id_fk": { + "name": "central_messages_channel_id_channels_id_fk", + "tableFrom": "central_messages", + "columnsFrom": [ + "channel_id" + ], + "tableTo": "channels", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "central_messages_in_reply_to_root_message_id_central_messages_id_fk": { + "name": "central_messages_in_reply_to_root_message_id_central_messages_id_fk", + "tableFrom": "central_messages", + "columnsFrom": [ + "in_reply_to_root_message_id" + ], + "tableTo": "central_messages", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.participants": { + "name": "participants", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "entity_id": { + "name": "entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "room_id": { + "name": "room_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "room_state": { + "name": "room_state", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_participants_user": { + "name": "idx_participants_user", + "columns": [ + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "idx_participants_room": { + "name": "idx_participants_room", + "columns": [ + { + "expression": "room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "participants_entity_id_entities_id_fk": { + "name": "participants_entity_id_entities_id_fk", + "tableFrom": "participants", + "columnsFrom": [ + "entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "participants_room_id_rooms_id_fk": { + "name": "participants_room_id_rooms_id_fk", + "tableFrom": "participants", + "columnsFrom": [ + "room_id" + ], + "tableTo": "rooms", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "participants_agent_id_agents_id_fk": { + "name": "participants_agent_id_agents_id_fk", + "tableFrom": "participants", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_room": { + "name": "fk_room", + "tableFrom": "participants", + "columnsFrom": [ + "room_id" + ], + "tableTo": "rooms", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_user": { + "name": "fk_user", + "tableFrom": "participants", + "columnsFrom": [ + "entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.relationships": { + "name": "relationships", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "source_entity_id": { + "name": "source_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "target_entity_id": { + "name": "target_entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_relationships_users": { + "name": "idx_relationships_users", + "columns": [ + { + "expression": "source_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "relationships_source_entity_id_entities_id_fk": { + "name": "relationships_source_entity_id_entities_id_fk", + "tableFrom": "relationships", + "columnsFrom": [ + "source_entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "relationships_target_entity_id_entities_id_fk": { + "name": "relationships_target_entity_id_entities_id_fk", + "tableFrom": "relationships", + "columnsFrom": [ + "target_entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "relationships_agent_id_agents_id_fk": { + "name": "relationships_agent_id_agents_id_fk", + "tableFrom": "relationships", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_user_a": { + "name": "fk_user_a", + "tableFrom": "relationships", + "columnsFrom": [ + "source_entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "fk_user_b": { + "name": "fk_user_b", + "tableFrom": "relationships", + "columnsFrom": [ + "target_entity_id" + ], + "tableTo": "entities", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "unique_relationship": { + "name": "unique_relationship", + "columns": [ + "source_entity_id", + "target_entity_id", + "agent_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rooms": { + "name": "rooms", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message_server_id": { + "name": "message_server_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "world_id": { + "name": "world_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "rooms_agent_id_agents_id_fk": { + "name": "rooms_agent_id_agents_id_fk", + "tableFrom": "rooms", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_summaries": { + "name": "session_summaries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar(36)", + "primaryKey": true, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true + }, + "room_id": { + "name": "room_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "varchar(36)", + "primaryKey": false, + "notNull": false + }, + "summary": { + "name": "summary", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message_count": { + "name": "message_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "last_message_offset": { + "name": "last_message_offset", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "start_time": { + "name": "start_time", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_time": { + "name": "end_time", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "topics": { + "name": "topics", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "embedding": { + "name": "embedding", + "type": "real[]", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_summaries_agent_room_idx": { + "name": "session_summaries_agent_room_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "session_summaries_entity_idx": { + "name": "session_summaries_entity_idx", + "columns": [ + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "session_summaries_start_time_idx": { + "name": "session_summaries_start_time_idx", + "columns": [ + { + "expression": "start_time", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.tasks": { + "name": "tasks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "room_id": { + "name": "room_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "world_id": { + "name": "world_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "entity_id": { + "name": "entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": false, + "default": "'{}'::text[]" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "tasks_agent_id_agents_id_fk": { + "name": "tasks_agent_id_agents_id_fk", + "tableFrom": "tasks", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.worlds": { + "name": "worlds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "message_server_id": { + "name": "message_server_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "worlds_agent_id_agents_id_fk": { + "name": "worlds_agent_id_agents_id_fk", + "tableFrom": "worlds", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "agents", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.eliza_room_characters": { + "name": "eliza_room_characters", + "schema": "", + "columns": { + "room_id": { + "name": "room_id", + "type": "uuid", + "primaryKey": true, + "notNull": true + }, + "character_id": { + "name": "character_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "eliza_room_characters_character_id_user_characters_id_fk": { + "name": "eliza_room_characters_character_id_user_characters_id_fk", + "tableFrom": "eliza_room_characters", + "columnsFrom": [ + "character_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agent_events": { + "name": "agent_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'info'" + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "duration_ms": { + "name": "duration_ms", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "container_id": { + "name": "container_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agent_events_agent_idx": { + "name": "agent_events_agent_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_events_organization_idx": { + "name": "agent_events_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_events_event_type_idx": { + "name": "agent_events_event_type_idx", + "columns": [ + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_events_level_idx": { + "name": "agent_events_level_idx", + "columns": [ + { + "expression": "level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_events_created_at_idx": { + "name": "agent_events_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_events_agent_created_idx": { + "name": "agent_events_agent_created_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "agent_events_agent_id_user_characters_id_fk": { + "name": "agent_events_agent_id_user_characters_id_fk", + "tableFrom": "agent_events", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "agent_events_organization_id_organizations_id_fk": { + "name": "agent_events_organization_id_organizations_id_fk", + "tableFrom": "agent_events", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_usage": { + "name": "mcp_usage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "mcp_id": { + "name": "mcp_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "credits_charged": { + "name": "credits_charged", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.0000'" + }, + "x402_amount_usd": { + "name": "x402_amount_usd", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "payment_type": { + "name": "payment_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'credits'" + }, + "creator_earnings": { + "name": "creator_earnings", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.0000'" + }, + "platform_earnings": { + "name": "platform_earnings", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.0000'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_usage_mcp_id_idx": { + "name": "mcp_usage_mcp_id_idx", + "columns": [ + { + "expression": "mcp_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "mcp_usage_organization_idx": { + "name": "mcp_usage_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "mcp_usage_user_idx": { + "name": "mcp_usage_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "mcp_usage_created_at_idx": { + "name": "mcp_usage_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "mcp_usage_mcp_org_idx": { + "name": "mcp_usage_mcp_org_idx", + "columns": [ + { + "expression": "mcp_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "mcp_usage_mcp_id_user_mcps_id_fk": { + "name": "mcp_usage_mcp_id_user_mcps_id_fk", + "tableFrom": "mcp_usage", + "columnsFrom": [ + "mcp_id" + ], + "tableTo": "user_mcps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mcp_usage_organization_id_organizations_id_fk": { + "name": "mcp_usage_organization_id_organizations_id_fk", + "tableFrom": "mcp_usage", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "mcp_usage_user_id_users_id_fk": { + "name": "mcp_usage_user_id_users_id_fk", + "tableFrom": "mcp_usage", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_mcps": { + "name": "user_mcps", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'1.0.0'" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_by_user_id": { + "name": "created_by_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "endpoint_type": { + "name": "endpoint_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'container'" + }, + "container_id": { + "name": "container_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "external_endpoint": { + "name": "external_endpoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint_path": { + "name": "endpoint_path", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'/mcp'" + }, + "transport_type": { + "name": "transport_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'streamable-http'" + }, + "mcp_version": { + "name": "mcp_version", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'2025-06-18'" + }, + "tools": { + "name": "tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'utilities'" + }, + "tags": { + "name": "tags", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'puzzle'" + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'#6366F1'" + }, + "pricing_type": { + "name": "pricing_type", + "type": "mcp_pricing_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'credits'" + }, + "credits_per_request": { + "name": "credits_per_request", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false, + "default": "'1.0000'" + }, + "x402_price_usd": { + "name": "x402_price_usd", + "type": "numeric(10, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000100'" + }, + "x402_enabled": { + "name": "x402_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "creator_share_percentage": { + "name": "creator_share_percentage", + "type": "numeric(5, 2)", + "primaryKey": false, + "notNull": true, + "default": "'80.00'" + }, + "platform_share_percentage": { + "name": "platform_share_percentage", + "type": "numeric(5, 2)", + "primaryKey": false, + "notNull": true, + "default": "'20.00'" + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_credits_earned": { + "name": "total_credits_earned", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": false, + "default": "'0.0000'" + }, + "total_x402_earned_usd": { + "name": "total_x402_earned_usd", + "type": "numeric(12, 6)", + "primaryKey": false, + "notNull": false, + "default": "'0.000000'" + }, + "unique_users": { + "name": "unique_users", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "mcp_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'draft'" + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_featured": { + "name": "is_featured", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_verified": { + "name": "is_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "verified_by": { + "name": "verified_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "documentation_url": { + "name": "documentation_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_code_url": { + "name": "source_code_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "support_email": { + "name": "support_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "erc8004_registered": { + "name": "erc8004_registered", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "erc8004_network": { + "name": "erc8004_network", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "erc8004_agent_id": { + "name": "erc8004_agent_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "erc8004_agent_uri": { + "name": "erc8004_agent_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "erc8004_tx_hash": { + "name": "erc8004_tx_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "erc8004_registered_at": { + "name": "erc8004_registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_mcps_slug_org_idx": { + "name": "user_mcps_slug_org_idx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_organization_idx": { + "name": "user_mcps_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_created_by_idx": { + "name": "user_mcps_created_by_idx", + "columns": [ + { + "expression": "created_by_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_container_idx": { + "name": "user_mcps_container_idx", + "columns": [ + { + "expression": "container_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_category_idx": { + "name": "user_mcps_category_idx", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_status_idx": { + "name": "user_mcps_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_is_public_idx": { + "name": "user_mcps_is_public_idx", + "columns": [ + { + "expression": "is_public", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_created_at_idx": { + "name": "user_mcps_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_mcps_erc8004_registered_idx": { + "name": "user_mcps_erc8004_registered_idx", + "columns": [ + { + "expression": "erc8004_registered", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_mcps_organization_id_organizations_id_fk": { + "name": "user_mcps_organization_id_organizations_id_fk", + "tableFrom": "user_mcps", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_mcps_created_by_user_id_users_id_fk": { + "name": "user_mcps_created_by_user_id_users_id_fk", + "tableFrom": "user_mcps", + "columnsFrom": [ + "created_by_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_mcps_container_id_containers_id_fk": { + "name": "user_mcps_container_id_containers_id_fk", + "tableFrom": "user_mcps", + "columnsFrom": [ + "container_id" + ], + "tableTo": "containers", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "user_mcps_verified_by_users_id_fk": { + "name": "user_mcps_verified_by_users_id_fk", + "tableFrom": "user_mcps", + "columnsFrom": [ + "verified_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.eliza_token_prices": { + "name": "eliza_token_prices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "network": { + "name": "network", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "price_usd": { + "name": "price_usd", + "type": "numeric(18, 8)", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "fetched_at": { + "name": "fetched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": { + "eliza_token_prices_network_source_idx": { + "name": "eliza_token_prices_network_source_idx", + "columns": [ + { + "expression": "network", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "eliza_token_prices_expires_idx": { + "name": "eliza_token_prices_expires_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redemption_limits": { + "name": "redemption_limits", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "daily_usd_total": { + "name": "daily_usd_total", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "redemption_count": { + "name": "redemption_count", + "type": "numeric(5, 0)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "redemption_limits_user_date_idx": { + "name": "redemption_limits_user_date_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "redemption_limits_user_id_users_id_fk": { + "name": "redemption_limits_user_id_users_id_fk", + "tableFrom": "redemption_limits", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.token_redemptions": { + "name": "token_redemptions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "points_amount": { + "name": "points_amount", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true + }, + "usd_value": { + "name": "usd_value", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true + }, + "eliza_price_usd": { + "name": "eliza_price_usd", + "type": "numeric(18, 8)", + "primaryKey": false, + "notNull": true + }, + "eliza_amount": { + "name": "eliza_amount", + "type": "numeric(24, 8)", + "primaryKey": false, + "notNull": true + }, + "price_quote_expires_at": { + "name": "price_quote_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "network": { + "name": "network", + "type": "redemption_network", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "payout_address": { + "name": "payout_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address_signature": { + "name": "address_signature", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "redemption_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_worker_id": { + "name": "processing_worker_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tx_hash": { + "name": "tx_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "failure_reason": { + "name": "failure_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "retry_count": { + "name": "retry_count", + "type": "numeric(3, 0)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "requires_review": { + "name": "requires_review", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "review_notes": { + "name": "review_notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "token_redemptions_user_idx": { + "name": "token_redemptions_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "token_redemptions_app_idx": { + "name": "token_redemptions_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "token_redemptions_status_idx": { + "name": "token_redemptions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "token_redemptions_status_created_idx": { + "name": "token_redemptions_status_created_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "token_redemptions_network_idx": { + "name": "token_redemptions_network_idx", + "columns": [ + { + "expression": "network", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "token_redemptions_payout_idx": { + "name": "token_redemptions_payout_idx", + "columns": [ + { + "expression": "payout_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "token_redemptions_pending_user_idx": { + "name": "token_redemptions_pending_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "where": "status = 'pending'", + "concurrently": false + } + }, + "foreignKeys": { + "token_redemptions_user_id_users_id_fk": { + "name": "token_redemptions_user_id_users_id_fk", + "tableFrom": "token_redemptions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "token_redemptions_app_id_apps_id_fk": { + "name": "token_redemptions_app_id_apps_id_fk", + "tableFrom": "token_redemptions", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "token_redemptions_reviewed_by_users_id_fk": { + "name": "token_redemptions_reviewed_by_users_id_fk", + "tableFrom": "token_redemptions", + "columnsFrom": [ + "reviewed_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redeemable_earnings": { + "name": "redeemable_earnings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "total_earned": { + "name": "total_earned", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "total_redeemed": { + "name": "total_redeemed", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "total_pending": { + "name": "total_pending", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "available_balance": { + "name": "available_balance", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "earned_from_miniapps": { + "name": "earned_from_miniapps", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "earned_from_agents": { + "name": "earned_from_agents", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "earned_from_mcps": { + "name": "earned_from_mcps", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "earned_from_affiliates": { + "name": "earned_from_affiliates", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "earned_from_app_owner_shares": { + "name": "earned_from_app_owner_shares", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "earned_from_creator_shares": { + "name": "earned_from_creator_shares", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "last_earning_at": { + "name": "last_earning_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_redemption_at": { + "name": "last_redemption_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "numeric(10, 0)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "redeemable_earnings_user_idx": { + "name": "redeemable_earnings_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "redeemable_earnings_user_id_users_id_fk": { + "name": "redeemable_earnings_user_id_users_id_fk", + "tableFrom": "redeemable_earnings", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redeemable_earnings_user_id_unique": { + "name": "redeemable_earnings_user_id_unique", + "columns": [ + "user_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": { + "available_balance_non_negative": { + "name": "available_balance_non_negative", + "value": "\"redeemable_earnings\".\"available_balance\" >= 0" + }, + "totals_consistent": { + "name": "totals_consistent", + "value": "\"redeemable_earnings\".\"total_earned\" >= \"redeemable_earnings\".\"total_redeemed\" + \"redeemable_earnings\".\"total_pending\"" + } + }, + "isRLSEnabled": false + }, + "public.redeemable_earnings_ledger": { + "name": "redeemable_earnings_ledger", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "entry_type": { + "name": "entry_type", + "type": "ledger_entry_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true + }, + "balance_after": { + "name": "balance_after", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true + }, + "earnings_source": { + "name": "earnings_source", + "type": "earnings_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "redemption_id": { + "name": "redemption_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "redeemable_earnings_ledger_user_idx": { + "name": "redeemable_earnings_ledger_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "redeemable_earnings_ledger_user_created_idx": { + "name": "redeemable_earnings_ledger_user_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "redeemable_earnings_ledger_type_idx": { + "name": "redeemable_earnings_ledger_type_idx", + "columns": [ + { + "expression": "entry_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "redeemable_earnings_ledger_redemption_idx": { + "name": "redeemable_earnings_ledger_redemption_idx", + "columns": [ + { + "expression": "redemption_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "redeemable_earnings_ledger_source_idx": { + "name": "redeemable_earnings_ledger_source_idx", + "columns": [ + { + "expression": "earnings_source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "redeemable_earnings_ledger_user_id_users_id_fk": { + "name": "redeemable_earnings_ledger_user_id_users_id_fk", + "tableFrom": "redeemable_earnings_ledger", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.redeemed_earnings_tracking": { + "name": "redeemed_earnings_tracking", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "ledger_entry_id": { + "name": "ledger_entry_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "redemption_id": { + "name": "redemption_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "amount_redeemed": { + "name": "amount_redeemed", + "type": "numeric(18, 4)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "redeemed_tracking_ledger_idx": { + "name": "redeemed_tracking_ledger_idx", + "columns": [ + { + "expression": "ledger_entry_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "redeemed_tracking_redemption_idx": { + "name": "redeemed_tracking_redemption_idx", + "columns": [ + { + "expression": "redemption_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "redeemed_earnings_tracking_ledger_entry_id_unique": { + "name": "redeemed_earnings_tracking_ledger_entry_id_unique", + "columns": [ + "ledger_entry_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.admin_users": { + "name": "admin_users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "wallet_address": { + "name": "wallet_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "admin_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'moderator'" + }, + "granted_by": { + "name": "granted_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "granted_by_wallet": { + "name": "granted_by_wallet", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "admin_users_wallet_address_idx": { + "name": "admin_users_wallet_address_idx", + "columns": [ + { + "expression": "wallet_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "admin_users_user_id_idx": { + "name": "admin_users_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "admin_users_role_idx": { + "name": "admin_users_role_idx", + "columns": [ + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "admin_users_is_active_idx": { + "name": "admin_users_is_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "admin_users_user_id_users_id_fk": { + "name": "admin_users_user_id_users_id_fk", + "tableFrom": "admin_users", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "admin_users_granted_by_users_id_fk": { + "name": "admin_users_granted_by_users_id_fk", + "tableFrom": "admin_users", + "columnsFrom": [ + "granted_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "admin_users_wallet_address_unique": { + "name": "admin_users_wallet_address_unique", + "columns": [ + "wallet_address" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.moderation_violations": { + "name": "moderation_violations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "room_id": { + "name": "room_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message_text": { + "name": "message_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "categories": { + "name": "categories", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "scores": { + "name": "scores", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "moderation_action", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "review_notes": { + "name": "review_notes", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "moderation_violations_user_id_idx": { + "name": "moderation_violations_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "moderation_violations_action_idx": { + "name": "moderation_violations_action_idx", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "moderation_violations_created_at_idx": { + "name": "moderation_violations_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "moderation_violations_room_id_idx": { + "name": "moderation_violations_room_id_idx", + "columns": [ + { + "expression": "room_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "moderation_violations_user_id_users_id_fk": { + "name": "moderation_violations_user_id_users_id_fk", + "tableFrom": "moderation_violations", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "moderation_violations_reviewed_by_users_id_fk": { + "name": "moderation_violations_reviewed_by_users_id_fk", + "tableFrom": "moderation_violations", + "columnsFrom": [ + "reviewed_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_moderation_status": { + "name": "user_moderation_status", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "user_mod_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'clean'" + }, + "total_violations": { + "name": "total_violations", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "warning_count": { + "name": "warning_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "risk_score": { + "name": "risk_score", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "banned_by": { + "name": "banned_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "banned_at": { + "name": "banned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_violation_at": { + "name": "last_violation_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_warning_at": { + "name": "last_warning_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_moderation_status_user_id_idx": { + "name": "user_moderation_status_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_moderation_status_status_idx": { + "name": "user_moderation_status_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_moderation_status_risk_score_idx": { + "name": "user_moderation_status_risk_score_idx", + "columns": [ + { + "expression": "risk_score", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_moderation_status_total_violations_idx": { + "name": "user_moderation_status_total_violations_idx", + "columns": [ + { + "expression": "total_violations", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_moderation_status_user_id_users_id_fk": { + "name": "user_moderation_status_user_id_users_id_fk", + "tableFrom": "user_moderation_status", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_moderation_status_banned_by_users_id_fk": { + "name": "user_moderation_status_banned_by_users_id_fk", + "tableFrom": "user_moderation_status", + "columnsFrom": [ + "banned_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_moderation_status_user_id_unique": { + "name": "user_moderation_status_user_id_unique", + "columns": [ + "user_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agent_budget_transactions": { + "name": "agent_budget_transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "budget_id": { + "name": "budget_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true + }, + "balance_after": { + "name": "balance_after", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true + }, + "daily_spent_after": { + "name": "daily_spent_after", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "operation_type": { + "name": "operation_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens_used": { + "name": "tokens_used", + "type": "numeric(12, 0)", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agent_budget_txns_budget_idx": { + "name": "agent_budget_txns_budget_idx", + "columns": [ + { + "expression": "budget_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_budget_txns_agent_idx": { + "name": "agent_budget_txns_agent_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_budget_txns_type_idx": { + "name": "agent_budget_txns_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_budget_txns_created_at_idx": { + "name": "agent_budget_txns_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "agent_budget_transactions_budget_id_agent_budgets_id_fk": { + "name": "agent_budget_transactions_budget_id_agent_budgets_id_fk", + "tableFrom": "agent_budget_transactions", + "columnsFrom": [ + "budget_id" + ], + "tableTo": "agent_budgets", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "agent_budget_transactions_agent_id_user_characters_id_fk": { + "name": "agent_budget_transactions_agent_id_user_characters_id_fk", + "tableFrom": "agent_budget_transactions", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agent_budgets": { + "name": "agent_budgets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "owner_org_id": { + "name": "owner_org_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "allocated_budget": { + "name": "allocated_budget", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "spent_budget": { + "name": "spent_budget", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "daily_limit": { + "name": "daily_limit", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false + }, + "daily_spent": { + "name": "daily_spent", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0.0000'" + }, + "daily_reset_at": { + "name": "daily_reset_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "auto_refill_enabled": { + "name": "auto_refill_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auto_refill_amount": { + "name": "auto_refill_amount", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false + }, + "auto_refill_threshold": { + "name": "auto_refill_threshold", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_paused": { + "name": "is_paused", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "pause_on_depleted": { + "name": "pause_on_depleted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "pause_reason": { + "name": "pause_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "paused_at": { + "name": "paused_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "low_budget_threshold": { + "name": "low_budget_threshold", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": false, + "default": "'5.0000'" + }, + "low_budget_alert_sent": { + "name": "low_budget_alert_sent", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agent_budgets_agent_idx": { + "name": "agent_budgets_agent_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_budgets_owner_org_idx": { + "name": "agent_budgets_owner_org_idx", + "columns": [ + { + "expression": "owner_org_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_budgets_paused_idx": { + "name": "agent_budgets_paused_idx", + "columns": [ + { + "expression": "is_paused", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "agent_budgets_agent_id_user_characters_id_fk": { + "name": "agent_budgets_agent_id_user_characters_id_fk", + "tableFrom": "agent_budgets", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "agent_budgets_owner_org_id_organizations_id_fk": { + "name": "agent_budgets_owner_org_id_organizations_id_fk", + "tableFrom": "agent_budgets", + "columnsFrom": [ + "owner_org_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agent_budgets_agent_id_unique": { + "name": "agent_budgets_agent_id_unique", + "columns": [ + "agent_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.crypto_payments": { + "name": "crypto_payments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "payment_address": { + "name": "payment_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_address": { + "name": "token_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "network": { + "name": "network", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expected_amount": { + "name": "expected_amount", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "received_amount": { + "name": "received_amount", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credits_to_add": { + "name": "credits_to_add", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_hash": { + "name": "transaction_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_number": { + "name": "block_number", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "confirmed_at": { + "name": "confirmed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'::jsonb" + } + }, + "indexes": { + "crypto_payments_organization_id_idx": { + "name": "crypto_payments_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_user_id_idx": { + "name": "crypto_payments_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_payment_address_idx": { + "name": "crypto_payments_payment_address_idx", + "columns": [ + { + "expression": "payment_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_status_idx": { + "name": "crypto_payments_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_transaction_hash_unique_idx": { + "name": "crypto_payments_transaction_hash_unique_idx", + "columns": [ + { + "expression": "transaction_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_network_idx": { + "name": "crypto_payments_network_idx", + "columns": [ + { + "expression": "network", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_created_at_idx": { + "name": "crypto_payments_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_expires_at_idx": { + "name": "crypto_payments_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "crypto_payments_metadata_gin_idx": { + "name": "crypto_payments_metadata_gin_idx", + "columns": [ + { + "expression": "metadata", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "gin", + "concurrently": false + } + }, + "foreignKeys": { + "crypto_payments_organization_id_organizations_id_fk": { + "name": "crypto_payments_organization_id_organizations_id_fk", + "tableFrom": "crypto_payments", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "crypto_payments_user_id_users_id_fk": { + "name": "crypto_payments_user_id_users_id_fk", + "tableFrom": "crypto_payments", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_builder_prompts": { + "name": "app_builder_prompts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "sandbox_session_id": { + "name": "sandbox_session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "files_affected": { + "name": "files_affected", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "commit_sha": { + "name": "commit_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "app_builder_prompts_session_idx": { + "name": "app_builder_prompts_session_idx", + "columns": [ + { + "expression": "sandbox_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_builder_prompts_created_at_idx": { + "name": "app_builder_prompts_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_builder_prompts_sandbox_session_id_app_sandbox_sessions_id_fk": { + "name": "app_builder_prompts_sandbox_session_id_app_sandbox_sessions_id_fk", + "tableFrom": "app_builder_prompts", + "columnsFrom": [ + "sandbox_session_id" + ], + "tableTo": "app_sandbox_sessions", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_sandbox_sessions": { + "name": "app_sandbox_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "sandbox_id": { + "name": "sandbox_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sandbox_url": { + "name": "sandbox_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "git_branch": { + "name": "git_branch", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'main'" + }, + "last_commit_sha": { + "name": "last_commit_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'initializing'" + }, + "status_message": { + "name": "status_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "app_name": { + "name": "app_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "app_description": { + "name": "app_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "initial_prompt": { + "name": "initial_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "template_type": { + "name": "template_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'blank'" + }, + "build_config": { + "name": "build_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "claude_session_id": { + "name": "claude_session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "claude_messages": { + "name": "claude_messages", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "generated_files": { + "name": "generated_files", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "cpu_seconds_used": { + "name": "cpu_seconds_used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "memory_mb_peak": { + "name": "memory_mb_peak", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "stopped_at": { + "name": "stopped_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "app_sandbox_sessions_user_id_idx": { + "name": "app_sandbox_sessions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_sandbox_sessions_org_id_idx": { + "name": "app_sandbox_sessions_org_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_sandbox_sessions_app_id_idx": { + "name": "app_sandbox_sessions_app_id_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_sandbox_sessions_sandbox_id_idx": { + "name": "app_sandbox_sessions_sandbox_id_idx", + "columns": [ + { + "expression": "sandbox_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_sandbox_sessions_status_idx": { + "name": "app_sandbox_sessions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_sandbox_sessions_created_at_idx": { + "name": "app_sandbox_sessions_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_sandbox_sessions_user_id_users_id_fk": { + "name": "app_sandbox_sessions_user_id_users_id_fk", + "tableFrom": "app_sandbox_sessions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_sandbox_sessions_organization_id_organizations_id_fk": { + "name": "app_sandbox_sessions_organization_id_organizations_id_fk", + "tableFrom": "app_sandbox_sessions", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_sandbox_sessions_app_id_apps_id_fk": { + "name": "app_sandbox_sessions_app_id_apps_id_fk", + "tableFrom": "app_sandbox_sessions", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "app_sandbox_sessions_sandbox_id_unique": { + "name": "app_sandbox_sessions_sandbox_id_unique", + "columns": [ + "sandbox_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_templates": { + "name": "app_templates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "preview_image_url": { + "name": "preview_image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "github_repo": { + "name": "github_repo", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "github_branch": { + "name": "github_branch", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'main'" + }, + "features": { + "name": "features", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "system_prompt": { + "name": "system_prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "example_prompts": { + "name": "example_prompts", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "usage_count": { + "name": "usage_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_featured": { + "name": "is_featured", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_templates_slug_idx": { + "name": "app_templates_slug_idx", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_templates_category_idx": { + "name": "app_templates_category_idx", + "columns": [ + { + "expression": "category", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_templates_is_active_idx": { + "name": "app_templates_is_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_templates_is_featured_idx": { + "name": "app_templates_is_featured_idx", + "columns": [ + { + "expression": "is_featured", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "app_templates_slug_unique": { + "name": "app_templates_slug_unique", + "columns": [ + "slug" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sandbox_template_snapshots": { + "name": "sandbox_template_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "snapshot_id": { + "name": "snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "template_key": { + "name": "template_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "github_repo": { + "name": "github_repo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "github_commit_sha": { + "name": "github_commit_sha", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "node_modules_size_mb": { + "name": "node_modules_size_mb", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "total_files": { + "name": "total_files", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'creating'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "usage_count": { + "name": "usage_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + } + }, + "indexes": { + "sandbox_snapshots_template_key_idx": { + "name": "sandbox_snapshots_template_key_idx", + "columns": [ + { + "expression": "template_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "sandbox_snapshots_status_idx": { + "name": "sandbox_snapshots_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "sandbox_snapshots_expires_at_idx": { + "name": "sandbox_snapshots_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "sandbox_snapshots_snapshot_id_idx": { + "name": "sandbox_snapshots_snapshot_id_idx", + "columns": [ + { + "expression": "snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sandbox_template_snapshots_snapshot_id_unique": { + "name": "sandbox_template_snapshots_snapshot_id_unique", + "columns": [ + "snapshot_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_file_snapshots": { + "name": "session_file_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "sandbox_session_id": { + "name": "sandbox_session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "file_path": { + "name": "file_path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "snapshot_type": { + "name": "snapshot_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'auto'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "session_file_snapshots_session_idx": { + "name": "session_file_snapshots_session_idx", + "columns": [ + { + "expression": "sandbox_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "session_file_snapshots_session_path_idx": { + "name": "session_file_snapshots_session_path_idx", + "columns": [ + { + "expression": "sandbox_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "file_path", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "session_file_snapshots_created_at_idx": { + "name": "session_file_snapshots_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "session_file_snapshots_sandbox_session_id_app_sandbox_sessions_id_fk": { + "name": "session_file_snapshots_sandbox_session_id_app_sandbox_sessions_id_fk", + "tableFrom": "session_file_snapshots", + "columnsFrom": [ + "sandbox_session_id" + ], + "tableTo": "app_sandbox_sessions", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session_restore_history": { + "name": "session_restore_history", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "sandbox_session_id": { + "name": "sandbox_session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "old_sandbox_id": { + "name": "old_sandbox_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "new_sandbox_id": { + "name": "new_sandbox_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "files_restored": { + "name": "files_restored", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "restore_duration_ms": { + "name": "restore_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_restore_history_session_idx": { + "name": "session_restore_history_session_idx", + "columns": [ + { + "expression": "sandbox_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "session_restore_history_sandbox_session_id_app_sandbox_sessions_id_fk": { + "name": "session_restore_history_sandbox_session_id_app_sandbox_sessions_id_fk", + "tableFrom": "session_restore_history", + "columnsFrom": [ + "sandbox_session_id" + ], + "tableTo": "app_sandbox_sessions", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook_events": { + "name": "webhook_events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payload_hash": { + "name": "payload_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_ip": { + "name": "source_ip", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "event_timestamp": { + "name": "event_timestamp", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "webhook_events_event_id_idx": { + "name": "webhook_events_event_id_idx", + "columns": [ + { + "expression": "event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "webhook_events_provider_idx": { + "name": "webhook_events_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "webhook_events_processed_at_idx": { + "name": "webhook_events_processed_at_idx", + "columns": [ + { + "expression": "processed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "webhook_events_provider_processed_idx": { + "name": "webhook_events_provider_processed_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "processed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "webhook_events_event_id_unique": { + "name": "webhook_events_event_id_unique", + "columns": [ + "event_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_secret_requirements": { + "name": "app_secret_requirements", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "secret_name": { + "name": "secret_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "approved": { + "name": "approved", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "approved_by": { + "name": "approved_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "approved_at": { + "name": "approved_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "app_secret_requirements_app_secret_idx": { + "name": "app_secret_requirements_app_secret_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_secret_requirements_app_idx": { + "name": "app_secret_requirements_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_secret_requirements_approved_idx": { + "name": "app_secret_requirements_approved_idx", + "columns": [ + { + "expression": "approved", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_secret_requirements_app_id_apps_id_fk": { + "name": "app_secret_requirements_app_id_apps_id_fk", + "tableFrom": "app_secret_requirements", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "app_secret_requirements_approved_by_users_id_fk": { + "name": "app_secret_requirements_approved_by_users_id_fk", + "tableFrom": "app_secret_requirements", + "columnsFrom": [ + "approved_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_sessions": { + "name": "oauth_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_account_id": { + "name": "provider_account_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_access_token": { + "name": "encrypted_access_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_refresh_token": { + "name": "encrypted_refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'Bearer'" + }, + "encryption_key_id": { + "name": "encryption_key_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_dek": { + "name": "encrypted_dek", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nonce": { + "name": "nonce", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_tag": { + "name": "auth_tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refresh_encrypted_dek": { + "name": "refresh_encrypted_dek", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_nonce": { + "name": "refresh_nonce", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_auth_tag": { + "name": "refresh_auth_tag", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "encrypted_provider_data": { + "name": "encrypted_provider_data", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_data_nonce": { + "name": "provider_data_nonce", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_data_auth_tag": { + "name": "provider_data_auth_tag", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_refreshed_at": { + "name": "last_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_count": { + "name": "refresh_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_valid": { + "name": "is_valid", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoke_reason": { + "name": "revoke_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "oauth_sessions_org_provider_idx": { + "name": "oauth_sessions_org_provider_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "oauth_sessions_user_provider_idx": { + "name": "oauth_sessions_user_provider_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "oauth_sessions_provider_idx": { + "name": "oauth_sessions_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "oauth_sessions_expires_idx": { + "name": "oauth_sessions_expires_idx", + "columns": [ + { + "expression": "access_token_expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "oauth_sessions_valid_idx": { + "name": "oauth_sessions_valid_idx", + "columns": [ + { + "expression": "is_valid", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "oauth_sessions_organization_id_organizations_id_fk": { + "name": "oauth_sessions_organization_id_organizations_id_fk", + "tableFrom": "oauth_sessions", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "oauth_sessions_user_id_users_id_fk": { + "name": "oauth_sessions_user_id_users_id_fk", + "tableFrom": "oauth_sessions", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.secret_audit_log": { + "name": "secret_audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "secret_id": { + "name": "secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "oauth_session_id": { + "name": "oauth_session_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "action": { + "name": "action", + "type": "secret_audit_action", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "secret_name": { + "name": "secret_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_type": { + "name": "actor_type", + "type": "secret_actor_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "actor_email": { + "name": "actor_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "secret_audit_log_secret_idx": { + "name": "secret_audit_log_secret_idx", + "columns": [ + { + "expression": "secret_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_audit_log_oauth_idx": { + "name": "secret_audit_log_oauth_idx", + "columns": [ + { + "expression": "oauth_session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_audit_log_org_idx": { + "name": "secret_audit_log_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_audit_log_action_idx": { + "name": "secret_audit_log_action_idx", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_audit_log_actor_idx": { + "name": "secret_audit_log_actor_idx", + "columns": [ + { + "expression": "actor_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_audit_log_created_at_idx": { + "name": "secret_audit_log_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_audit_log_org_action_time_idx": { + "name": "secret_audit_log_org_action_time_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.secret_bindings": { + "name": "secret_bindings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "secret_id": { + "name": "secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_type": { + "name": "project_type", + "type": "secret_project_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "secret_bindings_secret_project_idx": { + "name": "secret_bindings_secret_project_idx", + "columns": [ + { + "expression": "secret_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_bindings_org_idx": { + "name": "secret_bindings_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_bindings_project_idx": { + "name": "secret_bindings_project_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secret_bindings_secret_idx": { + "name": "secret_bindings_secret_idx", + "columns": [ + { + "expression": "secret_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "secret_bindings_organization_id_organizations_id_fk": { + "name": "secret_bindings_organization_id_organizations_id_fk", + "tableFrom": "secret_bindings", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "secret_bindings_secret_id_secrets_id_fk": { + "name": "secret_bindings_secret_id_secrets_id_fk", + "tableFrom": "secret_bindings", + "columnsFrom": [ + "secret_id" + ], + "tableTo": "secrets", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "secret_bindings_created_by_users_id_fk": { + "name": "secret_bindings_created_by_users_id_fk", + "tableFrom": "secret_bindings", + "columnsFrom": [ + "created_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.secrets": { + "name": "secrets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "scope": { + "name": "scope", + "type": "secret_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'organization'" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "project_type": { + "name": "project_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "secret_environment", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "secret_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "provider_metadata": { + "name": "provider_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "encrypted_value": { + "name": "encrypted_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encryption_key_id": { + "name": "encryption_key_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_dek": { + "name": "encrypted_dek", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nonce": { + "name": "nonce", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_tag": { + "name": "auth_tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "last_rotated_at": { + "name": "last_rotated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "last_accessed_at": { + "name": "last_accessed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "access_count": { + "name": "access_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "secrets_org_name_project_env_idx": { + "name": "secrets_org_name_project_env_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "environment", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secrets_org_idx": { + "name": "secrets_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secrets_project_idx": { + "name": "secrets_project_idx", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secrets_scope_idx": { + "name": "secrets_scope_idx", + "columns": [ + { + "expression": "scope", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secrets_env_idx": { + "name": "secrets_env_idx", + "columns": [ + { + "expression": "environment", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secrets_name_idx": { + "name": "secrets_name_idx", + "columns": [ + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secrets_expires_idx": { + "name": "secrets_expires_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "secrets_provider_idx": { + "name": "secrets_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "secrets_organization_id_organizations_id_fk": { + "name": "secrets_organization_id_organizations_id_fk", + "tableFrom": "secrets", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "secrets_created_by_users_id_fk": { + "name": "secrets_created_by_users_id_fk", + "tableFrom": "secrets", + "columnsFrom": [ + "created_by" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.app_domains": { + "name": "app_domains", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "subdomain": { + "name": "subdomain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "custom_domain": { + "name": "custom_domain", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "custom_domain_verified": { + "name": "custom_domain_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "verification_records": { + "name": "verification_records", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "ssl_status": { + "name": "ssl_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "ssl_error": { + "name": "ssl_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vercel_project_id": { + "name": "vercel_project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vercel_domain_id": { + "name": "vercel_domain_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "app_domains_app_id_idx": { + "name": "app_domains_app_id_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_domains_subdomain_idx": { + "name": "app_domains_subdomain_idx", + "columns": [ + { + "expression": "subdomain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_domains_custom_domain_idx": { + "name": "app_domains_custom_domain_idx", + "columns": [ + { + "expression": "custom_domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "app_domains_vercel_domain_idx": { + "name": "app_domains_vercel_domain_idx", + "columns": [ + { + "expression": "vercel_domain_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "app_domains_app_id_apps_id_fk": { + "name": "app_domains_app_id_apps_id_fk", + "tableFrom": "app_domains", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.managed_domains": { + "name": "managed_domains", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "registrar": { + "name": "registrar", + "type": "domain_registrar", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'vercel'" + }, + "vercel_domain_id": { + "name": "vercel_domain_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registered_at": { + "name": "registered_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "auto_renew": { + "name": "auto_renew", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "status": { + "name": "status", + "type": "domain_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "registrant_info": { + "name": "registrant_info", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "resource_type": { + "name": "resource_type", + "type": "domain_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "container_id": { + "name": "container_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "mcp_id": { + "name": "mcp_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "nameserver_mode": { + "name": "nameserver_mode", + "type": "domain_nameserver_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'vercel'" + }, + "dns_records": { + "name": "dns_records", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "ssl_status": { + "name": "ssl_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + }, + "ssl_expires_at": { + "name": "ssl_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "verification_token": { + "name": "verification_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "moderation_status": { + "name": "moderation_status", + "type": "domain_moderation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'clean'" + }, + "moderation_flags": { + "name": "moderation_flags", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "last_health_check": { + "name": "last_health_check", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_live": { + "name": "is_live", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "health_check_error": { + "name": "health_check_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_content_scan_at": { + "name": "last_content_scan_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_ai_scan_at": { + "name": "last_ai_scan_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ai_scan_model": { + "name": "ai_scan_model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_scan_confidence": { + "name": "content_scan_confidence", + "type": "real", + "primaryKey": false, + "notNull": false + }, + "content_scan_cache": { + "name": "content_scan_cache", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "suspension_reason": { + "name": "suspension_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "suspension_notification": { + "name": "suspension_notification", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "owner_notified_at": { + "name": "owner_notified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "purchase_price": { + "name": "purchase_price", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "renewal_price": { + "name": "renewal_price", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payment_method": { + "name": "payment_method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_payment_intent_id": { + "name": "stripe_payment_intent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "managed_domains_org_idx": { + "name": "managed_domains_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_domain_idx": { + "name": "managed_domains_domain_idx", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_app_idx": { + "name": "managed_domains_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_container_idx": { + "name": "managed_domains_container_idx", + "columns": [ + { + "expression": "container_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_agent_idx": { + "name": "managed_domains_agent_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_mcp_idx": { + "name": "managed_domains_mcp_idx", + "columns": [ + { + "expression": "mcp_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_status_idx": { + "name": "managed_domains_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_moderation_idx": { + "name": "managed_domains_moderation_idx", + "columns": [ + { + "expression": "moderation_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_expires_idx": { + "name": "managed_domains_expires_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_content_scan_idx": { + "name": "managed_domains_content_scan_idx", + "columns": [ + { + "expression": "last_content_scan_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "managed_domains_suspended_idx": { + "name": "managed_domains_suspended_idx", + "columns": [ + { + "expression": "suspended_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "managed_domains_organization_id_organizations_id_fk": { + "name": "managed_domains_organization_id_organizations_id_fk", + "tableFrom": "managed_domains", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "managed_domains_app_id_apps_id_fk": { + "name": "managed_domains_app_id_apps_id_fk", + "tableFrom": "managed_domains", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "managed_domains_container_id_containers_id_fk": { + "name": "managed_domains_container_id_containers_id_fk", + "tableFrom": "managed_domains", + "columnsFrom": [ + "container_id" + ], + "tableTo": "containers", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "managed_domains_agent_id_user_characters_id_fk": { + "name": "managed_domains_agent_id_user_characters_id_fk", + "tableFrom": "managed_domains", + "columnsFrom": [ + "agent_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "managed_domains_mcp_id_user_mcps_id_fk": { + "name": "managed_domains_mcp_id_user_mcps_id_fk", + "tableFrom": "managed_domains", + "columnsFrom": [ + "mcp_id" + ], + "tableTo": "user_mcps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "managed_domains_domain_unique": { + "name": "managed_domains_domain_unique", + "columns": [ + "domain" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.platform_credential_sessions": { + "name": "platform_credential_sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "requesting_user_id": { + "name": "requesting_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "platform": { + "name": "platform", + "type": "platform_credential_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "requested_scopes": { + "name": "requested_scopes", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "oauth_state": { + "name": "oauth_state", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "callback_url": { + "name": "callback_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "callback_type": { + "name": "callback_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "callback_context": { + "name": "callback_context", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "credential_id": { + "name": "credential_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "platform_credential_sessions_session_idx": { + "name": "platform_credential_sessions_session_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credential_sessions_org_idx": { + "name": "platform_credential_sessions_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credential_sessions_oauth_state_idx": { + "name": "platform_credential_sessions_oauth_state_idx", + "columns": [ + { + "expression": "oauth_state", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credential_sessions_status_idx": { + "name": "platform_credential_sessions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credential_sessions_expires_idx": { + "name": "platform_credential_sessions_expires_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "platform_credential_sessions_organization_id_organizations_id_fk": { + "name": "platform_credential_sessions_organization_id_organizations_id_fk", + "tableFrom": "platform_credential_sessions", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "platform_credential_sessions_app_id_apps_id_fk": { + "name": "platform_credential_sessions_app_id_apps_id_fk", + "tableFrom": "platform_credential_sessions", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "platform_credential_sessions_requesting_user_id_users_id_fk": { + "name": "platform_credential_sessions_requesting_user_id_users_id_fk", + "tableFrom": "platform_credential_sessions", + "columnsFrom": [ + "requesting_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "platform_credential_sessions_credential_id_platform_credentials_id_fk": { + "name": "platform_credential_sessions_credential_id_platform_credentials_id_fk", + "tableFrom": "platform_credential_sessions", + "columnsFrom": [ + "credential_id" + ], + "tableTo": "platform_credentials", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "platform_credential_sessions_session_id_unique": { + "name": "platform_credential_sessions_session_id_unique", + "columns": [ + "session_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.platform_credentials": { + "name": "platform_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "platform": { + "name": "platform", + "type": "platform_credential_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "platform_user_id": { + "name": "platform_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "platform_username": { + "name": "platform_username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "platform_display_name": { + "name": "platform_display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "platform_avatar_url": { + "name": "platform_avatar_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "platform_email": { + "name": "platform_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "platform_credential_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_secret_id": { + "name": "access_token_secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "refresh_token_secret_id": { + "name": "refresh_token_secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "token_expires_at": { + "name": "token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "api_key_secret_id": { + "name": "api_key_secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "granted_permissions": { + "name": "granted_permissions", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_context": { + "name": "source_context", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "profile_data": { + "name": "profile_data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "linked_at": { + "name": "linked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_refreshed_at": { + "name": "last_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "platform_credentials_org_idx": { + "name": "platform_credentials_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credentials_user_idx": { + "name": "platform_credentials_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credentials_app_idx": { + "name": "platform_credentials_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credentials_platform_user_idx": { + "name": "platform_credentials_platform_user_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "platform_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "platform_credentials_user_platform_idx": { + "name": "platform_credentials_user_platform_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "where": "\"platform_credentials\".\"user_id\" is not null", + "concurrently": false + }, + "platform_credentials_status_idx": { + "name": "platform_credentials_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "platform_credentials_organization_id_organizations_id_fk": { + "name": "platform_credentials_organization_id_organizations_id_fk", + "tableFrom": "platform_credentials", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "platform_credentials_user_id_users_id_fk": { + "name": "platform_credentials_user_id_users_id_fk", + "tableFrom": "platform_credentials", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "platform_credentials_app_id_apps_id_fk": { + "name": "platform_credentials_app_id_apps_id_fk", + "tableFrom": "platform_credentials", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ad_accounts": { + "name": "ad_accounts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "connected_by_user_id": { + "name": "connected_by_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_account_id": { + "name": "external_account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "account_name": { + "name": "account_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token_secret_id": { + "name": "access_token_secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "refresh_token_secret_id": { + "name": "refresh_token_secret_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "token_expires_at": { + "name": "token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ad_accounts_organization_idx": { + "name": "ad_accounts_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_accounts_platform_idx": { + "name": "ad_accounts_platform_idx", + "columns": [ + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_accounts_org_platform_idx": { + "name": "ad_accounts_org_platform_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_accounts_external_id_idx": { + "name": "ad_accounts_external_id_idx", + "columns": [ + { + "expression": "external_account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_accounts_status_idx": { + "name": "ad_accounts_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "ad_accounts_organization_id_organizations_id_fk": { + "name": "ad_accounts_organization_id_organizations_id_fk", + "tableFrom": "ad_accounts", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "ad_accounts_connected_by_user_id_users_id_fk": { + "name": "ad_accounts_connected_by_user_id_users_id_fk", + "tableFrom": "ad_accounts", + "columnsFrom": [ + "connected_by_user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "ad_accounts_access_token_secret_id_secrets_id_fk": { + "name": "ad_accounts_access_token_secret_id_secrets_id_fk", + "tableFrom": "ad_accounts", + "columnsFrom": [ + "access_token_secret_id" + ], + "tableTo": "secrets", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "ad_accounts_refresh_token_secret_id_secrets_id_fk": { + "name": "ad_accounts_refresh_token_secret_id_secrets_id_fk", + "tableFrom": "ad_accounts", + "columnsFrom": [ + "refresh_token_secret_id" + ], + "tableTo": "secrets", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ad_campaigns": { + "name": "ad_campaigns", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "ad_account_id": { + "name": "ad_account_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "external_campaign_id": { + "name": "external_campaign_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "objective": { + "name": "objective", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'draft'" + }, + "budget_type": { + "name": "budget_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "budget_amount": { + "name": "budget_amount", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "budget_currency": { + "name": "budget_currency", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'USD'" + }, + "credits_allocated": { + "name": "credits_allocated", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "credits_spent": { + "name": "credits_spent", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "start_date": { + "name": "start_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_date": { + "name": "end_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "targeting": { + "name": "targeting", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "total_spend": { + "name": "total_spend", + "type": "numeric(12, 2)", + "primaryKey": false, + "notNull": true, + "default": "'0.00'" + }, + "total_impressions": { + "name": "total_impressions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_clicks": { + "name": "total_clicks", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_conversions": { + "name": "total_conversions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ad_campaigns_organization_idx": { + "name": "ad_campaigns_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_campaigns_ad_account_idx": { + "name": "ad_campaigns_ad_account_idx", + "columns": [ + { + "expression": "ad_account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_campaigns_platform_idx": { + "name": "ad_campaigns_platform_idx", + "columns": [ + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_campaigns_status_idx": { + "name": "ad_campaigns_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_campaigns_external_id_idx": { + "name": "ad_campaigns_external_id_idx", + "columns": [ + { + "expression": "external_campaign_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_campaigns_app_idx": { + "name": "ad_campaigns_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_campaigns_created_at_idx": { + "name": "ad_campaigns_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_campaigns_org_status_idx": { + "name": "ad_campaigns_org_status_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "ad_campaigns_organization_id_organizations_id_fk": { + "name": "ad_campaigns_organization_id_organizations_id_fk", + "tableFrom": "ad_campaigns", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "ad_campaigns_ad_account_id_ad_accounts_id_fk": { + "name": "ad_campaigns_ad_account_id_ad_accounts_id_fk", + "tableFrom": "ad_campaigns", + "columnsFrom": [ + "ad_account_id" + ], + "tableTo": "ad_accounts", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "ad_campaigns_app_id_apps_id_fk": { + "name": "ad_campaigns_app_id_apps_id_fk", + "tableFrom": "ad_campaigns", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ad_creatives": { + "name": "ad_creatives", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "campaign_id": { + "name": "campaign_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "external_creative_id": { + "name": "external_creative_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'draft'" + }, + "headline": { + "name": "headline", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "primary_text": { + "name": "primary_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "call_to_action": { + "name": "call_to_action", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "destination_url": { + "name": "destination_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "media": { + "name": "media", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ad_creatives_campaign_idx": { + "name": "ad_creatives_campaign_idx", + "columns": [ + { + "expression": "campaign_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_creatives_type_idx": { + "name": "ad_creatives_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_creatives_status_idx": { + "name": "ad_creatives_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_creatives_external_id_idx": { + "name": "ad_creatives_external_id_idx", + "columns": [ + { + "expression": "external_creative_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_creatives_created_at_idx": { + "name": "ad_creatives_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "ad_creatives_campaign_id_ad_campaigns_id_fk": { + "name": "ad_creatives_campaign_id_ad_campaigns_id_fk", + "tableFrom": "ad_creatives", + "columnsFrom": [ + "campaign_id" + ], + "tableTo": "ad_campaigns", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.ad_transactions": { + "name": "ad_transactions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "campaign_id": { + "name": "campaign_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "credit_transaction_id": { + "name": "credit_transaction_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "amount": { + "name": "amount", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'USD'" + }, + "credits_amount": { + "name": "credits_amount", + "type": "numeric(12, 4)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_reference": { + "name": "external_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "ad_transactions_organization_idx": { + "name": "ad_transactions_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_transactions_campaign_idx": { + "name": "ad_transactions_campaign_idx", + "columns": [ + { + "expression": "campaign_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_transactions_credit_tx_idx": { + "name": "ad_transactions_credit_tx_idx", + "columns": [ + { + "expression": "credit_transaction_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_transactions_type_idx": { + "name": "ad_transactions_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_transactions_created_at_idx": { + "name": "ad_transactions_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "ad_transactions_org_type_idx": { + "name": "ad_transactions_org_type_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "ad_transactions_organization_id_organizations_id_fk": { + "name": "ad_transactions_organization_id_organizations_id_fk", + "tableFrom": "ad_transactions", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "ad_transactions_campaign_id_ad_campaigns_id_fk": { + "name": "ad_transactions_campaign_id_ad_campaigns_id_fk", + "tableFrom": "ad_transactions", + "columnsFrom": [ + "campaign_id" + ], + "tableTo": "ad_campaigns", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "ad_transactions_credit_transaction_id_credit_transactions_id_fk": { + "name": "ad_transactions_credit_transaction_id_credit_transactions_id_fk", + "tableFrom": "ad_transactions", + "columnsFrom": [ + "credit_transaction_id" + ], + "tableTo": "credit_transactions", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_artifacts": { + "name": "seo_artifacts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "request_id": { + "name": "request_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "seo_artifact_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "seo_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "seo_artifacts_request_idx": { + "name": "seo_artifacts_request_idx", + "columns": [ + { + "expression": "request_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "seo_artifacts_type_idx": { + "name": "seo_artifacts_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "seo_artifacts_request_id_seo_requests_id_fk": { + "name": "seo_artifacts_request_id_seo_requests_id_fk", + "tableFrom": "seo_artifacts", + "columnsFrom": [ + "request_id" + ], + "tableTo": "seo_requests", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_provider_calls": { + "name": "seo_provider_calls", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "request_id": { + "name": "request_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "seo_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "operation": { + "name": "operation", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "seo_provider_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "request_payload": { + "name": "request_payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "response_payload": { + "name": "response_payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "seo_provider_calls_request_idx": { + "name": "seo_provider_calls_request_idx", + "columns": [ + { + "expression": "request_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "seo_provider_calls_provider_idx": { + "name": "seo_provider_calls_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "seo_provider_calls_status_idx": { + "name": "seo_provider_calls_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "seo_provider_calls_request_id_seo_requests_id_fk": { + "name": "seo_provider_calls_request_id_seo_requests_id_fk", + "tableFrom": "seo_provider_calls", + "columnsFrom": [ + "request_id" + ], + "tableTo": "seo_requests", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.seo_requests": { + "name": "seo_requests", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "api_key_id": { + "name": "api_key_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "seo_request_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "seo_request_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "page_url": { + "name": "page_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "locale": { + "name": "locale", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'en-US'" + }, + "search_engine": { + "name": "search_engine", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'google'" + }, + "device": { + "name": "device", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'desktop'" + }, + "environment": { + "name": "environment", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'production'" + }, + "agent_identifier": { + "name": "agent_identifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "keywords": { + "name": "keywords", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'[]'::jsonb" + }, + "prompt_context": { + "name": "prompt_context", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "total_cost": { + "name": "total_cost", + "type": "numeric(10, 4)", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "seo_requests_org_idx": { + "name": "seo_requests_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "seo_requests_app_idx": { + "name": "seo_requests_app_idx", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "seo_requests_type_idx": { + "name": "seo_requests_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "seo_requests_status_idx": { + "name": "seo_requests_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "seo_requests_idempotency_idx": { + "name": "seo_requests_idempotency_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "idempotency_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "seo_requests_organization_id_organizations_id_fk": { + "name": "seo_requests_organization_id_organizations_id_fk", + "tableFrom": "seo_requests", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "seo_requests_app_id_apps_id_fk": { + "name": "seo_requests_app_id_apps_id_fk", + "tableFrom": "seo_requests", + "columnsFrom": [ + "app_id" + ], + "tableTo": "apps", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "seo_requests_user_id_users_id_fk": { + "name": "seo_requests_user_id_users_id_fk", + "tableFrom": "seo_requests", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + }, + "seo_requests_api_key_id_api_keys_id_fk": { + "name": "seo_requests_api_key_id_api_keys_id_fk", + "tableFrom": "seo_requests", + "columnsFrom": [ + "api_key_id" + ], + "tableTo": "api_keys", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.telegram_chats": { + "name": "telegram_chats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "chat_type": { + "name": "chat_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "can_post_messages": { + "name": "can_post_messages", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "telegram_chats_organization_id_idx": { + "name": "telegram_chats_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "telegram_chats_chat_id_idx": { + "name": "telegram_chats_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "telegram_chats_organization_id_organizations_id_fk": { + "name": "telegram_chats_organization_id_organizations_id_fk", + "tableFrom": "telegram_chats", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord_guilds": { + "name": "discord_guilds", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "guild_name": { + "name": "guild_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "icon_hash": { + "name": "icon_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bot_permissions": { + "name": "bot_permissions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bot_joined_at": { + "name": "bot_joined_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "discord_guilds_organization_id_idx": { + "name": "discord_guilds_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_guilds_guild_id_idx": { + "name": "discord_guilds_guild_id_idx", + "columns": [ + { + "expression": "guild_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_guilds_org_guild_idx": { + "name": "discord_guilds_org_guild_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "guild_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "discord_guilds_organization_id_organizations_id_fk": { + "name": "discord_guilds_organization_id_organizations_id_fk", + "tableFrom": "discord_guilds", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord_channels": { + "name": "discord_channels", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_name": { + "name": "channel_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "channel_type": { + "name": "channel_type", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "can_send_messages": { + "name": "can_send_messages", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "can_embed_links": { + "name": "can_embed_links", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "can_attach_files": { + "name": "can_attach_files", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_nsfw": { + "name": "is_nsfw", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "discord_channels_organization_id_idx": { + "name": "discord_channels_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_channels_guild_id_idx": { + "name": "discord_channels_guild_id_idx", + "columns": [ + { + "expression": "guild_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_channels_channel_id_idx": { + "name": "discord_channels_channel_id_idx", + "columns": [ + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_channels_guild_channel_idx": { + "name": "discord_channels_guild_channel_idx", + "columns": [ + { + "expression": "guild_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "channel_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "discord_channels_organization_id_organizations_id_fk": { + "name": "discord_channels_organization_id_organizations_id_fk", + "tableFrom": "discord_channels", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.discord_connections": { + "name": "discord_connections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "character_id": { + "name": "character_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "application_id": { + "name": "application_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bot_user_id": { + "name": "bot_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bot_token_encrypted": { + "name": "bot_token_encrypted", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_dek": { + "name": "encrypted_dek", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_nonce": { + "name": "token_nonce", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_auth_tag": { + "name": "token_auth_tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encryption_key_id": { + "name": "encryption_key_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "assigned_pod": { + "name": "assigned_pod", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "guild_count": { + "name": "guild_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "events_received": { + "name": "events_received", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "events_routed": { + "name": "events_routed", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_heartbeat": { + "name": "last_heartbeat", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "connected_at": { + "name": "connected_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "intents": { + "name": "intents", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 38401 + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "discord_connections_organization_id_idx": { + "name": "discord_connections_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_connections_character_id_idx": { + "name": "discord_connections_character_id_idx", + "columns": [ + { + "expression": "character_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_connections_org_app_unique_idx": { + "name": "discord_connections_org_app_unique_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "application_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_connections_assigned_pod_idx": { + "name": "discord_connections_assigned_pod_idx", + "columns": [ + { + "expression": "assigned_pod", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_connections_status_idx": { + "name": "discord_connections_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "discord_connections_is_active_idx": { + "name": "discord_connections_is_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "discord_connections_organization_id_organizations_id_fk": { + "name": "discord_connections_organization_id_organizations_id_fk", + "tableFrom": "discord_connections", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "discord_connections_character_id_user_characters_id_fk": { + "name": "discord_connections_character_id_user_characters_id_fk", + "tableFrom": "discord_connections", + "columnsFrom": [ + "character_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agent_phone_numbers": { + "name": "agent_phone_numbers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "phone_number": { + "name": "phone_number", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "friendly_name": { + "name": "friendly_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "phone_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "phone_type": { + "name": "phone_type", + "type": "phone_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'sms'" + }, + "provider_phone_id": { + "name": "provider_phone_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "webhook_url": { + "name": "webhook_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "webhook_configured": { + "name": "webhook_configured", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "can_send_sms": { + "name": "can_send_sms", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "can_receive_sms": { + "name": "can_receive_sms", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "can_send_mms": { + "name": "can_send_mms", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "can_receive_mms": { + "name": "can_receive_mms", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "can_voice": { + "name": "can_voice", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "max_messages_per_minute": { + "name": "max_messages_per_minute", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'60'" + }, + "max_messages_per_day": { + "name": "max_messages_per_day", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'1000'" + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_message_at": { + "name": "last_message_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "agent_phone_numbers_phone_org_idx": { + "name": "agent_phone_numbers_phone_org_idx", + "columns": [ + { + "expression": "phone_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_phone_numbers_organization_idx": { + "name": "agent_phone_numbers_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_phone_numbers_agent_idx": { + "name": "agent_phone_numbers_agent_idx", + "columns": [ + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_phone_numbers_provider_idx": { + "name": "agent_phone_numbers_provider_idx", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_phone_numbers_is_active_idx": { + "name": "agent_phone_numbers_is_active_idx", + "columns": [ + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "agent_phone_numbers_organization_id_organizations_id_fk": { + "name": "agent_phone_numbers_organization_id_organizations_id_fk", + "tableFrom": "agent_phone_numbers", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.phone_message_log": { + "name": "phone_message_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "phone_number_id": { + "name": "phone_number_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "direction": { + "name": "direction", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_number": { + "name": "from_number", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "to_number": { + "name": "to_number", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "message_body": { + "name": "message_body", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "message_type": { + "name": "message_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'sms'" + }, + "media_urls": { + "name": "media_urls", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_message_id": { + "name": "provider_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'received'" + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_response": { + "name": "agent_response", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "response_time_ms": { + "name": "response_time_ms", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "responded_at": { + "name": "responded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "phone_message_log_phone_number_idx": { + "name": "phone_message_log_phone_number_idx", + "columns": [ + { + "expression": "phone_number_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "phone_message_log_direction_idx": { + "name": "phone_message_log_direction_idx", + "columns": [ + { + "expression": "direction", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "phone_message_log_status_idx": { + "name": "phone_message_log_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "phone_message_log_created_at_idx": { + "name": "phone_message_log_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "phone_message_log_from_number_idx": { + "name": "phone_message_log_from_number_idx", + "columns": [ + { + "expression": "from_number", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "phone_message_log_conversation_idx": { + "name": "phone_message_log_conversation_idx", + "columns": [ + { + "expression": "from_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "to_number", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "phone_number_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "phone_message_log_phone_number_id_agent_phone_numbers_id_fk": { + "name": "phone_message_log_phone_number_id_agent_phone_numbers_id_fk", + "tableFrom": "phone_message_log", + "columnsFrom": [ + "phone_number_id" + ], + "tableTo": "agent_phone_numbers", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.idempotency_keys": { + "name": "idempotency_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "idempotency_keys_expires_idx": { + "name": "idempotency_keys_expires_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "idempotency_keys_source_idx": { + "name": "idempotency_keys_source_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "idempotency_keys_key_unique": { + "name": "idempotency_keys_key_unique", + "columns": [ + "key" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.entity_settings": { + "name": "entity_settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "agent_id": { + "name": "agent_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_value": { + "name": "encrypted_value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encryption_key_id": { + "name": "encryption_key_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_dek": { + "name": "encrypted_dek", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "nonce": { + "name": "nonce", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auth_tag": { + "name": "auth_tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "entity_settings_user_agent_key_idx": { + "name": "entity_settings_user_agent_key_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "entity_settings_user_idx": { + "name": "entity_settings_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "entity_settings_user_agent_idx": { + "name": "entity_settings_user_agent_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "agent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "entity_settings_key_idx": { + "name": "entity_settings_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "entity_settings_user_id_users_id_fk": { + "name": "entity_settings_user_id_users_id_fk", + "tableFrom": "entity_settings", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.affiliate_codes": { + "name": "affiliate_codes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_referral_id": { + "name": "parent_referral_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "markup_percent": { + "name": "markup_percent", + "type": "numeric(6, 2)", + "primaryKey": false, + "notNull": true, + "default": "'20.00'" + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "affiliate_codes_user_idx": { + "name": "affiliate_codes_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "affiliate_codes_code_idx": { + "name": "affiliate_codes_code_idx", + "columns": [ + { + "expression": "code", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "affiliate_codes_user_id_users_id_fk": { + "name": "affiliate_codes_user_id_users_id_fk", + "tableFrom": "affiliate_codes", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "affiliate_codes_parent_referral_id_affiliate_codes_id_fk": { + "name": "affiliate_codes_parent_referral_id_affiliate_codes_id_fk", + "tableFrom": "affiliate_codes", + "columnsFrom": [ + "parent_referral_id" + ], + "tableTo": "affiliate_codes", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "affiliate_codes_code_unique": { + "name": "affiliate_codes_code_unique", + "columns": [ + "code" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": { + "markup_percent_range": { + "name": "markup_percent_range", + "value": "\"affiliate_codes\".\"markup_percent\" >= 0 AND \"affiliate_codes\".\"markup_percent\" <= 1000" + } + }, + "isRLSEnabled": false + }, + "public.user_affiliates": { + "name": "user_affiliates", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "affiliate_code_id": { + "name": "affiliate_code_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_affiliates_user_idx": { + "name": "user_affiliates_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "user_affiliates_affiliate_idx": { + "name": "user_affiliates_affiliate_idx", + "columns": [ + { + "expression": "affiliate_code_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "user_affiliates_user_id_users_id_fk": { + "name": "user_affiliates_user_id_users_id_fk", + "tableFrom": "user_affiliates", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "user_affiliates_affiliate_code_id_affiliate_codes_id_fk": { + "name": "user_affiliates_affiliate_code_id_affiliate_codes_id_fk", + "tableFrom": "user_affiliates", + "columnsFrom": [ + "affiliate_code_id" + ], + "tableTo": "affiliate_codes", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.agent_server_wallets": { + "name": "agent_server_wallets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "character_id": { + "name": "character_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "privy_wallet_id": { + "name": "privy_wallet_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chain_type": { + "name": "chain_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_address": { + "name": "client_address", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "agent_server_wallets_organization_idx": { + "name": "agent_server_wallets_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_server_wallets_user_idx": { + "name": "agent_server_wallets_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_server_wallets_character_idx": { + "name": "agent_server_wallets_character_idx", + "columns": [ + { + "expression": "character_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_server_wallets_privy_wallet_idx": { + "name": "agent_server_wallets_privy_wallet_idx", + "columns": [ + { + "expression": "privy_wallet_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_server_wallets_address_idx": { + "name": "agent_server_wallets_address_idx", + "columns": [ + { + "expression": "address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "agent_server_wallets_client_address_idx": { + "name": "agent_server_wallets_client_address_idx", + "columns": [ + { + "expression": "client_address", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "agent_server_wallets_organization_id_organizations_id_fk": { + "name": "agent_server_wallets_organization_id_organizations_id_fk", + "tableFrom": "agent_server_wallets", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "agent_server_wallets_user_id_users_id_fk": { + "name": "agent_server_wallets_user_id_users_id_fk", + "tableFrom": "agent_server_wallets", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "agent_server_wallets_character_id_user_characters_id_fk": { + "name": "agent_server_wallets_character_id_user_characters_id_fk", + "tableFrom": "agent_server_wallets", + "columnsFrom": [ + "character_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "agent_server_wallets_client_address_unique": { + "name": "agent_server_wallets_client_address_unique", + "columns": [ + "client_address" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.milady_sandbox_backups": { + "name": "milady_sandbox_backups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "sandbox_record_id": { + "name": "sandbox_record_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "snapshot_type": { + "name": "snapshot_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_data": { + "name": "state_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "vercel_snapshot_id": { + "name": "vercel_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "size_bytes": { + "name": "size_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "milady_sandbox_backups_sandbox_idx": { + "name": "milady_sandbox_backups_sandbox_idx", + "columns": [ + { + "expression": "sandbox_record_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "milady_sandbox_backups_created_at_idx": { + "name": "milady_sandbox_backups_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "milady_sandbox_backups_sandbox_record_id_milady_sandboxes_id_fk": { + "name": "milady_sandbox_backups_sandbox_record_id_milady_sandboxes_id_fk", + "tableFrom": "milady_sandbox_backups", + "columnsFrom": [ + "sandbox_record_id" + ], + "tableTo": "milady_sandboxes", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.milady_sandboxes": { + "name": "milady_sandboxes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "organization_id": { + "name": "organization_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "character_id": { + "name": "character_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "sandbox_id": { + "name": "sandbox_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "bridge_url": { + "name": "bridge_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "health_url": { + "name": "health_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_name": { + "name": "agent_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agent_config": { + "name": "agent_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "neon_project_id": { + "name": "neon_project_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "neon_branch_id": { + "name": "neon_branch_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "database_uri": { + "name": "database_uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "database_status": { + "name": "database_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'none'" + }, + "database_error": { + "name": "database_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "snapshot_id": { + "name": "snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_backup_at": { + "name": "last_backup_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "last_heartbeat_at": { + "name": "last_heartbeat_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_count": { + "name": "error_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "environment_vars": { + "name": "environment_vars", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "node_id": { + "name": "node_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "container_name": { + "name": "container_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bridge_port": { + "name": "bridge_port", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "web_ui_port": { + "name": "web_ui_port", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "headscale_ip": { + "name": "headscale_ip", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "docker_image": { + "name": "docker_image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "milady_sandboxes_organization_idx": { + "name": "milady_sandboxes_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "milady_sandboxes_user_idx": { + "name": "milady_sandboxes_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "milady_sandboxes_status_idx": { + "name": "milady_sandboxes_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "milady_sandboxes_character_idx": { + "name": "milady_sandboxes_character_idx", + "columns": [ + { + "expression": "character_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "milady_sandboxes_sandbox_id_idx": { + "name": "milady_sandboxes_sandbox_id_idx", + "columns": [ + { + "expression": "sandbox_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": { + "milady_sandboxes_organization_id_organizations_id_fk": { + "name": "milady_sandboxes_organization_id_organizations_id_fk", + "tableFrom": "milady_sandboxes", + "columnsFrom": [ + "organization_id" + ], + "tableTo": "organizations", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "milady_sandboxes_user_id_users_id_fk": { + "name": "milady_sandboxes_user_id_users_id_fk", + "tableFrom": "milady_sandboxes", + "columnsFrom": [ + "user_id" + ], + "tableTo": "users", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "cascade" + }, + "milady_sandboxes_character_id_user_characters_id_fk": { + "name": "milady_sandboxes_character_id_user_characters_id_fk", + "tableFrom": "milady_sandboxes", + "columnsFrom": [ + "character_id" + ], + "tableTo": "user_characters", + "columnsTo": [ + "id" + ], + "onUpdate": "no action", + "onDelete": "set null" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.docker_nodes": { + "name": "docker_nodes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "node_id": { + "name": "node_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hostname": { + "name": "hostname", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ssh_port": { + "name": "ssh_port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 22 + }, + "capacity": { + "name": "capacity", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 8 + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'unknown'" + }, + "allocated_count": { + "name": "allocated_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_health_check": { + "name": "last_health_check", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "ssh_user": { + "name": "ssh_user", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'root'" + }, + "host_key_fingerprint": { + "name": "host_key_fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "docker_nodes_node_id_idx": { + "name": "docker_nodes_node_id_idx", + "columns": [ + { + "expression": "node_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "docker_nodes_status_idx": { + "name": "docker_nodes_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + }, + "docker_nodes_enabled_idx": { + "name": "docker_nodes_enabled_idx", + "columns": [ + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "docker_nodes_node_id_unique": { + "name": "docker_nodes_node_id_unique", + "columns": [ + "node_id" + ], + "nullsNotDistinct": false + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.daily_metrics": { + "name": "daily_metrics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "date": { + "name": "date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dau": { + "name": "dau", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "new_signups": { + "name": "new_signups", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_messages": { + "name": "total_messages", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "messages_per_user": { + "name": "messages_per_user", + "type": "numeric(10, 2)", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "daily_metrics_date_platform_idx": { + "name": "daily_metrics_date_platform_idx", + "columns": [ + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + }, + "daily_metrics_date_idx": { + "name": "daily_metrics_date_idx", + "columns": [ + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.retention_cohorts": { + "name": "retention_cohorts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cohort_date": { + "name": "cohort_date", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cohort_size": { + "name": "cohort_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "d1_retained": { + "name": "d1_retained", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "d7_retained": { + "name": "d7_retained", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "d30_retained": { + "name": "d30_retained", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "retention_cohorts_cohort_platform_idx": { + "name": "retention_cohorts_cohort_platform_idx", + "columns": [ + { + "expression": "cohort_date", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "platform", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "with": {}, + "method": "btree", + "concurrently": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.app_deployment_status": { + "name": "app_deployment_status", + "schema": "public", + "values": [ + "draft", + "building", + "deploying", + "deployed", + "failed" + ] + }, + "public.user_database_status": { + "name": "user_database_status", + "schema": "public", + "values": [ + "none", + "provisioning", + "ready", + "error" + ] + }, + "public.share_type": { + "name": "share_type", + "schema": "public", + "values": [ + "app_share", + "character_share", + "invite_share" + ] + }, + "public.social_platform": { + "name": "social_platform", + "schema": "public", + "values": [ + "x", + "farcaster", + "telegram", + "discord" + ] + }, + "public.mcp_pricing_type": { + "name": "mcp_pricing_type", + "schema": "public", + "values": [ + "free", + "credits", + "x402" + ] + }, + "public.mcp_status": { + "name": "mcp_status", + "schema": "public", + "values": [ + "draft", + "pending_review", + "live", + "suspended", + "deprecated" + ] + }, + "public.redemption_network": { + "name": "redemption_network", + "schema": "public", + "values": [ + "ethereum", + "base", + "bnb", + "solana" + ] + }, + "public.redemption_status": { + "name": "redemption_status", + "schema": "public", + "values": [ + "pending", + "approved", + "processing", + "completed", + "failed", + "rejected", + "expired" + ] + }, + "public.earnings_source": { + "name": "earnings_source", + "schema": "public", + "values": [ + "miniapp", + "agent", + "mcp", + "affiliate", + "app_owner_revenue_share", + "creator_revenue_share" + ] + }, + "public.ledger_entry_type": { + "name": "ledger_entry_type", + "schema": "public", + "values": [ + "earning", + "redemption", + "adjustment", + "refund" + ] + }, + "public.admin_role": { + "name": "admin_role", + "schema": "public", + "values": [ + "super_admin", + "moderator", + "viewer" + ] + }, + "public.moderation_action": { + "name": "moderation_action", + "schema": "public", + "values": [ + "refused", + "warned", + "flagged_for_ban", + "banned" + ] + }, + "public.user_mod_status": { + "name": "user_mod_status", + "schema": "public", + "values": [ + "clean", + "warned", + "spammer", + "scammer", + "banned" + ] + }, + "public.secret_actor_type": { + "name": "secret_actor_type", + "schema": "public", + "values": [ + "user", + "api_key", + "system", + "deployment", + "workflow" + ] + }, + "public.secret_audit_action": { + "name": "secret_audit_action", + "schema": "public", + "values": [ + "created", + "read", + "updated", + "deleted", + "rotated" + ] + }, + "public.secret_environment": { + "name": "secret_environment", + "schema": "public", + "values": [ + "development", + "preview", + "production" + ] + }, + "public.secret_project_type": { + "name": "secret_project_type", + "schema": "public", + "values": [ + "character", + "app", + "workflow", + "container", + "mcp" + ] + }, + "public.secret_provider": { + "name": "secret_provider", + "schema": "public", + "values": [ + "openai", + "anthropic", + "google", + "elevenlabs", + "fal", + "stripe", + "discord", + "telegram", + "twitter", + "github", + "slack", + "aws", + "vercel", + "custom" + ] + }, + "public.secret_scope": { + "name": "secret_scope", + "schema": "public", + "values": [ + "organization", + "project", + "environment" + ] + }, + "public.domain_moderation_status": { + "name": "domain_moderation_status", + "schema": "public", + "values": [ + "clean", + "pending_review", + "flagged", + "suspended" + ] + }, + "public.domain_nameserver_mode": { + "name": "domain_nameserver_mode", + "schema": "public", + "values": [ + "vercel", + "external" + ] + }, + "public.domain_registrar": { + "name": "domain_registrar", + "schema": "public", + "values": [ + "vercel", + "external" + ] + }, + "public.domain_resource_type": { + "name": "domain_resource_type", + "schema": "public", + "values": [ + "app", + "container", + "agent", + "mcp" + ] + }, + "public.domain_status": { + "name": "domain_status", + "schema": "public", + "values": [ + "pending", + "active", + "expired", + "suspended", + "transferring" + ] + }, + "public.platform_credential_status": { + "name": "platform_credential_status", + "schema": "public", + "values": [ + "pending", + "active", + "expired", + "revoked", + "error" + ] + }, + "public.platform_credential_type": { + "name": "platform_credential_type", + "schema": "public", + "values": [ + "discord", + "telegram", + "twitter", + "gmail", + "slack", + "github", + "google", + "bluesky", + "reddit", + "facebook", + "instagram", + "tiktok", + "linkedin", + "mastodon", + "twilio", + "google_calendar", + "linear", + "notion", + "hubspot", + "salesforce", + "jira", + "asana", + "airtable", + "dropbox", + "spotify", + "zoom", + "microsoft" + ] + }, + "public.seo_artifact_type": { + "name": "seo_artifact_type", + "schema": "public", + "values": [ + "keywords", + "meta", + "schema", + "serp_snapshot", + "health_report", + "indexnow_submission" + ] + }, + "public.seo_provider": { + "name": "seo_provider", + "schema": "public", + "values": [ + "dataforseo", + "serpapi", + "claude", + "indexnow", + "bing" + ] + }, + "public.seo_provider_status": { + "name": "seo_provider_status", + "schema": "public", + "values": [ + "pending", + "completed", + "failed" + ] + }, + "public.seo_request_status": { + "name": "seo_request_status", + "schema": "public", + "values": [ + "pending", + "in_progress", + "completed", + "failed" + ] + }, + "public.seo_request_type": { + "name": "seo_request_type", + "schema": "public", + "values": [ + "keyword_research", + "serp_snapshot", + "meta_generate", + "schema_generate", + "publish_bundle", + "index_now", + "health_check" + ] + }, + "public.phone_provider": { + "name": "phone_provider", + "schema": "public", + "values": [ + "twilio", + "blooio", + "vonage", + "whatsapp", + "other" + ] + }, + "public.phone_type": { + "name": "phone_type", + "schema": "public", + "values": [ + "sms", + "voice", + "both", + "imessage", + "whatsapp" + ] + } + }, + "schemas": {}, + "views": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 7f95ffc82..86470d90e 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -300,7 +300,7 @@ "idx": 42, "version": "7", "when": 1772775400000, - "tag": "0043_seed_chain_data_pricing", + "tag": "0044_seed_chain_data_pricing", "breakpoints": true }, { @@ -314,63 +314,63 @@ "idx": 44, "version": "7", "when": 1772873400000, - "tag": "0044_add_whatsapp_identity_columns", + "tag": "0045_add_whatsapp_identity_columns", "breakpoints": true }, { "idx": 45, "version": "7", "when": 1772969400000, - "tag": "0045_add_redeemable_earnings_breakdown_columns", + "tag": "0046_add_redeemable_earnings_breakdown_columns", "breakpoints": true }, { "idx": 46, "version": "7", "when": 1773060000000, - "tag": "0046_docker_nodes", + "tag": "0047_docker_nodes", "breakpoints": true }, { "idx": 47, "version": "7", "when": 1773061000000, - "tag": "0047_add_token_agent_linkage", + "tag": "0048_add_token_agent_linkage", "breakpoints": true }, { "idx": 48, "version": "7", "when": 1773199471391, - "tag": "0048_elite_rumiko_fujikawa", + "tag": "0049_elite_rumiko_fujikawa", "breakpoints": true }, { "idx": 49, "version": "7", "when": 1773269349581, - "tag": "0049_repair_existing_user_identity_privy_claims", + "tag": "0050_repair_existing_user_identity_privy_claims", "breakpoints": true }, { "idx": 50, "version": "7", "when": 1773269349582, - "tag": "0050_backfill_user_identities_from_users", + "tag": "0051_backfill_user_identities_from_users", "breakpoints": true }, { "idx": 51, "version": "7", "when": 1773570000000, - "tag": "0051_add_milady_pairing_tokens", + "tag": "0052_add_milady_pairing_tokens", "breakpoints": true }, { "idx": 52, "version": "7", "when": 1773868800000, - "tag": "0052_add_milady_billing_columns", + "tag": "0053_add_milady_billing_columns", "breakpoints": true } ] diff --git a/packages/db/schemas/milady-sandboxes.ts b/packages/db/schemas/milady-sandboxes.ts index 27857246e..7842ec6ab 100644 --- a/packages/db/schemas/milady-sandboxes.ts +++ b/packages/db/schemas/milady-sandboxes.ts @@ -65,7 +65,7 @@ export const miladySandboxes = pgTable( .$type>() .notNull() .default({}), - // Docker infrastructure columns (added by 0046_docker_nodes migration) + // Docker infrastructure columns (added by 0047_docker_nodes migration) node_id: text("node_id"), container_name: text("container_name"), bridge_port: integer("bridge_port"), diff --git a/packages/lib/constants/agent-flavors.ts b/packages/lib/constants/agent-flavors.ts index 121f1514b..35e723276 100644 --- a/packages/lib/constants/agent-flavors.ts +++ b/packages/lib/constants/agent-flavors.ts @@ -1,9 +1,13 @@ /** * Agent Flavor Presets — predefined Docker image configurations for different - * agent types. The default flavor ("milady") preserves backwards compatibility - * with the existing hardcoded image. + * agent types. The default Milady flavor resolves its image at runtime from + * the MILADY_DOCKER_IMAGE env var so operators can pin a tag without touching code. */ +/** Runtime-resolved default image for the Milady flavor. */ +const DEFAULT_MILADY_IMAGE = + process.env.MILADY_DOCKER_IMAGE || "ghcr.io/milady-ai/agent:v2.0.0-steward-5"; + export interface AgentFlavor { id: string; name: string; @@ -16,8 +20,8 @@ export const AGENT_FLAVORS: AgentFlavor[] = [ { id: "milady", name: "Milady", - description: "Full milady agent with VRM companion UI", - dockerImage: "milady/agent:cloud-full-ui", + description: "Full milady agent with Steward wallet vault integration and VRM companion UI", + dockerImage: DEFAULT_MILADY_IMAGE, }, { id: "cloud-agent", diff --git a/packages/lib/services/docker-sandbox-provider.ts b/packages/lib/services/docker-sandbox-provider.ts index 631234ee0..65cbf54e7 100644 --- a/packages/lib/services/docker-sandbox-provider.ts +++ b/packages/lib/services/docker-sandbox-provider.ts @@ -21,9 +21,13 @@ import { getContainerName, getVolumePath, parseDockerNodes, + requiresDockerHostGateway, + resolveStewardContainerUrl, shellQuote, validateAgentId, validateAgentName, + validateEnvKey, + validateEnvValue, WEBUI_PORT_MAX, WEBUI_PORT_MIN, } from "./docker-sandbox-utils"; @@ -68,7 +72,22 @@ interface ContainerMeta { // Helpers // --------------------------------------------------------------------------- -const DOCKER_IMAGE = process.env.MILADY_DOCKER_IMAGE || "milady/agent:cloud-full-ui"; +const DOCKER_IMAGE = process.env.MILADY_DOCKER_IMAGE || "ghcr.io/milady-ai/agent:v2.0.0-steward-5"; +const DOCKER_NETWORK = process.env.MILADY_DOCKER_NETWORK || "milady-isolated"; +// URL for host-side Steward API calls (registration, token minting). +// The orchestrator (or SSH-executed scripts on the Docker host) can reach Steward via localhost. +const STEWARD_HOST_URL = process.env.STEWARD_API_URL || "http://localhost:3200"; + +// URL injected into container env vars. Containers on the bridge network (milady-isolated) +// cannot reach the host via localhost. On Linux we pair host.docker.internal with an +// explicit host-gateway alias in docker create so the same default works cross-platform. +const STEWARD_CONTAINER_URL = resolveStewardContainerUrl( + STEWARD_HOST_URL, + process.env.STEWARD_CONTAINER_URL, +); +const DEFAULT_MILADY_PORT = process.env.MILADY_CONTAINER_PORT || "2138"; +const DEFAULT_AGENT_PORT = process.env.MILADY_AGENT_PORT || "2139"; +const DEFAULT_BRIDGE_PORT = process.env.MILADY_BRIDGE_INTERNAL_PORT || "31337"; /** Default SSH port when not specified by DB node record. */ const DEFAULT_SSH_PORT = 22; @@ -116,6 +135,101 @@ async function getUsedPorts(nodeId: string): Promise> { return used; } +function getDockerHealthCmd(port: string): string { + if (!/^\d+$/.test(port)) { + throw new Error(`[docker-sandbox] Invalid port "${port}": must be a numeric string.`); + } + return `sh -lc 'wget -qO- "http://127.0.0.1:${port}/health" >/dev/null 2>&1 || curl -fsS "http://127.0.0.1:${port}/health" >/dev/null 2>&1'`; +} + +function extractStewardToken(raw: string): string { + const trimmed = raw.trim(); + if (!trimmed) { + throw new Error("[docker-sandbox] Steward token endpoint returned an empty response"); + } + + try { + const parsed = JSON.parse(trimmed) as Record; + + // Steward API returns { token: "..." }. Keep one fallback for agentToken + // in case an older Steward build uses that field name. + const candidate = parsed.token ?? parsed.agentToken; + + if (typeof candidate === "string" && candidate.trim()) { + return candidate.trim(); + } + } catch { + // Some Steward builds may return the token as plain text. + } + + // Sanity check: reject responses that look like HTML error pages or are + // unreasonably long (e.g. a full HTML document instead of a token). + if (trimmed.length > 512) { + throw new Error( + "[docker-sandbox] Steward token response exceeds 512 chars — likely not a valid token", + ); + } + if (trimmed.includes("<") || trimmed.includes(">")) { + throw new Error( + "[docker-sandbox] Steward token response contains HTML markers — likely an error page", + ); + } + if (/\s/.test(trimmed)) { + throw new Error( + "[docker-sandbox] Steward token response contains whitespace — likely not a valid token", + ); + } + + return trimmed; +} + +async function registerAgentWithSteward( + ssh: DockerSSHClient, + agentId: string, + agentName: string, +): Promise { + const script = `python3 - <<'PY' +import json +import sys +import urllib.error +import urllib.request + +base_url = ${JSON.stringify(STEWARD_HOST_URL)} +agent_id = ${JSON.stringify(agentId)} +agent_name = ${JSON.stringify(agentName)} + + +def post(path, payload): + req = urllib.request.Request( + f"{base_url}{path}", + data=json.dumps(payload).encode("utf-8"), + headers={"Content-Type": "application/json"}, + method="POST", + ) + try: + with urllib.request.urlopen(req, timeout=15) as response: + return response.status, response.read().decode("utf-8") + except urllib.error.HTTPError as error: + return error.code, error.read().decode("utf-8") + + +status, body = post("/agents", {"id": agent_id, "name": agent_name}) +if status not in (200, 201, 202, 409): + print(body, file=sys.stderr) + raise SystemExit(f"Steward agent registration failed with status {status}") + +status, body = post(f"/agents/{agent_id}/token", {"name": "milady-cloud"}) +if status not in (200, 201): + print(body, file=sys.stderr) + raise SystemExit(f"Steward token mint failed with status {status}") + +print(body) +PY`; + + const rawToken = await ssh.exec(script, DOCKER_CMD_TIMEOUT_MS); + return extractStewardToken(rawToken); +} + // --------------------------------------------------------------------------- // DockerSandboxProvider // --------------------------------------------------------------------------- @@ -277,19 +391,23 @@ export class DockerSandboxProvider implements SandboxProvider { } } - // 5. Build environment flags (spread to avoid mutating caller's environmentVars) - const allEnv: Record = { + // 5. Build the base environment (spread to avoid mutating caller's environmentVars) + const baseEnv: Record = { ...environmentVars, ...vpnEnvVars, AGENT_NAME: agentName, - // cloud-full-ui image runs two processes: + MILADY_CLOUD_PROVISIONED: "1", + ELIZA_CLOUD_PROVISIONED: "1", + STEWARD_API_URL: STEWARD_CONTAINER_URL, + STEWARD_AGENT_ID: agentId, + // steward-enabled image runs two processes: // milady.mjs (UI) on MILADY_PORT (default 2138) // cloud-agent on PORT (default 2139) // Do NOT set PORT=2138 here — it would collide with MILADY_PORT // and the API service would steal the UI port. - MILADY_PORT: "2138", - PORT: "2139", - BRIDGE_PORT: "31337", + MILADY_PORT: DEFAULT_MILADY_PORT, + PORT: DEFAULT_AGENT_PORT, + BRIDGE_PORT: DEFAULT_BRIDGE_PORT, // Eliza server requires JWT_SECRET in production mode. // Generate a unique per-container secret if the caller didn't provide one. JWT_SECRET: environmentVars.JWT_SECRET || crypto.randomUUID(), @@ -303,39 +421,9 @@ export class DockerSandboxProvider implements SandboxProvider { MILADY_ALLOWED_ORIGINS: `https://${agentId}.${getAgentBaseDomain()}`, }; - // Validate env var keys to prevent shell command injection via malformed keys - for (const key of Object.keys(allEnv)) { - if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) { - throw new Error(`[docker-sandbox] Invalid environment variable key: "${key}"`); - } - } - - // Note: Values do not need control-character validation. The shellQuote() function - // wraps each "key=value" pair in single quotes and escapes embedded single quotes as '"'"', - // which makes all values (including those with newlines, tabs, or other control chars) - // safe inside the shell command. Single-quoted strings in bash preserve all characters - // literally except single quotes (which shellQuote already handles). - - const envFlags = Object.entries(allEnv) - .map(([key, value]) => `-e ${shellQuote(`${key}=${value}`)}`) - .join(" "); - - // 6. Build docker run command - // Only add NET_ADMIN and /dev/net/tun when headscale is actually enabled - const dockerRunCmd = [ - "docker run -d", - `--name ${shellQuote(containerName)}`, - "--restart unless-stopped", - ...(headscaleEnabled ? ["--cap-add=NET_ADMIN", "--device /dev/net/tun"] : []), - `-v ${shellQuote(volumePath)}:/app/data`, - `-p ${bridgePort}:31337`, - `-p ${webUiPort}:2138`, - envFlags, - shellQuote(resolvedImage), - ].join(" "); - - // 7. SSH to node, ensure volume dir, pull image, run container - // Pass hostKeyFingerprint so pooled clients pin the key when available + // 6. SSH to node, ensure volume dir, pull image, register in Steward, + // then create/start the container. Pass hostKeyFingerprint so pooled + // clients pin the key when available. const ssh = DockerSSHClient.getClient(hostname, sshPort, hostKeyFingerprint, sshUser); try { @@ -353,13 +441,73 @@ export class DockerSandboxProvider implements SandboxProvider { ); } - // Run container - const output = await ssh.exec(dockerRunCmd, DOCKER_CMD_TIMEOUT_MS); - const containerId = output.trim().slice(0, 12); + logger.info(`[docker-sandbox] Registering ${agentId} with Steward on ${nodeId}`); + const stewardAgentToken = await registerAgentWithSteward(ssh, agentId, agentName); + + const allEnv: Record = { + ...baseEnv, + STEWARD_AGENT_TOKEN: stewardAgentToken, + }; + + // Validate env keys/values before they are interpolated into remote shell commands. + // Internal env vars must also remain UPPER_SNAKE_CASE so validation stays + // consistent across caller-supplied and provider-generated values. + for (const [key, value] of Object.entries(allEnv)) { + validateEnvKey(key); + validateEnvValue(key, value); + } + + const envFlags = Object.entries(allEnv) + .map(([key, value]) => `-e ${shellQuote(`${key}=${value}`)}`) + .join(" "); + + const dockerCreateCmd = [ + "docker create", + `--name ${shellQuote(containerName)}`, + "--restart unless-stopped", + `--network ${shellQuote(DOCKER_NETWORK)}`, + ...(requiresDockerHostGateway(STEWARD_CONTAINER_URL) + ? ["--add-host host.docker.internal:host-gateway"] + : []), + `--health-cmd ${shellQuote(getDockerHealthCmd(allEnv.MILADY_PORT || DEFAULT_MILADY_PORT))}`, + "--health-interval 10s", + "--health-timeout 5s", + "--health-start-period 15s", + "--health-retries 6", + ...(headscaleEnabled ? ["--cap-add=NET_ADMIN", "--device /dev/net/tun"] : []), + `-v ${shellQuote(volumePath)}:/app/data`, + `-p ${bridgePort}:${DEFAULT_BRIDGE_PORT}`, + `-p ${webUiPort}:${allEnv.MILADY_PORT || DEFAULT_MILADY_PORT}`, + envFlags, + shellQuote(resolvedImage), + ].join(" "); + + const containerId = (await ssh.exec(dockerCreateCmd, DOCKER_CMD_TIMEOUT_MS)) + .trim() + .slice(0, 12); + await ssh.exec(`docker start ${shellQuote(containerName)}`, DOCKER_CMD_TIMEOUT_MS); logger.info( `[docker-sandbox] Container created on ${nodeId}: ${containerId} (${containerName})`, ); } catch (err) { + // Best-effort Steward deregistration — the agent was registered but the + // container failed to start, so we try to clean up the Steward record. + try { + await ssh.exec( + `curl -s -X DELETE ${shellQuote(`${STEWARD_HOST_URL}/agents/${agentId}`)} || true`, + DOCKER_CMD_TIMEOUT_MS, + ); + logger.info(`[docker-sandbox] Cleaned up Steward agent ${agentId} after container failure`); + } catch (cleanupErr) { + logger.warn( + `[docker-sandbox] Failed to cleanup Steward agent ${agentId}: ${cleanupErr instanceof Error ? cleanupErr.message : String(cleanupErr)}`, + ); + } + + await ssh + .exec(`docker rm -f ${shellQuote(containerName)}`, DOCKER_CMD_TIMEOUT_MS) + .catch(() => {}); + // Rollback allocated_count on failure if (dbNode) { await dockerNodesRepository.decrementAllocated(nodeId).catch(() => {}); diff --git a/packages/lib/services/docker-sandbox-utils.ts b/packages/lib/services/docker-sandbox-utils.ts index 85cb12b98..02be407d8 100644 --- a/packages/lib/services/docker-sandbox-utils.ts +++ b/packages/lib/services/docker-sandbox-utils.ts @@ -26,6 +26,10 @@ export const BRIDGE_PORT_MIN = 18790; export const BRIDGE_PORT_MAX = 19790; export const WEBUI_PORT_MIN = 20000; export const WEBUI_PORT_MAX = 25000; +export const DOCKER_CONTAINER_NAME_MAX_LENGTH = 128; +export const MILADY_CONTAINER_NAME_PREFIX = "milady-"; +export const MAX_AGENT_ID_LENGTH = + DOCKER_CONTAINER_NAME_MAX_LENGTH - MILADY_CONTAINER_NAME_PREFIX.length; // --------------------------------------------------------------------------- // Shell Quoting @@ -43,14 +47,24 @@ export function shellQuote(value: string): string { // Validation // --------------------------------------------------------------------------- +function hasControlChars(value: string): boolean { + return /[\x00-\x1f\x7f]/.test(value); +} + /** - * Validate an agent ID before using it in shell commands. - * Must be a UUID (hex + hyphens) or alphanumeric with hyphens/underscores. + * Validate an agent ID before using it in Docker-derived names and shell commands. + * Must fit within Docker's 128-char container name limit after the `milady-` + * prefix is applied. */ export function validateAgentId(agentId: string): void { - if (!/^[a-zA-Z0-9_-]{1,128}$/.test(agentId)) { + if ( + agentId.length === 0 || + agentId.length > MAX_AGENT_ID_LENGTH || + hasControlChars(agentId) || + !/^[a-zA-Z0-9_-]+$/.test(agentId) + ) { throw new Error( - `Invalid agent ID "${agentId}": must be 1-128 chars, alphanumeric / hyphens / underscores only.`, + `Invalid agent ID "${agentId}": must be 1-${MAX_AGENT_ID_LENGTH} chars, alphanumeric / hyphens / underscores only.`, ); } } @@ -61,11 +75,107 @@ export function validateAgentName(name: string): void { throw new Error(`Invalid agent name: must be 1-64 characters.`); } // Block characters that could break shell commands even inside quotes - if (/[\x00-\x1f\x7f]/.test(name)) { + if (hasControlChars(name)) { throw new Error(`Invalid agent name "${name}": contains control characters.`); } } +/** Env keys must be shell-safe identifiers; allow lowercase for caller-supplied env vars. */ +export function validateEnvKey(key: string): void { + if (hasControlChars(key) || !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) { + throw new Error( + `Invalid environment variable key "${key}": must match ^[A-Za-z_][A-Za-z0-9_]*$.`, + ); + } +} + +/** + * Env values are shell-safe once single-quoted, but we still reject control + * characters so multi-line payloads and invisible bytes cannot reach the remote + * shell command. Callers should pass a key so production errors are debuggable. + */ +export function validateEnvValue(key: string, value: string): void { + if (hasControlChars(value)) { + throw new Error( + `Invalid environment variable value for key "${key}": contains control characters (newlines and PEM-encoded values are not supported).`, + ); + } +} + +/** Docker container names must be simple shell-safe identifiers. */ +export function validateContainerName(containerName: string): void { + if (hasControlChars(containerName) || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(containerName)) { + throw new Error( + `Invalid container name "${containerName}": must match ^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$.`, + ); + } +} + +/** Docker host volume paths must be absolute, normalized, and shell-safe. */ +export function validateVolumePath(volumePath: string): void { + // First allow only absolute shell-safe path characters, reject the root path, + // then separately enforce normalized-form rules like no traversal, repeated + // separators, or trailing slash. + if ( + hasControlChars(volumePath) || + volumePath === "/" || + !/^\/[A-Za-z0-9._/-]+$/.test(volumePath) + ) { + throw new Error(`Invalid volume path "${volumePath}".`); + } + if ( + volumePath.includes("//") || + volumePath.includes("/./") || + volumePath.includes("/../") || + volumePath.endsWith("/.") || + volumePath.endsWith("/..") || + (volumePath.length > 1 && volumePath.endsWith("/")) + ) { + throw new Error(`Invalid volume path "${volumePath}": path must be normalized.`); + } +} + +// --------------------------------------------------------------------------- +// Steward / Docker host routing +// --------------------------------------------------------------------------- + +/** + * Resolve the URL injected into containers for talking back to Steward. + * + * - Explicit STEWARD_CONTAINER_URL wins. + * - Otherwise, when the host-side Steward URL points at localhost/loopback, + * rewrite it to host.docker.internal for container reachability. + * - Non-loopback host URLs pass through unchanged. + */ +export function resolveStewardContainerUrl( + stewardHostUrl: string = process.env.STEWARD_API_URL || "http://localhost:3200", + stewardContainerUrl?: string, +): string { + const override = stewardContainerUrl?.trim(); + if (override) { + return override.replace(/\/$/, ""); + } + + try { + const url = new URL(stewardHostUrl); + if (["localhost", "127.0.0.1", "::1"].includes(url.hostname)) { + url.hostname = "host.docker.internal"; + } + return url.toString().replace(/\/$/, ""); + } catch { + return "http://host.docker.internal:3200"; + } +} + +/** Linux Docker needs an explicit host-gateway alias for host.docker.internal. */ +export function requiresDockerHostGateway(targetUrl: string): boolean { + try { + return new URL(targetUrl).hostname === "host.docker.internal"; + } catch { + return false; + } +} + // --------------------------------------------------------------------------- // Port Allocation // --------------------------------------------------------------------------- @@ -107,13 +217,19 @@ export function allocatePort(min: number, max: number, excluded: Set): n * patterns and can collide on the same node). */ export function getContainerName(agentId: string): string { - return `milady-${agentId}`; + validateAgentId(agentId); + const containerName = `${MILADY_CONTAINER_NAME_PREFIX}${agentId}`; + // Keep this derived-output validation as a guardrail if the naming template changes. + validateContainerName(containerName); + return containerName; } /** Volume path on the Docker host for persistent agent data. */ export function getVolumePath(agentId: string): string { validateAgentId(agentId); - return `/data/agents/${agentId}`; + const volumePath = `/data/agents/${agentId}`; + validateVolumePath(volumePath); + return volumePath; } // --------------------------------------------------------------------------- diff --git a/packages/lib/services/docker-ssh.ts b/packages/lib/services/docker-ssh.ts index e60b24512..c892022f3 100644 --- a/packages/lib/services/docker-ssh.ts +++ b/packages/lib/services/docker-ssh.ts @@ -89,6 +89,8 @@ export class DockerSSHClient { /** Idle timeout — pooled connections unused for this long are auto-closed. */ private static readonly IDLE_TIMEOUT_MS = 5 * 60 * 1000; // 5 minutes + /** Max number of concurrent SSH connections in pool to prevent unbounded growth. */ + private static readonly MAX_POOL_SIZE = 50; /** * Get (or create) a pooled client for the given hostname. @@ -132,12 +134,34 @@ export class DockerSSHClient { } } if (!client) { + if (DockerSSHClient.pool.size >= DockerSSHClient.MAX_POOL_SIZE) { + let oldestKey = ""; + let oldestTime = Infinity; + for (const [k, v] of DockerSSHClient.pool.entries()) { + if (v.lastActivityMs < oldestTime) { + oldestTime = v.lastActivityMs; + oldestKey = k; + } + } + if (oldestKey) { + logger.warn( + `[docker-ssh] Pool max size (${DockerSSHClient.MAX_POOL_SIZE}) reached, evicting oldest connection: ${oldestKey}`, + ); + DockerSSHClient.pool + .get(oldestKey) + ?.disconnect() + .catch(() => {}); + DockerSSHClient.pool.delete(oldestKey); + } + } + client = new DockerSSHClient({ hostname, port: effectivePort, username: effectiveUser, hostKeyFingerprint, }); + client.lastActivityMs = Date.now(); DockerSSHClient.pool.set(poolKey, client); } return client; diff --git a/packages/lib/services/milady-managed-launch.ts b/packages/lib/services/milady-managed-launch.ts index 3755c8d62..63ff59c2e 100644 --- a/packages/lib/services/milady-managed-launch.ts +++ b/packages/lib/services/milady-managed-launch.ts @@ -110,8 +110,10 @@ function buildManagedAllowedOrigins(): string[] { if (appOrigin) origins.add(appOrigin); if (cloudOrigin) origins.add(cloudOrigin); - for (const origin of DEV_MILADY_APP_ORIGINS) { - origins.add(origin); + if (process.env.NODE_ENV !== "production") { + for (const origin of DEV_MILADY_APP_ORIGINS) { + origins.add(origin); + } } const extraOrigins = process.env.MILADY_MANAGED_ALLOWED_ORIGINS; @@ -407,13 +409,13 @@ export async function launchManagedMiladyAgent(params: { } if (!launchSessionId) { - if (!cache.isAvailable()) { - logger.warn( - "[milady-managed-launch] Cache unavailable; falling back to direct launch params", - ); - } - appUrl.searchParams.set("apiBase", connection.apiBase); - appUrl.searchParams.set("token", connection.token); + logger.error( + "[milady-managed-launch] Cache unavailable; cannot launch safely without leaking token", + ); + throw new ManagedMiladyLaunchError( + "Managed launch is unavailable because the session cache is unreachable.", + 503, + ); } return { diff --git a/packages/lib/services/milady-sandbox.ts b/packages/lib/services/milady-sandbox.ts index a266e28e3..2dcf2567e 100644 --- a/packages/lib/services/milady-sandbox.ts +++ b/packages/lib/services/milady-sandbox.ts @@ -235,7 +235,7 @@ export class MiladySandboxService { // Provision async provision(agentId: string, orgId: string): Promise { - const rec = await miladySandboxesRepository.findByIdAndOrg(agentId, orgId); + let rec = await miladySandboxesRepository.findByIdAndOrg(agentId, orgId); if (!rec) return { success: false, error: "Agent not found" } as ProvisionResult; const lock = await miladySandboxesRepository.trySetProvisioning(rec.id); @@ -267,6 +267,11 @@ export class MiladySandboxService { }; } dbUri = db.connectionUri!; + // Neon provision updates DB but doesn't return the full record; re-fetch to avoid stale data + const refreshed = await miladySandboxesRepository.findByIdAndOrg(agentId, orgId); + if (refreshed) { + rec = refreshed; + } } // 2-5. Sandbox creation + DB persistence with retry for port collision @@ -487,11 +492,9 @@ export class MiladySandboxService { const hasDockerNodeSignal = !!sandbox.node_id; // Older Docker-backed records may predate the node/headscale backfill but // still carry the provider-generated `sandbox_id`/container name. - const hasLegacyDockerSandboxId = this.isLegacyDockerSandboxId(sandbox.sandbox_id); return ( hasMatchingHeadscaleIp || - hasLegacyDockerSandboxId || (hasDockerNodeSignal && hasMatchingBridgePort) || (hasDockerNodeSignal && hasMatchingHeadscaleIp) ); @@ -507,7 +510,15 @@ export class MiladySandboxService { } const [first, second] = hostname.split(".").map((part) => Number.parseInt(part, 10)); - return first === 100 && second >= 64 && second <= 127; + // CGNAT (100.64.0.0/10) + if (first === 100 && second >= 64 && second <= 127) return true; + // RFC1918: 10.0.0.0/8 + if (first === 10) return true; + // RFC1918: 172.16.0.0/12 + if (first === 172 && second >= 16 && second <= 31) return true; + // RFC1918: 192.168.0.0/16 + if (first === 192 && second === 168) return true; + return false; } private matchesTrustedDockerBridge( @@ -634,6 +645,11 @@ export class MiladySandboxService { : await miladySandboxesRepository.getLatestBackup(rec.id); if (!backup) return { success: false, error: "No backup found" }; + // Verify backup belongs to this sandbox to prevent cross-agent restore + if (backup.sandbox_record_id !== rec.id) { + return { success: false, error: "Backup does not belong to this agent" }; + } + if (rec.status !== "running" && backupId) { const latestBackup = await miladySandboxesRepository.getLatestBackup(rec.id); if (!latestBackup || backup.id !== latestBackup.id) { diff --git a/packages/lib/services/pairing-token.ts b/packages/lib/services/pairing-token.ts index 743e472e4..686df5ae8 100644 --- a/packages/lib/services/pairing-token.ts +++ b/packages/lib/services/pairing-token.ts @@ -17,7 +17,35 @@ function hashToken(token: string): string { return crypto.createHash("sha256").update(token).digest("hex"); } +// Domain aliases — waifu.fun and milady.ai resolve to the same containers. +// The dashboard rewrites URLs from one to the other, so the Origin header +// sent by pair.html may use either domain. +const DOMAIN_ALIASES: [string, string][] = [[".waifu.fun", ".milady.ai"]]; + class PairingTokenService { + /** + * Given an origin like https://uuid.waifu.fun, return https://uuid.milady.ai + * (and vice versa). Returns null if no alias applies. + */ + private getAlternateDomainOrigin(origin: string): string | null { + for (const [a, b] of DOMAIN_ALIASES) { + try { + const url = new URL(origin); + if (url.hostname.endsWith(a)) { + url.hostname = url.hostname.replace(new RegExp(`${a.replaceAll(".", "\\.")}$`), b); + return url.origin; + } + if (url.hostname.endsWith(b)) { + url.hostname = url.hostname.replace(new RegExp(`${b.replaceAll(".", "\\.")}$`), a); + return url.origin; + } + } catch { + // Invalid URL — skip + } + } + return null; + } + async generateToken( userId: string, orgId: string, @@ -53,11 +81,25 @@ class PairingTokenService { return null; } - const row = await miladyPairingTokensRepository.consumeValidToken( + // Try the exact origin first + let row = await miladyPairingTokensRepository.consumeValidToken( hashToken(token), normalizedOrigin, ); + // If no match, try the alternate domain. The dashboard may rewrite + // waifu.fun → milady.ai (or vice versa) which changes the Origin header + // but both domains resolve to the same agent container. + if (!row) { + const alternateOrigin = this.getAlternateDomainOrigin(normalizedOrigin); + if (alternateOrigin) { + row = await miladyPairingTokensRepository.consumeValidToken( + hashToken(token), + alternateOrigin, + ); + } + } + if (!row) { return null; } diff --git a/packages/lib/services/provisioning-jobs.ts b/packages/lib/services/provisioning-jobs.ts index 9b96d3b71..b2b64915d 100644 --- a/packages/lib/services/provisioning-jobs.ts +++ b/packages/lib/services/provisioning-jobs.ts @@ -21,7 +21,7 @@ import { jobs } from "@/db/schemas/jobs"; import { miladySandboxes } from "@/db/schemas/milady-sandboxes"; import { assertSafeOutboundUrl } from "@/lib/security/outbound-url"; import { miladyProvisionAdvisoryLockSql } from "@/lib/services/milady-provision-lock"; -import { miladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { miladySandboxService } from "@/lib/services/milady-sandbox"; import { logger } from "@/lib/utils/logger"; // --------------------------------------------------------------------------- diff --git a/packages/scripts/check-migration-journal.ts b/packages/scripts/check-migration-journal.ts new file mode 100644 index 000000000..47510a594 --- /dev/null +++ b/packages/scripts/check-migration-journal.ts @@ -0,0 +1,81 @@ +/** + * Fail fast when Drizzle migration files and the repo journal drift apart. + * + * This guards against: + * - duplicate numeric prefixes (e.g. two 0043_*.sql files) + * - missing journal entries for SQL files + * - journal tags pointing at missing SQL files + * - journal/file ordering drift after manual renames + */ + +import { readdir, readFile } from "node:fs/promises"; +import path from "node:path"; + +interface JournalEntry { + idx: number; + tag: string; +} + +interface Journal { + entries: JournalEntry[]; +} + +const MIGRATIONS_DIR = path.join(process.cwd(), "packages/db/migrations"); +const JOURNAL_PATH = path.join(MIGRATIONS_DIR, "meta/_journal.json"); + +function sortByNumericPrefix(a: string, b: string): number { + const numA = parseInt(a.split("_")[0] ?? "0", 10); + const numB = parseInt(b.split("_")[0] ?? "0", 10); + if (numA !== numB) return numA - numB; + return a.localeCompare(b); +} + +async function main() { + const journal = JSON.parse(await readFile(JOURNAL_PATH, "utf8")) as Journal; + const migrationFilesOnDisk = (await readdir(MIGRATIONS_DIR)) + .filter((name) => name.endsWith(".sql")) + .sort(sortByNumericPrefix); + + const errors: string[] = []; + const journalFiles = journal.entries.map((entry) => `${entry.tag}.sql`); + const diskFileSet = new Set(migrationFilesOnDisk); + + // Only enforce duplicate-prefix checks for journal-tracked files. The repo has a + // few historical helper/legacy SQL files that are intentionally not in the Drizzle journal. + const trackedFilesByPrefix = new Map(); + for (const file of journalFiles) { + const prefix = file.split("_")[0] ?? ""; + const list = trackedFilesByPrefix.get(prefix) ?? []; + list.push(file); + trackedFilesByPrefix.set(prefix, list); + } + + for (const [prefix, files] of trackedFilesByPrefix) { + if (files.length > 1) { + errors.push(`Duplicate journal-tracked migration prefix ${prefix}: ${files.join(", ")}`); + } + } + + for (const file of journalFiles) { + if (!diskFileSet.has(file)) { + errors.push(`Journal entry points to missing migration file: ${file}`); + } + } + + if (errors.length > 0) { + console.error("Migration journal check failed:\n"); + for (const error of errors) { + console.error(`- ${error}`); + } + process.exit(1); + } + + console.log( + `Migration journal OK (${journal.entries.length} journal entries, ${migrationFilesOnDisk.length} SQL files on disk).`, + ); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/packages/scripts/repair-drizzle-journal.ts b/packages/scripts/repair-drizzle-journal.ts new file mode 100644 index 000000000..f22eeb2a6 --- /dev/null +++ b/packages/scripts/repair-drizzle-journal.ts @@ -0,0 +1,75 @@ +/** + * Repair Drizzle journal entries after local migration file renames. + * + * Why this exists: + * - Drizzle reads migration filenames from packages/db/migrations/meta/_journal.json + * - PR #403 renumbered migration files 0043-0053 to remove a duplicate 0043 + * - The database tracks applied migrations by hash + created_at in __drizzle_migrations + * - Fresh DBs / CI still fail if the journal points at old filenames that no longer exist + * + * This helper rewrites the affected journal tags so the repo's on-disk journal matches + * the current migration filenames. + * + * Usage: + * bun run packages/scripts/repair-drizzle-journal.ts + */ + +import { readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; + +interface JournalEntry { + idx: number; + version: string; + when: number; + tag: string; + breakpoints: boolean; +} + +interface Journal { + version: string; + dialect: string; + entries: JournalEntry[]; +} + +const JOURNAL_PATH = path.join(process.cwd(), "packages/db/migrations/meta/_journal.json"); + +const TAG_RENAMES = new Map([ + [42, "0044_seed_chain_data_pricing"], + [43, "0043_add_missing_referral_context_columns"], + [44, "0045_add_whatsapp_identity_columns"], + [45, "0046_add_redeemable_earnings_breakdown_columns"], + [46, "0047_docker_nodes"], + [47, "0048_add_token_agent_linkage"], + [48, "0049_elite_rumiko_fujikawa"], + [49, "0050_repair_existing_user_identity_privy_claims"], + [50, "0051_backfill_user_identities_from_users"], + [51, "0052_add_milady_pairing_tokens"], + [52, "0053_add_milady_billing_columns"], +]); + +async function main() { + const journal = JSON.parse(await readFile(JOURNAL_PATH, "utf8")) as Journal; + + let changed = 0; + for (const entry of journal.entries) { + const nextTag = TAG_RENAMES.get(entry.idx); + if (!nextTag || entry.tag === nextTag) continue; + + console.log(`idx ${entry.idx}: ${entry.tag} -> ${nextTag}`); + entry.tag = nextTag; + changed++; + } + + if (changed === 0) { + console.log("Drizzle journal already matches the current migration filenames."); + return; + } + + await writeFile(JOURNAL_PATH, `${JSON.stringify(journal, null, 2)}\n`); + console.log(`Updated ${JOURNAL_PATH} (${changed} entries repaired).`); +} + +main().catch((error) => { + console.error(error); + process.exit(1); +}); diff --git a/packages/tests/unit/auth-pair-route.test.ts b/packages/tests/unit/auth-pair-route.test.ts index 8db10acb4..3c5e9965f 100644 --- a/packages/tests/unit/auth-pair-route.test.ts +++ b/packages/tests/unit/auth-pair-route.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, mock, test } from "bun:test"; import { jsonRequest } from "./api/route-test-helpers"; const mockValidateToken = mock(); -const mockFindById = mock(); +const mockFindByIdAndOrg = mock(); mock.module("@/lib/services/pairing-token", () => ({ getPairingTokenService: () => ({ @@ -12,7 +12,7 @@ mock.module("@/lib/services/pairing-token", () => ({ mock.module("@/db/repositories/milady-sandboxes", () => ({ miladySandboxesRepository: { - findById: mockFindById, + findByIdAndOrg: mockFindByIdAndOrg, }, })); @@ -21,7 +21,7 @@ import { POST } from "@/app/api/auth/pair/route"; describe("POST /api/auth/pair", () => { beforeEach(() => { mockValidateToken.mockReset(); - mockFindById.mockReset(); + mockFindByIdAndOrg.mockReset(); }); test("requires a pairing code", async () => { @@ -70,8 +70,9 @@ describe("POST /api/auth/pair", () => { test("returns only the explicit Milady API token", async () => { mockValidateToken.mockResolvedValue({ agentId: "agent-1", + orgId: "org-1", }); - mockFindById.mockResolvedValue({ + mockFindByIdAndOrg.mockResolvedValue({ agent_name: "Milady Agent", environment_vars: { MILADY_API_TOKEN: "milady-token", @@ -102,8 +103,9 @@ describe("POST /api/auth/pair", () => { test("does not fall back to generic secrets when no Milady API token exists", async () => { mockValidateToken.mockResolvedValue({ agentId: "agent-1", + orgId: "org-1", }); - mockFindById.mockResolvedValue({ + mockFindByIdAndOrg.mockResolvedValue({ agent_name: "Milady Agent", environment_vars: { JWT_SECRET: "jwt-secret", diff --git a/packages/tests/unit/docker-infrastructure.test.ts b/packages/tests/unit/docker-infrastructure.test.ts index 655a6e591..f67e8f10f 100644 --- a/packages/tests/unit/docker-infrastructure.test.ts +++ b/packages/tests/unit/docker-infrastructure.test.ts @@ -9,10 +9,17 @@ import { allocatePort, getContainerName, getVolumePath, + MAX_AGENT_ID_LENGTH, parseDockerNodes, + requiresDockerHostGateway, + resolveStewardContainerUrl, shellQuote, validateAgentId, validateAgentName, + validateContainerName, + validateEnvKey, + validateEnvValue, + validateVolumePath, } from "@/lib/services/docker-sandbox-utils"; // --------------------------------------------------------------------------- @@ -79,18 +86,11 @@ describe("Docker Infrastructure - Pure Functions", () => { }); test("escapes an embedded single quote", () => { - // it's → 'it'"'"'s' expect(shellQuote("it's")).toBe("'it'\"'\"'s'"); }); test("safely quotes $HOME && rm -rf / (no variable expansion)", () => { - const result = shellQuote("$HOME && rm -rf /"); - // The result must start and end with single-quote so the shell treats - // the whole thing as a literal string. - expect(result.startsWith("'")).toBe(true); - expect(result.endsWith("'")).toBe(true); - // The literal characters must survive round-trip - expect(result).toBe("'$HOME && rm -rf /'"); + expect(shellQuote("$HOME && rm -rf /")).toBe("'$HOME && rm -rf /'"); }); test("wraps a string with double quotes (no escaping needed)", () => { @@ -105,9 +105,7 @@ describe("Docker Infrastructure - Pure Functions", () => { }); test("safely quotes $(whoami) — no command substitution possible", () => { - // Wrapped in single quotes → shell never evaluates $() inside - const result = shellQuote("$(whoami)"); - expect(result).toBe("'$(whoami)'"); + expect(shellQuote("$(whoami)")).toBe("'$(whoami)'"); }); }); @@ -125,8 +123,8 @@ describe("Docker Infrastructure - Pure Functions", () => { expect(() => validateAgentId("a")).not.toThrow(); }); - test("accepts exactly 128 characters", () => { - const id = "a".repeat(128); + test("accepts exactly the Docker-safe maximum length", () => { + const id = "a".repeat(MAX_AGENT_ID_LENGTH); expect(() => validateAgentId(id)).not.toThrow(); }); @@ -134,8 +132,8 @@ describe("Docker Infrastructure - Pure Functions", () => { expect(() => validateAgentId("")).toThrow(/Invalid agent ID/); }); - test("throws for 129 characters (too long)", () => { - const id = "a".repeat(129); + test("throws when the agentId would exceed the Docker container name limit", () => { + const id = "a".repeat(MAX_AGENT_ID_LENGTH + 1); expect(() => validateAgentId(id)).toThrow(/Invalid agent ID/); }); @@ -143,6 +141,10 @@ describe("Docker Infrastructure - Pure Functions", () => { expect(() => validateAgentId("agent;rm -rf /")).toThrow(/Invalid agent ID/); }); + test("throws for trailing newline", () => { + expect(() => validateAgentId("agent_1\n")).toThrow(/Invalid agent ID/); + }); + test("throws for dots", () => { expect(() => validateAgentId("agent.1")).toThrow(/Invalid agent ID/); }); @@ -180,15 +182,15 @@ describe("Docker Infrastructure - Pure Functions", () => { expect(() => validateAgentName(name)).toThrow(/Invalid agent name/); }); - test("now accepts spaces (relaxed for existing agents)", () => { + test("accepts spaces (shell-safe via quoting)", () => { expect(() => validateAgentName("my agent")).not.toThrow(); }); - test("now accepts dots (relaxed for existing agents)", () => { + test("accepts dots (shell-safe via quoting)", () => { expect(() => validateAgentName("my.agent")).not.toThrow(); }); - test("now accepts semicolons (shell-safe via quoting)", () => { + test("accepts semicolons (shell-safe via quoting)", () => { expect(() => validateAgentName("agent;drop")).not.toThrow(); }); @@ -205,6 +207,96 @@ describe("Docker Infrastructure - Pure Functions", () => { }); }); + // ------------------------------------------------------------------------- + describe("validateEnvKey", () => { + test("accepts uppercase and lowercase underscore keys", () => { + expect(() => validateEnvKey("JWT_SECRET")).not.toThrow(); + expect(() => validateEnvKey("jwt_secret")).not.toThrow(); + expect(() => validateEnvKey("A1_B2")).not.toThrow(); + }); + + test("rejects empty keys", () => { + expect(() => validateEnvKey("")).toThrow(/Invalid environment variable key/); + }); + + test("rejects keys starting with a digit", () => { + expect(() => validateEnvKey("1SECRET")).toThrow(/Invalid environment variable key/); + }); + + test("rejects punctuation", () => { + expect(() => validateEnvKey("JWT-SECRET")).toThrow(/Invalid environment variable key/); + }); + + test("rejects trailing newlines", () => { + expect(() => validateEnvKey("JWT_SECRET\n")).toThrow(/Invalid environment variable key/); + }); + }); + + // ------------------------------------------------------------------------- + describe("validateEnvValue", () => { + test("accepts printable values", () => { + expect(() => validateEnvValue("JWT_SECRET", "hello-world_123")).not.toThrow(); + }); + + test("accepts UUIDs, URLs, and base64-like tokens", () => { + expect(() => + validateEnvValue( + "MIXED_VALUE", + "550e8400-e29b-41d4-a716-446655440000 https://example.com/a?b=c token+/=", + ), + ).not.toThrow(); + }); + + test("rejects null bytes and includes the key name", () => { + expect(() => validateEnvValue("JWT_SECRET", "abc\x00def")).toThrow( + /JWT_SECRET.*control characters/, + ); + }); + + test("rejects newlines and explains PEM-style values are unsupported", () => { + expect(() => validateEnvValue("TLS_CERT", "abc\ndef")).toThrow( + /TLS_CERT.*newlines and PEM-encoded values are not supported/, + ); + }); + + test("rejects tabs", () => { + expect(() => validateEnvValue("JWT_SECRET", "abc\tdef")).toThrow(/control characters/); + }); + }); + + // ------------------------------------------------------------------------- + describe("resolveStewardContainerUrl", () => { + test("preserves explicit STEWARD_CONTAINER_URL overrides", () => { + expect( + resolveStewardContainerUrl("http://localhost:3200", "http://steward.internal:9999"), + ).toBe("http://steward.internal:9999"); + }); + + test("rewrites localhost host URLs for container reachability", () => { + expect(resolveStewardContainerUrl("http://localhost:3200")).toBe( + "http://host.docker.internal:3200", + ); + expect(resolveStewardContainerUrl("http://127.0.0.1:3200")).toBe( + "http://host.docker.internal:3200", + ); + }); + + test("passes through non-loopback URLs unchanged", () => { + expect(resolveStewardContainerUrl("http://10.0.0.8:3200")).toBe("http://10.0.0.8:3200"); + }); + }); + + // ------------------------------------------------------------------------- + describe("requiresDockerHostGateway", () => { + test("returns true for host.docker.internal", () => { + expect(requiresDockerHostGateway("http://host.docker.internal:3200")).toBe(true); + }); + + test("returns false for non-host-gateway URLs", () => { + expect(requiresDockerHostGateway("http://10.0.0.8:3200")).toBe(false); + }); + }); + // ------------------------------------------------------------------------- describe("allocatePort", () => { test("returns a port within [min, max)", () => { @@ -214,8 +306,6 @@ describe("Docker Infrastructure - Pure Functions", () => { }); test("never returns an excluded port (large range, many iterations)", () => { - // Range [1000, 2000) → 1000 ports; exclude 3 specific ones. - // retry cap = 2000, so finding an available port is virtually certain. const excluded = new Set([1000, 1001, 1002]); for (let i = 0; i < 50; i++) { const port = allocatePort(1000, 2000, excluded); @@ -226,10 +316,7 @@ describe("Docker Infrastructure - Pure Functions", () => { }); test("finds an available port when most of the range is excluded", () => { - // Range [500, 600) → 100 ports; exclude 95 leaving 5 available. - // retry cap = 200, P(failure per call) ≈ 0.035% — deterministic enough. const excluded = new Set(Array.from({ length: 95 }, (_, i) => 500 + i)); - // Available ports: 595, 596, 597, 598, 599 const available = new Set([595, 596, 597, 598, 599]); for (let i = 0; i < 20; i++) { const port = allocatePort(500, 600, excluded); @@ -240,9 +327,7 @@ describe("Docker Infrastructure - Pure Functions", () => { }); test("throws when all ports in range are excluded", () => { - // Range [10, 13) = 3 ports; exclude all 3 - const excluded = new Set([10, 11, 12]); - expect(() => allocatePort(10, 13, excluded)).toThrow(/No available ports in range/); + expect(() => allocatePort(10, 13, new Set([10, 11, 12]))).toThrow(/No available ports/); }); test("works with an empty exclusion set", () => { @@ -252,7 +337,6 @@ describe("Docker Infrastructure - Pure Functions", () => { }); test("single-port range with no exclusions returns that port", () => { - // Range [42, 43) → only port 42 expect(allocatePort(42, 43, new Set())).toBe(42); }); }); @@ -268,13 +352,31 @@ describe("Docker Infrastructure - Pure Functions", () => { expect(getContainerName(agentId)).toBe(`milady-${agentId}`); }); - test("works with a short agentId", () => { - expect(getContainerName("x")).toBe("milady-x"); + test("throws when the derived Docker container name would be too long", () => { + expect(() => getContainerName("a".repeat(MAX_AGENT_ID_LENGTH + 1))).toThrow( + /Invalid agent ID/, + ); + }); + + test("rejects an agentId that would exceed the Docker container name limit", () => { + const longId = "a".repeat(MAX_AGENT_ID_LENGTH + 1); + expect(() => getContainerName(longId)).toThrow(/Invalid agent ID/); + }); + }); + + // ------------------------------------------------------------------------- + describe("validateContainerName", () => { + test("accepts Docker-safe names", () => { + expect(() => validateContainerName("milady-abc_123.def")).not.toThrow(); + }); + + test("rejects invalid leading characters", () => { + expect(() => validateContainerName("-bad")).toThrow(/Invalid container name/); }); }); // ------------------------------------------------------------------------- - describe("getVolumePath", () => { + describe("getVolumePath / validateVolumePath", () => { test("returns the correct path for a valid agentId", () => { expect(getVolumePath("abc-123")).toBe("/data/agents/abc-123"); }); @@ -288,8 +390,9 @@ describe("Docker Infrastructure - Pure Functions", () => { expect(() => getVolumePath("agent.1")).toThrow(/Invalid agent ID/); }); - test("throws for an empty agentId", () => { - expect(() => getVolumePath("")).toThrow(/Invalid agent ID/); + test("rejects traversal and repeated separators", () => { + expect(() => validateVolumePath("/data//agents/test")).toThrow(/normalized/); + expect(() => validateVolumePath("/data/../agents/test")).toThrow(/normalized/); }); }); @@ -350,7 +453,7 @@ describe("Docker Infrastructure - Pure Functions", () => { process.env.MILADY_DOCKER_NODES = "node1:10.0.0.1:4"; const first = parseDockerNodes(); const second = parseDockerNodes(); - expect(first).toBe(second); // Same object reference = cache hit + expect(first).toBe(second); }); }); diff --git a/packages/tests/unit/milady-create-routes.test.ts b/packages/tests/unit/milady-create-routes.test.ts index caad2c2f2..e15a3ec21 100644 --- a/packages/tests/unit/milady-create-routes.test.ts +++ b/packages/tests/unit/milady-create-routes.test.ts @@ -68,7 +68,35 @@ mock.module("@/lib/utils/logger", () => ({ })); import { POST as postCompatAgent } from "@/app/api/compat/agents/route"; -import { POST as postV1MiladyAgent } from "@/app/api/v1/milady/agents/route"; +import { + GET as getV1MiladyAgents, + POST as postV1MiladyAgent, +} from "@/app/api/v1/milady/agents/route"; +import { AuthenticationError } from "@/lib/api/errors"; + +describe("Milady v1 agents auth error handling", () => { + beforeEach(() => { + mockRequireAuthOrApiKeyWithOrg.mockReset(); + }); + + test("GET returns 401 instead of 500 for invalid API keys", async () => { + mockRequireAuthOrApiKeyWithOrg.mockRejectedValue( + new AuthenticationError("Invalid or expired API key"), + ); + + const response = await getV1MiladyAgents( + jsonRequest("https://example.com/api/v1/milady/agents", "GET"), + ); + const body = await response.json(); + + expect(response.status).toBe(401); + expect(body).toEqual({ + success: false, + error: "Invalid or expired API key", + code: "authentication_required", + }); + }); +}); describe("Milady create routes reserved config stripping", () => { const savedAutoProvision = process.env.WAIFU_AUTO_PROVISION; diff --git a/packages/tests/unit/milady-sandbox-service.test.ts b/packages/tests/unit/milady-sandbox-service.test.ts index 206114e6f..4982a702c 100644 --- a/packages/tests/unit/milady-sandbox-service.test.ts +++ b/packages/tests/unit/milady-sandbox-service.test.ts @@ -72,7 +72,7 @@ vi.mock("@/lib/services/sandbox-provider", () => ({ createSandboxProvider: vi.fn(), })); -import { MiladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { MiladySandboxService } from "@/lib/services/milady-sandbox"; describe("MiladySandboxService lifecycle guards", () => { beforeEach(() => { diff --git a/packages/tests/unit/milaidy-sandbox-bridge-security.test.ts b/packages/tests/unit/milaidy-sandbox-bridge-security.test.ts index bb4dd4102..8dc0a0aca 100644 --- a/packages/tests/unit/milaidy-sandbox-bridge-security.test.ts +++ b/packages/tests/unit/milaidy-sandbox-bridge-security.test.ts @@ -62,7 +62,7 @@ mock.module("@/lib/utils/logger", () => ({ }, })); -import { MiladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { MiladySandboxService } from "@/lib/services/milady-sandbox"; describe("MiladySandboxService bridge SSRF guards", () => { const originalFetch = globalThis.fetch; @@ -295,48 +295,6 @@ describe("MiladySandboxService bridge SSRF guards", () => { }); }); - test("allows legacy private bridge URLs when only the docker sandbox_id remains", async () => { - mockFindRunningSandbox.mockResolvedValue({ - id: "agent-1", - sandbox_id: "milady-11111111-2222-4333-8444-555555555555", - bridge_url: "http://100.64.0.10:31337", - node_id: null, - bridge_port: null, - headscale_ip: null, - status: "running", - }); - fetchMock.mockResolvedValue( - new Response( - JSON.stringify({ - jsonrpc: "2.0", - id: "req-legacy", - result: { ok: true }, - }), - { - status: 200, - headers: { "Content-Type": "application/json" }, - }, - ), - ); - - const result = await service.bridge("agent-1", "org-1", { - jsonrpc: "2.0", - id: "req-legacy", - method: "status.get", - }); - - expect(mockAssertSafeOutboundUrl).not.toHaveBeenCalled(); - expect(fetchMock).toHaveBeenCalledWith( - "http://100.64.0.10:31337/bridge", - expect.objectContaining({ method: "POST" }), - ); - expect(result).toEqual({ - jsonrpc: "2.0", - id: "req-legacy", - result: { ok: true }, - }); - }); - test("keeps rejecting private bridge URLs without enough docker-managed evidence", async () => { mockFindRunningSandbox.mockResolvedValue({ id: "agent-1", diff --git a/packages/tests/unit/milaidy-sandbox-service-followups.test.ts b/packages/tests/unit/milaidy-sandbox-service-followups.test.ts index b2102bd55..ad35d0263 100644 --- a/packages/tests/unit/milaidy-sandbox-service-followups.test.ts +++ b/packages/tests/unit/milaidy-sandbox-service-followups.test.ts @@ -75,7 +75,7 @@ mock.module("@/lib/utils/logger", () => ({ }, })); -import { MiladySandboxService } from "@/lib/services/milaidy-sandbox"; +import { MiladySandboxService } from "@/lib/services/milady-sandbox"; describe("MiladySandboxService follow-ups", () => { const provider = { diff --git a/packages/tests/unit/provisioning-jobs.test.ts b/packages/tests/unit/provisioning-jobs.test.ts index fb700e72e..8cef304a6 100644 --- a/packages/tests/unit/provisioning-jobs.test.ts +++ b/packages/tests/unit/provisioning-jobs.test.ts @@ -59,6 +59,10 @@ vi.mock("@/lib/services/milaidy-sandbox", () => ({ miladySandboxService: mockMiladySandboxService, })); +vi.mock("@/lib/services/milady-sandbox", () => ({ + miladySandboxService: mockMiladySandboxService, +})); + vi.mock("@/lib/security/outbound-url", () => ({ assertSafeOutboundUrl: mockAssertSafeOutboundUrl, }));