omgkit 2.0.7 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/package.json +2 -2
  2. package/plugin/skills/backend/api-architecture/SKILL.md +857 -0
  3. package/plugin/skills/backend/caching-strategies/SKILL.md +755 -0
  4. package/plugin/skills/backend/event-driven-architecture/SKILL.md +753 -0
  5. package/plugin/skills/backend/real-time-systems/SKILL.md +635 -0
  6. package/plugin/skills/databases/database-optimization/SKILL.md +571 -0
  7. package/plugin/skills/databases/postgresql/SKILL.md +494 -18
  8. package/plugin/skills/devops/docker/SKILL.md +466 -18
  9. package/plugin/skills/devops/monorepo-management/SKILL.md +595 -0
  10. package/plugin/skills/devops/observability/SKILL.md +622 -0
  11. package/plugin/skills/devops/performance-profiling/SKILL.md +905 -0
  12. package/plugin/skills/frameworks/nextjs/SKILL.md +407 -44
  13. package/plugin/skills/frameworks/react/SKILL.md +1006 -32
  14. package/plugin/skills/frontend/advanced-ui-design/SKILL.md +426 -0
  15. package/plugin/skills/integrations/ai-integration/SKILL.md +730 -0
  16. package/plugin/skills/integrations/payment-integration/SKILL.md +735 -0
  17. package/plugin/skills/languages/python/SKILL.md +489 -25
  18. package/plugin/skills/languages/typescript/SKILL.md +379 -30
  19. package/plugin/skills/methodology/problem-solving/SKILL.md +355 -0
  20. package/plugin/skills/methodology/research-validation/SKILL.md +668 -0
  21. package/plugin/skills/methodology/sequential-thinking/SKILL.md +260 -0
  22. package/plugin/skills/mobile/mobile-development/SKILL.md +756 -0
  23. package/plugin/skills/security/security-hardening/SKILL.md +633 -0
  24. package/plugin/skills/tools/document-processing/SKILL.md +916 -0
  25. package/plugin/skills/tools/image-processing/SKILL.md +748 -0
  26. package/plugin/skills/tools/mcp-development/SKILL.md +883 -0
  27. package/plugin/skills/tools/media-processing/SKILL.md +831 -0
@@ -1,43 +1,519 @@
1
1
  ---
2
2
  name: postgresql
3
- description: PostgreSQL database. Use for schema design, queries, optimization.
3
+ description: PostgreSQL database design, queries, optimization, and best practices
4
+ category: databases
5
+ triggers:
6
+ - postgresql
7
+ - postgres
8
+ - sql
9
+ - database
10
+ - query
11
+ - schema
4
12
  ---
5
13
 
6
- # PostgreSQL Skill
14
+ # PostgreSQL
15
+
16
+ Enterprise-grade **PostgreSQL database** design and optimization following industry best practices. This skill covers schema design, query optimization, indexing strategies, and production-ready patterns.
17
+
18
+ ## Purpose
19
+
20
+ Build performant, scalable database systems:
21
+
22
+ - Design efficient schemas
23
+ - Write optimized queries
24
+ - Implement proper indexing
25
+ - Handle transactions correctly
26
+ - Optimize for performance
27
+ - Ensure data integrity
28
+
29
+ ## Features
30
+
31
+ ### 1. Schema Design
7
32
 
