jorgex-stack 1.0.1 → 1.0.3

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 (99) hide show
  1. package/PRD.md +310 -297
  2. package/README.md +68 -56
  3. package/dist/cli.js +37 -3
  4. package/package.json +1 -1
  5. package/stack/agents/code-simplifier.md +21 -10
  6. package/stack/agents/implementer.md +1 -0
  7. package/stack/agents/orchestrator.md +194 -192
  8. package/stack/agents/security-auditor.md +7 -0
  9. package/stack/agents/silent-failure-hunter.md +7 -0
  10. package/stack/agents/test-analyzer.md +7 -0
  11. package/stack/agents/tester.md +71 -71
  12. package/stack/agents/type-design-analyzer.md +1 -1
  13. package/stack/commands/lean-audit.md +59 -0
  14. package/stack/commands/xreview.md +82 -80
  15. package/stack/hooks/hooks.json +18 -18
  16. package/stack/scripts/post-pr-review.cjs +159 -156
  17. package/stack/skills/diagnose/SKILL.md +117 -117
  18. package/stack/skills/diagnose/scripts/hitl-loop.template.sh +41 -41
  19. package/stack/skills/find-skills/SKILL.md +133 -133
  20. package/stack/skills/lean-code/SKILL.md +69 -0
  21. package/stack/skills/mcp-builder/LICENSE.txt +201 -201
  22. package/stack/skills/mcp-builder/SKILL.md +236 -236
  23. package/stack/skills/mcp-builder/reference/evaluation.md +601 -601
  24. package/stack/skills/mcp-builder/reference/mcp_best_practices.md +249 -249
  25. package/stack/skills/mcp-builder/reference/node_mcp_server.md +969 -969
  26. package/stack/skills/mcp-builder/reference/python_mcp_server.md +718 -718
  27. package/stack/skills/mcp-builder/scripts/connections.py +151 -151
  28. package/stack/skills/mcp-builder/scripts/evaluation.py +373 -373
  29. package/stack/skills/mcp-builder/scripts/example_evaluation.xml +22 -22
  30. package/stack/skills/mcp-builder/scripts/requirements.txt +2 -2
  31. package/stack/skills/obsidian-cli/SKILL.md +106 -106
  32. package/stack/skills/obsidian-markdown/SKILL.md +196 -196
  33. package/stack/skills/obsidian-markdown/references/CALLOUTS.md +58 -58
  34. package/stack/skills/obsidian-markdown/references/EMBEDS.md +63 -63
  35. package/stack/skills/obsidian-markdown/references/PROPERTIES.md +61 -61
  36. package/stack/skills/react-doctor/SKILL.md +19 -19
  37. package/stack/skills/skill-creator/LICENSE.txt +201 -201
  38. package/stack/skills/skill-creator/agents/analyzer.md +274 -274
  39. package/stack/skills/skill-creator/agents/comparator.md +202 -202
  40. package/stack/skills/skill-creator/agents/grader.md +223 -223
  41. package/stack/skills/skill-creator/assets/eval_review.html +146 -146
  42. package/stack/skills/skill-creator/eval-viewer/generate_review.py +471 -471
  43. package/stack/skills/skill-creator/eval-viewer/viewer.html +1325 -1325
  44. package/stack/skills/skill-creator/references/schemas.md +430 -430
  45. package/stack/skills/skill-creator/scripts/aggregate_benchmark.py +401 -401
  46. package/stack/skills/skill-creator/scripts/generate_report.py +326 -326
  47. package/stack/skills/skill-creator/scripts/improve_description.py +248 -248
  48. package/stack/skills/skill-creator/scripts/package_skill.py +136 -136
  49. package/stack/skills/skill-creator/scripts/quick_validate.py +102 -102
  50. package/stack/skills/skill-creator/scripts/run_eval.py +310 -310
  51. package/stack/skills/skill-creator/scripts/run_loop.py +332 -332
  52. package/stack/skills/skill-creator/scripts/utils.py +47 -47
  53. package/stack/skills/supabase/SKILL.md +135 -135
  54. package/stack/skills/supabase/assets/feedback-issue-template.md +17 -17
  55. package/stack/skills/supabase/references/skill-feedback.md +17 -17
  56. package/stack/skills/supabase-postgres-best-practices/SKILL.md +64 -64
  57. package/stack/skills/supabase-postgres-best-practices/references/_contributing.md +170 -170
  58. package/stack/skills/supabase-postgres-best-practices/references/_sections.md +39 -39
  59. package/stack/skills/supabase-postgres-best-practices/references/_template.md +34 -34
  60. package/stack/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -55
  61. package/stack/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -49
  62. package/stack/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -46
  63. package/stack/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -44
  64. package/stack/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -41
  65. package/stack/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -46
  66. package/stack/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -54
  67. package/stack/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -53
  68. package/stack/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -50
  69. package/stack/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -50
  70. package/stack/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -56
  71. package/stack/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -68
  72. package/stack/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -50
  73. package/stack/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -54
  74. package/stack/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -45
  75. package/stack/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -55
  76. package/stack/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -55
  77. package/stack/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -44
  78. package/stack/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -40
  79. package/stack/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -48
  80. package/stack/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -43
  81. package/stack/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -45
  82. package/stack/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -80
  83. package/stack/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -46
  84. package/stack/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -59
  85. package/stack/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -55
  86. package/stack/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -55
  87. package/stack/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -61
  88. package/stack/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -54
  89. package/stack/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -50
  90. package/stack/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -63
  91. package/stack/skills/tdd/SKILL.md +109 -109
  92. package/stack/skills/tdd/deep-modules.md +33 -33
  93. package/stack/skills/tdd/interface-design.md +31 -31
  94. package/stack/skills/tdd/mocking.md +59 -59
  95. package/stack/skills/tdd/refactoring.md +10 -10
  96. package/stack/skills/tdd/tests.md +61 -61
  97. package/stack/skills/to-issues/SKILL.md +83 -83
  98. package/stack/skills/to-prd/SKILL.md +72 -72
  99. package/upstreams.json +96 -96
