idea-analogist
想法群聊室 — 类比者角色。被 idea-team 主编排器调用,或用户单独说"类比一下"、"别的行业有没有"、"yes-and 扩展"、"X 让你想到什么"、"跨界启示"时触发。**专门做跨界类比 + yes-and…
Use when designing PostgreSQL + Redis data models, indexes, caching strategies, JSONB usage, tiered storage, or cache consistency contracts.
Claude Code
$ npx -y skills add majiayu000/spellbook --skill database-patterns --agent claude-code
Codex
$ npx skills add majiayu000/spellbook --skill database-patterns -a codex -y
Cursor
$ npx skills add majiayu000/spellbook --skill database-patterns -a cursor -y
Gemini CLI
$ npx skills add majiayu000/spellbook --skill database-patterns -a gemini-cli -y
GitHub Copilot
$ npx skills add majiayu000/spellbook --skill database-patterns -a github-copilot -y
OpenCode
$ npx skills add majiayu000/spellbook --skill database-patterns -a opencode -y
Windsurf
$ npx skills add majiayu000/spellbook --skill database-patterns -a windsurf -y
name: database-patterns description: Use when designing PostgreSQL + Redis data models, indexes, caching strategies, JSONB usage, tiered storage, or cache consistency contracts.
---
| Use Case | Type | Avoid | |----------|------|-------| | Primary Key | `UUID` / `BIGSERIAL` | `INT` (range limits) | | Timestamps | `TIMESTAMPTZ` | `TIMESTAMP` (no timezone) | | Money | `NUMERIC(19,4)` | `FLOAT` (precision loss) | | Status | `TEXT` + CHECK | `INT` (unreadable) | | Semi-structured | `JSONB` | `JSON` (no indexing) | | Full-text | `TSVECTOR` | `LIKE '%..%'` |
-- Use UUID for distributed-friendly IDs
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active'
CHECK (status IN ('active', 'inactive', 'suspended')),
metadata JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Updated timestamp trigger
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();-- B-Tree: Equality, range, sorting (default)
CREATE INDEX idx_users_email ON users(email);
-- Composite: Leftmost prefix rule
-- Supports: (user_id), (user_id, created_at)
-- Does NOT support: (created_at) alone
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at DESC);
-- Partial: Reduce index size
CREATE INDEX idx_active_users ON users(email)
WHERE status = 'active';
-- GIN for JSONB: Containment queries
CREATE INDEX idx_metadata ON users USING GIN (metadata jsonb_path_ops);
-- Expression: Specific JSONB field
CREATE INDEX idx_user_role ON users ((metadata->>'role'));
-- Full-text search
CREATE INDEX idx_search ON products USING GIN (to_tsvector('english', name || ' ' || description));-- Good: Dynamic attributes, rarely queried fields
CREATE TABLE products (
id UUID PRIMARY KEY,
name TEXT NOT NULL,
price NUMERIC(19,4) NOT NULL,
category TEXT NOT NULL, -- Extracted: frequently queried
attributes JSONB DEFAULT '{}' -- Dynamic: color, size, specs
);
-- Query with containment
SELECT * FROM products
WHERE category = 'electronics' -- B-Tree index
AND attributes @> '{"brand": "Apple"}'; -- GIN index
-- Query specific field
SELECT * FROM products
WHERE attributes->>'color' = 'black'; -- Expression index
-- Update JSONB field
UPDATE products
SET attributes = attributes || '{"featured": true}'
WHERE id = '...';-- Always use EXPLAIN ANALYZE EXPLAIN ANALYZE SELECT u.*, COUNT(o.id) as order_count FROM users u LEFT JOIN orders o ON o.user_id = u.id WHERE u.status = 'active' GROUP BY u.id ORDER BY u.created_at DESC LIMIT 20; -- Watch for: -- ❌ Seq Scan on large tables → Add index -- ❌ Sort → Use index for ordering -- ❌ Nested Loop with many rows → Consider JOIN order -- ❌ Hash Join on huge tables → Add indexes
// PgBouncer or built-in pool
import { Pool } from 'pg';
const pool = new Pool({
max: 20, // Max connections
idleTimeoutMillis: 30000, // Close idle connections
connectionTimeoutMillis: 2000, // Fail fast
});
// Connection count formula:
// connections = (cores * 2) + effective_spindle_count
// Usually 10-30 is enough---
| Use Case | Structure | Example | |----------|-----------|---------| | Cache objects | String | `user:123` → JSON | | Counters | String + INCR | `views:article:456` | | Sessions | Hash | `session:abc` → {userId, ...} | | Leaderboards | Sorted Set | `scores` → {userId: score} | | Queues | List/Stream | `tasks` → LPUSH/RPOP | | Unique sets | Set | `online_users` | | Real-time | Pub/Sub/Stream | Notifications |
# Format: <entity>:<id>:<attribute> user:123:profile user:123:settings order:456:items session:abc123 # Use colons for hierarchy # Enables pattern matching with SCAN SCAN 0 MATCH "user:*:profile" COUNT 100
const TTL = {
SESSION: 24 * 60 * 60, // 24 hours
CACHE: 15 * 60, // 15 minutes
RATE_LIMIT: 60, // 1 minute
LOCK: 30, // 30 seconds
};
// Set with TTL
await redis.set(`cache:user:${id}`, JSON.stringify(user), 'EX', TTL.CACHE);
// Check TTL
const remaining = await redis.ttl(`cache:user:${id}`);---
async function getUser(id: string): Promise<User> {
const cacheKey = `user:${id}`;
// 1. Check cache
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
// 2. Cache miss → Query database
const user = await db.user.findUnique({ where: { id } });
if (!user) {
throw new NotFoundError('User not found');
}
// 3. Populate cache
await redis.set(cacheKey, JSON.stringify(user), 'EX', 900);
return user;
}async function updateUser(id: string, data: UpdateInput): Promise<User> {
// 1. Update database
const user = await db.user.update({
where: { id },
data,
});
// 2. Update cache immediately
await redis.set(`user:${i想法群聊室 — 类比者角色。被 idea-team 主编排器调用,或用户单独说"类比一下"、"别的行业有没有"、"yes-and 扩展"、"X 让你想到什么"、"跨界启示"时触发。**专门做跨界类比 + yes-and…
想法群聊室 — 反方角色。被 idea-team 主编排器调用,或用户单独说"反方意见"、"挑这个想法的刺"、"为什么会失败"、"找漏洞 / 反例"、"devil's…
想法群聊室 — 调研员角色。被 idea-team 主编排器调用,或用户单独说"调研一下 X"、"X 的现状/竞品/数据"、"找 2026 数据"、"事实底"时触发。**用 WebSearch 拉真实 2026…
想法群聊室主持人 — 把一句话想法丢给多角色 AI 团队(调研员/反方/类比者)做查漏补缺。每个角色有自己的 voice,他们互相 @ 接话;你随时插话。**这是创意扩展工具,不打分、不否决、不堵路**。Use when…
端到端产品教练 — 把一句话想法走到 PRD + 可点击 HTML 原型。会顶嘴、强制砍功能、用 Nielsen + Norman 做友好性硬检。Use when user 说"我有一个想法"、"想做一个产品"、"做 MVP"、"写…
Mobile app UI design expert for iOS and Android. Use when designing app interfaces, creating design systems, ensuring…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.