8
- ## Schema Design
9
33
  ```sql
34
+ -- Users table with proper constraints
10
35
  CREATE TABLE users (
11
36
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
12
37
  email VARCHAR(255) UNIQUE NOT NULL,
13
38
  password_hash VARCHAR(255) NOT NULL,
39
+ name VARCHAR(100) NOT NULL,
40
+ role VARCHAR(20) DEFAULT 'user' CHECK (role IN ('user', 'admin', 'moderator')),
41
+ is_active BOOLEAN DEFAULT TRUE,
42
+ email_verified_at TIMESTAMPTZ,
43
+ created_at TIMESTAMPTZ DEFAULT NOW(),
44
+ updated_at TIMESTAMPTZ DEFAULT NOW()
45
+ );
46
+
47
+ -- Products table with foreign key
48
+ CREATE TABLE products (
49
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
50
+ name VARCHAR(255) NOT NULL,
51
+ description TEXT,
52
+ price DECIMAL(10, 2) NOT NULL CHECK (price >= 0),
53
+ stock_quantity INTEGER DEFAULT 0 CHECK (stock_quantity >= 0),
54
+ category_id UUID REFERENCES categories(id) ON DELETE SET NULL,
55
+ seller_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
56
+ is_published BOOLEAN DEFAULT FALSE,
57
+ published_at TIMESTAMPTZ,
58
+ created_at TIMESTAMPTZ DEFAULT NOW(),
59
+ updated_at TIMESTAMPTZ DEFAULT NOW()
60
+ );
61
+
62
+ -- Orders table with status tracking
63
+ CREATE TABLE orders (
64
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
65
+ user_id UUID NOT NULL REFERENCES users(id),
66
+ status VARCHAR(20) DEFAULT 'pending' CHECK (status IN (
67
+ 'pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled'
68
+ )),
69
+ total_amount DECIMAL(12, 2) NOT NULL,
70
+ shipping_address JSONB NOT NULL,
71
+ notes TEXT,
14
72
  created_at TIMESTAMPTZ DEFAULT NOW(),
15
73
  updated_at TIMESTAMPTZ DEFAULT NOW()
16
74
  );
17
75
 
18
- CREATE INDEX idx_users_email ON users(email);
76
+ -- Order items junction table
77
+ CREATE TABLE order_items (
78
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
79
+ order_id UUID NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
80
+ product_id UUID NOT NULL REFERENCES products(id),
81
+ quantity INTEGER NOT NULL CHECK (quantity > 0),
82
+ unit_price DECIMAL(10, 2) NOT NULL,
83
+ UNIQUE(order_id, product_id)
84
+ );
85
+
86
+ -- Updated at trigger function
87
+ CREATE OR REPLACE FUNCTION update_updated_at()
88
+ RETURNS TRIGGER AS $$
89
+ BEGIN
90
+ NEW.updated_at = NOW();
91
+ RETURN NEW;
92
+ END;
93
+ $$ LANGUAGE plpgsql;
94
+
95
+ -- Apply trigger to tables
96
+ CREATE TRIGGER users_updated_at
97
+ BEFORE UPDATE ON users
98
+ FOR EACH ROW EXECUTE FUNCTION update_updated_at();
99
+
100
+ CREATE TRIGGER products_updated_at
101
+ BEFORE UPDATE ON products
102
+ FOR EACH ROW EXECUTE FUNCTION update_updated_at();
103
+
104
+ CREATE TRIGGER orders_updated_at
105
+ BEFORE UPDATE ON orders
106
+ FOR EACH ROW EXECUTE FUNCTION update_updated_at();
19
107
  ```
20
108
 
