@polymorphism-tech/morph-spec 6.0.0 → 7.1.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 (114) hide show
  1. package/README.md +367 -366
  2. package/docs/CHEATSHEET.md +3 -3
  3. package/docs/QUICKSTART.md +4 -4
  4. package/framework/CLAUDE.md +13 -0
  5. package/framework/MORPH.md +57 -36
  6. package/framework/agents.json +132 -127
  7. package/framework/commands/morph-apply.md +4 -21
  8. package/framework/commands/morph-archive.md +1 -1
  9. package/framework/commands/morph-proposal.md +2 -0
  10. package/framework/hooks/claude-code/core/enforce-phase-writes.js +1 -1
  11. package/framework/hooks/claude-code/core/protect-spec-files.js +1 -1
  12. package/framework/hooks/claude-code/core/state-sync.js +212 -0
  13. package/framework/hooks/shared/phase-utils.js +5 -4
  14. package/framework/hooks/shared/state-reader.js +1 -1
  15. package/framework/phases.json +1 -1
  16. package/framework/rubrics/backend.json +41 -36
  17. package/framework/rules/ai-agents-standards.md +45 -15
  18. package/framework/rules/morph-workflow.md +15 -34
  19. package/framework/rules/neon-standards.md +25 -26
  20. package/framework/schemas/tasks.schema.json +35 -0
  21. package/framework/skills/core/morph-apply/SKILL.md +154 -0
  22. package/framework/skills/core/morph-brainstorming/SKILL.md +53 -30
  23. package/framework/skills/core/morph-implement/SKILL.md +25 -14
  24. package/framework/skills/core/morph-plan/SKILL.md +91 -23
  25. package/framework/skills/core/morph-proposal/SKILL.md +137 -0
  26. package/framework/skills/core/morph-review/SKILL.md +43 -7
  27. package/framework/skills/core/morph-stack-scan/SKILL.md +40 -1
  28. package/framework/standards/STANDARDS.json +1729 -1134
  29. package/framework/standards/ai-agents/agent-session.md +160 -0
  30. package/framework/standards/ai-agents/batching.md +193 -0
  31. package/framework/standards/ai-agents/context-providers.md +188 -0
  32. package/framework/standards/ai-agents/mcp-server.md +250 -0
  33. package/framework/standards/ai-agents/mcp-tools.md +197 -0
  34. package/framework/standards/ai-agents/middleware-patterns.md +207 -0
  35. package/framework/standards/ai-agents/modalities-image-gen.md +173 -0
  36. package/framework/standards/ai-agents/modalities-speech-to-text.md +171 -0
  37. package/framework/standards/ai-agents/modalities-text-to-speech.md +181 -0
  38. package/framework/standards/ai-agents/modalities-vision.md +201 -0
  39. package/framework/standards/ai-agents/multi-agent-patterns.md +155 -0
  40. package/framework/standards/ai-agents/production.md +114 -258
  41. package/framework/standards/ai-agents/prompts-in-db.md +214 -0
  42. package/framework/standards/ai-agents/providers/model-registry.md +158 -0
  43. package/framework/standards/ai-agents/rag-custom-pgvector.md +243 -0
  44. package/framework/standards/ai-agents/service-tier-flex.md +135 -0
  45. package/framework/standards/ai-agents/setup.md +142 -316
  46. package/framework/standards/ai-agents/structured-output.md +249 -0
  47. package/framework/standards/ai-agents/sweet-spot.md +109 -0
  48. package/framework/standards/ai-agents/workflows.md +114 -284
  49. package/framework/standards/architecture/vertical-slice/vertical-slice.md +433 -429
  50. package/framework/standards/backend/api/validation.md +92 -88
  51. package/framework/standards/backend/database/postgresql/database.md +336 -332
  52. package/framework/standards/backend/database/vector-search-rag.md +599 -541
  53. package/framework/standards/backend/dotnet/fluent-validation-vsa.md +4 -0
  54. package/framework/standards/backend/dotnet/result-pattern.md +4 -0
  55. package/framework/standards/backend/dotnet/scalar-ui.md +176 -172
  56. package/framework/standards/backend/dotnet/scrutor.md +4 -0
  57. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +278 -274
  58. package/framework/standards/backend/integrations/asaas/asaas-api.md +260 -216
  59. package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +354 -350
  60. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +30 -19
  61. package/framework/standards/backend/integrations/resend/resend-email.md +400 -385
  62. package/framework/standards/data/nosql/cache/redis.md +106 -97
  63. package/framework/standards/data/nosql/cosmos-db.md +127 -118
  64. package/framework/standards/data/vector-search/rag-chunking.md +113 -104
  65. package/framework/standards/frontend/design-system/ai-image-generation.md +4 -0
  66. package/framework/standards/frontend/design-system/animations.md +164 -160
  67. package/framework/standards/frontend/design-system/naming.md +68 -64
  68. package/framework/standards/frontend/gsap/gsap-core.md +14 -8
  69. package/framework/standards/frontend/gsap/gsap-plugins.md +26 -21
  70. package/framework/standards/frontend/gsap/gsap-scrolltrigger.md +9 -7
  71. package/framework/standards/frontend/nextjs/app-router.md +127 -123
  72. package/framework/standards/frontend/nextjs/components.md +136 -132
  73. package/framework/standards/frontend/nextjs/data-fetching.md +130 -126
  74. package/framework/standards/frontend/nextjs/forms.md +134 -128
  75. package/framework/standards/frontend/nextjs/motion-patterns.md +328 -322
  76. package/framework/standards/frontend/nextjs/naming-conventions.md +71 -67
  77. package/framework/standards/frontend/nextjs/nextjs-patterns.md +229 -225
  78. package/framework/standards/frontend/nextjs/project-structure.md +106 -102
  79. package/framework/standards/frontend/nextjs/state-management.md +76 -72
  80. package/framework/standards/frontend/nextjs/testing.md +115 -111
  81. package/framework/standards/infrastructure/docker/easypanel-deploy.md +196 -192
  82. package/framework/standards/infrastructure/neon/neon-pgrag.md +6 -2
  83. package/framework/standards/infrastructure/neon/neon-pgvector.md +4 -0
  84. package/framework/standards/infrastructure/neon/neon-setup.md +5 -1
  85. package/framework/standards/integration/mcp/mcp-tools.md +471 -462
  86. package/framework/templates/REGISTRY.json +1745 -1239
  87. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -0
  88. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -0
  89. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -0
  90. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -0
  91. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -0
  92. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -0
  93. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -0
  94. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -0
  95. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -0
  96. package/framework/templates/docs/onboarding.md +4 -4
  97. package/framework/templates/tasks.template.json +17 -0
  98. package/package.json +89 -83
  99. package/src/commands/project/init.js +16 -0
  100. package/src/commands/validation/validate-feature.js +1 -1
  101. package/src/core/paths/output-schema.js +6 -6
  102. package/src/core/state/state-manager.js +1 -1
  103. package/src/core/templates/template-registry.js +289 -256
  104. package/src/lib/detectors/design-system-detector.js +1 -1
  105. package/src/lib/generators/context-generator.js +516 -518
  106. package/src/lib/generators/scaffold-generator.js +23 -26
  107. package/src/lib/installers/memory-installer.js +138 -0
  108. package/src/lib/phase-chain/phase-validator.js +4 -4
  109. package/src/lib/risk-detector.js +80 -0
  110. package/src/lib/tasks/tasks-json-parser.js +185 -0
  111. package/src/scripts/setup-infra.js +25 -0
  112. package/src/utils/hooks-installer.js +59 -10
  113. package/framework/standards/infrastructure/neon/neon-semantic-kernel.md +0 -310
  114. package/framework/templates/integrations/semantic-kernel-neon.cs +0 -125
