@polymorphism-tech/morph-spec 4.16.0 → 4.18.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 (107) hide show
  1. package/CLAUDE.md +36 -0
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +3 -0
  4. package/bin/task-manager.js +999 -962
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +1 -1
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/agents/ai-agents/vector-search-expert.md +247 -233
  9. package/framework/agents/backend/ms-agent-expert.md +1 -1
  10. package/framework/agents/backend/neon-expert.md +379 -0
  11. package/framework/agents/frontend/gsap-animator.md +131 -0
  12. package/framework/agents/integrations/neon-auth.md +151 -0
  13. package/framework/agents.json +1183 -1085
  14. package/framework/commands/morph-preflight.md +200 -192
  15. package/framework/hooks/claude-code/session-start/inject-morph-context.js +1 -1
  16. package/framework/rules/gsap-standards.md +13 -0
  17. package/framework/rules/neon-auth-standards.md +13 -0
  18. package/framework/rules/neon-standards.md +26 -0
  19. package/framework/skills/level-0-meta/mcp-registry.json +1 -1
  20. package/framework/skills/level-0-meta/morph-agent-teams/SKILL.md +472 -472
  21. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
  22. package/framework/skills/level-0-meta/morph-init/SKILL.md +12 -12
  23. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +5 -5
  24. package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +5 -5
  25. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +7 -7
  26. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +24 -24
  27. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +12 -12
  28. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +9 -9
  29. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +1 -1
  30. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +1 -1
  31. package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +143 -143
  32. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +1 -1
  33. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
  34. package/framework/standards/STANDARDS.json +197 -116
  35. package/framework/standards/ai-agents/production.md +1 -0
  36. package/framework/standards/ai-agents/setup.md +3 -2
  37. package/framework/standards/ai-agents/workflows.md +1 -0
  38. package/framework/standards/architecture/vertical-slice/vertical-slice.md +4 -4
  39. package/framework/standards/backend/database/postgresql/database.md +63 -83
  40. package/framework/standards/backend/dotnet/scalar-ui.md +172 -172
  41. package/framework/standards/backend/dotnet/vsa-handler-patterns.md +274 -274
  42. package/framework/standards/backend/integrations/asaas/asaas-api.md +2 -2
  43. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +364 -0
  44. package/framework/standards/frontend/design-system/animations.md +9 -0
  45. package/framework/standards/frontend/gsap/gsap-core.md +463 -0
  46. package/framework/standards/frontend/gsap/gsap-plugins.md +294 -0
  47. package/framework/standards/frontend/gsap/gsap-scrolltrigger.md +318 -0
  48. package/framework/standards/frontend/nextjs/motion-patterns.md +1 -0
  49. package/framework/standards/frontend/nextjs/nextjs-patterns.md +47 -37
  50. package/framework/standards/infrastructure/docker/easypanel-deploy.md +4 -8
  51. package/framework/standards/infrastructure/neon/neon-pgrag.md +239 -0
  52. package/framework/standards/infrastructure/neon/neon-pgvector.md +236 -0
  53. package/framework/standards/infrastructure/neon/neon-semantic-kernel.md +310 -0
  54. package/framework/standards/infrastructure/neon/neon-setup.md +186 -0
  55. package/framework/standards/integration/mcp/mcp-tools.md +32 -34
  56. package/framework/templates/README.md +20 -20
  57. package/framework/templates/REGISTRY.json +54 -101
  58. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  59. package/framework/templates/code/dotnet/backend/repository.cs +148 -148
  60. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
  61. package/framework/templates/code/dotnet/database/vector-entity.cs +93 -0
  62. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +1 -1
  63. package/framework/templates/code/sql/{supabase-migration.sql → postgresql-migration.sql} +12 -21
  64. package/framework/templates/code/sql/{supabase-migration.template.sql → postgresql-migration.template.sql} +13 -18
  65. package/framework/templates/code/sql/{rls-policy.sql → postgresql-rls-policy.sql} +6 -9
  66. package/framework/templates/code/typescript/contracts.ts +167 -168
  67. package/framework/templates/context/CONTEXT.md +3 -3
  68. package/framework/templates/docs/proposal.md +6 -6
  69. package/framework/templates/docs/ui-components.md +1 -1
  70. package/framework/templates/feature/decisions.md +122 -121
  71. package/framework/templates/feature/recap.md +145 -145
  72. package/framework/templates/feature/tasks.md +199 -199
  73. package/framework/templates/frontend/nextjs/gsap-scroll-section.tsx.hbs +44 -0
  74. package/framework/templates/infrastructure/docker/docker-compose.template.yml +50 -67
  75. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  76. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  77. package/framework/templates/infrastructure/docker/easypanel.template.json +46 -54
  78. package/framework/templates/infrastructure/github/README.md +56 -56
  79. package/framework/templates/integrations/neon-auth-config.cs +133 -0
  80. package/framework/templates/integrations/semantic-kernel-neon.cs +125 -0
  81. package/framework/workflows/README.md +1 -1
  82. package/framework/workflows/docs/full-morph.md +69 -69
  83. package/package.json +1 -1
  84. package/src/commands/agents/dispatch-agents.js +19 -15
  85. package/src/commands/state/advance-phase.js +5 -0
  86. package/src/commands/tasks/task.js +3 -0
  87. package/src/core/state/state-manager.js +45 -1
  88. package/src/core/templates/template-registry.js +1 -66
  89. package/src/lib/detectors/index.js +4 -4
  90. package/src/lib/generators/architecture-scanner.js +639 -640
  91. package/src/lib/installers/mcp-installer.js +1 -1
  92. package/src/lib/tasks/task-classifier.js +15 -1
  93. package/src/lib/tasks/test-runner.js +5 -1
  94. package/src/lib/validators/content/content-validator.js +9 -10
  95. package/src/lib/validators/validation-runner.js +7 -5
  96. package/framework/agents/backend/supabase-expert.md +0 -256
  97. package/framework/agents/integrations/clerk-auth.md +0 -109
  98. package/framework/rules/clerk-standards.md +0 -13
  99. package/framework/rules/supabase-standards.md +0 -29
  100. package/framework/standards/backend/integrations/clerk/clerk-auth.md +0 -290
  101. package/framework/standards/infrastructure/supabase/mcp-setup.md +0 -142
  102. package/framework/standards/infrastructure/supabase/supabase-auth.md +0 -176
  103. package/framework/standards/infrastructure/supabase/supabase-custom-jwt.md +0 -206
  104. package/framework/standards/infrastructure/supabase/supabase-pgvector.md +0 -169
  105. package/framework/standards/infrastructure/supabase/supabase-rls.md +0 -184
  106. package/framework/standards/infrastructure/supabase/supabase-storage.md +0 -153
  107. package/framework/templates/integrations/clerk-config.cs +0 -217