21
- ## Query Patterns
109
+ ### 2. Indexing Strategies
110
+
22
111
  ```sql
23
- -- Pagination
24
- SELECT * FROM users
112
+ -- Primary indexes (created automatically)
113
+ -- B-tree indexes for equality and range queries
114
+ CREATE INDEX idx_products_category ON products(category_id);
115
+ CREATE INDEX idx_products_seller ON products(seller_id);
116
+ CREATE INDEX idx_orders_user ON orders(user_id);
117
+ CREATE INDEX idx_orders_status ON orders(status);
118
+
119
+ -- Composite indexes for common query patterns
120
+ CREATE INDEX idx_products_category_price ON products(category_id, price);
121
+ CREATE INDEX idx_orders_user_status ON orders(user_id, status);
122
+ CREATE INDEX idx_orders_created_status ON orders(created_at DESC, status);
123
+
124
+ -- Partial indexes for filtered queries
125
+ CREATE INDEX idx_products_published ON products(category_id, created_at)
126
+ WHERE is_published = TRUE;
127
+
128
+ CREATE INDEX idx_orders_pending ON orders(user_id, created_at)
129
+ WHERE status = 'pending';
130
+
131
+ -- Full-text search indexes
132
+ CREATE INDEX idx_products_search ON products
133
+ USING GIN(to_tsvector('english', name || ' ' || COALESCE(description, '')));
134
+
135
+ -- JSONB indexes
136
+ CREATE INDEX idx_orders_shipping_city ON orders
137
+ USING GIN((shipping_address->'city'));
138
+
139
+ -- Expression indexes
140
+ CREATE INDEX idx_users_email_lower ON users(LOWER(email));
141
+
142
+ -- Covering indexes (index-only scans)
143
+ CREATE INDEX idx_products_list ON products(category_id, is_published)
144
+ INCLUDE (name, price);
145
+ ```
146
+
147
+ ### 3. Query Patterns
148
+
149
+ ```sql
150
+ -- Pagination with cursor (more efficient than OFFSET)
151
+ SELECT id, name, price, created_at
152
+ FROM products
153
+ WHERE created_at < '2024-01-01' -- cursor value
154
+ AND is_published = TRUE
155
+ ORDER BY created_at DESC
156
+ LIMIT 20;
157
+
158
+ -- Efficient offset pagination when needed
159
+ SELECT id, name, price
160
+ FROM products
161
+ WHERE is_published = TRUE
25
162
  ORDER BY created_at DESC
26
- LIMIT 10 OFFSET 20;
163
+ LIMIT 20 OFFSET 40;
164
+
165
+ -- Search with full-text search
166
+ SELECT id, name, description,
167
+ ts_rank(to_tsvector('english', name || ' ' || COALESCE(description, '')),
168
+ plainto_tsquery('english', 'laptop gaming')) as rank
169
+ FROM products
170
+ WHERE to_tsvector('english', name || ' ' || COALESCE(description, ''))
171
+ @@ plainto_tsquery('english', 'laptop gaming')
172
+ ORDER BY rank DESC
173
+ LIMIT 20;
174
+
175
+ -- Aggregation with filtering
176
+ SELECT
177
+ DATE_TRUNC('day', created_at) as date,
178
+ COUNT(*) as order_count,
179
+ SUM(total_amount) as revenue,
180
+ AVG(total_amount) as avg_order_value
181
+ FROM orders
182
+ WHERE status = 'delivered'
183
+ AND created_at >= NOW() - INTERVAL '30 days'
184
+ GROUP BY DATE_TRUNC('day', created_at)
185
+ ORDER BY date DESC;
186
+
187
+ -- Window functions
188
+ SELECT
189
+ id, name, price, category_id,
190
+ RANK() OVER (PARTITION BY category_id ORDER BY price DESC) as price_rank,
191
+ LAG(price) OVER (PARTITION BY category_id ORDER BY price) as prev_price,
192
+ AVG(price) OVER (PARTITION BY category_id) as category_avg
193
+ FROM products
194
+ WHERE is_published = TRUE;
195
+
196
+ -- Common Table Expressions (CTE)
197
+ WITH monthly_sales AS (
198
+ SELECT
199
+ DATE_TRUNC('month', o.created_at) as month,
200
+ SUM(oi.quantity * oi.unit_price) as revenue
201
+ FROM orders o
202
+ JOIN order_items oi ON o.id = oi.order_id
203
+ WHERE o.status = 'delivered'
204
+ GROUP BY DATE_TRUNC('month', o.created_at)
205
+ ),
206
+ sales_with_growth AS (
207
+ SELECT
208
+ month,
209
+ revenue,
210
+ LAG(revenue) OVER (ORDER BY month) as prev_revenue,
211
+ revenue - LAG(revenue) OVER (ORDER BY month) as growth
212
+ FROM monthly_sales
213
+ )
214
+ SELECT * FROM sales_with_growth
215
+ ORDER BY month DESC;
216
+
217
+ -- Recursive CTE for hierarchical data
218
+ WITH RECURSIVE category_tree AS (
219
+ -- Base case
220
+ SELECT id, name, parent_id, 0 as depth, ARRAY[id] as path
221
+ FROM categories
222
+ WHERE parent_id IS NULL
223
+
224
+ UNION ALL
225
+
226
+ -- Recursive case
227
+ SELECT c.id, c.name, c.parent_id, ct.depth + 1, ct.path || c.id
228
+ FROM categories c
229
+ JOIN category_tree ct ON c.parent_id = ct.id
230
+ )
231
+ SELECT * FROM category_tree
232
+ ORDER BY path;
233
+ ```
234
+
235
+ ### 4. Transactions and Locking
236
+
237
+ ```sql
238
+ -- Basic transaction
239
+ BEGIN;
240
+
241
+ UPDATE accounts SET balance = balance - 100 WHERE id = 'sender_id';
242
+ UPDATE accounts SET balance = balance + 100 WHERE id = 'receiver_id';
243
+
244
+ INSERT INTO transactions (from_id, to_id, amount)
245
+ VALUES ('sender_id', 'receiver_id', 100);
246
+
247
+ COMMIT;
248
+
249
+ -- Transaction with savepoint
250
+ BEGIN;
27
251
 
28
- -- Search
29
- SELECT * FROM users
30
- WHERE email ILIKE '%@example.com';
252
+ UPDATE products SET stock_quantity = stock_quantity - 1 WHERE id = 'product_id';
253
+ SAVEPOINT after_stock_update;
31
254
 
32
- -- Aggregation
33
- SELECT DATE(created_at), COUNT(*)
34
- FROM users
35
- GROUP BY DATE(created_at);
255
+ INSERT INTO orders (user_id, total_amount)
256
+ VALUES ('user_id', 99.99)
257
+ RETURNING id INTO order_id;
258
+
259
+ -- If something goes wrong
260
+ ROLLBACK TO SAVEPOINT after_stock_update;
261
+
262
+ COMMIT;
263
+
264
+ -- Pessimistic locking (FOR UPDATE)
265
+ BEGIN;
266
+
267
+ SELECT * FROM products WHERE id = 'product_id' FOR UPDATE;
268
+ -- Row is now locked until transaction ends
269
+
270
+ UPDATE products SET stock_quantity = stock_quantity - 1 WHERE id = 'product_id';
271
+
272
+ COMMIT;
273
+
274
+ -- Skip locked rows (for job queues)
275
+ SELECT * FROM jobs
276
+ WHERE status = 'pending'
277
+ ORDER BY created_at
278
+ LIMIT 1
279
+ FOR UPDATE SKIP LOCKED;
280
+
281
+ -- Advisory locks
282
+ SELECT pg_advisory_lock(hashtext('unique_process_name'));
283
+ -- Do exclusive work
284
+ SELECT pg_advisory_unlock(hashtext('unique_process_name'));
285
+ ```
286
+
287
+ ### 5. Performance Optimization
288
+
289
+ ```sql
290
+ -- Analyze query performance
291
+ EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
292
+ SELECT p.*, c.name as category_name
293
+ FROM products p
294
+ LEFT JOIN categories c ON p.category_id = c.id
295
+ WHERE p.is_published = TRUE
296
+ AND p.price BETWEEN 10 AND 100
297
+ ORDER BY p.created_at DESC
298
+ LIMIT 20;
299
+
300
+ -- Table statistics
301
+ ANALYZE products;
302
+
303
+ -- Vacuum to reclaim space
304
+ VACUUM (VERBOSE, ANALYZE) products;
305
+
306
+ -- Check index usage
307
+ SELECT
308
+ schemaname, tablename, indexname,
309
+ idx_scan, idx_tup_read, idx_tup_fetch
310
+ FROM pg_stat_user_indexes
311
+ WHERE tablename = 'products'
312
+ ORDER BY idx_scan DESC;
313
+
314
+ -- Find unused indexes
315
+ SELECT
316
+ schemaname, tablename, indexname, idx_scan
317
+ FROM pg_stat_user_indexes
318
+ WHERE idx_scan = 0
319
+ AND schemaname = 'public';
320
+
321
+ -- Table bloat check
322
+ SELECT
323
+ schemaname, tablename,
324
+ pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) as total_size,
325
+ n_dead_tup as dead_tuples,
326
+ n_live_tup as live_tuples
327
+ FROM pg_stat_user_tables
328
+ WHERE n_dead_tup > 1000
329
+ ORDER BY n_dead_tup DESC;
330
+
331
+ -- Connection monitoring
332
+ SELECT
333
+ datname, usename, application_name,
334
+ client_addr, state, query_start,
335
+ NOW() - query_start as query_duration
336
+ FROM pg_stat_activity
337
+ WHERE state = 'active'
338
+ ORDER BY query_start;
339
+ ```
340
+
341
+ ### 6. JSONB Operations
342
+
343
+ ```sql
344
+ -- JSONB column
345
+ CREATE TABLE events (
346
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
347
+ type VARCHAR(50) NOT NULL,
348
+ payload JSONB NOT NULL,
349
+ created_at TIMESTAMPTZ DEFAULT NOW()
350
+ );
351
+
352
+ -- Insert JSONB data
353
+ INSERT INTO events (type, payload)
354
+ VALUES ('user.created', '{"user_id": "123", "email": "test@example.com", "metadata": {"source": "web"}}');
355
+
356
+ -- Query JSONB
357
+ SELECT * FROM events
358
+ WHERE payload->>'user_id' = '123';
359
+
360
+ SELECT * FROM events
361
+ WHERE payload @> '{"metadata": {"source": "web"}}';
362
+
363
+ -- JSONB operators
364
+ SELECT
365
+ payload->'user_id' as user_id, -- Get as JSONB
366
+ payload->>'email' as email, -- Get as text
367
+ payload#>'{metadata,source}' as source,
368
+ payload ? 'email' as has_email,
369
+ payload ?& ARRAY['user_id', 'email'] as has_all
370
+ FROM events;
371
+
372
+ -- Update JSONB
373
+ UPDATE events
374
+ SET payload = payload || '{"processed": true}'
375
+ WHERE id = 'event_id';
376
+
377
+ UPDATE events
378
+ SET payload = jsonb_set(payload, '{metadata,updated_at}', '"2024-01-01"')
379
+ WHERE id = 'event_id';
380
+
381
+ -- Remove key from JSONB
382
+ UPDATE events
383
+ SET payload = payload - 'temporary_field'
384
+ WHERE id = 'event_id';
385
+ ```
386
+
387
+ ### 7. Stored Procedures
388
+
389
+ ```sql
390
+ -- Function to get user stats
391
+ CREATE OR REPLACE FUNCTION get_user_stats(p_user_id UUID)
392
+ RETURNS TABLE (
393
+ total_orders BIGINT,
394
+ total_spent DECIMAL,
395
+ avg_order_value DECIMAL,
396
+ last_order_date TIMESTAMPTZ
397
+ ) AS $$
398
+ BEGIN
399
+ RETURN QUERY
400
+ SELECT
401
+ COUNT(*)::BIGINT,
402
+ COALESCE(SUM(total_amount), 0),
403
+ COALESCE(AVG(total_amount), 0),
404
+ MAX(created_at)
405
+ FROM orders
406
+ WHERE user_id = p_user_id
407
+ AND status = 'delivered';
408
+ END;
409
+ $$ LANGUAGE plpgsql;
410
+
411
+ -- Usage
412
+ SELECT * FROM get_user_stats('user-uuid-here');
413
+
414
+ -- Procedure for order creation
415
+ CREATE OR REPLACE PROCEDURE create_order(
416
+ p_user_id UUID,
417
+ p_items JSONB,
418
+ OUT p_order_id UUID
419
+ )
420
+ LANGUAGE plpgsql AS $$
421
+ DECLARE
422
+ v_total DECIMAL := 0;
423
+ v_item JSONB;
424
+ BEGIN
425
+ -- Calculate total
426
+ FOR v_item IN SELECT * FROM jsonb_array_elements(p_items)
427
+ LOOP
428
+ v_total := v_total + (v_item->>'price')::DECIMAL * (v_item->>'quantity')::INTEGER;
429
+ END LOOP;
430
+
431
+ -- Create order
432
+ INSERT INTO orders (user_id, total_amount, status)
433
+ VALUES (p_user_id, v_total, 'pending')
434
+ RETURNING id INTO p_order_id;
435
+
436
+ -- Create order items
437
+ INSERT INTO order_items (order_id, product_id, quantity, unit_price)
438
+ SELECT
439
+ p_order_id,
440
+ (value->>'product_id')::UUID,
441
+ (value->>'quantity')::INTEGER,
442
+ (value->>'price')::DECIMAL
443
+ FROM jsonb_array_elements(p_items);
444
+
445
+ -- Update stock
446
+ UPDATE products p
447
+ SET stock_quantity = stock_quantity - (i.value->>'quantity')::INTEGER
448
+ FROM jsonb_array_elements(p_items) i
449
+ WHERE p.id = (i.value->>'product_id')::UUID;
450
+ END;
451
+ $$;
452
+ ```
453
+
454
+ ## Use Cases
455
+
456
+ ### E-commerce Analytics
457
+ ```sql
458
+ SELECT
459
+ p.category_id,
460
+ c.name as category_name,
461
+ COUNT(DISTINCT o.id) as order_count,
462
+ SUM(oi.quantity) as units_sold,
463
+ SUM(oi.quantity * oi.unit_price) as revenue
464
+ FROM products p
465
+ JOIN categories c ON p.category_id = c.id
466
+ JOIN order_items oi ON p.id = oi.product_id
467
+ JOIN orders o ON oi.order_id = o.id
468
+ WHERE o.status = 'delivered'
469
+ AND o.created_at >= NOW() - INTERVAL '30 days'
470
+ GROUP BY p.category_id, c.name
471
+ ORDER BY revenue DESC;
472
+ ```
473
+
474
+ ### User Activity Report
475
+ ```sql
476
+ WITH user_activity AS (
477
+ SELECT
478
+ u.id,
479
+ u.email,
480
+ COUNT(o.id) as order_count,
481
+ COALESCE(SUM(o.total_amount), 0) as total_spent,
482
+ MAX(o.created_at) as last_order_date
483
+ FROM users u
484
+ LEFT JOIN orders o ON u.id = o.user_id AND o.status = 'delivered'
485
+ GROUP BY u.id, u.email
486
+ )
487
+ SELECT
488
+ *,
489
+ CASE
490
+ WHEN total_spent >= 1000 THEN 'VIP'
491
+ WHEN total_spent >= 500 THEN 'Regular'
492
+ ELSE 'New'
493
+ END as customer_tier
494
+ FROM user_activity
495
+ ORDER BY total_spent DESC;
36
496
  ```
37
497
 
38
498
  ## Best Practices
39
- - Use UUIDs for IDs
40
- - Add indexes for queries
499
+
500
+ ### Do's
501
+ - Use UUIDs for primary keys
502
+ - Add indexes for common queries
41
503
  - Use EXPLAIN ANALYZE
42
- - Use transactions
504
+ - Use transactions for data integrity
43
505
  - Use connection pooling
506
+ - Regular VACUUM and ANALYZE
507
+
508
+ ### Don'ts
509
+ - Don't use SELECT *
510
+ - Don't ignore query plans
511
+ - Don't forget foreign keys
512
+ - Don't skip migrations
513
+ - Don't use raw SQL without parameterization
514
+
515
+ ## References
516
+
517
+ - [PostgreSQL Documentation](https://www.postgresql.org/docs/)
518
+ - [Use The Index, Luke](https://use-the-index-luke.com/)
519
+ - [PostgreSQL Wiki](https://wiki.postgresql.org/)