@@ -1,45 +1,45 @@
1
- ---
2
- title: Use Partial Indexes for Filtered Queries
3
- impact: HIGH
4
- impactDescription: 5-20x smaller indexes, faster writes and queries
5
- tags: indexes, partial-index, query-optimization, storage
6
- ---
7
-
8
- ## Use Partial Indexes for Filtered Queries
9
-
10
- Partial indexes only include rows matching a WHERE condition, making them smaller and faster when queries consistently filter on the same condition.
11
-
12
- **Incorrect (full index includes irrelevant rows):**
13
-
14
- ```sql
15
- -- Index includes all rows, even soft-deleted ones
16
- create index users_email_idx on users (email);
17
-
18
- -- Query always filters active users
19
- select * from users where email = 'user@example.com' and deleted_at is null;
20
- ```
21
-
22
- **Correct (partial index matches query filter):**
23
-
24
- ```sql
25
- -- Index only includes active users
26
- create index users_active_email_idx on users (email)
27
- where deleted_at is null;
28
-
29
- -- Query uses the smaller, faster index
30
- select * from users where email = 'user@example.com' and deleted_at is null;
31
- ```
32
-
33
- Common use cases for partial indexes:
34
-
35
- ```sql
36
- -- Only pending orders (status rarely changes once completed)
37
- create index orders_pending_idx on orders (created_at)
38
- where status = 'pending';
39
-
40
- -- Only non-null values
41
- create index products_sku_idx on products (sku)
42
- where sku is not null;
43
- ```
44
-
45
- Reference: [Partial Indexes](https://www.postgresql.org/docs/current/indexes-partial.html)
1
+ ---
2
+ title: Use Partial Indexes for Filtered Queries
3
+ impact: HIGH
4
+ impactDescription: 5-20x smaller indexes, faster writes and queries
5
+ tags: indexes, partial-index, query-optimization, storage
6
+ ---
7
+
8
+ ## Use Partial Indexes for Filtered Queries
9
+
10
+ Partial indexes only include rows matching a WHERE condition, making them smaller and faster when queries consistently filter on the same condition.
11
+
12
+ **Incorrect (full index includes irrelevant rows):**
13
+
14
+ ```sql
15
+ -- Index includes all rows, even soft-deleted ones
16
+ create index users_email_idx on users (email);
17
+
18
+ -- Query always filters active users
19
+ select * from users where email = 'user@example.com' and deleted_at is null;
20
+ ```
21
+
22
+ **Correct (partial index matches query filter):**
23
+
24
+ ```sql
25
+ -- Index only includes active users
26
+ create index users_active_email_idx on users (email)
27
+ where deleted_at is null;
28
+
29
+ -- Query uses the smaller, faster index
30
+ select * from users where email = 'user@example.com' and deleted_at is null;
31
+ ```
32
+
33
+ Common use cases for partial indexes:
34
+
35
+ ```sql
36
+ -- Only pending orders (status rarely changes once completed)
37
+ create index orders_pending_idx on orders (created_at)
38
+ where status = 'pending';
39
+
40
+ -- Only non-null values
41
+ create index products_sku_idx on products (sku)
42
+ where sku is not null;
43
+ ```
44
+
45
+ Reference: [Partial Indexes](https://www.postgresql.org/docs/current/indexes-partial.html)
@@ -1,80 +1,80 @@
1
- ---
2
- title: Add Constraints Safely in Migrations
3
- impact: HIGH
4
- impactDescription: Prevents migration failures and enables idempotent schema changes
5
- tags: constraints, migrations, schema, alter-table
6
- ---
7
-
8
- ## Add Constraints Safely in Migrations
9
-
10
- PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail.
11
-
12
- **Incorrect (causes syntax error):**
13
-
14
- ```sql
15
- -- ERROR: syntax error at or near "not" (SQLSTATE 42601)
16
- alter table public.profiles
17
- add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id);
18
- ```
19
-
20
- **Correct (idempotent constraint creation):**
21
-
22
- ```sql
23
- -- Use DO block to check before adding
24
- do $$
25
- begin
26
- if not exists (
27
- select 1 from pg_constraint
28
- where conname = 'profiles_birthchart_id_unique'
29
- and conrelid = 'public.profiles'::regclass
30
- ) then
31
- alter table public.profiles
32
- add constraint profiles_birthchart_id_unique unique (birthchart_id);
33
- end if;
34
- end $$;
35
- ```
36
-
37
- For all constraint types:
38
-
39
- ```sql
40
- -- Check constraints
41
- do $$
42
- begin
43
- if not exists (
44
- select 1 from pg_constraint
45
- where conname = 'check_age_positive'
46
- ) then
47
- alter table users add constraint check_age_positive check (age > 0);
48
- end if;
49
- end $$;
50
-
51
- -- Foreign keys
52
- do $$
53
- begin
54
- if not exists (
55
- select 1 from pg_constraint
56
- where conname = 'profiles_birthchart_id_fkey'
57
- ) then
58
- alter table profiles
59
- add constraint profiles_birthchart_id_fkey
60
- foreign key (birthchart_id) references birthcharts(id);
61
- end if;
62
- end $$;
63
- ```
64
-
65
- Check if constraint exists:
66
-
67
- ```sql
68
- -- Query to check constraint existence
69
- select conname, contype, pg_get_constraintdef(oid)
70
- from pg_constraint
71
- where conrelid = 'public.profiles'::regclass;
72
-
73
- -- contype values:
74
- -- 'p' = PRIMARY KEY
75
- -- 'f' = FOREIGN KEY
76
- -- 'u' = UNIQUE
77
- -- 'c' = CHECK
78
- ```
79
-
80
- Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)
1
+ ---
2
+ title: Add Constraints Safely in Migrations
3
+ impact: HIGH
4
+ impactDescription: Prevents migration failures and enables idempotent schema changes
5
+ tags: constraints, migrations, schema, alter-table
6
+ ---
7
+
8
+ ## Add Constraints Safely in Migrations
9
+
10
+ PostgreSQL does not support `ADD CONSTRAINT IF NOT EXISTS`. Migrations using this syntax will fail.
11
+
12
+ **Incorrect (causes syntax error):**
13
+
14
+ ```sql
15
+ -- ERROR: syntax error at or near "not" (SQLSTATE 42601)
16
+ alter table public.profiles
17
+ add constraint if not exists profiles_birthchart_id_unique unique (birthchart_id);
18
+ ```
19
+
20
+ **Correct (idempotent constraint creation):**
21
+
22
+ ```sql
23
+ -- Use DO block to check before adding
24
+ do $$
25
+ begin
26
+ if not exists (
27
+ select 1 from pg_constraint
28
+ where conname = 'profiles_birthchart_id_unique'
29
+ and conrelid = 'public.profiles'::regclass
30
+ ) then
31
+ alter table public.profiles
32
+ add constraint profiles_birthchart_id_unique unique (birthchart_id);
33
+ end if;
34
+ end $$;
35
+ ```
36
+
37
+ For all constraint types:
38
+
39
+ ```sql
40
+ -- Check constraints
41
+ do $$
42
+ begin
43
+ if not exists (
44
+ select 1 from pg_constraint
45
+ where conname = 'check_age_positive'
46
+ ) then
47
+ alter table users add constraint check_age_positive check (age > 0);
48
+ end if;
49
+ end $$;
50
+
51
+ -- Foreign keys
52
+ do $$
53
+ begin
54
+ if not exists (
55
+ select 1 from pg_constraint
56
+ where conname = 'profiles_birthchart_id_fkey'
57
+ ) then
58
+ alter table profiles
59
+ add constraint profiles_birthchart_id_fkey
60
+ foreign key (birthchart_id) references birthcharts(id);
61
+ end if;
62
+ end $$;
63
+ ```
64
+
65
+ Check if constraint exists:
66
+
67
+ ```sql
68
+ -- Query to check constraint existence
69
+ select conname, contype, pg_get_constraintdef(oid)
70
+ from pg_constraint
71
+ where conrelid = 'public.profiles'::regclass;
72
+
73
+ -- contype values:
74
+ -- 'p' = PRIMARY KEY
75
+ -- 'f' = FOREIGN KEY
76
+ -- 'u' = UNIQUE
77
+ -- 'c' = CHECK
78
+ ```
79
+
80
+ Reference: [Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html)
@@ -1,46 +1,46 @@
1
- ---
2
- title: Choose Appropriate Data Types
3
- impact: HIGH
4
- impactDescription: 50% storage reduction, faster comparisons
5
- tags: data-types, schema, storage, performance
6
- ---
7
-
8
- ## Choose Appropriate Data Types
9
-
10
- Using the right data types reduces storage, improves query performance, and prevents bugs.
11
-
12
- **Incorrect (wrong data types):**
13
-
14
- ```sql
15
- create table users (
16
- id int, -- Will overflow at 2.1 billion
17
- email varchar(255), -- Unnecessary length limit
18
- created_at timestamp, -- Missing timezone info
19
- is_active varchar(5), -- String for boolean
20
- price varchar(20) -- String for numeric
21
- );
22
- ```
23
-
24
- **Correct (appropriate data types):**
25
-
26
- ```sql
27
- create table users (
28
- id bigint generated always as identity primary key, -- 9 quintillion max
29
- email text, -- No artificial limit, same performance as varchar
30
- created_at timestamptz, -- Always store timezone-aware timestamps
31
- is_active boolean default true, -- 1 byte vs variable string length
32
- price numeric(10,2) -- Exact decimal arithmetic
33
- );
34
- ```
35
-
36
- Key guidelines:
37
-
38
- ```sql
39
- -- IDs: use bigint, not int (future-proofing)
40
- -- Strings: use text, not varchar(n) unless constraint needed
41
- -- Time: use timestamptz, not timestamp
42
- -- Money: use numeric, not float (precision matters)
43
- -- Enums: use text with check constraint or create enum type
44
- ```
45
-
46
- Reference: [Data Types](https://www.postgresql.org/docs/current/datatype.html)
1
+ ---
2
+ title: Choose Appropriate Data Types
3
+ impact: HIGH
4
+ impactDescription: 50% storage reduction, faster comparisons
5
+ tags: data-types, schema, storage, performance
6
+ ---
7
+
8
+ ## Choose Appropriate Data Types
9
+
10
+ Using the right data types reduces storage, improves query performance, and prevents bugs.
11
+
12
+ **Incorrect (wrong data types):**
13
+
14
+ ```sql
15
+ create table users (
16
+ id int, -- Will overflow at 2.1 billion
17
+ email varchar(255), -- Unnecessary length limit
18
+ created_at timestamp, -- Missing timezone info
19
+ is_active varchar(5), -- String for boolean
20
+ price varchar(20) -- String for numeric
21
+ );
22
+ ```
23
+
24
+ **Correct (appropriate data types):**
25
+
26
+ ```sql
27
+ create table users (
28
+ id bigint generated always as identity primary key, -- 9 quintillion max
29
+ email text, -- No artificial limit, same performance as varchar
30
+ created_at timestamptz, -- Always store timezone-aware timestamps
31
+ is_active boolean default true, -- 1 byte vs variable string length
32
+ price numeric(10,2) -- Exact decimal arithmetic
33
+ );
34
+ ```
35
+
36
+ Key guidelines:
37
+
38
+ ```sql
39
+ -- IDs: use bigint, not int (future-proofing)
40
+ -- Strings: use text, not varchar(n) unless constraint needed
41
+ -- Time: use timestamptz, not timestamp
42
+ -- Money: use numeric, not float (precision matters)
43
+ -- Enums: use text with check constraint or create enum type
44
+ ```
45
+
46
+ Reference: [Data Types](https://www.postgresql.org/docs/current/datatype.html)
@@ -1,59 +1,59 @@
1
- ---
2
- title: Index Foreign Key Columns
3
- impact: HIGH
4
- impactDescription: 10-100x faster JOINs and CASCADE operations
5
- tags: foreign-key, indexes, joins, schema
6
- ---
7
-
8
- ## Index Foreign Key Columns
9
-
10
- Postgres does not automatically index foreign key columns. Missing indexes cause slow JOINs and CASCADE operations.
11
-
12
- **Incorrect (unindexed foreign key):**
13
-
14
- ```sql
15
- create table orders (
16
- id bigint generated always as identity primary key,
17
- customer_id bigint references customers(id) on delete cascade,
18
- total numeric(10,2)
19
- );
20
-
21
- -- No index on customer_id!
22
- -- JOINs and ON DELETE CASCADE both require full table scan
23
- select * from orders where customer_id = 123; -- Seq Scan
24
- delete from customers where id = 123; -- Locks table, scans all orders
25
- ```
26
-
27
- **Correct (indexed foreign key):**
28
-
29
- ```sql
30
- create table orders (
31
- id bigint generated always as identity primary key,
32
- customer_id bigint references customers(id) on delete cascade,
33
- total numeric(10,2)
34
- );
35
-
36
- -- Always index the FK column
37
- create index orders_customer_id_idx on orders (customer_id);
38
-
39
- -- Now JOINs and cascades are fast
40
- select * from orders where customer_id = 123; -- Index Scan
41
- delete from customers where id = 123; -- Uses index, fast cascade
42
- ```
43
-
44
- Find missing FK indexes:
45
-
46
- ```sql
47
- select
48
- conrelid::regclass as table_name,
49
- a.attname as fk_column
50
- from pg_constraint c
51
- join pg_attribute a on a.attrelid = c.conrelid and a.attnum = any(c.conkey)
52
- where c.contype = 'f'
53
- and not exists (
54
- select 1 from pg_index i
55
- where i.indrelid = c.conrelid and a.attnum = any(i.indkey)
56
- );
57
- ```
58
-
59
- Reference: [Foreign Keys](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK)
1
+ ---
2
+ title: Index Foreign Key Columns
3
+ impact: HIGH
4
+ impactDescription: 10-100x faster JOINs and CASCADE operations
5
+ tags: foreign-key, indexes, joins, schema
6
+ ---
7
+
8
+ ## Index Foreign Key Columns
9
+
10
+ Postgres does not automatically index foreign key columns. Missing indexes cause slow JOINs and CASCADE operations.
11
+
12
+ **Incorrect (unindexed foreign key):**
13
+
14
+ ```sql
15
+ create table orders (
16
+ id bigint generated always as identity primary key,
17
+ customer_id bigint references customers(id) on delete cascade,
18
+ total numeric(10,2)
19
+ );
20
+
21
+ -- No index on customer_id!
22
+ -- JOINs and ON DELETE CASCADE both require full table scan
23
+ select * from orders where customer_id = 123; -- Seq Scan
24
+ delete from customers where id = 123; -- Locks table, scans all orders
25
+ ```
26
+
27
+ **Correct (indexed foreign key):**
28
+
29
+ ```sql
30
+ create table orders (
31
+ id bigint generated always as identity primary key,
32
+ customer_id bigint references customers(id) on delete cascade,
33
+ total numeric(10,2)
34
+ );
35
+
36
+ -- Always index the FK column
37
+ create index orders_customer_id_idx on orders (customer_id);
38
+
39
+ -- Now JOINs and cascades are fast
40
+ select * from orders where customer_id = 123; -- Index Scan
41
+ delete from customers where id = 123; -- Uses index, fast cascade
42
+ ```
43
+
44
+ Find missing FK indexes:
45
+
46
+ ```sql
47
+ select
48
+ conrelid::regclass as table_name,
49
+ a.attname as fk_column
50
+ from pg_constraint c
51
+ join pg_attribute a on a.attrelid = c.conrelid and a.attnum = any(c.conkey)
52
+ where c.contype = 'f'
53
+ and not exists (
54
+ select 1 from pg_index i
55
+ where i.indrelid = c.conrelid and a.attnum = any(i.indkey)
56
+ );
57
+ ```
58
+
59
+ Reference: [Foreign Keys](https://www.postgresql.org/docs/current/ddl-constraints.html#DDL-CONSTRAINTS-FK)
@@ -1,55 +1,55 @@
1
- ---
2
- title: Use Lowercase Identifiers for Compatibility
3
- impact: MEDIUM
4
- impactDescription: Avoid case-sensitivity bugs with tools, ORMs, and AI assistants
5
- tags: naming, identifiers, case-sensitivity, schema, conventions
6
- ---
7
-
8
- ## Use Lowercase Identifiers for Compatibility
9
-
10
- PostgreSQL folds unquoted identifiers to lowercase. Quoted mixed-case identifiers require quotes forever and cause issues with tools, ORMs, and AI assistants that may not recognize them.
11
-
12
- **Incorrect (mixed-case identifiers):**
13
-
14
- ```sql
15
- -- Quoted identifiers preserve case but require quotes everywhere
16
- CREATE TABLE "Users" (
17
- "userId" bigint PRIMARY KEY,
18
- "firstName" text,
19
- "lastName" text
20
- );
21
-
22
- -- Must always quote or queries fail
23
- SELECT "firstName" FROM "Users" WHERE "userId" = 1;
24
-
25
- -- This fails - Users becomes users without quotes
26
- SELECT firstName FROM Users;
27
- -- ERROR: relation "users" does not exist
28
- ```
29
-
30
- **Correct (lowercase snake_case):**
31
-
32
- ```sql
33
- -- Unquoted lowercase identifiers are portable and tool-friendly
34
- CREATE TABLE users (
35
- user_id bigint PRIMARY KEY,
36
- first_name text,
37
- last_name text
38
- );
39
-
40
- -- Works without quotes, recognized by all tools
41
- SELECT first_name FROM users WHERE user_id = 1;
42
- ```
43
-
44
- Common sources of mixed-case identifiers:
45
-
46
- ```sql
47
- -- ORMs often generate quoted camelCase - configure them to use snake_case
48
- -- Migrations from other databases may preserve original casing
49
- -- Some GUI tools quote identifiers by default - disable this
50
-
51
- -- If stuck with mixed-case, create views as a compatibility layer
52
- CREATE VIEW users AS SELECT "userId" AS user_id, "firstName" AS first_name FROM "Users";
53
- ```
54
-
55
- Reference: [Identifiers and Key Words](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)
1
+ ---
2
+ title: Use Lowercase Identifiers for Compatibility
3
+ impact: MEDIUM
4
+ impactDescription: Avoid case-sensitivity bugs with tools, ORMs, and AI assistants
5
+ tags: naming, identifiers, case-sensitivity, schema, conventions
6
+ ---
7
+
8
+ ## Use Lowercase Identifiers for Compatibility
9
+
10
+ PostgreSQL folds unquoted identifiers to lowercase. Quoted mixed-case identifiers require quotes forever and cause issues with tools, ORMs, and AI assistants that may not recognize them.
11
+
12
+ **Incorrect (mixed-case identifiers):**
13
+
14
+ ```sql
15
+ -- Quoted identifiers preserve case but require quotes everywhere
16
+ CREATE TABLE "Users" (
17
+ "userId" bigint PRIMARY KEY,
18
+ "firstName" text,
19
+ "lastName" text
20
+ );
21
+
22
+ -- Must always quote or queries fail
23
+ SELECT "firstName" FROM "Users" WHERE "userId" = 1;
24
+
25
+ -- This fails - Users becomes users without quotes
26
+ SELECT firstName FROM Users;
27
+ -- ERROR: relation "users" does not exist
28
+ ```
29
+
30
+ **Correct (lowercase snake_case):**
31
+
32
+ ```sql
33
+ -- Unquoted lowercase identifiers are portable and tool-friendly
34
+ CREATE TABLE users (
35
+ user_id bigint PRIMARY KEY,
36
+ first_name text,
37
+ last_name text
38
+ );
39
+
40
+ -- Works without quotes, recognized by all tools
41
+ SELECT first_name FROM users WHERE user_id = 1;
42
+ ```
43
+
44
+ Common sources of mixed-case identifiers:
45
+
46
+ ```sql
47
+ -- ORMs often generate quoted camelCase - configure them to use snake_case
48
+ -- Migrations from other databases may preserve original casing
49
+ -- Some GUI tools quote identifiers by default - disable this
50
+
51
+ -- If stuck with mixed-case, create views as a compatibility layer
52
+ CREATE VIEW users AS SELECT "userId" AS user_id, "firstName" AS first_name FROM "Users";
53
+ ```
54
+
55
+ Reference: [Identifiers and Key Words](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)