@@ -0,0 +1,310 @@
1
+ # Neon Semantic Kernel Vector Store Standard
2
+
3
+ > **Scope:** neon, dotnet-vsa
4
+ > **Layer:** 2 (on keyword)
5
+ > **Keywords:** semantic kernel, vector store, PostgresVectorStore, VectorStoreTextSearch, MAF
6
+ > **Load When:** semantic kernel postgres vector keywords detected
7
+
8
+ Stack: .NET VSA + Neon Serverless Postgres + Semantic Kernel
9
+
10
+ ## Core Rules
11
+
12
+ - ALWAYS call `UseVector()` on `NpgsqlDataSourceBuilder` -- without it the vector store fails silently
13
+ - ALWAYS use `AddPostgresVectorStore()` for DI registration -- handles datasource lifecycle
14
+ - NEVER mix pgvector-dotnet `Vector` type with SK `ReadOnlyMemory<float>` -- SK uses its own mapping
15
+ - ALWAYS annotate data model properties with `[VectorStoreKey]`, `[VectorStoreData]`, `[VectorStoreVector]`
16
+ - Use `PostgresCollection<TKey, TRecord>` for typed collection access
17
+
18
+ ## NuGet Packages
19
+
20
+ ```bash
21
+ dotnet add package Microsoft.SemanticKernel.Connectors.PgVector --prerelease
22
+ dotnet add package Microsoft.SemanticKernel.Connectors.OpenAI
23
+ dotnet add package Npgsql
24
+ ```
25
+
26
+ ## PostgresVectorStore Initialization
27
+
28
+ ### Via Dependency Injection (Recommended)
29
+
30
+ ```csharp
31
+ using Microsoft.Extensions.DependencyInjection;
32
+ using Microsoft.SemanticKernel;
33
+ using Npgsql;
34
+
35
+ var builder = WebApplication.CreateBuilder(args);
36
+
37
+ // Option 1: Connection string (UseVector applied automatically)
38
+ builder.Services.AddPostgresVectorStore(
39
+ builder.Configuration.GetConnectionString("DefaultConnection")!);
40
+
41
+ // Option 2: Manual NpgsqlDataSource (full control)
42
+ builder.Services.AddSingleton<NpgsqlDataSource>(sp =>
43
+ {
44
+ var dataSourceBuilder = new NpgsqlDataSourceBuilder(
45
+ builder.Configuration.GetConnectionString("DefaultConnection"));
46
+ dataSourceBuilder.UseVector();
47
+ return dataSourceBuilder.Build();
48
+ });
49
+ builder.Services.AddPostgresVectorStore();
50
+ ```
51
+
52
+ ### Direct Construction
53
+
54
+ ```csharp
55
+ using Microsoft.SemanticKernel.Connectors.PgVector;
56
+ using Npgsql;
57
+
58
+ var dataSourceBuilder = new NpgsqlDataSourceBuilder(connectionString);
59
+ dataSourceBuilder.UseVector();
60
+ var dataSource = dataSourceBuilder.Build();
61
+
62
+ var vectorStore = new PostgresVectorStore(dataSource, ownsDataSource: true);
63
+ ```
64
+
65
+ ## Data Model Definition
66
+
67
+ Annotate your record type with SK vector store attributes:
68
+
69
+ ```csharp
70
+ using System;
71
+ using Microsoft.Extensions.VectorData;
72
+
73
+ public class KnowledgeEntry
74
+ {
75
+ [VectorStoreKey(StorageName = "id")]
76
+ public Guid Id { get; set; }
77
+
78
+ [VectorStoreData(StorageName = "title")]
79
+ public string Title { get; set; } = string.Empty;
80
+
81
+ [VectorStoreData(StorageName = "content")]
82
+ public string Content { get; set; } = string.Empty;
83
+
84
+ [VectorStoreData(StorageName = "source")]
85
+ public string? Source { get; set; }
86
+
87
+ [VectorStoreData(StorageName = "created_at")]
88
+ public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
89
+
90
+ [VectorStoreVector(
91
+ Dimensions: 1536,
92
+ DistanceFunction = DistanceFunction.CosineDistance,
93
+ IndexKind = IndexKind.Hnsw,
94
+ StorageName = "embedding")]
95
+ public ReadOnlyMemory<float>? Embedding { get; set; }
96
+ }
97
+ ```
98
+
99
+ This maps to the following Postgres table (auto-created by `EnsureCollectionExistsAsync`):
100
+
101
+ ```sql
102
+ CREATE TABLE IF NOT EXISTS public."knowledge_entries" (
103
+ "id" UUID PRIMARY KEY NOT NULL,
104
+ "title" TEXT,
105
+ "content" TEXT,
106
+ "source" TEXT,
107
+ "created_at" TIMESTAMPTZ,
108
+ "embedding" VECTOR(1536)
109
+ );
110
+ ```
111
+
112
+ ## Collection Operations
113
+
114
+ ```csharp
115
+ using Microsoft.SemanticKernel.Connectors.PgVector;
116
+
117
+ // Get a typed collection
118
+ var collection = vectorStore.GetCollection<Guid, KnowledgeEntry>("knowledge_entries");
119
+
120
+ // Create table if it doesn't exist (includes HNSW index)
121
+ await collection.EnsureCollectionExistsAsync();
122
+
123
+ // Upsert a record
124
+ var entry = new KnowledgeEntry
125
+ {
126
+ Id = Guid.NewGuid(),
127
+ Title = "Neon Overview",
128
+ Content = "Neon is a serverless Postgres platform...",
129
+ Source = "docs",
130
+ Embedding = new ReadOnlyMemory<float>(embeddingVector)
131
+ };
132
+ await collection.UpsertAsync(entry);
133
+
134
+ // Get by key
135
+ var retrieved = await collection.GetAsync(entry.Id);
136
+
137
+ // Delete
138
+ await collection.DeleteAsync(entry.Id);
139
+ ```
140
+
141
+ ## Embedding Generation with OpenAI
142
+
143
+ ```csharp
144
+ using Microsoft.SemanticKernel;
145
+ using Microsoft.SemanticKernel.Connectors.OpenAI;
146
+ using Microsoft.SemanticKernel.Embeddings;
147
+
148
+ // Register embedding service
149
+ builder.Services.AddOpenAITextEmbeddingGeneration(
150
+ modelId: "text-embedding-3-small",
151
+ apiKey: builder.Configuration["OpenAI:ApiKey"]!);
152
+
153
+ // Generate embeddings
154
+ public class EmbeddingService(ITextEmbeddingGenerationService embeddingService)
155
+ {
156
+ public async Task<ReadOnlyMemory<float>> GenerateAsync(string text)
157
+ {
158
+ var embeddings = await embeddingService.GenerateEmbeddingsAsync([text]);
159
+ return embeddings[0];
160
+ }
161
+
162
+ public async Task<IList<ReadOnlyMemory<float>>> GenerateBatchAsync(IList<string> texts)
163
+ {
164
+ return await embeddingService.GenerateEmbeddingsAsync(texts);
165
+ }
166
+ }
167
+ ```
168
+
169
+ ## VectorStoreTextSearch Usage
170
+
171
+ `VectorStoreTextSearch<T>` provides a high-level search API that automatically generates embeddings for queries:
172
+
173
+ ```csharp
174
+ using Microsoft.Extensions.VectorData;
175
+ using Microsoft.SemanticKernel.Data;
176
+
177
+ // Create text search from collection + embedding service
178
+ var textSearch = new VectorStoreTextSearch<KnowledgeEntry>(
179
+ collection,
180
+ embeddingGenerationService);
181
+
182
+ // Search with natural language
183
+ var query = "How does Neon branching work?";
184
+ KernelSearchResults<TextSearchResult> results = await textSearch.GetTextSearchResultsAsync(
185
+ query, new() { Top = 5, Skip = 0 });
186
+
187
+ await foreach (TextSearchResult result in results.Results)
188
+ {
189
+ Console.WriteLine($"Name: {result.Name}");
190
+ Console.WriteLine($"Value: {result.Value}");
191
+ Console.WriteLine($"Link: {result.Link}");
192
+ }
193
+ ```
194
+
195
+ ### Use as Kernel Plugin (RAG in Prompts)
196
+
197
+ ```csharp
198
+ using Microsoft.SemanticKernel;
199
+ using Microsoft.SemanticKernel.Data;
200
+ using Microsoft.SemanticKernel.PromptTemplates.Handlebars;
201
+
202
+ var kernel = builder.Build();
203
+
204
+ // Register text search as a plugin
205
+ var searchPlugin = textSearch.CreateWithGetTextSearchResults("KnowledgeSearch");
206
+ kernel.Plugins.Add(searchPlugin);
207
+
208
+ // Use in prompt with automatic retrieval
209
+ var promptTemplate = """
210
+ {{#with (KnowledgeSearch-GetTextSearchResults query)}}
211
+ {{#each this}}
212
+ Name: {{Name}}
213
+ Value: {{Value}}
214
+ ---
215
+ {{/each}}
216
+ {{/with}}
217
+
218
+ Based on the above context, answer: {{query}}
219
+ """;
220
+
221
+ var function = KernelFunctionFactory.CreateFromPrompt(
222
+ new PromptTemplateConfig
223
+ {
224
+ Template = promptTemplate,
225
+ TemplateFormat = "handlebars"
226
+ },
227
+ new HandlebarsPromptTemplateFactory());
228
+
229
+ var result = await kernel.InvokeAsync(function,
230
+ new KernelArguments { ["query"] = "How does Neon branching work?" });
231
+ ```
232
+
233
+ ## Integration with MAF Agents
234
+
235
+ Use the vector store as a plugin for ChatCompletionAgent to give agents vector memory:
236
+
237
+ ```csharp
238
+ using Microsoft.SemanticKernel;
239
+ using Microsoft.SemanticKernel.Agents;
240
+ using Microsoft.SemanticKernel.Data;
241
+
242
+ // Build kernel with vector search plugin
243
+ var kernelBuilder = Kernel.CreateBuilder();
244
+ kernelBuilder.AddOpenAIChatCompletion("gpt-4o", apiKey);
245
+ kernelBuilder.AddOpenAITextEmbeddingGeneration("text-embedding-3-small", apiKey);
246
+ var kernel = kernelBuilder.Build();
247
+
248
+ // Register vector search as a kernel plugin
249
+ var searchPlugin = textSearch.CreateWithGetTextSearchResults("KnowledgeBase");
250
+ kernel.Plugins.Add(searchPlugin);
251
+
252
+ // Create agent with vector memory
253
+ var agent = new ChatCompletionAgent
254
+ {
255
+ Name = "KnowledgeAgent",
256
+ Instructions = """
257
+ You are a knowledge assistant. Use the KnowledgeBase plugin to search for
258
+ relevant information before answering questions. Always cite your sources.
259
+ """,
260
+ Kernel = kernel,
261
+ Arguments = new KernelArguments(
262
+ new OpenAIPromptExecutionSettings { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() })
263
+ };
264
+
265
+ // Agent automatically calls vector search when needed
266
+ await foreach (var message in agent.InvokeAsync(chatHistory))
267
+ {
268
+ Console.WriteLine(message.Content);
269
+ }
270
+ ```
271
+
272
+ ## Service Registration Summary
273
+
274
+ ```csharp
275
+ // Program.cs -- complete registration
276
+ var builder = WebApplication.CreateBuilder(args);
277
+
278
+ // 1. Vector store (Neon + pgvector)
279
+ builder.Services.AddPostgresVectorStore(
280
+ builder.Configuration.GetConnectionString("DefaultConnection")!);
281
+
282
+ // 2. Embedding generation
283
+ builder.Services.AddOpenAITextEmbeddingGeneration(
284
+ modelId: "text-embedding-3-small",
285
+ apiKey: builder.Configuration["OpenAI:ApiKey"]!);
286
+
287
+ // 3. Chat completion (for agents)
288
+ builder.Services.AddOpenAIChatCompletion(
289
+ modelId: "gpt-4o",
290
+ apiKey: builder.Configuration["OpenAI:ApiKey"]!);
291
+
292
+ // 4. Application services
293
+ builder.Services.AddSingleton<EmbeddingService>();
294
+ builder.Services.AddSingleton(sp =>
295
+ {
296
+ var vectorStore = sp.GetRequiredService<PostgresVectorStore>();
297
+ return vectorStore.GetCollection<Guid, KnowledgeEntry>("knowledge_entries");
298
+ });
299
+ ```
300
+
301
+ ## Common Mistakes
302
+
303
+ | Wrong | Right | Why |
304
+ |-------|-------|-----|
305
+ | Missing `UseVector()` on data source | Always call `dataSourceBuilder.UseVector()` | Vector type mapping fails without it |
306
+ | Using `float[]` for vector property | `ReadOnlyMemory<float>` with `[VectorStoreVector]` | SK connector expects its own vector types |
307
+ | No `StorageName` on attributes | Set `StorageName` for snake_case columns | C# PascalCase won't match Postgres columns |
308
+ | Creating collection without `EnsureCollectionExistsAsync` | Call before first upsert/search | Table and index won't exist |
309
+ | Hardcoded embedding dimensions | Match `Dimensions` to your model (1536 for ada-002/3-small) | Mismatch causes insertion errors |
310
+ | Using pgvector-dotnet `Vector` with SK | Use `ReadOnlyMemory<float>` | SK has its own type mapping layer |
@@ -0,0 +1,186 @@
1
+ # Neon Serverless Postgres Standard
2
+
3
+ > **Scope:** neon
4
+ > **Layer:** 0 (always load)
5
+ > **Keywords:** neon, serverless postgres, branching, scale-to-zero, connection string, neonctl
6
+ > **Load When:** neon stack detected
7
+
8
+ Stack: .NET + Neon Serverless Postgres
9
+
10
+ ## Core Rules
11
+
12
+ - ALWAYS use pooled connection strings (`-pooler` endpoint) for application traffic
13
+ - ALWAYS use direct connection strings for migrations and schema changes
14
+ - NEVER hardcode connection strings -- use environment variables
15
+ - ALWAYS enable SSL (`SSL Mode=Require`) for all connections
16
+ - ALWAYS configure retry policies for cold-start resilience
17
+ - NEVER leave branches without expiration -- set TTL for dev/CI branches
18
+
19
+ ## Neon CLI Setup
20
+
21
+ ```bash
22
+ # Install neonctl globally
23
+ npm install -g neonctl
24
+
25
+ # Authenticate (opens browser)
26
+ neonctl auth
27
+
28
+ # Verify connection
29
+ neonctl projects list
30
+ ```
31
+
32
+ ## Connection Strings
33
+
34
+ ### Pooled vs Direct
35
+
36
+ | Type | Hostname Pattern | Use Case |
37
+ |------|-----------------|----------|
38
+ | Pooled | `ep-xxxx-pooler.region.aws.neon.tech` | Application queries, high concurrency |
39
+ | Direct | `ep-xxxx.region.aws.neon.tech` | Migrations, EF Core `dotnet ef`, advisory locks |
40
+
41
+ ### Environment Variables
42
+
43
+ | Variable | Purpose |
44
+ |----------|---------|
45
+ | `DATABASE_URL` | Pooled connection for application runtime |
46
+ | `DATABASE_URL_UNPOOLED` | Direct connection for migrations and CLI tools |
47
+
48
+ ```ini
49
+ # Pooled (application)
50
+ DATABASE_URL="Host=ep-cool-darkness-123456-pooler.us-east-2.aws.neon.tech;Database=mydb;Username=myuser;Password=secret;SSL Mode=Require"
51
+
52
+ # Direct (migrations)
53
+ DATABASE_URL_UNPOOLED="Host=ep-cool-darkness-123456.us-east-2.aws.neon.tech;Database=mydb;Username=myuser;Password=secret;SSL Mode=Require"
54
+ ```
55
+
56
+ ## EF Core Configuration
57
+
58
+ ### appsettings.json
59
+
60
+ ```json
61
+ {
62
+ "ConnectionStrings": {
63
+ "DefaultConnection": "Host=ep-cool-darkness-123456-pooler.us-east-2.aws.neon.tech;Database=mydb;Username=myuser;Password=secret;SSL Mode=Require;Trust Server Certificate=true",
64
+ "MigrationConnection": "Host=ep-cool-darkness-123456.us-east-2.aws.neon.tech;Database=mydb;Username=myuser;Password=secret;SSL Mode=Require;Trust Server Certificate=true"
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### DbContext Registration
70
+
71
+ ```csharp
72
+ builder.Services.AddDbContext<AppDbContext>(options =>
73
+ options.UseNpgsql(
74
+ builder.Configuration.GetConnectionString("DefaultConnection"),
75
+ npgsqlOptions =>
76
+ {
77
+ npgsqlOptions.EnableRetryOnFailure(
78
+ maxRetryCount: 5,
79
+ maxRetryDelay: TimeSpan.FromSeconds(10),
80
+ errorCodesToAdd: null);
81
+ npgsqlOptions.CommandTimeout(30);
82
+ }));
83
+ ```
84
+
85
+ ### Design-Time Factory (for migrations using direct connection)
86
+
87
+ ```csharp
88
+ public class AppDbContextFactory : IDesignTimeDbContextFactory<AppDbContext>
89
+ {
90
+ public AppDbContext CreateDbContext(string[] args)
91
+ {
92
+ var configuration = new ConfigurationBuilder()
93
+ .AddJsonFile("appsettings.json")
94
+ .AddEnvironmentVariables()
95
+ .Build();
96
+
97
+ var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
98
+ optionsBuilder.UseNpgsql(
99
+ configuration.GetConnectionString("MigrationConnection"));
100
+
101
+ return new AppDbContext(optionsBuilder.Options);
102
+ }
103
+ }
104
+ ```
105
+
106
+ ## Branching Workflow
107
+
108
+ Neon branches are copy-on-write clones of your database -- instant, zero-cost until data diverges.
109
+
110
+ ```bash
111
+ # List branches
112
+ neonctl branches list --project-id <project-id>
113
+
114
+ # Create feature branch from main
115
+ neonctl branches create --project-id <project-id> \
116
+ --name feature/my-feature \
117
+ --parent main
118
+
119
+ # Create branch with auto-expiration (CI/CD)
120
+ neonctl branches create --project-id <project-id> \
121
+ --name ci-test-run-42 \
122
+ --parent main \
123
+ --expires-at "2026-04-01T00:00:00Z"
124
+
125
+ # Reset branch to parent state
126
+ neonctl branches reset feature/my-feature --parent --project-id <project-id>
127
+
128
+ # Delete branch
129
+ neonctl branches delete feature/my-feature --project-id <project-id>
130
+ ```
131
+
132
+ ### Branch Strategy
133
+
134
+ | Branch | Purpose | Expiration |
135
+ |--------|---------|------------|
136
+ | `main` | Production database | Never |
137
+ | `dev` | Development shared | Never |
138
+ | `feature/*` | Feature development | 7 days |
139
+ | `ci-*` | CI test runs | 1 day |
140
+
141
+ ## Scale-to-Zero
142
+
143
+ Neon automatically suspends computes after inactivity (default: 5 minutes). This saves cost but introduces cold-start latency (~300-500ms on first request).
144
+
145
+ ### Mitigate Cold Starts
146
+
147
+ ```csharp
148
+ // 1. Configure retry policy to handle connection drops on wake-up
149
+ builder.Services.AddDbContext<AppDbContext>(options =>
150
+ options.UseNpgsql(connectionString, npgsqlOptions =>
151
+ {
152
+ npgsqlOptions.EnableRetryOnFailure(
153
+ maxRetryCount: 5,
154
+ maxRetryDelay: TimeSpan.FromSeconds(10),
155
+ errorCodesToAdd: null);
156
+ }));
157
+
158
+ // 2. Health check to warm the connection pool
159
+ builder.Services.AddHealthChecks()
160
+ .AddNpgSql(connectionString, name: "neon-db");
161
+ ```
162
+
163
+ ### Suspend Timeout Configuration
164
+
165
+ ```bash
166
+ # Set suspend timeout to 10 minutes (600 seconds)
167
+ neonctl branches create --project-id <project-id> \
168
+ --name main \
169
+ --suspend-timeout 600
170
+
171
+ # Compute size range (autoscaling)
172
+ neonctl branches create --project-id <project-id> \
173
+ --name main \
174
+ --cu "0.25-4"
175
+ ```
176
+
177
+ ## Common Mistakes
178
+
179
+ | Wrong | Right | Why |
180
+ |-------|-------|-----|
181
+ | Direct connection for app queries | Pooled (`-pooler`) connection | Direct connections exhaust compute limits |
182
+ | No retry policy | `EnableRetryOnFailure()` | Cold starts drop first connection |
183
+ | Hardcoded connection strings | Environment variables | Branches have unique endpoints |
184
+ | Permanent CI branches | `--expires-at` TTL | Orphaned branches waste resources |
185
+ | Running migrations on pooled connection | Direct connection for `dotnet ef` | PgBouncer doesn't support advisory locks |
186
+ | No SSL | `SSL Mode=Require` | Neon requires encrypted connections |
@@ -19,8 +19,8 @@ await mcp__context7__resolve_library_id({ libraryName: "react" });
19
19
  // Playwright (browser automation)
20
20
  await mcp__playwright__browser_navigate({ url: "https://example.com" });
21
21
 
22
- // Supabase — use CLI, not MCP (always target local Docker instance)
23
- // npx supabase status → get DB URL
22
+ // Neon — use `neonctl` CLI + `psql`
23
+ // neonctl connection-string → get DB URL
24
24
  // psql <DB_URL> -c "SELECT ..."
25
25
  ```
26
26
 
@@ -85,39 +85,38 @@ const docs = await mcp__context7__query_docs({
85
85
 
86
86
  | Tool | Use Case | Example |
87
87
  |------|----------|---------|
88
- | **Supabase CLI / psql** | Database schema, tables, relationships, RLS (local Docker) | `psql <DB_URL> -c "SELECT ..."` |
88
+ | **Neon CLI (`neonctl`) / psql** | Database schema, tables, relationships, RLS | `psql <DB_URL> -c "SELECT ..."` |
89
89
  | **Context7** | Library docs for architecture decisions | `mcp__context7__query_docs()` |
90
90
  | **GitHub** | Check existing code patterns, PRs | `mcp__github__search_code()` |
91
91
 
92
92
  ```bash
93
93
  # === SCHEMA ANALYSIS (Critical for contracts.cs) ===
94
- # Always target local Docker instance — never production.
95
94
 
96
- # 0. Get local DB URL (port may vary per instance)
97
- npx supabase status
98
- # → Extract "DB URL" line, e.g.: postgresql://postgres:postgres@127.0.0.1:54322/postgres
95
+ # 0. Get Neon DB connection string
96
+ neonctl connection-string
97
+ # → e.g.: postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb?sslmode=require
99
98
 
100
99
  # 1. List all tables
101
- npx supabase db dump --local --schema public 2>/dev/null | grep "CREATE TABLE"
100
+ pg_dump $(neonctl connection-string) --schema-only --schema public 2>/dev/null | grep "CREATE TABLE"
102
101
 
103
102
  # 2. Get schema for each relevant table
104
- psql $DB_URL -c "SELECT column_name, data_type, is_nullable, column_default \
103
+ psql $(neonctl connection-string) -c "SELECT column_name, data_type, is_nullable, column_default \
105
104
  FROM information_schema.columns WHERE table_name = 'leads' ORDER BY ordinal_position"
106
105
 
107
106
  # 3. Get foreign key relationships
108
- psql $DB_URL -c "SELECT tc.table_name, kcu.column_name, ccu.table_name AS foreign_table, \
107
+ psql $(neonctl connection-string) -c "SELECT tc.table_name, kcu.column_name, ccu.table_name AS foreign_table, \
109
108
  ccu.column_name AS foreign_column FROM information_schema.table_constraints tc \
110
109
  JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name \
111
110
  JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name \
112
111
  WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_name = 'leads'"
113
112
 
114
113
  # 4. Check RLS policies (security-critical)
115
- psql $DB_URL -c "SELECT tablename, policyname, cmd, qual FROM pg_policies WHERE tablename = 'leads'"
114
+ psql $(neonctl connection-string) -c "SELECT tablename, policyname, cmd, qual FROM pg_policies WHERE tablename = 'leads'"
116
115
  ```
117
116
 
118
- **Fallback (local Supabase not running):**
117
+ **Fallback (Neon database not accessible):**
119
118
  ```
120
- 1. Grep: "\.from\(|\.select\(|SELECT |supabase\.|DbSet<" → find query files
119
+ 1. Grep: "\.from\(|\.select\(|SELECT |DbSet<" → find query files
121
120
  2. Read each query file → extract table/column names
122
121
  3. Glob: "src/**/types/**/*.ts" or "**/Entities/**/*.cs" → find type definitions
