jorgex-stack 1.0.0

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 (124) hide show
  1. package/LICENSE +21 -0
  2. package/PRD.md +297 -0
  3. package/README.md +58 -0
  4. package/dist/cli.js +2894 -0
  5. package/package.json +51 -0
  6. package/stack/agents/README.md +33 -0
  7. package/stack/agents/backend-analyst.md +61 -0
  8. package/stack/agents/code-reviewer.md +66 -0
  9. package/stack/agents/code-simplifier.md +81 -0
  10. package/stack/agents/comment-fixer.md +54 -0
  11. package/stack/agents/docs-maintainer.md +88 -0
  12. package/stack/agents/engram.md +124 -0
  13. package/stack/agents/frontend-analyst.md +51 -0
  14. package/stack/agents/implementer.md +55 -0
  15. package/stack/agents/orchestrator.md +192 -0
  16. package/stack/agents/security-auditor.md +66 -0
  17. package/stack/agents/silent-failure-hunter.md +167 -0
  18. package/stack/agents/test-analyzer.md +91 -0
  19. package/stack/agents/tester.md +71 -0
  20. package/stack/agents/translator.md +101 -0
  21. package/stack/agents/type-design-analyzer.md +128 -0
  22. package/stack/commands/xreview.md +80 -0
  23. package/stack/config/defaults.json +37 -0
  24. package/stack/hooks/hooks.json +18 -0
  25. package/stack/mcp/servers.json +19 -0
  26. package/stack/plugins/opencode/engram.ts +378 -0
  27. package/stack/plugins/opencode/hooks.ts +766 -0
  28. package/stack/plugins/opencode/package.json +10 -0
  29. package/stack/plugins/opencode/worktree.ts +405 -0
  30. package/stack/scripts/post-pr-review.cjs +156 -0
  31. package/stack/skills/agent-browser/SKILL.md +55 -0
  32. package/stack/skills/agent-delegation/SKILL.md +58 -0
  33. package/stack/skills/deploy-to-vercel/SKILL.md +296 -0
  34. package/stack/skills/deploy-to-vercel/resources/deploy-codex.sh +301 -0
  35. package/stack/skills/deploy-to-vercel/resources/deploy.sh +301 -0
  36. package/stack/skills/diagnose/SKILL.md +117 -0
  37. package/stack/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
  38. package/stack/skills/find-skills/SKILL.md +133 -0
  39. package/stack/skills/graphify/.graphify_version +1 -0
  40. package/stack/skills/graphify/SKILL.md +1319 -0
  41. package/stack/skills/mcp-builder/LICENSE.txt +202 -0
  42. package/stack/skills/mcp-builder/SKILL.md +236 -0
  43. package/stack/skills/mcp-builder/reference/evaluation.md +602 -0
  44. package/stack/skills/mcp-builder/reference/mcp_best_practices.md +249 -0
  45. package/stack/skills/mcp-builder/reference/node_mcp_server.md +970 -0
  46. package/stack/skills/mcp-builder/reference/python_mcp_server.md +719 -0
  47. package/stack/skills/mcp-builder/scripts/connections.py +151 -0
  48. package/stack/skills/mcp-builder/scripts/evaluation.py +373 -0
  49. package/stack/skills/mcp-builder/scripts/example_evaluation.xml +22 -0
  50. package/stack/skills/mcp-builder/scripts/requirements.txt +2 -0
  51. package/stack/skills/obsidian-cli/SKILL.md +106 -0
  52. package/stack/skills/obsidian-markdown/SKILL.md +196 -0
  53. package/stack/skills/obsidian-markdown/references/CALLOUTS.md +58 -0
  54. package/stack/skills/obsidian-markdown/references/EMBEDS.md +63 -0
  55. package/stack/skills/obsidian-markdown/references/PROPERTIES.md +61 -0
  56. package/stack/skills/react-doctor/SKILL.md +19 -0
  57. package/stack/skills/skill-creator/LICENSE.txt +202 -0
  58. package/stack/skills/skill-creator/SKILL.md +485 -0
  59. package/stack/skills/skill-creator/agents/analyzer.md +274 -0
  60. package/stack/skills/skill-creator/agents/comparator.md +202 -0
  61. package/stack/skills/skill-creator/agents/grader.md +223 -0
  62. package/stack/skills/skill-creator/assets/eval_review.html +146 -0
  63. package/stack/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  64. package/stack/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  65. package/stack/skills/skill-creator/references/schemas.md +430 -0
  66. package/stack/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  67. package/stack/skills/skill-creator/scripts/generate_report.py +326 -0
  68. package/stack/skills/skill-creator/scripts/improve_description.py +248 -0
  69. package/stack/skills/skill-creator/scripts/package_skill.py +136 -0
  70. package/stack/skills/skill-creator/scripts/quick_validate.py +103 -0
  71. package/stack/skills/skill-creator/scripts/run_eval.py +310 -0
  72. package/stack/skills/skill-creator/scripts/run_loop.py +332 -0
  73. package/stack/skills/skill-creator/scripts/utils.py +47 -0
  74. package/stack/skills/supabase/SKILL.md +135 -0
  75. package/stack/skills/supabase/assets/feedback-issue-template.md +17 -0
  76. package/stack/skills/supabase/references/skill-feedback.md +17 -0
  77. package/stack/skills/supabase-postgres-best-practices/SKILL.md +64 -0
  78. package/stack/skills/supabase-postgres-best-practices/references/_contributing.md +170 -0
  79. package/stack/skills/supabase-postgres-best-practices/references/_sections.md +39 -0
  80. package/stack/skills/supabase-postgres-best-practices/references/_template.md +34 -0
  81. package/stack/skills/supabase-postgres-best-practices/references/advanced-full-text-search.md +55 -0
  82. package/stack/skills/supabase-postgres-best-practices/references/advanced-jsonb-indexing.md +49 -0
  83. package/stack/skills/supabase-postgres-best-practices/references/conn-idle-timeout.md +46 -0
  84. package/stack/skills/supabase-postgres-best-practices/references/conn-limits.md +44 -0
  85. package/stack/skills/supabase-postgres-best-practices/references/conn-pooling.md +41 -0
  86. package/stack/skills/supabase-postgres-best-practices/references/conn-prepared-statements.md +46 -0
  87. package/stack/skills/supabase-postgres-best-practices/references/data-batch-inserts.md +54 -0
  88. package/stack/skills/supabase-postgres-best-practices/references/data-n-plus-one.md +53 -0
  89. package/stack/skills/supabase-postgres-best-practices/references/data-pagination.md +50 -0
  90. package/stack/skills/supabase-postgres-best-practices/references/data-upsert.md +50 -0
  91. package/stack/skills/supabase-postgres-best-practices/references/lock-advisory.md +56 -0
  92. package/stack/skills/supabase-postgres-best-practices/references/lock-deadlock-prevention.md +68 -0
  93. package/stack/skills/supabase-postgres-best-practices/references/lock-short-transactions.md +50 -0
  94. package/stack/skills/supabase-postgres-best-practices/references/lock-skip-locked.md +54 -0
  95. package/stack/skills/supabase-postgres-best-practices/references/monitor-explain-analyze.md +45 -0
  96. package/stack/skills/supabase-postgres-best-practices/references/monitor-pg-stat-statements.md +55 -0
  97. package/stack/skills/supabase-postgres-best-practices/references/monitor-vacuum-analyze.md +55 -0
  98. package/stack/skills/supabase-postgres-best-practices/references/query-composite-indexes.md +44 -0
  99. package/stack/skills/supabase-postgres-best-practices/references/query-covering-indexes.md +40 -0
  100. package/stack/skills/supabase-postgres-best-practices/references/query-index-types.md +48 -0
  101. package/stack/skills/supabase-postgres-best-practices/references/query-missing-indexes.md +43 -0
  102. package/stack/skills/supabase-postgres-best-practices/references/query-partial-indexes.md +45 -0
  103. package/stack/skills/supabase-postgres-best-practices/references/schema-constraints.md +80 -0
  104. package/stack/skills/supabase-postgres-best-practices/references/schema-data-types.md +46 -0
  105. package/stack/skills/supabase-postgres-best-practices/references/schema-foreign-key-indexes.md +59 -0
  106. package/stack/skills/supabase-postgres-best-practices/references/schema-lowercase-identifiers.md +55 -0
  107. package/stack/skills/supabase-postgres-best-practices/references/schema-partitioning.md +55 -0
  108. package/stack/skills/supabase-postgres-best-practices/references/schema-primary-keys.md +61 -0
  109. package/stack/skills/supabase-postgres-best-practices/references/security-privileges.md +54 -0
  110. package/stack/skills/supabase-postgres-best-practices/references/security-rls-basics.md +50 -0
  111. package/stack/skills/supabase-postgres-best-practices/references/security-rls-performance.md +63 -0
  112. package/stack/skills/tdd/SKILL.md +109 -0
  113. package/stack/skills/tdd/deep-modules.md +33 -0
  114. package/stack/skills/tdd/interface-design.md +31 -0
  115. package/stack/skills/tdd/mocking.md +59 -0
  116. package/stack/skills/tdd/refactoring.md +10 -0
  117. package/stack/skills/tdd/tests.md +61 -0
  118. package/stack/skills/to-issues/SKILL.md +83 -0
  119. package/stack/skills/to-prd/SKILL.md +72 -0
  120. package/stack/skills/work-lifecycle/SKILL.md +79 -0
  121. package/stack/skills/work-lifecycle/references/plan-template.md +185 -0
  122. package/stack/system-prompt/AGENTS.md +171 -0
  123. package/stack/system-prompt/engram-protocol.md +53 -0
  124. package/upstreams.json +96 -0
