Design a table.
Ship an API.
Core DB reads the Postgres schema you already have and serves it as a versioned REST API — scoped keys, filters, pagination and an OpenAPI document generated from the live catalog.
Installation is a single page: it checks the connection, runs the control-plane migrations, seeds roles, creates the owner account and writes a lock file.
Tables
- products 6
- orders 4
- customers 5
products · 3 rows
| id | title | price | in_stock |
|---|---|---|---|
| 1 | Field notebook | 18.00 | true |
| 2 | Brass pen | 42.50 | false |
| 3 | Desk mat | 29.00 | true |
$ curl -H "X-CoreDB-Key: $COREDB_KEY" \
example.com/api/v1/products?sort=-id&limit=3
200 OK 14 ms
{ "id": 3, "title": "Desk mat", "price": 29.0, "in_stock": true }
- Database
- PostgreSQL 14+
- Runtime
- PHP 8.3+
- Isolation
- Schema per project
- Orchestration
- None required
Three moves, and the endpoint is live.
Nothing to generate, nothing to deploy in between. The table, the key and the request are the whole workflow.
-
Define the table
Database Studio writes real DDL: an identity primary key, typed columns, constraints and an index. Point it at a schema you already own and it reads the catalog instead.
products(id, title, price, in_stock)
-
Issue a key
Abilities per resource, an expiry, a rate limit. The secret is hashed once, shown once, and can be revoked without touching the data.
X-CoreDB-Key: cdb_••••••••7Hg
-
Call the endpoint
Filter, sort, search, paginate, project. Every value in the response is typed from the live catalog rather than guessed by the driver.
GET /api/v1/products
One query language for every table.
Parameters are validated against the catalog before they reach SQL: an unknown column or operator comes back as a 422 with the allowed values listed.
- filter[price][gte]=10
- eq · ne · gt · gte · lt · lte · like · ilike · in · nin · null · notnull
- filter[status]=new
- Shorthand for equals; hand it a list instead of an operator and you get in.
- search=notebook
- Case-insensitive across string, uuid and json columns.
- sort=-created_at,id
- Minus prefix for descending. Up to three columns.
- select=id,title,price
- Fetch only these columns. Up to fifty.
- limit=25&page=2
- One to a hundred per page. count=estimated skips the exact total.
curl -G https://example.com/api/v1/products \
-H "X-CoreDB-Key: $COREDB_KEY" \
--data-urlencode "filter[price][gte]=10" \
--data-urlencode "filter[in_stock]=true" \
--data-urlencode "search=note" \
--data-urlencode "sort=-created_at" \
--data-urlencode "select=id,title,price" \
--data-urlencode "limit=25"
{
"data": [
{ "id": 1, "title": "Field notebook", "price": 18.0 }
],
"meta": {
"pagination": { "page": 1, "per_page": 25, "total": 1,
"total_pages": 1, "has_more": false,
"count": "exact" }
}
}
An OpenAPI 3.1 document for every resource is served at /api/v1/openapi.json.
A schema per project.
Isolation is structural, not a where clause. A key issued for one project cannot resolve a table in another, and every identifier is quoted rather than interpolated.
Reserved schema and table names are rejected at creation time, and the control schema itself is never reachable through the API.
Projects, members, keys and every schema change are written to an append-only audit log with the request id that caused them.
No Docker. No Redis.
No queue workers.
No root.
Core DB deploys the way a PHP application deploys: upload the release, point the web root at public/, open the installer. The asset build is committed, so the host never needs Node.
- PHP 8.3 with the pdo_pgsql driver
- PostgreSQL 14 or newer, one database
- A web root pointed at public/
- Writable storage/ and .env
# 1. release goes on the server, web root is public/
$ unzip coredb.zip -d ~/public_html
# 2. database credentials
$ vi .env
# 3. migrations, roles, owner account, lock file
$ open https://example.com/install
6 steps · 454 ms installer disabled
Control schema
coredb
Project schema
proj_<slug>
Key header
X-CoreDB-Key
Point it at a database and press Install.
From there it is a table, a key, a request.