@@ -1,332 +1,336 @@
1
- # Neon PostgreSQL Database Standards
2
-
3
- > **Scope:** nextjs-neon
4
- > **Layer:** 2 (on keyword)
5
- > **Keywords:** postgresql, postgres, sql, neon, database schema
6
- > **Load When:** neon or postgresql keywords detected
7
-
8
- Database schema design, migrations, and Row Level Security (RLS) patterns for Neon PostgreSQL.
9
-
10
- ---
11
-
12
- ## Schema Design
13
-
14
- ### Naming Conventions
15
-
16
- | Element | Convention | Example |
17
- |---------|-----------|---------|
18
- | **Tables** | snake_case, plural | `users`, `user_profiles`, `order_items` |
19
- | **Columns** | snake_case | `created_at`, `user_id`, `is_active` |
20
- | **Primary Keys** | `id` | `id uuid primary key default gen_random_uuid()` |
21
- | **Foreign Keys** | `{table}_id` | `user_id`, `order_id` |
22
- | **Timestamps** | `created_at`, `updated_at` | Always include |
23
- | **Boolean** | `is_` or `has_` prefix | `is_active`, `has_verified_email` |
24
- | **Indexes** | `idx_{table}_{column}` | `idx_users_email` |
25
-
26
- ### Standard Table Template
27
-
28
- ```sql
29
- create table public.users (
30
- id uuid primary key default gen_random_uuid(),
31
- email text unique not null,
32
- full_name text,
33
- avatar_url text,
34
- is_active boolean default true,
35
- created_at timestamptz default now() not null,
36
- updated_at timestamptz default now() not null
37
- );
38
-
39
- -- Updated timestamp trigger
40
- create or replace function public.handle_updated_at()
41
- returns trigger as $$
42
- begin
43
- new.updated_at = now();
44
- return new;
45
- end;
46
- $$ language plpgsql;
47
-
48
- create trigger users_updated_at
49
- before update on public.users
50
- for each row execute function public.handle_updated_at();
51
- ```
52
-
53
- ---
54
-
55
- ## Row Level Security (RLS)
56
-
57
- ### Enable RLS
58
-
59
- ```sql
60
- -- Always enable RLS on user-facing tables
61
- alter table public.profiles enable row level security;
62
- ```
63
-
64
- ### Common RLS Policies
65
-
66
- #### User can read own profile
67
-
68
- ```sql
69
- create policy "Users can view own profile"
70
- on public.profiles for select
71
- using (auth.user_id() = user_id);
72
- ```
73
-
74
- #### User can update own profile
75
-
76
- ```sql
77
- create policy "Users can update own profile"
78
- on public.profiles for update
79
- using (auth.user_id() = user_id)
80
- with check (auth.user_id() = user_id);
81
- ```
82
-
83
- #### User can insert own profile
84
-
85
- ```sql
86
- create policy "Users can insert own profile"
87
- on public.profiles for insert
88
- with check (auth.user_id() = user_id);
89
- ```
90
-
91
- #### Admin can do anything
92
-
93
- ```sql
94
- create policy "Admins have full access"
95
- on public.profiles for all
96
- using (
97
- exists (
98
- select 1 from public.user_roles
99
- where user_id = auth.user_id() and role = 'admin'
100
- )
101
- );
102
- ```
103
-
104
- #### Public read access
105
-
106
- ```sql
107
- create policy "Public profiles are viewable by everyone"
108
- on public.profiles for select
109
- using (is_public = true);
110
- ```
111
-
112
- ---
113
-
114
- ## Migrations
115
-
116
- ### Migration Management (EF Core)
117
-
118
- ```bash
119
- # Create a new migration
120
- dotnet ef migrations add CreateUsersTable
121
-
122
- # Apply migrations to Neon database
123
- dotnet ef database update
124
-
125
- # Generate SQL script for review
126
- dotnet ef migrations script --idempotent
127
- ```
128
-
129
- ### Migration Template (SQL for manual migrations)
130
-
131
- ```sql
132
- -- Create table
133
- create table if not exists public.example_table (
134
- id uuid primary key default gen_random_uuid(),
135
- name text not null,
136
- created_at timestamptz default now() not null
137
- );
138
-
139
- -- Enable RLS
140
- alter table public.example_table enable row level security;
141
-
142
- -- Create policies
143
- create policy "Example policy"
144
- on public.example_table for select
145
- using (true);
146
-
147
- -- Create indexes
148
- create index if not exists idx_example_table_name
149
- on public.example_table (name);
150
-
151
- -- Rollback (always include)
152
- -- drop table if exists public.example_table cascade;
153
- ```
154
-
155
- ---
156
-
157
- ## Relationships
158
-
159
- ### One-to-Many
160
-
161
- ```sql
162
- create table public.posts (
163
- id uuid primary key default gen_random_uuid(),
164
- author_id uuid references public.users(id) on delete cascade,
165
- title text not null,
166
- content text,
167
- created_at timestamptz default now()
168
- );
169
-
170
- create index idx_posts_author_id on public.posts (author_id);
171
- ```
172
-
173
- ### Many-to-Many (Join Table)
174
-
175
- ```sql
176
- create table public.user_teams (
177
- user_id uuid references public.users(id) on delete cascade,
178
- team_id uuid references public.teams(id) on delete cascade,
179
- role text not null default 'member',
180
- joined_at timestamptz default now(),
181
- primary key (user_id, team_id)
182
- );
183
- ```
184
-
185
- ---
186
-
187
- ## Indexes
188
-
189
- ### When to Add Indexes
190
-
191
- - Foreign keys (for joins)
192
- - Columns used in WHERE clauses
193
- - Columns used in ORDER BY
194
- - Columns used in GROUP BY
195
- - Text search columns (GIN index)
196
-
197
- ### Index Examples
198
-
199
- ```sql
200
- -- B-tree (default, most common)
201
- create index idx_users_email on public.users (email);
202
-
203
- -- Partial index (for specific queries)
204
- create index idx_users_active_email
205
- on public.users (email) where is_active = true;
206
-
207
- -- Composite index (multiple columns)
208
- create index idx_posts_author_created
209
- on public.posts (author_id, created_at desc);
210
-
211
- -- GIN index (full-text search)
212
- create index idx_posts_content_search
213
- on public.posts using gin(to_tsvector('english', content));
214
- ```
215
-
216
- ---
217
-
218
- ## Functions & Triggers
219
-
220
- ### Auto-update Timestamp
221
-
222
- ```sql
223
- create or replace function public.handle_updated_at()
224
- returns trigger as $$
225
- begin
226
- new.updated_at = now();
227
- return new;
228
- end;
229
- $$ language plpgsql;
230
-
231
- -- Apply to any table
232
- create trigger users_updated_at
233
- before update on public.users
234
- for each row execute function public.handle_updated_at();
235
- ```
236
-
237
- ### Soft Delete
238
-
239
- ```sql
240
- create or replace function public.soft_delete()
241
- returns trigger as $$
242
- begin
243
- update public.users
244
- set deleted_at = now()
245
- where id = old.id;
246
- return null;
247
- end;
248
- $$ language plpgsql;
249
-
250
- create trigger users_soft_delete
251
- instead of delete on public.users
252
- for each row execute function public.soft_delete();
253
- ```
254
-
255
- ---
256
-
257
- ## Database Queries (EF Core / SQL)
258
-
259
- ### Select (EF Core)
260
-
261
- ```csharp
262
- var users = await db.Users
263
- .Where(u => u.IsActive)
264
- .OrderByDescending(u => u.CreatedAt)
265
- .Take(10)
266
- .Select(u => new { u.Id, u.Name, u.Email })
267
- .ToListAsync(ct);
268
- ```
269
-
270
- ### Insert (EF Core)
271
-
272
- ```csharp
273
- var user = new User { Name = "John", Email = "john@example.com" };
274
- db.Users.Add(user);
275
- await db.SaveChangesAsync(ct);
276
- ```
277
-
278
- ### Update (EF Core)
279
-
280
- ```csharp
281
- var user = await db.Users.FindAsync([userId], ct);
282
- if (user is not null)
283
- {
284
- user.Name = "John Doe";
285
- await db.SaveChangesAsync(ct);
286
- }
287
- ```
288
-
289
- ### Delete (EF Core)
290
-
291
- ```csharp
292
- await db.Users.Where(u => u.Id == userId).ExecuteDeleteAsync(ct);
293
- ```
294
-
295
- ### Joins (Navigation Properties)
296
-
297
- ```csharp
298
- var posts = await db.Posts
299
- .Include(p => p.Author)
300
- .Select(p => new
301
- {
302
- p.Id,
303
- p.Title,
304
- Author = new { p.Author.Id, p.Author.Name, p.Author.AvatarUrl }
305
- })
306
- .ToListAsync(ct);
307
- ```
308
-
309
- ### Direct SQL via Npgsql (Next.js / serverless)
310
-
311
- ```typescript
312
- import { neon } from '@neondatabase/serverless';
313
-
314
- const sql = neon(process.env.DATABASE_URL!);
315
- const users = await sql`SELECT id, name, email FROM users WHERE is_active = true ORDER BY created_at DESC LIMIT 10`;
316
- ```
317
-
318
- ---
319
-
320
- ## Performance Best Practices
321
-
322
- 1. **Use select() specific columns** - Don't select `*` unnecessarily
323
- 2. **Add indexes** - For foreign keys and WHERE/ORDER BY columns
324
- 3. **Limit results** - Use `.limit()` for pagination
325
- 4. **Use RLS efficiently** - Simple policies are faster
326
- 5. **Batch operations** - Use array inserts instead of loops
327
- 6. **Use materialized views** - For complex aggregations
328
- 7. **Enable statement timeout** - Prevent long-running queries
329
-
330
- ---
331
-
332
- *Neon PostgreSQL Database Standards - MORPH-SPEC by Polymorphism Tech*
1
+ # Neon PostgreSQL Database Standards
2
+
3
+ > **Scope:** nextjs-neon
4
+ > **Layer:** 2 (on keyword)
5
+ > **Keywords:** postgresql, postgres, sql, neon, database schema
6
+ > **Load When:** neon or postgresql keywords detected
7
+
8
+ **Verified against:** PostgreSQL 16/17 + EF Core 10 + @neondatabase/serverless. Last-verified: 2026-05-20.
9
+
10
+ ---
11
+
12
+ Database schema design, migrations, and Row Level Security (RLS) patterns for Neon PostgreSQL.
13
+
14
+ ---
15
+
16
+ ## Schema Design
17
+
18
+ ### Naming Conventions
19
+
20
+ | Element | Convention | Example |
21
+ |---------|-----------|---------|
22
+ | **Tables** | snake_case, plural | `users`, `user_profiles`, `order_items` |
23
+ | **Columns** | snake_case | `created_at`, `user_id`, `is_active` |
24
+ | **Primary Keys** | `id` | `id uuid primary key default gen_random_uuid()` |
25
+ | **Foreign Keys** | `{table}_id` | `user_id`, `order_id` |
26
+ | **Timestamps** | `created_at`, `updated_at` | Always include |
27
+ | **Boolean** | `is_` or `has_` prefix | `is_active`, `has_verified_email` |
28
+ | **Indexes** | `idx_{table}_{column}` | `idx_users_email` |
29
+
30
+ ### Standard Table Template
31
+
32
+ ```sql
33
+ create table public.users (
34
+ id uuid primary key default gen_random_uuid(),
35
+ email text unique not null,
36
+ full_name text,
37
+ avatar_url text,
38
+ is_active boolean default true,
39
+ created_at timestamptz default now() not null,
40
+ updated_at timestamptz default now() not null
41
+ );
42
+
43
+ -- Updated timestamp trigger
44
+ create or replace function public.handle_updated_at()
45
+ returns trigger as $$
46
+ begin
47
+ new.updated_at = now();
48
+ return new;
49
+ end;
50
+ $$ language plpgsql;
51
+
52
+ create trigger users_updated_at
53
+ before update on public.users
54
+ for each row execute function public.handle_updated_at();
55
+ ```
56
+
57
+ ---
58
+
59
+ ## Row Level Security (RLS)
60
+
61
+ ### Enable RLS
62
+
63
+ ```sql
64
+ -- Always enable RLS on user-facing tables
65
+ alter table public.profiles enable row level security;
66
+ ```
67
+
68
+ ### Common RLS Policies
69
+
70
+ #### User can read own profile
71
+
72
+ ```sql
73
+ create policy "Users can view own profile"
74
+ on public.profiles for select
75
+ using (auth.user_id() = user_id);
76
+ ```
77
+
78
+ #### User can update own profile
79
+
80
+ ```sql
81
+ create policy "Users can update own profile"
82
+ on public.profiles for update
83
+ using (auth.user_id() = user_id)
84
+ with check (auth.user_id() = user_id);
85
+ ```
86
+
87
+ #### User can insert own profile
88
+
89
+ ```sql
90
+ create policy "Users can insert own profile"
91
+ on public.profiles for insert
92
+ with check (auth.user_id() = user_id);
93
+ ```
94
+
95
+ #### Admin can do anything
96
+
97
+ ```sql
98
+ create policy "Admins have full access"
99
+ on public.profiles for all
100
+ using (
101
+ exists (
102
+ select 1 from public.user_roles
103
+ where user_id = auth.user_id() and role = 'admin'
104
+ )
105
+ );
106
+ ```
107
+
108
+ #### Public read access
109
+
110
+ ```sql
111
+ create policy "Public profiles are viewable by everyone"
112
+ on public.profiles for select
113
+ using (is_public = true);
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Migrations
119
+
120
+ ### Migration Management (EF Core)
121
+
122
+ ```bash
123
+ # Create a new migration
124
+ dotnet ef migrations add CreateUsersTable
125
+
126
+ # Apply migrations to Neon database
127
+ dotnet ef database update
128
+
129
+ # Generate SQL script for review
130
+ dotnet ef migrations script --idempotent
131
+ ```
132
+
133
+ ### Migration Template (SQL for manual migrations)
134
+
135
+ ```sql
136
+ -- Create table
137
+ create table if not exists public.example_table (
138
+ id uuid primary key default gen_random_uuid(),
139
+ name text not null,
140
+ created_at timestamptz default now() not null
141
+ );
142
+
143
+ -- Enable RLS
144
+ alter table public.example_table enable row level security;
145
+
146
+ -- Create policies
147
+ create policy "Example policy"
148
+ on public.example_table for select
149
+ using (true);
150
+
151
+ -- Create indexes
152
+ create index if not exists idx_example_table_name
153
+ on public.example_table (name);
154
+
155
+ -- Rollback (always include)
156
+ -- drop table if exists public.example_table cascade;
157
+ ```
158
+
159
+ ---
160
+
161
+ ## Relationships
162
+
163
+ ### One-to-Many
164
+
165
+ ```sql
166
+ create table public.posts (
167
+ id uuid primary key default gen_random_uuid(),
168
+ author_id uuid references public.users(id) on delete cascade,
169
+ title text not null,
170
+ content text,
171
+ created_at timestamptz default now()
172
+ );
173
+
174
+ create index idx_posts_author_id on public.posts (author_id);
175
+ ```
176
+
177
+ ### Many-to-Many (Join Table)
178
+
179
+ ```sql
180
+ create table public.user_teams (
181
+ user_id uuid references public.users(id) on delete cascade,
182
+ team_id uuid references public.teams(id) on delete cascade,
183
+ role text not null default 'member',
184
+ joined_at timestamptz default now(),
185
+ primary key (user_id, team_id)
186
+ );
187
+ ```
188
+
189
+ ---
190
+
191
+ ## Indexes
192
+
193
+ ### When to Add Indexes
194
+
195
+ - Foreign keys (for joins)
196
+ - Columns used in WHERE clauses
197
+ - Columns used in ORDER BY
198
+ - Columns used in GROUP BY
199
+ - Text search columns (GIN index)
200
+
201
+ ### Index Examples
202
+
203
+ ```sql
204
+ -- B-tree (default, most common)
205
+ create index idx_users_email on public.users (email);
206
+
207
+ -- Partial index (for specific queries)
208
+ create index idx_users_active_email
209
+ on public.users (email) where is_active = true;
210
+
211
+ -- Composite index (multiple columns)
212
+ create index idx_posts_author_created
213
+ on public.posts (author_id, created_at desc);
214
+
215
+ -- GIN index (full-text search)
216
+ create index idx_posts_content_search
217
+ on public.posts using gin(to_tsvector('english', content));
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Functions & Triggers
223
+
224
+ ### Auto-update Timestamp
225
+
226
+ ```sql
227
+ create or replace function public.handle_updated_at()
228
+ returns trigger as $$
229
+ begin
230
+ new.updated_at = now();
231
+ return new;
232
+ end;
233
+ $$ language plpgsql;
234
+
235
+ -- Apply to any table
236
+ create trigger users_updated_at
237
+ before update on public.users
238
+ for each row execute function public.handle_updated_at();
239
+ ```
240
+
241
+ ### Soft Delete
242
+
243
+ ```sql
244
+ create or replace function public.soft_delete()
245
+ returns trigger as $$
246
+ begin
247
+ update public.users
248
+ set deleted_at = now()
249
+ where id = old.id;
250
+ return null;
251
+ end;
252
+ $$ language plpgsql;
253
+
254
+ create trigger users_soft_delete
255
+ instead of delete on public.users
256
+ for each row execute function public.soft_delete();
257
+ ```
258
+
259
+ ---
260
+
261
+ ## Database Queries (EF Core / SQL)
262
+
263
+ ### Select (EF Core)
264
+
265
+ ```csharp
266
+ var users = await db.Users
267
+ .Where(u => u.IsActive)
268
+ .OrderByDescending(u => u.CreatedAt)
269
+ .Take(10)
270
+ .Select(u => new { u.Id, u.Name, u.Email })
271
+ .ToListAsync(ct);
272
+ ```
273
+
274
+ ### Insert (EF Core)
275
+
276
+ ```csharp
277
+ var user = new User { Name = "John", Email = "john@example.com" };
278
+ db.Users.Add(user);
279
+ await db.SaveChangesAsync(ct);
280
+ ```
281
+
282
+ ### Update (EF Core)
283
+
284
+ ```csharp
285
+ var user = await db.Users.FindAsync([userId], ct);
286
+ if (user is not null)
287
+ {
288
+ user.Name = "John Doe";
289
+ await db.SaveChangesAsync(ct);
290
+ }
291
+ ```
292
+
293
+ ### Delete (EF Core)
294
+
295
+ ```csharp
296
+ await db.Users.Where(u => u.Id == userId).ExecuteDeleteAsync(ct);
297
+ ```
298
+
299
+ ### Joins (Navigation Properties)
300
+
301
+ ```csharp
302
+ var posts = await db.Posts
303
+ .Include(p => p.Author)
304
+ .Select(p => new
305
+ {
306
+ p.Id,
307
+ p.Title,
308
+ Author = new { p.Author.Id, p.Author.Name, p.Author.AvatarUrl }
309
+ })
310
+ .ToListAsync(ct);
311
+ ```
312
+
313
+ ### Direct SQL via Npgsql (Next.js / serverless)
314
+
315
+ ```typescript
316
+ import { neon } from '@neondatabase/serverless';
317
+
318
+ const sql = neon(process.env.DATABASE_URL!);
319
+ const users = await sql`SELECT id, name, email FROM users WHERE is_active = true ORDER BY created_at DESC LIMIT 10`;
320
+ ```
321
+
322
+ ---
323
+
324
+ ## Performance Best Practices
325
+
326
+ 1. **Use select() specific columns** - Don't select `*` unnecessarily
327
+ 2. **Add indexes** - For foreign keys and WHERE/ORDER BY columns
328
+ 3. **Limit results** - Use `.limit()` for pagination
329
+ 4. **Use RLS efficiently** - Simple policies are faster
330
+ 5. **Batch operations** - Use array inserts instead of loops
331
+ 6. **Use materialized views** - For complex aggregations
332
+ 7. **Enable statement timeout** - Prevent long-running queries
333
+
334
+ ---
335
+
336
+ *Neon PostgreSQL Database Standards - MORPH-SPEC by Polymorphism Tech*