一键导入
database-schema-design
// Database schema design best practices. Use when creating tables, reviewing migrations, planning data models, or answering schema design questions.
// Database schema design best practices. Use when creating tables, reviewing migrations, planning data models, or answering schema design questions.
Release workflow for stella Go CLI project. Create releases with semantic versioned tags, update changelog, and trigger automated CI/CD builds. Use when the user asks to "release", "create a release", "tag a version", "update changelog", "prepare release", "cut a release", or discusses versioning and release artifacts.
Self-knowledge about stella, the self-hosted AI assistant. Use when the user asks about stella itself: configuration, setup, onboarding, providers, models, agents, channels (Telegram/QQ/Feishu/WeChat), memory system (LCM), scheduled jobs, heartbeat, skills, plugins, session compaction, notifications, self-update, multi-agent, multi-user, or general "how does stella work" / "help me get started" questions. Also triggers on "change my model", "set up telegram", "set up wechat", "configure provider", "update stella", "what can you do", "how do I install skills", "stella onboard", "switch agent".
Automate Stella web UI testing with tap-web browser automation. Use when the user asks to "test the UI", "check the web page", "verify the frontend", "run UI tests", "browser test", or wants to interact with stella.localhost in a browser.
Access websites, search the web, and extract clean content using the `tap` CLI. Supports structured site scripts, readable page extraction, and browser automation for tabs, screenshots, forms, cookies, JavaScript evaluation, and network capture. Use for web lookup, page reading, content extraction, browser interaction, authenticated sessions, request interception, or CDP-connected desktop apps.
Reading assistant for saving, organizing, and recalling web content. Use when the user says "save this article", "read this link", "summarize this", "check my feeds", "add to my library", or asks about previously saved content. Handles articles, tweets, YouTube videos, GitHub repos, PDFs, and RSS feeds. Articles are stored as markdown files with metadata and indexed for fast search.
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
| name | database-schema-design |
| description | Database schema design best practices. Use when creating tables, reviewing migrations, planning data models, or answering schema design questions. |
Model real business concepts: users, orders, invoices, events. Name tables after entities. Avoid designing around screens or API responses — UI changes faster than core data.
One style, applied everywhere:
{group}_{entity}, singular, snake_case — auth_user, auth_session, sched_job, order_itemsnake_case — user_id, created_at, statusidx_{table}_{columns} — idx_auth_user_emailREFERENCES in column definitionGroup prefix: Related tables share a short prefix so they sort together and ownership is clear:
auth_user, auth_session, auth_identity
sched_job, sched_job_run
ctx_message, ctx_conversation, ctx_summary
Singular: A table name is the entity type, not the collection. This keeps FK references natural (user_id → auth_user), avoids irregular plurals (identity not identities), and keeps compound names unambiguous (order_item not order_items).
Avoid vague names: data, type, value, flag, status2.
id UUID PRIMARY KEY DEFAULT gen_random_uuid().BIGINT only when you have a specific reason (high-volume append-only tables, external system compatibility).Every table must include:
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
These are non-negotiable. No table ships without them.
Choose the most specific type that fits:
| Concept | Type | Why |
|---|---|---|
| Primary key | UUID | Globally unique, no coordination needed |
| Timestamps | TIMESTAMPTZ | Real-world events need timezone awareness |
| Calendar dates | DATE | Birthdays, billing dates — no time component |
| Money | INTEGER (cents) or NUMERIC | Never float — rounding errors compound |
| Boolean | BOOLEAN | Not integer, not text |
| Enum/state | TEXT | Keep valid values in code so future extensions don't require schema migrations |
| Structured blob | JSONB | Only for metadata, external payloads, rarely-queried data |
Don't store everything as TEXT. The type system exists to catch bugs at the boundary.
Use the database to enforce structural rules — application code can have bugs, constraints cannot be bypassed. Do not add schema-level enums or enum-like CHECK constraints for values that may grow, such as scope TEXT NOT NULL CHECK (scope IN ('system','agent','user')); enforce those allowed values in code so adding a new value does not require a schema migration.
CREATE TABLE shop_product (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
sku TEXT NOT NULL UNIQUE,
price_cents INTEGER NOT NULL CHECK (price_cents >= 0),
name TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
Checklist:
NOT NULL — default stance. Allow NULL only when absence is semantically meaningful.UNIQUE — enforce on natural identifiers.CHECK — validate ranges and stable invariants, but not enums or extensible state lists.FOREIGN KEY ... ON DELETE — choose CASCADE, SET NULL, or RESTRICT deliberately.Start at third normal form:
phone_1, phone_2, phone_3).Bad:
user_ids TEXT -- "1,2,3"
Better:
CREATE TABLE org_team_member (
team_id UUID NOT NULL REFERENCES org_team(id),
user_id UUID NOT NULL REFERENCES auth_user(id),
PRIMARY KEY (team_id, user_id)
);
Denormalize later only for measured performance reasons, and document when you do.
| Pattern | Implementation |
|---|---|
| One-to-many | FK on the "many" side: shop_order.user_id REFERENCES auth_user(id) |
| Many-to-many | Join table with composite PK |
| One-to-one | FK as PK: auth_user_profile.user_id PRIMARY KEY REFERENCES auth_user(id) |
Make relationships explicit. Implicit relationships (matching IDs without FK constraints) rot silently.
CREATE INDEX idx_shop_order_user_id ON shop_order(user_id);
CREATE INDEX idx_shop_order_user_status_created
ON shop_order(user_id, status, created_at DESC);
Partial indexes for selective queries:
CREATE INDEX idx_shop_order_pending ON shop_order(created_at)
WHERE status = 'pending';
Decide per table — don't default to one approach everywhere:
| Strategy | When |
|---|---|
| Hard delete | Transient data, logs, ephemeral records |
Soft delete (deleted_at) | User-visible records needing undo or audit |
| CASCADE | Tightly-coupled children (messages of a conversation) |
| RESTRICT | Prevent silently orphaning important references |
| Archive | Move cold data to separate storage |
CASCADE is convenient but dangerous — it can remove more than you expect.
Use for:
Never use for:
If you're querying inside JSON frequently, extract it into proper columns.
Before approving any schema change:
{group}_{entity} singular naming?id UUID, created_at, and updated_at?NOT NULL?