一键导入
postgresql
Rules when working with PostgreSQL database in Gram
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Rules when working with PostgreSQL database in Gram
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Rules when working with ClickHouse database in Gram for analytics and telemetry features, including editing the ClickHouse schema (server/clickhouse/schema.sql) and creating or fixing ClickHouse migrations
Rules and best practices when working on the dashboard and elements React frontend codebases
Concepts, external interfaces, and conventions for Gram's audit logging subsystem — the internal Go API for recording actor/action/subject events and the `/rpc/auditlogs.*` management API that exposes them. Activate whenever the task involves recording or exposing audit events (adding or changing audit coverage on a service, introducing a new audited subject or action, writing tests that assert an event was recorded, changing how entries are displayed or filtered).
Concepts, external interfaces, and conventions for Gram's management API — the Goa-designed HTTP-RPC surface under `/rpc/<service>.<method>` that powers the dashboard, CLI, and public SDK. Activate whenever the task involves designing, implementing, or modifying a management endpoint (new service, new method, payload/result changes, OpenAPI/SDK surface changes, CLI changes, wiring a new service into the server).
Concepts, external interfaces, and conventions for Gram's role-based access control (RBAC) subsystem — scopes, grants, principals, system roles, and the `authz.Engine.Require` enforcement path used inside handlers. Activate whenever the task involves authorization (adding or modifying a scope or resource type, declaring a new role or grant, gating a handler, changing scope inheritance, exposing RBAC state through the dashboard).
Use the Playwright MCP browser to capture a demo (screenshots or a GIF recording) of a user-visible frontend change and post it as a PR comment
| name | postgresql |
| description | Rules when working with PostgreSQL database in Gram |
Comprehensive guidelines when working with PostgreSQL database to build Gram which include rules for schema design, database migration and application logic. All rules are kept in a rules folder with names of each rule outlined below (e.g. rules/<rule-name>.md).
Reference these guidelines when:
Code Formatting and Comments:
pgformatter or similar.-- a comment); do not add a space for commented-out code (--raise notice).Naming Conventions:
snake_case for identifiers (e.g., user_id, customer_name).customers, products).Data Integrity and Data Types:
INTEGER, VARCHAR, TIMESTAMP).NOT NULL, FOREIGN KEY) to enforce data integrity but not for UNIQUE-ness — that is enforced with unique indexes.CHECK constraints for pure enumeration / value validation (e.g. CHECK (status IN ('active', 'inactive'))). Validate allowed values in application code, where they can evolve without a migration. Exception: keep CHECKs that are structural to the Class Table Inheritance (CTI) pattern, e.g. pinning a subtype's discriminator (CHECK (provider = 'aws_kms')) so the composite foreign key back to the supertype enforces 1:1 semantics.ON DELETE SET NULL clause.Indexing:
WHERE clauses and JOIN conditions.B-tree, Hash, GIN, GiST) based on the data and query requirements.(organization_id, id) key that a tenant-scoped child composite-FKs to for tenancy pinning), declare it as a CREATE UNIQUE INDEX, not a table-level UNIQUE constraint. Postgres accepts a non-partial, plain-column unique index as an FK target. This matters when adding the key to an existing table: ALTER TABLE ... ADD CONSTRAINT ... UNIQUE takes an ACCESS EXCLUSIVE lock and builds the index synchronously, whereas a CREATE UNIQUE INDEX (which Atlas automatically emits as CONCURRENTLY per its concurrent_index policy) does not. Trade-off: a concurrent index makes the migration non-transactional (Atlas emits -- atlas:txmode none for you), so keep such migrations minimal.Schema evolution:
mise db:diff <migration-name> after making schema changes to generate a migration file. Replace <migration-name> with a clear snake-case migration id such as users-add-email-column.mise run db:reset 2. mise run db:migrate to re-run all migrations from the beginning.mise run db:diff <name-of-migrations>: Create a database migrationmise run db:reset: Drop the database and re-create it. No migrations applied at this point.mise run db:migrate: Run all pending database migrations. If you have just reset the database, this will run all migrations from the beginning.When creating any tables, add a non-nullable column named project_id of type uuid with a foreign key constraint to the projects table. If appropriate to the nature and usage patterns of the table also include organization_id TEXT NOT NULL column.
All tables should have created_at and updated_at columns:
create table if not exists example (
-- ...
created_at timestamptz not null default clock_timestamp(),
updated_at timestamptz not null default clock_timestamp() on update clock_timestamp(),
-- ...
);
A nullable deleted_at column may be added to tables to perform soft deletes:
create table if not exists example (
-- ...
deleted_at timestamptz,
deleted boolean not null generated always as (deleted_at is not null) stored,
-- ...
);
Deleting rows with DELETE FROM table is not strongly discouraged. Instead,
use:
UPDATE example SET deleted_at = clock_timestamp() WHERE id = ?;
server/database/schema.sql is DDL only — no DO, ALTER, or other procedural blocks. Declare tables in dependency order so every FOREIGN KEY resolves inline; if a target is declared later, move it up.
All constraints should be named with this format:
{tablename}_{columnname(s)}_{suffix}
Where suffix is:
key for a unique constraintfkey for a foreign key constraintidx for any other kind of indexcheck for a check constraintexcl for an exclusion constraintseq for an sequencesEnsure that all schema changes are designed for backwards compatibility.
These are examples of terrible practices to avoid:
Instead, strongly consider these better alternatives:
These rules apply any time you touch server/migrations/, atlas.sum, or server/database/schema.sql. They are non-negotiable.
Gram uses Atlas in versioned mode. Two file kinds are involved, and they are not the same thing:
server/database/schema.sql is the SDL — the declarative, desired-state schema. This is the file you edit.server/migrations/*.sql are the DDL diff Atlas generates from that schema. Running mise db:diff <name> computes the delta (e.g. ALTER TABLE ... ADD COLUMN ...), writes a new timestamped migration file, and updates atlas.sum.Rules:
atlas.sum are produced only by the Atlas CLI (mise db:diff). Never hand-edit, rename, or rehash them.INSERT / UPDATE / DELETE) do not belong in a migration file. Data migrations live in application code, not migrations.mise lint:migrations (or CI) reports a migration timestamp at or before the latest on main, do NOT rename the file. Delete the offending migration on your branch, rebase/merge main, then re-run mise db:diff <name> so the migration is regenerated on top with a fresh timestamp.main, then re-run mise db:diff so your changes are recreated on top.All SQLc queries live in **/queries.sql files in the codebase. This is an important convention to maintain.
When writing SQLc queries, follow these guidelines:
project_id to explicitly limit the scope of writes.mise run infra:start: bring up the local Postgres/ClickHouse/etc containers — required before running sqlc, since sqlc connects to the database to type-check queries.mise run gen:sqlc-server: generates Go code from SQLc queries (requires the local database from mise run infra:start).