123
122
  4. Read type files → map properties to database columns
@@ -167,7 +166,7 @@ for (const task of tasks) {
167
166
 
168
167
  | Tool | Use Case | Example |
169
168
  |------|----------|---------|
170
- | **Supabase CLI / psql** | Run migrations, create RLS policies (local Docker) | `npx supabase migration up --local` |
169
+ | **Neon CLI (`neonctl`) / psql** | Run migrations, create RLS policies | `dotnet ef database update` |
171
170
  | **GitHub** | Create PR, push branches | `mcp__github__create_pull_request()` |
172
171
  | **Context7** | Look up API usage during coding | `mcp__context7__query_docs()` |
173
172
  | **Playwright** | Smoke test deployed features, verify UI | `mcp__playwright__browser_navigate()` |
@@ -176,20 +175,19 @@ for (const task of tasks) {
176
175
  | **Docker CLI** | Build, run, compose, logs (local) | `docker` commands |
177
176
 
178
177
  ```bash
179
- # === SUPABASE (Migrations & RLS — local Docker) ===
178
+ # === NEON (Migrations & RLS via EF Core) ===
180
179
 
181
- # Create migration file
182
- npx supabase migration new add_status_to_leads
183
- # → Edit the generated SQL file in supabase/migrations/
180
+ # Create migration
181
+ dotnet ef migrations add AddStatusToLeads
184
182
 
185
- # Apply migration to local instance
186
- npx supabase migration up --local
183
+ # Apply migration to Neon database
184
+ dotnet ef database update
187
185
 
188
186
  # Verify schema after migration
189
- psql $DB_URL -c "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'leads'"
187
+ psql $(neonctl connection-string) -c "SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'leads'"
190
188
 
191
189
  # Verify RLS policies
192
- psql $DB_URL -c "SELECT policyname, cmd, qual FROM pg_policies WHERE tablename = 'leads'"
190
+ psql $(neonctl connection-string) -c "SELECT policyname, cmd, qual FROM pg_policies WHERE tablename = 'leads'"
193
191
  ```
194
192
 
195
193
  ```javascript
@@ -238,7 +236,7 @@ await mcp__vercel__manage_env_vars({
238
236
 
239
237
  | Need | MCP Tool | Native Alternative |
240
238
  |------|----------|--------------------|
241
- | Database schema | Supabase CLI / psql (local Docker) | Grep queries + Read types |
239
+ | Database schema | Neon CLI (`neonctl`) / psql | Grep queries + Read types |
242
240
  | Repo metadata | GitHub MCP | Bash `gh` CLI |
243
241
  | Library docs | Context7 | WebSearch + WebFetch |
244
242
  | Live page preview | Playwright MCP | WebFetch URL |
@@ -249,7 +247,7 @@ await mcp__vercel__manage_env_vars({
249
247
  | Cloud resources | Azure CLI (`az resource`, `az deployment`) | — |
250
248
  | Vercel deployments | Vercel MCP | Bash `vercel` CLI |
251
249
 
252
- **Rule:** MCP tools provide structured data (JSON responses). Native tools require manual parsing. **Always prefer MCP when available** — fall back to native when not. **Exceptions:** Supabase, Docker, and Azure always use their respective CLIs directly — never MCP.
250
+ **Rule:** MCP tools provide structured data (JSON responses). Native tools require manual parsing. **Always prefer MCP when available** — fall back to native when not. **Exceptions:** Neon, Docker, and Azure always use their respective CLIs directly — never MCP.
253
251
 
254
252
  ---
255
253
 
@@ -345,26 +343,26 @@ await mcp__playwright__browser_file_upload({ ref: "s1e20", paths: ["/path/to/fil
345
343
 
346
344
  ---
347
345
 
348
- ### Supabase: Full Schema Discovery (Local Docker via CLI)
346
+ ### Neon: Full Schema Discovery (via neonctl + psql)
349
347
 
350
- > **Primary:** Supabase CLI + psql targeting local Docker instance (`npx supabase start`).
351
- > **Port detection:** Always use `npx supabase status` to get the DB URL — port may vary across instances.
348
+ > **Primary:** Neon CLI (`neonctl`) + psql connecting to Neon database.
349
+ > **Connection:** Always use `neonctl connection-string` to get the DB URL.
352
350
 
353
351
  ```bash
354
352
  # Complete workflow for Phase 3 schema analysis
355
353
 
356
- # 1. Get local DB URL
357
- npx supabase status # → extract "DB URL" line
354
+ # 1. Get Neon DB URL
355
+ neonctl connection-string # → pooled connection string
358
356
 
359
357
  # 2. List all tables
360
- npx supabase db dump --local --schema public 2>/dev/null | grep "CREATE TABLE"
358
+ pg_dump $(neonctl connection-string) --schema-only --schema public 2>/dev/null | grep "CREATE TABLE"
361
359
 
362
360
  # 3. For each relevant table:
363
- psql $DB_URL -c "SELECT column_name, data_type, is_nullable, column_default \
361
+ psql $(neonctl connection-string) -c "SELECT column_name, data_type, is_nullable, column_default \
364
362
  FROM information_schema.columns WHERE table_name = 'TABLE_NAME' ORDER BY ordinal_position"
365
363
 
366
364
  # 4. Get relationships
367
- psql $DB_URL -c "SELECT tc.table_name, kcu.column_name, ccu.table_name AS foreign_table \
365
+ psql $(neonctl connection-string) -c "SELECT tc.table_name, kcu.column_name, ccu.table_name AS foreign_table \
368
366
  FROM information_schema.table_constraints tc \
369
367
  JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name \
370
368
  JOIN information_schema.constraint_column_usage ccu ON tc.constraint_name = ccu.constraint_name \
@@ -397,7 +395,7 @@ const docs = await mcp__context7__query_docs({
397
395
  ```javascript
398
396
  // Find patterns in large codebase during Phase 2
399
397
  const results = await mcp__github__search_code({
400
- query: "supabase.from leads repo:myorg/myrepo",
398
+ query: "DbSet leads repo:myorg/myrepo",
401
399
  });
402
400
  // → Find all places that query the leads table
403
401
  ```
@@ -407,7 +405,7 @@ const results = await mcp__github__search_code({
407
405
  ## Security Considerations
408
406
 
409
407
  - **Never pass secrets** in MCP tool parameters (API keys, tokens, passwords)
410
- - **Supabase** uses CLI/psql targeting local Docker — never connect to production
408
+ - **Neon** uses neonctl/psql — use database branches for development, not production
411
409
  - **GitHub MCP** inherits the configured token's permissions
412
410
  - **Always validate tool responses** before using in contracts or code generation
413
411