> ## Documentation Index
> Fetch the complete documentation index at: https://docs.powabase.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture

> Understand the control plane / data plane split, per-project isolation, authentication model, and database schemas.

<Note>
  New to Powabase? Start with [Platform overview](/concepts/platform-overview) and [Auth & Connection](/guides/auth-connection) for the basics, then return here for the infrastructure details.
</Note>

## Control Plane vs Data Plane

The platform uses a two-tier architecture. A single shared Control Plane manages organizations, projects, users, and authentication. It provisions an isolated Data Plane for each project, with its own Postgres database, API gateway, auth service, storage, and AI service.

<Frame caption="Two tiers: a shared control plane for management, and per-project data planes for runtime traffic">
  <img src="https://mintcdn.com/powabase/B-6sRgQRCSKyNrPg/diagrams/architecture-overview.svg?fit=max&auto=format&n=B-6sRgQRCSKyNrPg&q=85&s=9fcf6f1220feb602b0c5c85da2c3738b" alt="Architecture diagram: Browser → Next.js Frontend → Control Plane API for management; runtime requests go Browser → Per-Project Kong → Per-Project Stack (GoTrue Auth, PostgREST, Project Service, Postgres with pgvector, Storage, Realtime). The control plane provisions and manages projects but is not in the data-plane path for runtime traffic." width="800" height="280" data-path="diagrams/architecture-overview.svg" />
</Frame>

## Per-Project Isolation

Each project gets its own infrastructure stack in its own Kubernetes namespace (`project-{ref}`). One project's data, users, and configuration are fully separate from another's; projects can't see each other's databases, storage buckets, or API keys. Isolation is enforced at three layers:

* **Compute:** each project runs its own Postgres StatefulSet (defaults: 400m CPU, 1Gi memory, 10Gi gp3 storage, overridable per project), its own GoTrue auth pod, its own Storage and Realtime pods, and its own Project Service worker.
* **Network:** a `project-isolation` NetworkPolicy on the namespace allows ingress only from `shared-services` (where Kong and PgBouncer live) and `control-plane` (the management tier). Cross-project pod-to-pod traffic is blocked.
* **Storage:** the Storage API is configured with a per-project S3 prefix; even though buckets share an underlying S3 backend, projects can only access object paths under their own prefix.

## API Authentication

Every API request requires two headers: an apikey header and a Bearer token in the Authorization header, both set to the same key. Powabase ships two keys per project, both surfaced in the Studio's Connect modal. The Service Role (Secret) Key gives full access and bypasses Row Level Security, so use it for server-side calls only. The Anon (Publishable) Key respects RLS policies and is safe to embed in browsers and mobile clients.

<Warning>
  **Never expose the Service Role key**

  The Service Role (Secret) Key bypasses all Row Level Security policies. Only use it in server-side code. For client-side applications, use the Anon (Publishable) Key with appropriate RLS policies. The Connect modal also exposes JWT Secret and Database URL; both must stay server-side.
</Warning>

Both keys live in the Connect modal in the Studio. Click the Connect button in your project header (or append ?showConnect=true to any project URL) to copy the Project URL, Anon (Publishable) Key, Service Role (Secret) Key, JWT Secret, Database URL, and pre-built Postgres connection strings.

## Request Routing

When you make an API call to your project URL (`<ref>.p.powabase.ai`), the request hits the per-project Kong gateway directly; the control plane is **not** in the data-plane path. Kong matches the project hostname and routes `/api/*` paths to the Project Service (AI features), `/auth/v1/*` to GoTrue (authentication), `/rest/v1/*` to PostgREST (direct database access), `/storage/v1/*` to the Storage API, and `/realtime/v1/*` to the Realtime service.

The wildcard ALB ingress that fronts every project sits in front of Kong with an **idle timeout of 900 seconds**, long enough that agent and workflow SSE streams (which can run for minutes) won't get cut by an intermediary. CORS is permissive by default at the Kong layer (`origins: ["*"]`, `credentials: true`), so browsers can call any project URL directly with the Anon (Publishable) Key without you wiring up an allowlist. If you need a narrower posture for compliance, the gateway config is customizable on self-hosted deployments.

## Database Schemas

Each project database has four user-visible schemas. The `ai` schema is managed by the platform and stores all AI-related data. The `public` schema is yours to use for application data. The `auth` and `storage` schemas are managed by GoTrue and the Storage API respectively.

| Schema    | Owner       | Purpose                                                                         | PostgREST exposed?         |
| --------- | ----------- | ------------------------------------------------------------------------------- | -------------------------- |
| `public`  | You         | Your application tables                                                         | Yes                        |
| `ai`      | Platform    | Sources, knowledge bases, chunks, embeddings, agents, sessions, runs, workflows | Yes (read+write under RLS) |
| `storage` | Storage API | File metadata, bucket configuration                                             | Yes                        |
| `auth`    | GoTrue      | User accounts, sessions, tokens                                                 | No (use the Auth API)      |

PostgREST is configured to expose `public`, `ai`, `storage`, and `graphql_public` schemas. That means you can query, filter, and (with the right RLS posture) write to `ai.*` tables directly via `/rest/v1/*`. This is useful for custom dashboards over agent runs, bulk operations on sources, or any case where the typed `/api/*` endpoints don't cover what you need. Treat `ai.*` writes carefully: the platform's own services assume the schema's invariants, so prefer the typed endpoints for state-changing operations on agent / KB / workflow tables.

## Next Steps

<CardGroup cols={2}>
  <Card title="Auth & Connection" href="/guides/auth-connection">
    Open the Connect modal, pick the right key, and make your first request.
  </Card>

  <Card title="Sources & Extraction" href="/concepts/sources-extraction">
    Learn how document ingestion works.
  </Card>

  <Card title="Database Access" href="/concepts/database-access">
    Query your project database via PostgREST.
  </Card>
</CardGroup>
