xiaohongshu
xiaohongshu
grey-haven-database-conventions
Apply Grey Haven database conventions - snake_case fields, multi-tenant with tenant_id and RLS, proper indexing, migrations for Drizzle (TypeScript) and SQLModel (Python). Use when designing schemas, writing database code, creating migrations, setting up RLS policies, or when user mentions 'datab...
Full skill instructions
Database schema standards for Drizzle ORM (TypeScript) and SQLModel (Python).
Follow these conventions for all Grey Haven multi-tenant database schemas.
Database columns MUST use snake_case, never camelCase.
// ✅ CORRECT
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
created_at: timestamp("created_at").defaultNow().notNull(),
tenant_id: uuid("tenant_id").notNull(),
email_address: text("email_address").notNull(),
});
// ❌ WRONG - Don't use camelCase
export const users = pgTable("users", {
createdAt: timestamp("createdAt"), // WRONG!
tenantId: uuid("tenantId"), // WRONG!
});
Every table MUST include tenant_id for data isolation.
// TypeScript - Drizzle
export const organizations = pgTable("organizations", {
id: uuid("id").primaryKey().defaultRandom(),
tenant_id: uuid("tenant_id").notNull(), // REQUIRED
name: text("name").notNull(),
});
# Python - SQLModel
class Organization(SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
tenant_id: UUID = Field(foreign_key="tenants.id", index=True) # REQUIRED
name: str = Field(max_length=255)
See examples/drizzle-schemas.md and examples/sqlmodel-schemas.md for complete examples.
All tables must have created_at and updated_at.
// TypeScript - Reusable timestamps
export const baseTimestamps = {
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull().$onUpdate(() => new Date()),
};
export const teams = pgTable("teams", {
id: uuid("id").primaryKey().defaultRandom(),
...baseTimestamps, // Spread operator
tenant_id: uuid("tenant_id").notNull(),
name: text("name").notNull(),
});
# Python - Mixin pattern
class TimestampMixin:
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow, sa_column_kwargs={"onupdate": datetime.utcnow})
class Team(TimestampMixin, SQLModel, table=True):
id: UUID = Field(default_factory=uuid4, primary_key=True)
tenant_id: UUID = Field(index=True)
name: str = Field(max_length=255)
Enable RLS on all tables with tenant_id.
-- Enable RLS
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Tenant isolation policy
CREATE POLICY "tenant_isolation" ON users
FOR ALL TO authenticated
USING (tenant_id = (current_setting('request.jwt.claims')::json->>'tenant_id')::uuid);
See examples/rls-policies.md for complete RLS patterns.
Boolean fields: Prefix with is_, has_, can_
is_active: boolean("is_active")
has_access: boolean("has_access")
can_edit: boolean("can_edit")
Timestamp fields: Suffix with _at
created_at: timestamp("created_at")
updated_at: timestamp("updated_at")
deleted_at: timestamp("deleted_at")
last_login_at: timestamp("last_login_at")
Foreign keys: Suffix with _id
tenant_id: uuid("tenant_id")
user_id: uuid("user_id")
organization_id: uuid("organization_id")
See reference/field-naming.md for complete naming guide.
Always index:
tenant_id (for multi-tenant queries)// Composite index for tenant + lookup
export const usersIndex = index("users_tenant_email_idx").on(
users.tenant_id,
users.email_address
);
See reference/indexing.md for index strategies.
One-to-many:
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts), // User has many posts
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.user_id], references: [users.id] }),
}));
See reference/relationships.md for all relationship patterns.
Installation:
bun add drizzle-orm postgres
bun add -d drizzle-kit
Basic schema:
// db/schema.ts
import { pgTable, uuid, text, timestamp, boolean } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull(),
tenant_id: uuid("tenant_id").notNull(),
email_address: text("email_address").notNull().unique(),
is_active: boolean("is_active").default(true).notNull(),
});
Generate migration:
bun run drizzle-kit generate:pg
bun run drizzle-kit push:pg
See examples/migrations.md for migration workflow.
Installation:
pip install sqlmodel psycopg2-binary
Basic model:
# app/models/user.py
from sqlmodel import Field, SQLModel
from uuid import UUID, uuid4
from datetime import datetime
class User(SQLModel, table=True):
__tablename__ = "users"
id: UUID = Field(default_factory=uuid4, primary_key=True)
created_at: datetime = Field(default_factory=datetime.utcnow)
updated_at: datetime = Field(default_factory=datetime.utcnow)
tenant_id: UUID = Field(foreign_key="tenants.id", index=True)
email_address: str = Field(unique=True, index=True, max_length=255)
is_active: bool = Field(default=True)
Generate migration:
alembic revision --autogenerate -m "Add users table"
alembic upgrade head
See examples/migrations.md for Alembic setup.
Use this skill when:
cvi-template (Drizzle ORM + PlanetScale)cvi-backend-template (SQLModel + PostgreSQL)xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience