@centia-io/mcp-server 1.0.15 → 1.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +72 -0
- package/centia-api.json +4 -4
- package/package.json +5 -3
- package/skills/README.md +29 -0
- package/skills/centia-auth-model/SKILL.md +88 -0
- package/skills/centia-delivery/SKILL.md +74 -0
- package/skills/centia-feature/SKILL.md +50 -0
- package/skills/centia-file-import/SKILL.md +54 -0
- package/skills/centia-json-rpc/SKILL.md +86 -0
- package/skills/centia-keyvalue/SKILL.md +52 -0
- package/skills/centia-map-styling/SKILL.md +100 -0
- package/skills/centia-openapi-docs/SKILL.md +55 -0
- package/skills/centia-privileges/SKILL.md +66 -0
- package/skills/centia-provisioning/SKILL.md +105 -0
- package/skills/centia-realtime/SKILL.md +186 -0
- package/skills/centia-runtime-sdk/SKILL.md +98 -0
- package/skills/centia-types-formats/SKILL.md +74 -0
- package/skills/danish-search/SKILL.md +224 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: centia-openapi-docs
|
|
3
|
+
description: OpenAPI and documentation fallback policy for Centia BaaS, including source priority, local caching workflow, and rules for docs-backed endpoint usage.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# OpenAPI and Docs Policy
|
|
7
|
+
|
|
8
|
+
Use this skill when MCP/SDK are insufficient and HTTP contracts are needed.
|
|
9
|
+
|
|
10
|
+
## Source priority
|
|
11
|
+
|
|
12
|
+
Use this order:
|
|
13
|
+
|
|
14
|
+
1. Local `openapi/openapi.json`
|
|
15
|
+
2. URL from `CENTIA_OPENAPI_URL`
|
|
16
|
+
3. User-provided OpenAPI JSON
|
|
17
|
+
|
|
18
|
+
OpenAPI is the contract for described endpoints.
|
|
19
|
+
|
|
20
|
+
## Fetch pattern
|
|
21
|
+
|
|
22
|
+
If allowed and needed, fetch into local cache:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
mkdir -p openapi
|
|
26
|
+
if [ -n "$CENTIA_OPENAPI_URL" ] && [ ! -f "openapi/openapi.fetched.json" ]; then
|
|
27
|
+
curl -fsSL -H "Authorization: Bearer $CENTIA_ACCESS_TOKEN" "$CENTIA_OPENAPI_URL" -o openapi/openapi.fetched.json
|
|
28
|
+
fi
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Documentation fallback
|
|
32
|
+
|
|
33
|
+
Primary docs:
|
|
34
|
+
|
|
35
|
+
- `https://centia.io/docs/intro`
|
|
36
|
+
|
|
37
|
+
Optional local vendor mirror:
|
|
38
|
+
|
|
39
|
+
```sh
|
|
40
|
+
mkdir -p vendor
|
|
41
|
+
if [ ! -d "vendor/centia-docs/docs" ]; then
|
|
42
|
+
git clone --depth 1 --filter=blob:none --sparse https://github.com/centia-io/website.git vendor/centia-docs
|
|
43
|
+
cd vendor/centia-docs
|
|
44
|
+
git sparse-checkout set docs
|
|
45
|
+
cd ../..
|
|
46
|
+
fi
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
If clone fails (auth/network), use web docs directly.
|
|
50
|
+
|
|
51
|
+
## Rules
|
|
52
|
+
|
|
53
|
+
- Use docs-backed endpoints only when fully specified.
|
|
54
|
+
- Do not invent undocumented payloads.
|
|
55
|
+
- Document source URL for each HTTP fallback implementation.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: centia-privileges
|
|
3
|
+
description: Sub-user privileges and rights inheritance for Centia BaaS, including per-table privilege grants, group membership via user_group, transitive inheritance where the highest privilege wins, schema ownership, and layer authentication levels.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Privileges and Rights Inheritance
|
|
7
|
+
|
|
8
|
+
Use this skill when granting sub-users access to tables/layers, managing groups, or reasoning about which effective privilege a sub-user ends up with.
|
|
9
|
+
|
|
10
|
+
## Model
|
|
11
|
+
|
|
12
|
+
- Privileges are **per relation** (per `schema.table`), not schema-wide grants.
|
|
13
|
+
- A grant maps a sub-user *or group* name to a level: `none` | `read` | `write` (API values; internally ranked none=0 < read=1 < read/write=2).
|
|
14
|
+
- **Groups are themselves sub-users.** There is no separate group entity or membership endpoint — any sub-user name can act as a group.
|
|
15
|
+
|
|
16
|
+
## Endpoints and MCP tools
|
|
17
|
+
|
|
18
|
+
| Task | Route | MCP tool |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Read grants for a table | `GET /api/v4/schemas/{s}/tables/{t}/privileges` | `getPrivileges` |
|
|
21
|
+
| Set grants | `PATCH .../privileges` with `{subuser, privilege}` (one or array) | `patchPrivileges` |
|
|
22
|
+
| Group membership | `user_group` field on `POST/PATCH/GET /api/v4/users` | `postUser` / `patchUser` / `getUser` |
|
|
23
|
+
|
|
24
|
+
`user_group` is a **JSON array of group names** (e.g. `["editors", "gis_admins"]`). A JSON-array *string* is accepted for back-compat; `null` clears membership; GET returns a decoded array (or null).
|
|
25
|
+
|
|
26
|
+
## Inheritance — highest privilege wins
|
|
27
|
+
|
|
28
|
+
Evaluation is fully server-side:
|
|
29
|
+
|
|
30
|
+
1. The full inheritance chain is resolved: the sub-user plus all ancestor groups, transitively (groups can belong to groups; breadth-first, diamond/cycle-safe).
|
|
31
|
+
2. Effective privilege on a table = the **highest** level found among the sub-user's own grant and every group in the chain.
|
|
32
|
+
|
|
33
|
+
Example: `joe` has `read` directly, is member of `editors` which has `write` → joe's effective privilege is `write`.
|
|
34
|
+
|
|
35
|
+
This applies to token auth, Basic-auth WFS/OWS, and SQL authorization alike.
|
|
36
|
+
|
|
37
|
+
## Schema ownership
|
|
38
|
+
|
|
39
|
+
A sub-user is **owner** of a schema if their own name — or any group in their transitive chain — equals the schema name. Owners bypass all privilege checks (full read/write on every layer in that schema). This is how schema-wide access is inherited: put the sub-user (directly or via intermediate groups) in a group named after the schema.
|
|
40
|
+
|
|
41
|
+
## Layer authentication levels
|
|
42
|
+
|
|
43
|
+
Orthogonal to per-user grants, each layer has an `authentication` level (capitalized values) deciding *when* grants are enforced:
|
|
44
|
+
|
|
45
|
+
| Level | Anonymous | Authenticated sub-user |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `Read/write` | No read, no write (403) | Read requires privilege ≠ `none`; write requires `write` (owner bypasses) |
|
|
48
|
+
| `Write` | Read allowed | Read allowed for all; write requires `write` (owner bypasses) |
|
|
49
|
+
| `Read` / `None` | Read open | No per-user enforcement on read |
|
|
50
|
+
|
|
51
|
+
OGC endpoints are merged, database-qualified routes (`/api/v4/ows/schema/{schema}/database/{database}`, `/api/v4/wfs/schema/{schema}/database/{database}/srs/...`; the old token-only variants are removed). Auth is decided per request: Bearer token (must match `{database}`, else 401 — never a silent anonymous downgrade), anonymous for publicly readable layers, or an HTTP Basic challenge for protected layers. WFS-T always requires credentials with `write`.
|
|
52
|
+
|
|
53
|
+
## Common mistakes
|
|
54
|
+
|
|
55
|
+
| Mistake | Reality |
|
|
56
|
+
|---|---|
|
|
57
|
+
| Expecting a schema-wide grant endpoint | Grants are per table; schema-wide access only via ownership (group named = schema) |
|
|
58
|
+
| `PATCH /users/{name}` without `default_user` | The flag is **reset to false** when omitted — always send it explicitly |
|
|
59
|
+
| Promoting a new default user first | Only one default user per parent db (partial unique index) → 23505; demote the old one first |
|
|
60
|
+
| Treating groups as a separate concept | Groups are sub-users; membership lives on the member's `user_group` field |
|
|
61
|
+
| Assuming grants alone control access | The layer's `authentication` level decides whether grants are even consulted |
|
|
62
|
+
| Expecting `200` from `patchPrivileges`/`patchUser` | Provisioning PATCH returns `303 See Other` (see `centia-provisioning`) |
|
|
63
|
+
|
|
64
|
+
Spec quirk: the `Privilege` schema's `required` list names `privileges` (plural) but the actual property is singular `privilege` — use the singular key.
|
|
65
|
+
|
|
66
|
+
Auth context selection (tokens, OAuth, service vs browser) is covered in `centia-auth-model`.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: centia-provisioning
|
|
3
|
+
description: Provisioning and schema lifecycle guidance for Centia BaaS, including schema/table/column/index/constraint operations, migration structure, SQL API limits, and destructive-change safety.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Provisioning Rules
|
|
7
|
+
|
|
8
|
+
Use this skill for schema changes, migrations, seed data, and platform setup.
|
|
9
|
+
|
|
10
|
+
## Scope
|
|
11
|
+
|
|
12
|
+
Provisioning includes:
|
|
13
|
+
|
|
14
|
+
- schemas
|
|
15
|
+
- tables
|
|
16
|
+
- columns
|
|
17
|
+
- indexes
|
|
18
|
+
- constraints
|
|
19
|
+
- policies
|
|
20
|
+
- relations
|
|
21
|
+
- relation metadata (titles, descriptions, tags, field aliases)
|
|
22
|
+
- seed data
|
|
23
|
+
- migrations
|
|
24
|
+
|
|
25
|
+
Provisioning is not runtime logic.
|
|
26
|
+
|
|
27
|
+
## Hard rules
|
|
28
|
+
|
|
29
|
+
- Preferred execution order: MCP tools, then OpenAPI, then docs-backed endpoints.
|
|
30
|
+
- Runtime app code must never call provisioning endpoints.
|
|
31
|
+
- Schema changes happen only in provisioning/codegen flows.
|
|
32
|
+
|
|
33
|
+
## PATCH returns 303 See Other
|
|
34
|
+
|
|
35
|
+
All provisioning PATCH endpoints return `303 See Other` with a `Location` header pointing to the updated resource. HTTP clients that automatically follow redirects will receive an unexpected `200 OK` from the subsequent GET instead of the expected `303`.
|
|
36
|
+
|
|
37
|
+
External clients **must** disable automatic redirect-following:
|
|
38
|
+
|
|
39
|
+
- `fetch`: `{ redirect: 'manual' }` in `RequestInit`
|
|
40
|
+
- `axios`: `{ maxRedirects: 0 }` (catch the resulting error)
|
|
41
|
+
- `curl`: omit the `-L` flag
|
|
42
|
+
- Postman: disable "Automatically follow redirects" in Settings
|
|
43
|
+
|
|
44
|
+
The SDK already handles this via `redirect: 'manual'` in all fetch calls.
|
|
45
|
+
|
|
46
|
+
## SQL dialect and API limits
|
|
47
|
+
|
|
48
|
+
- SQL dialect is PostgreSQL with PostGIS enabled.
|
|
49
|
+
- SQL API accepts only: `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `MERGE`.
|
|
50
|
+
- DDL and transaction control are not accepted by SQL API; use provisioning tools.
|
|
51
|
+
|
|
52
|
+
## Provisioning output structure
|
|
53
|
+
|
|
54
|
+
Store artifacts in:
|
|
55
|
+
|
|
56
|
+
- `provision/`
|
|
57
|
+
- `migrations/`
|
|
58
|
+
- `schema/plan.json`
|
|
59
|
+
- `schema/plan.md`
|
|
60
|
+
|
|
61
|
+
Example runners:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npx tsx provision/apply.ts
|
|
65
|
+
npx tsx migrations/001_create_tables.ts
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Safety for destructive operations
|
|
69
|
+
|
|
70
|
+
Before destructive operations, present:
|
|
71
|
+
|
|
72
|
+
- method
|
|
73
|
+
- MCP tool or endpoint
|
|
74
|
+
- purpose
|
|
75
|
+
|
|
76
|
+
Proceed only with explicit user confirmation.
|
|
77
|
+
|
|
78
|
+
Destructive includes:
|
|
79
|
+
|
|
80
|
+
- `DROP TABLE`
|
|
81
|
+
- `TRUNCATE`
|
|
82
|
+
- column deletion
|
|
83
|
+
- policy overwrite
|
|
84
|
+
- `DELETE` without safe filter
|
|
85
|
+
- `deleteTable`, `deleteColumn`, `deleteSchema`, `deleteConstraint`, `deleteIndex`
|
|
86
|
+
|
|
87
|
+
## Project structure target
|
|
88
|
+
|
|
89
|
+
```txt
|
|
90
|
+
src/
|
|
91
|
+
baas/
|
|
92
|
+
client.ts
|
|
93
|
+
http.ts
|
|
94
|
+
types.ts
|
|
95
|
+
features/
|
|
96
|
+
|
|
97
|
+
provision/
|
|
98
|
+
schema/
|
|
99
|
+
migrations/
|
|
100
|
+
docs/
|
|
101
|
+
|
|
102
|
+
.env.example
|
|
103
|
+
openapi/
|
|
104
|
+
vendor/
|
|
105
|
+
```
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: centia-realtime
|
|
3
|
+
description: Realtime events via WebSocket for Centia BaaS using @centia-io/sdk, including broadcast connections, subscriptions with shapes, event handling, and enabling table-level change events.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Realtime Events
|
|
7
|
+
|
|
8
|
+
Use this skill for WebSocket-based realtime database change events.
|
|
9
|
+
|
|
10
|
+
## Hard rules
|
|
11
|
+
|
|
12
|
+
- Use `Ws` from `@centia-io/sdk` for all realtime connections.
|
|
13
|
+
- Do not implement raw WebSocket connections in runtime app code.
|
|
14
|
+
- Never hardcode tokens in connection URLs.
|
|
15
|
+
- Always use `encodeURIComponent` if building URLs manually (the SDK handles this).
|
|
16
|
+
|
|
17
|
+
## Architecture
|
|
18
|
+
|
|
19
|
+
- WebSocket endpoint: `wss://event.centia.io/`
|
|
20
|
+
- Auth: JWT token passed as query parameter.
|
|
21
|
+
- Server validates the token and enforces per-relation access for sub-users.
|
|
22
|
+
- Events are batched (10 notifications or 2 seconds, whichever comes first).
|
|
23
|
+
|
|
24
|
+
## SDK bootstrap
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { Ws } from '@centia-io/sdk';
|
|
28
|
+
|
|
29
|
+
const ws = new Ws({
|
|
30
|
+
host: 'wss://event.centia.io',
|
|
31
|
+
rels: 'schema.table1,schema.table2', // optional: broadcast filter
|
|
32
|
+
reconnect: true, // default: true
|
|
33
|
+
reconnectInterval: 3000, // default: 3000ms
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
ws.connect();
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Options
|
|
40
|
+
|
|
41
|
+
| Option | Type | Required | Default | Description |
|
|
42
|
+
|---|---|---|---|---|
|
|
43
|
+
| `host` | string | yes | - | WebSocket endpoint URL |
|
|
44
|
+
| `rels` | string | no | - | Comma-separated relations for broadcast filtering |
|
|
45
|
+
| `wsClient` | unknown | no | `WebSocket` | Custom WebSocket implementation (e.g. `ws` for Node) |
|
|
46
|
+
| `reconnect` | boolean | no | `true` | Auto-reconnect on disconnect |
|
|
47
|
+
| `reconnectInterval` | number | no | `3000` | Reconnect delay in ms |
|
|
48
|
+
|
|
49
|
+
## Event listeners
|
|
50
|
+
|
|
51
|
+
The `Ws` class uses a typed event system. `on()` returns an unsubscribe function.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
ws.on('open', () => { /* connected */ });
|
|
55
|
+
|
|
56
|
+
ws.on('batch', (msg) => {
|
|
57
|
+
// msg.db, msg.batch
|
|
58
|
+
for (const [rel, data] of Object.entries(msg.batch[msg.db])) {
|
|
59
|
+
if (data.INSERT) { /* handle inserts */ }
|
|
60
|
+
if (data.UPDATE) { /* handle updates */ }
|
|
61
|
+
if (data.DELETE) { /* handle deletes */ }
|
|
62
|
+
if (data.full_data) { /* full row data */ }
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
ws.on('subscription_ack', (msg) => {
|
|
67
|
+
// msg.id — matches the subscription id
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
ws.on('error', (msg) => {
|
|
71
|
+
// msg.error: 'missing_token' | 'invalid_token' | 'not_allowed'
|
|
72
|
+
// msg.message: human-readable
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
ws.on('close', ({ code, reason }) => { /* disconnected */ });
|
|
76
|
+
|
|
77
|
+
// Unsubscribe
|
|
78
|
+
const unsub = ws.on('batch', handler);
|
|
79
|
+
unsub(); // removes listener
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Subscriptions with shapes
|
|
83
|
+
|
|
84
|
+
Subscriptions provide server-side filtering so the client only receives matching events. Send after the connection is open.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
ws.on('open', () => {
|
|
88
|
+
ws.subscribe({
|
|
89
|
+
id: 'active-users',
|
|
90
|
+
schema: 'public',
|
|
91
|
+
rel: 'users',
|
|
92
|
+
where: "status = 'active' AND age >= 18",
|
|
93
|
+
columns: 'id,name,email',
|
|
94
|
+
op: 'UPDATE',
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Subscription fields
|
|
100
|
+
|
|
101
|
+
| Field | Type | Required | Description |
|
|
102
|
+
|---|---|---|---|
|
|
103
|
+
| `id` | string | yes | Client-chosen identifier |
|
|
104
|
+
| `schema` | string | yes | Database schema name |
|
|
105
|
+
| `rel` | string | yes | Table name |
|
|
106
|
+
| `where` | string | no | SQL-like filter on `full_data` rows |
|
|
107
|
+
| `columns` | string | no | Comma-separated column projection |
|
|
108
|
+
| `op` | string | no | Limit to `INSERT`, `UPDATE`, or `DELETE` |
|
|
109
|
+
|
|
110
|
+
### Where syntax
|
|
111
|
+
|
|
112
|
+
Supports: `=`, `!=`, `<>`, `>`, `<`, `>=`, `<=`, `AND`, `OR`, parentheses, `IN`/`NOT IN`, `LIKE`/`ILIKE`.
|
|
113
|
+
|
|
114
|
+
### Multiple subscriptions
|
|
115
|
+
|
|
116
|
+
A single client can register multiple subscriptions:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
ws.subscribe({ id: 'sub1', schema: 'public', rel: 'orders' });
|
|
120
|
+
ws.subscribe({ id: 'sub2', schema: 'public', rel: 'users', op: 'INSERT' });
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Enabling table events (provisioning)
|
|
124
|
+
|
|
125
|
+
To emit change events for a table, enable `emit_events` via the events endpoint. This is a provisioning operation.
|
|
126
|
+
|
|
127
|
+
Use MCP tool `postEvents` or HTTP:
|
|
128
|
+
|
|
129
|
+
```http
|
|
130
|
+
PATCH https://api.centia.io/api/v4/schemas/{schema}/tables/{table}/events
|
|
131
|
+
Content-Type: application/json
|
|
132
|
+
Authorization: Bearer <token>
|
|
133
|
+
|
|
134
|
+
{
|
|
135
|
+
"emit_events": true
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Broadcast vs subscriptions
|
|
140
|
+
|
|
141
|
+
| Feature | Broadcast (legacy) | Subscriptions |
|
|
142
|
+
|---|---|---|
|
|
143
|
+
| Setup | Pass `rels` in constructor | Call `ws.subscribe()` after connect |
|
|
144
|
+
| Filtering | Client-side only | Server-side (where, columns, op) |
|
|
145
|
+
| Use case | Simple monitoring | Production apps needing efficiency |
|
|
146
|
+
|
|
147
|
+
Prefer subscriptions for new code. Broadcast is supported but sends all events for matched relations.
|
|
148
|
+
|
|
149
|
+
## Node.js usage
|
|
150
|
+
|
|
151
|
+
Pass a WebSocket implementation for non-browser environments:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
import WebSocket from 'ws';
|
|
155
|
+
import { Ws } from '@centia-io/sdk';
|
|
156
|
+
|
|
157
|
+
const ws = new Ws({
|
|
158
|
+
host: 'wss://event.centia.io',
|
|
159
|
+
wsClient: WebSocket,
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Lifecycle
|
|
164
|
+
|
|
165
|
+
```ts
|
|
166
|
+
ws.connect(); // start connection
|
|
167
|
+
ws.connected; // boolean — check state
|
|
168
|
+
ws.send('SELECT 1'); // send raw message
|
|
169
|
+
ws.disconnect(); // close and stop reconnecting
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Exported types
|
|
173
|
+
|
|
174
|
+
All types are available from `@centia-io/sdk`:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import type {
|
|
178
|
+
WsOptions,
|
|
179
|
+
WsMessage,
|
|
180
|
+
BatchMessage,
|
|
181
|
+
TableBatch,
|
|
182
|
+
SubscriptionAckMessage,
|
|
183
|
+
WsErrorMessage,
|
|
184
|
+
SubscriptionRequest,
|
|
185
|
+
} from '@centia-io/sdk';
|
|
186
|
+
```
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: centia-runtime-sdk
|
|
3
|
+
description: Runtime application guidance for Centia BaaS using @centia-io/sdk, including SDK client initialization, GraphQL/JSON-RPC/SQL method selection, HTTP fallback boundaries, and frontend tooling defaults.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Runtime SDK Rules
|
|
7
|
+
|
|
8
|
+
Use this skill for JS/TS runtime application work.
|
|
9
|
+
|
|
10
|
+
## Hard rules
|
|
11
|
+
|
|
12
|
+
- Use `@centia-io/sdk` for runtime access.
|
|
13
|
+
- Do not use direct REST calls in runtime app code.
|
|
14
|
+
- If SDK lacks needed functionality, implement a documented fallback in `src/baas/http.ts`.
|
|
15
|
+
|
|
16
|
+
## Query method selection
|
|
17
|
+
|
|
18
|
+
Choose in this order:
|
|
19
|
+
|
|
20
|
+
1. GraphQL (`Gql`) for straightforward CRUD, filtering, pagination, nested relations.
|
|
21
|
+
2. JSON-RPC (`createApi<T>()` or `Rpc`) for reusable complex SQL (joins, CTEs, aggregations).
|
|
22
|
+
3. SQL (`Sql` and `createSqlBuilder`) as last resort for runtime-dynamic queries.
|
|
23
|
+
|
|
24
|
+
## SDK bootstrap
|
|
25
|
+
|
|
26
|
+
Create shared clients in `src/baas/client.ts`.
|
|
27
|
+
|
|
28
|
+
Prefer exports:
|
|
29
|
+
|
|
30
|
+
- `Sql`
|
|
31
|
+
- `Rpc`
|
|
32
|
+
- `Gql`
|
|
33
|
+
- `createApi`
|
|
34
|
+
- `createSqlBuilder`
|
|
35
|
+
- `CodeFlow`, `PasswordFlow`, `SignUp` (by runtime context)
|
|
36
|
+
|
|
37
|
+
## GraphQL notes
|
|
38
|
+
|
|
39
|
+
Auto-generated naming conventions by table:
|
|
40
|
+
|
|
41
|
+
- Select: `get[TableName]`
|
|
42
|
+
- Insert: `insert[TableName]`
|
|
43
|
+
- Update: `update[TableName]`
|
|
44
|
+
- Delete: `delete[TableName]`
|
|
45
|
+
|
|
46
|
+
Filtering operators:
|
|
47
|
+
|
|
48
|
+
- Comparison: `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `in`, `like`, `ilike`
|
|
49
|
+
- Logical: `and`, `or`, `not`
|
|
50
|
+
|
|
51
|
+
## SQL builder pattern
|
|
52
|
+
|
|
53
|
+
Prefer typed SQL builder for dynamic conditions:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const b = createSqlBuilder(schema);
|
|
57
|
+
let req = b.table("logs").select(["id", "message"]);
|
|
58
|
+
if (level) req = req.andWhere({ level });
|
|
59
|
+
if (since) req = req.andWhere({ created_at: { gte: since } });
|
|
60
|
+
const rows = (await sql.exec(req.toSql())).data;
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## HTTP fallback layer
|
|
64
|
+
|
|
65
|
+
File: `src/baas/http.ts`
|
|
66
|
+
|
|
67
|
+
Rules:
|
|
68
|
+
|
|
69
|
+
- Centralize headers.
|
|
70
|
+
- Use typed payloads.
|
|
71
|
+
- Prevent token leakage.
|
|
72
|
+
- Add source comments for each fallback endpoint.
|
|
73
|
+
|
|
74
|
+
Comment template:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
// Fallback to HTTP: not supported in @centia-io/sdk yet
|
|
78
|
+
// Source: https://centia.io/docs/...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Web app defaults when scaffolding
|
|
82
|
+
|
|
83
|
+
Use these defaults only if project has no existing conventions:
|
|
84
|
+
|
|
85
|
+
- Package manager: `pnpm`
|
|
86
|
+
- Build tool: `Vite`
|
|
87
|
+
- Framework: React + TypeScript
|
|
88
|
+
- Styling: Tailwind CSS
|
|
89
|
+
- Routing: React Router
|
|
90
|
+
|
|
91
|
+
Do not mix package managers.
|
|
92
|
+
|
|
93
|
+
## Code quality
|
|
94
|
+
|
|
95
|
+
- Prefer TypeScript strict mode.
|
|
96
|
+
- Centralize schema and table names.
|
|
97
|
+
- Avoid magic strings.
|
|
98
|
+
- Handle API errors explicitly.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: centia-types-formats
|
|
3
|
+
description: PostgreSQL and PostGIS type guidance for Centia BaaS, including SQL parameter casts, type_hints, type_formats, and supported output formats for SQL and JSON-RPC responses.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Types and Formats
|
|
7
|
+
|
|
8
|
+
Use this skill for SQL typing, RPC type hints, and output format decisions.
|
|
9
|
+
|
|
10
|
+
## SQL type system baseline
|
|
11
|
+
|
|
12
|
+
Use PostgreSQL types (including PostGIS-enabled environments).
|
|
13
|
+
|
|
14
|
+
Common groups:
|
|
15
|
+
|
|
16
|
+
- Numeric: `smallint`, `integer`, `bigint`, `numeric`, `real`, `double precision`
|
|
17
|
+
- Character: `varchar(n)`, `char(n)`, `text`
|
|
18
|
+
- Boolean: `boolean`
|
|
19
|
+
- JSON: `json`, `jsonb`
|
|
20
|
+
- Date/time: `date`, `time`, `timetz`, `timestamp`, `timestamptz`, `interval`
|
|
21
|
+
- Range: `int4range`, `int8range`, `numrange`, `daterange`, `tsrange`, `tstzrange`
|
|
22
|
+
- Arrays: append `[]` (for example `integer[]`, `text[]`)
|
|
23
|
+
|
|
24
|
+
## SQL parameter syntax
|
|
25
|
+
|
|
26
|
+
Centia uses **PDO-style named parameters** (`:name`). Positional placeholders (`$1`, `$2`, …) are NOT supported and fail with `SQLSTATE[HY093]: Invalid parameter number`.
|
|
27
|
+
|
|
28
|
+
Pass a single-object `params` array where keys match the placeholder names:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"q": "SELECT * FROM schema.relation WHERE id = :id AND code = :code",
|
|
33
|
+
"params": [{ "id": 42, "code": "A1" }]
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Always cast parameters when types are ambiguous or for JSON-RPC type inference:
|
|
38
|
+
|
|
39
|
+
```sql
|
|
40
|
+
SELECT :name::text, :age::integer, :joined::date
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## type_hints
|
|
44
|
+
|
|
45
|
+
Use `type_hints` when server-side inference is ambiguous.
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{ "date": "timestamptz", "days": "integer" }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## type_formats
|
|
54
|
+
|
|
55
|
+
Use `type_formats` to format temporal output columns.
|
|
56
|
+
|
|
57
|
+
Example:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{ "date": "D M d Y", "time": "H:i:s T" }
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Output formats (SQL and JSON-RPC)
|
|
64
|
+
|
|
65
|
+
Supported through `output_format`:
|
|
66
|
+
|
|
67
|
+
- Standard: `json`, `geojson`, `csv`, `excel`, `ogr/[format]`
|
|
68
|
+
- Streaming: `ndjson`, `ccsv`
|
|
69
|
+
|
|
70
|
+
Rules:
|
|
71
|
+
|
|
72
|
+
- Standard formats are single-response and capped at 100000 rows.
|
|
73
|
+
- Streaming formats have no row cap and are suitable for large exports/pipelines.
|
|
74
|
+
- Default format is `json` with `schema` and `data` fields.
|