@@ -0,0 +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)
@@ -0,0 +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)
@@ -0,0 +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)
@@ -0,0 +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)
@@ -0,0 +1,55 @@
1
+ ---
2
+ title: Partition Large Tables for Better Performance
3
+ impact: MEDIUM-HIGH
4
+ impactDescription: 5-20x faster queries and maintenance on large tables
5
+ tags: partitioning, large-tables, time-series, performance
6
+ ---
7
+
8
+ ## Partition Large Tables for Better Performance
9
+
10
+ Partitioning splits a large table into smaller pieces, improving query performance and maintenance operations.
11
+
12
+ **Incorrect (single large table):**
13
+
14
+ ```sql
15
+ create table events (
16
+ id bigint generated always as identity,
17
+ created_at timestamptz,
18
+ data jsonb
19
+ );
20
+
21
+ -- 500M rows, queries scan everything
22
+ select * from events where created_at > '2024-01-01'; -- Slow
23
+ vacuum events; -- Takes hours, locks table
24
+ ```
25
+
26
+ **Correct (partitioned by time range):**
27
+
28
+ ```sql
29
+ create table events (
30
+ id bigint generated always as identity,
31
+ created_at timestamptz not null,
32
+ data jsonb
33
+ ) partition by range (created_at);
34
+
35
+ -- Create partitions for each month
36
+ create table events_2024_01 partition of events
37
+ for values from ('2024-01-01') to ('2024-02-01');
38
+
39
+ create table events_2024_02 partition of events
40
+ for values from ('2024-02-01') to ('2024-03-01');
41
+
42
+ -- Queries only scan relevant partitions
43
+ select * from events where created_at > '2024-01-15'; -- Only scans events_2024_01+
44
+
45
+ -- Drop old data instantly
46
+ drop table events_2023_01; -- Instant vs DELETE taking hours
47
+ ```
48
+
49
+ When to partition:
50
+
51
+ - Tables > 100M rows
52
+ - Time-series data with date-based queries
53
+ - Need to efficiently drop old data
54
+
55
+ Reference: [Table Partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html)
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Select Optimal Primary Key Strategy
3
+ impact: HIGH
4
+ impactDescription: Better index locality, reduced fragmentation
5
+ tags: primary-key, identity, uuid, serial, schema
6
+ ---
7
+
8
+ ## Select Optimal Primary Key Strategy
9
+
10
+ Primary key choice affects insert performance, index size, and replication
11
+ efficiency.
12
+
13
+ **Incorrect (problematic PK choices):**
14
+
15
+ ```sql
16
+ -- identity is the SQL-standard approach
17
+ create table users (
18
+ id serial primary key -- Works, but IDENTITY is recommended
19
+ );
20
+
21
+ -- Random UUIDs (v4) cause index fragmentation
22
+ create table orders (
23
+ id uuid default gen_random_uuid() primary key -- UUIDv4 = random = scattered inserts
24
+ );
25
+ ```
26
+
27
+ **Correct (optimal PK strategies):**
28
+
29
+ ```sql
30
+ -- Use IDENTITY for sequential IDs (SQL-standard, best for most cases)
31
+ create table users (
32
+ id bigint generated always as identity primary key
33
+ );
34
+
35
+ -- For distributed systems needing UUIDs, use UUIDv7 (time-ordered)
36
+ -- Requires pg_uuidv7 extension: create extension pg_uuidv7;
37
+ create table orders (
38
+ id uuid default uuid_generate_v7() primary key -- Time-ordered, no fragmentation
39
+ );
40
+
41
+ -- Alternative: time-prefixed IDs for sortable, distributed IDs (no extension needed)
42
+ create table events (
43
+ id text default concat(
44
+ to_char(now() at time zone 'utc', 'YYYYMMDDHH24MISSMS'),
45
+ gen_random_uuid()::text
46
+ ) primary key
47
+ );
48
+ ```
49
+
50
+ Guidelines:
51
+
52
+ - Single database: `bigint identity` (sequential, 8 bytes, SQL-standard)
53
+ - Distributed/exposed IDs: UUIDv7 (requires pg_uuidv7) or ULID (time-ordered, no
54
+ fragmentation)
55
+ - `serial` works but `identity` is SQL-standard and preferred for new
56
+ applications
57
+ - Avoid random UUIDs (v4) as primary keys on large tables (causes index
58
+ fragmentation)
59
+
60
+ Reference:
61
+ [Identity Columns](https://www.postgresql.org/docs/current/sql-createtable.html#SQL-CREATETABLE-PARMS-GENERATED-IDENTITY)
@@ -0,0 +1,54 @@
1
+ ---
2
+ title: Apply Principle of Least Privilege
3
+ impact: MEDIUM
4
+ impactDescription: Reduced attack surface, better audit trail
5
+ tags: privileges, security, roles, permissions
6
+ ---
7
+
8
+ ## Apply Principle of Least Privilege
9
+
10
+ Grant only the minimum permissions required. Never use superuser for application queries.
11
+
12
+ **Incorrect (overly broad permissions):**
13
+
14
+ ```sql
15
+ -- Application uses superuser connection
16
+ -- Or grants ALL to application role
17
+ grant all privileges on all tables in schema public to app_user;
18
+ grant all privileges on all sequences in schema public to app_user;
19
+
20
+ -- Any SQL injection becomes catastrophic
21
+ -- drop table users; cascades to everything
22
+ ```
23
+
24
+ **Correct (minimal, specific grants):**
25
+
26
+ ```sql
27
+ -- Create role with no default privileges
28
+ create role app_readonly nologin;
29
+
30
+ -- Grant only SELECT on specific tables
31
+ grant usage on schema public to app_readonly;
32
+ grant select on public.products, public.categories to app_readonly;
33
+
34
+ -- Create role for writes with limited scope
35
+ create role app_writer nologin;
36
+ grant usage on schema public to app_writer;
37
+ grant select, insert, update on public.orders to app_writer;
38
+ grant usage on sequence orders_id_seq to app_writer;
39
+ -- No DELETE permission
40
+
41
+ -- Login role inherits from these
42
+ create role app_user login password 'xxx';
43
+ grant app_writer to app_user;
44
+ ```
45
+
46
+ Revoke public defaults:
47
+
48
+ ```sql
49
+ -- Revoke default public access
50
+ revoke all on schema public from public;
51
+ revoke all on all tables in schema public from public;
52
+ ```
53
+
54
+ Reference: [Roles and Privileges](https://supabase.com/blog/postgres-roles-and-privileges)
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: Enable Row Level Security for Multi-Tenant Data
3
+ impact: CRITICAL
4
+ impactDescription: Database-enforced tenant isolation, prevent data leaks
5
+ tags: rls, row-level-security, multi-tenant, security
6
+ ---
7
+
8
+ ## Enable Row Level Security for Multi-Tenant Data
9
+
10
+ Row Level Security (RLS) enforces data access at the database level, ensuring users only see their own data.
11
+
12
+ **Incorrect (application-level filtering only):**
13
+
14
+ ```sql
15
+ -- Relying only on application to filter
16
+ select * from orders where user_id = $current_user_id;
17
+
18
+ -- Bug or bypass means all data is exposed!
19
+ select * from orders; -- Returns ALL orders
20
+ ```
21
+
22
+ **Correct (database-enforced RLS):**
23
+
24
+ ```sql
25
+ -- Enable RLS on the table
26
+ alter table orders enable row level security;
27
+
28
+ -- Create policy for users to see only their orders
29
+ create policy orders_user_policy on orders
30
+ for all
31
+ using (user_id = current_setting('app.current_user_id')::bigint);
32
+
33
+ -- Force RLS even for table owners
34
+ alter table orders force row level security;
35
+
36
+ -- Set user context and query
37
+ set app.current_user_id = '123';
38
+ select * from orders; -- Only returns orders for user 123
39
+ ```
40
+
41
+ Policy for authenticated role:
42
+
43
+ ```sql
44
+ create policy orders_user_policy on orders
45
+ for all
46
+ to authenticated
47
+ using (user_id = auth.uid());
48
+ ```
49
+
50
+ Reference: [Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security)
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: Optimize RLS Policies for Performance
3
+ impact: HIGH
4
+ impactDescription: 5-10x faster RLS queries with proper patterns
5
+ tags: rls, performance, security, optimization
6
+ ---
7
+
8
+ ## Optimize RLS Policies for Performance
9
+
10
+ Poorly written RLS policies can cause severe performance issues. Use subqueries and indexes strategically.
11
+
12
+ **Incorrect (function called for every row):**
13
+
14
+ ```sql
15
+ create policy orders_policy on orders
16
+ using (auth.uid() = user_id); -- auth.uid() called per row!
17
+
18
+ -- With 1M rows, auth.uid() is called 1M times
19
+ ```
20
+
21
+ **Correct (wrap functions in SELECT):**
22
+
23
+ ```sql
24
+ create policy orders_policy on orders
25
+ using ((select auth.uid()) = user_id); -- Called once, cached
26
+
27
+ -- 100x+ faster on large tables
28
+ ```
29
+
30
+ Use security definer functions for complex checks:
31
+
32
+ `SECURITY DEFINER` functions run with the creator's privileges and bypass RLS on any tables they touch — which is what makes them useful for internal lookups, but also what makes them dangerous if misused. Always include an explicit `auth.uid()` check inside the function body, keep them in a non-exposed schema, and revoke `EXECUTE` from any role that shouldn't call them directly.
33
+
34
+ ```sql
35
+ -- Create helper function in a private schema
36
+ create or replace function private.is_team_member(team_id bigint)
37
+ returns boolean
38
+ language sql
39
+ security definer
40
+ set search_path = ''
41
+ as $$
42
+ select exists (
43
+ select 1 from public.team_members
44
+ -- always check the calling user's identity inside the function
45
+ where team_id = $1 and user_id = (select auth.uid())
46
+ );
47
+ $$;
48
+
49
+ -- Revoke direct execution from public roles
50
+ revoke execute on function private.is_team_member(bigint) from PUBLIC, anon, authenticated, service_role;
51
+
52
+ -- Use in policy (indexed lookup, not per-row check)
53
+ create policy team_orders_policy on orders
54
+ using ((select private.is_team_member(team_id)));
55
+ ```
56
+
57
+ Always add indexes on columns used in RLS policies:
58
+
59
+ ```sql
60
+ create index orders_user_id_idx on orders (user_id);
61
+ ```
62
+
63
+ Reference: [RLS Performance](https://supabase.com/docs/guides/database/postgres/row-level-security#rls-performance-recommendations)
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: tdd
3
+ description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
4
+ ---
5
+
6
+ # Test-Driven Development
7
+
8
+ ## Philosophy
9
+
10
+ **Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
11
+
12
+ **Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
13
+
14
+ **Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
15
+
16
+ See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
17
+
18
+ ## Anti-Pattern: Horizontal Slices
19
+
20
+ **DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
21
+
22
+ This produces **crap tests**:
23
+
24
+ - Tests written in bulk test _imagined_ behavior, not _actual_ behavior
25
+ - You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
26
+ - Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
27
+ - You outrun your headlights, committing to test structure before understanding the implementation
28
+
29
+ **Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
30
+
31
+ ```
32
+ WRONG (horizontal):
33
+ RED: test1, test2, test3, test4, test5
34
+ GREEN: impl1, impl2, impl3, impl4, impl5
35
+
36
+ RIGHT (vertical):
37
+ RED→GREEN: test1→impl1
38
+ RED→GREEN: test2→impl2
39
+ RED→GREEN: test3→impl3
40
+ ...
41
+ ```
42
+
43
+ ## Workflow
44
+
45
+ ### 1. Planning
46
+
47
+ When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching.
48
+
49
+ Before writing any code:
50
+
51
+ - [ ] Confirm with user what interface changes are needed
52
+ - [ ] Confirm with user which behaviors to test (prioritize)
53
+ - [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
54
+ - [ ] Design interfaces for [testability](interface-design.md)
55
+ - [ ] List the behaviors to test (not implementation steps)
56
+ - [ ] Get user approval on the plan
57
+
58
+ Ask: "What should the public interface look like? Which behaviors are most important to test?"
59
+
60
+ **You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
61
+
62
+ ### 2. Tracer Bullet
63
+
64
+ Write ONE test that confirms ONE thing about the system:
65
+
66
+ ```
67
+ RED: Write test for first behavior → test fails
68
+ GREEN: Write minimal code to pass → test passes
69
+ ```
70
+
71
+ This is your tracer bullet - proves the path works end-to-end.
72
+
73
+ ### 3. Incremental Loop
74
+
75
+ For each remaining behavior:
76
+
77
+ ```
78
+ RED: Write next test → fails
79
+ GREEN: Minimal code to pass → passes
80
+ ```
81
+
82
+ Rules:
83
+
84
+ - One test at a time
85
+ - Only enough code to pass current test
86
+ - Don't anticipate future tests
87
+ - Keep tests focused on observable behavior
88
+
89
+ ### 4. Refactor
90
+
91
+ After all tests pass, look for [refactor candidates](refactoring.md):
92
+
93
+ - [ ] Extract duplication
94
+ - [ ] Deepen modules (move complexity behind simple interfaces)
95
+ - [ ] Apply SOLID principles where natural
96
+ - [ ] Consider what new code reveals about existing code
97
+ - [ ] Run tests after each refactor step
98
+
99
+ **Never refactor while RED.** Get to GREEN first.
100
+
101
+ ## Checklist Per Cycle
102
+
103
+ ```
104
+ [ ] Test describes behavior, not implementation
105
+ [ ] Test uses public interface only
106
+ [ ] Test would survive internal refactor
107
+ [ ] Code is minimal for this test
108
+ [ ] No speculative features added
109
+ ```
@@ -0,0 +1,33 @@
1
+ # Deep Modules
2
+
3
+ From "A Philosophy of Software Design":
4
+
5
+ **Deep module** = small interface + lots of implementation
6
+
7
+ ```
8
+ ┌─────────────────────┐
9
+ │ Small Interface │ ← Few methods, simple params
10
+ ├─────────────────────┤
11
+ │ │
12
+ │ │
13
+ │ Deep Implementation│ ← Complex logic hidden
14
+ │ │
15
+ │ │
16
+ └─────────────────────┘
17
+ ```
18
+
19
+ **Shallow module** = large interface + little implementation (avoid)
20
+
21
+ ```
22
+ ┌─────────────────────────────────┐
23
+ │ Large Interface │ ← Many methods, complex params
24
+ ├─────────────────────────────────┤
25
+ │ Thin Implementation │ ← Just passes through
26
+ └─────────────────────────────────┘
27
+ ```
28
+
29
+ When designing interfaces, ask:
30
+
31
+ - Can I reduce the number of methods?
32
+ - Can I simplify the parameters?
33
+ - Can I hide more complexity inside?