con un clic
database-fundamentals
// Reviews schema design, SQL queries, ORM patterns. Use when junior creates schema, writes queries, adds migrations, works with Prisma/MongoDB/PostgreSQL, or asks "is this SQL safe", "N+1", "index".
// Reviews schema design, SQL queries, ORM patterns. Use when junior creates schema, writes queries, adds migrations, works with Prisma/MongoDB/PostgreSQL, or asks "is this SQL safe", "N+1", "index".
Transforms completed work into powerful resume bullet points with action verbs, technical context, and quantified impact. Use when completing tasks, updating portfolio, or preparing job applications.
Transforms completed work into STAR interview stories (Situation, Task, Action, Result). Use when completing tasks, preparing for behavioral interviews, or documenting achievements.
Reviews accessibility including WCAG, ARIA, keyboard navigation. Use when junior builds forms, buttons, modals, interactive elements, or asks "is this accessible", "a11y", "screen reader".
Reviews API design, REST conventions, and backend architecture. Use when junior builds API endpoints, Express routes, middleware, controllers, or asks "is this RESTful", "check my endpoint".
Guides systematic debugging through Protocol D (READ, ISOLATE, DOCS, HYPOTHESIZE, VERIFY). Use when junior says "stuck", "not working", "broken", "bug", "error", "crashed", "failing", "can't figure out", or expresses frustration. Do NOT use for general questions.
Guides documentation standards including READMEs, JSDoc, and code comments. Use when writing documentation, adding comments, or explaining code. Enforces "WHY not WHAT" principle.
| name | database-fundamentals |
| description | Reviews schema design, SQL queries, ORM patterns. Use when junior creates schema, writes queries, adds migrations, works with Prisma/MongoDB/PostgreSQL, or asks "is this SQL safe", "N+1", "index". |
"Your database is the foundation. Build it wrong, and everything above it will crack."
Activate this skill when reviewing:
SELECT *?❌ // 1 query for users + N queries for posts
const users = await User.findAll();
for (const user of users) {
user.posts = await Post.findAll({ where: { userId: user.id } });
}
✅ // 1 query with JOIN
const users = await User.findAll({
include: [{ model: Post }]
});
// Or 2 queries with IN clause
const users = await User.findAll();
const userIds = users.map(u => u.id);
const posts = await Post.findAll({ where: { userId: userIds } });
❌ // Queried frequently, but no index
SELECT * FROM orders WHERE user_id = ?
SELECT * FROM products WHERE category = ? AND status = 'active'
✅ CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_products_category_status ON products(category, status);
❌ SELECT * FROM users; // Returns 50 columns
✅ SELECT id, name, email FROM users; // Only what's needed
❌ db.query(`SELECT * FROM users WHERE email = '${email}'`);
✅ db.query('SELECT * FROM users WHERE email = ?', [email]);
❌ -- Can't be rolled back
DROP TABLE users;
ALTER TABLE orders DROP COLUMN status;
✅ -- Add new, migrate data, then drop old (in separate migrations)
-- Migration 1: Add new column
ALTER TABLE orders ADD COLUMN status_new VARCHAR(20);
-- Migration 2: Copy data
UPDATE orders SET status_new = status;
-- Migration 3: Drop old (after verification)
ALTER TABLE orders DROP COLUMN status;
Ask the junior these questions instead of giving answers:
| Form | Rule | Example Issue |
|---|---|---|
| 1NF | No repeating groups | tags: "js,react,node" should be separate table |
| 2NF | No partial dependencies | Order item price duplicated from products |
| 3NF | No transitive dependencies | Storing city AND zip code (zip determines city) |
-- Single column (most common)
CREATE INDEX idx_users_email ON users(email);
-- Composite (for multi-column queries)
-- Order matters! Most selective first
CREATE INDEX idx_orders_user_date ON orders(user_id, created_at);
-- Partial (for filtered queries)
CREATE INDEX idx_active_users ON users(email) WHERE active = true;
-- Unique (enforces constraint)
CREATE UNIQUE INDEX idx_users_email_unique ON users(email);
| Flag | Question to Ask |
|---|---|
| Query in a loop | "Can we fetch all this data in one query?" |
| No pagination | "What if there are 1 million records?" |
| SELECT * | "Do we need all 50 columns?" |
| String in query | "Is this protected against SQL injection?" |
| No indexes on foreign keys | "How fast are JOINs on this table?" |
| DROP TABLE in migration | "How do we roll this back?" |
| TEXT for everything | "Should this be an INT or DATE instead?" |
| No foreign key constraints | "What prevents orphaned records?" |
// Eager loading (avoid N+1)
const users = await User.findAll({
include: [{ model: Post, attributes: ['id', 'title'] }]
});
// Select specific fields
const users = await User.findAll({
attributes: ['id', 'name', 'email']
});
// Pagination
const users = await User.findAll({
limit: 20,
offset: (page - 1) * 20
});
// Raw queries for complex operations
const results = await sequelize.query(
'SELECT ... complex query ...',
{ type: QueryTypes.SELECT }
);