@polymorphism-tech/morph-spec 4.17.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 (40) hide show
  1. package/CLAUDE.md +36 -0
  2. package/README.md +2 -2
  3. package/claude-plugin.json +1 -1
  4. package/docs/CHEATSHEET.md +1 -1
  5. package/docs/QUICKSTART.md +1 -1
  6. package/framework/agents/backend/neon-expert.md +9 -27
  7. package/framework/agents/integrations/neon-auth.md +151 -0
  8. package/framework/agents.json +21 -13
  9. package/framework/rules/neon-auth-standards.md +13 -0
  10. package/framework/rules/neon-standards.md +1 -0
  11. package/framework/skills/level-0-meta/morph-agent-teams/SKILL.md +3 -3
  12. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
  13. package/framework/skills/level-0-meta/morph-init/SKILL.md +4 -4
  14. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +1 -1
  15. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +1 -1
  16. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +1 -1
  17. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +1 -1
  18. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +1 -1
  19. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +1 -1
  20. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
  21. package/framework/standards/STANDARDS.json +13 -9
  22. package/framework/standards/backend/database/postgresql/database.md +5 -5
  23. package/framework/standards/backend/integrations/asaas/asaas-api.md +1 -1
  24. package/framework/standards/backend/integrations/neon-auth/neon-auth.md +364 -0
  25. package/framework/standards/frontend/nextjs/nextjs-patterns.md +9 -9
  26. package/framework/templates/README.md +2 -2
  27. package/framework/templates/REGISTRY.json +5 -5
  28. package/framework/templates/code/sql/postgresql-migration.sql +10 -10
  29. package/framework/templates/code/sql/postgresql-migration.template.sql +12 -14
  30. package/framework/templates/code/sql/postgresql-rls-policy.sql +6 -9
  31. package/framework/templates/feature/decisions.md +8 -7
  32. package/framework/templates/integrations/neon-auth-config.cs +133 -0
  33. package/framework/workflows/docs/full-morph.md +1 -1
  34. package/package.json +1 -1
  35. package/src/lib/detectors/index.js +2 -2
  36. package/src/lib/generators/architecture-scanner.js +2 -3
  37. package/framework/agents/integrations/clerk-auth.md +0 -109
  38. package/framework/rules/clerk-standards.md +0 -13
  39. package/framework/standards/backend/integrations/clerk/clerk-auth.md +0 -292
  40. package/framework/templates/integrations/clerk-config.cs +0 -217
@@ -0,0 +1,133 @@
1
+ // ==============================================================================
2
+ // MORPH-SPEC - Neon Auth Configuration Template
3
+ // Configuracao de autenticacao com Neon Auth (Better Auth) para .NET
4
+ // ==============================================================================
5
+
6
+ using Microsoft.AspNetCore.Authentication;
7
+ using Microsoft.AspNetCore.Authentication.JwtBearer;
8
+ using Microsoft.IdentityModel.Tokens;
9
+ using System.Security.Claims;
10
+
11
+ namespace {{Namespace}}.Infrastructure.Auth;
12
+
13
+ // ==============================================================================
14
+ // OPTIONS
15
+ // ==============================================================================
16
+
17
+ public class NeonAuthOptions
18
+ {
19
+ public const string SectionName = "NeonAuth";
20
+
21
+ /// <summary>
22
+ /// Neon Auth Base URL (e.g., https://ep-xxx.neonauth.us-east-2.aws.neon.build/neondb/auth)
23
+ /// </summary>
24
+ public string BaseUrl { get; set; } = string.Empty;
25
+ }
26
+
27
+ // ==============================================================================
28
+ // SERVICE EXTENSIONS
29
+ // ==============================================================================
30
+
31
+ public static class NeonAuthServiceExtensions
32
+ {
33
+ /// <summary>
34
+ /// Adds Neon Auth JWT Bearer authentication to the project.
35
+ /// Validates JWTs issued by Neon Auth service.
36
+ /// </summary>
37
+ public static IServiceCollection AddNeonAuthentication(
38
+ this IServiceCollection services,
39
+ IConfiguration configuration)
40
+ {
41
+ services.Configure<NeonAuthOptions>(configuration.GetSection(NeonAuthOptions.SectionName));
42
+
43
+ var neonAuthOptions = configuration.GetSection(NeonAuthOptions.SectionName).Get<NeonAuthOptions>()!;
44
+
45
+ services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
46
+ .AddJwtBearer(options =>
47
+ {
48
+ options.Authority = neonAuthOptions.BaseUrl;
49
+ options.TokenValidationParameters = new TokenValidationParameters
50
+ {
51
+ ValidateIssuer = true,
52
+ ValidateAudience = false,
53
+ ValidateLifetime = true,
54
+ ValidateIssuerSigningKey = true,
55
+ NameClaimType = "sub"
56
+ };
57
+ });
58
+
59
+ services.AddAuthorization();
60
+
61
+ return services;
62
+ }
63
+ }
64
+
65
+ // ==============================================================================
66
+ // USER CONTEXT SERVICE
67
+ // ==============================================================================
68
+
69
+ public interface ICurrentUserService
70
+ {
71
+ string? UserId { get; }
72
+ string? Email { get; }
73
+ bool IsAuthenticated { get; }
74
+ }
75
+
76
+ public class CurrentUserService(IHttpContextAccessor httpContextAccessor) : ICurrentUserService
77
+ {
78
+ public string? UserId =>
79
+ httpContextAccessor.HttpContext?.User.FindFirstValue("sub");
80
+
81
+ public string? Email =>
82
+ httpContextAccessor.HttpContext?.User.FindFirstValue("email");
83
+
84
+ public bool IsAuthenticated =>
85
+ httpContextAccessor.HttpContext?.User.Identity?.IsAuthenticated ?? false;
86
+ }
87
+
88
+ // ==============================================================================
89
+ // MIDDLEWARE PIPELINE
90
+ // ==============================================================================
91
+
92
+ public static class NeonAuthMiddlewareExtensions
93
+ {
94
+ public static IApplicationBuilder UseNeonAuthentication(this IApplicationBuilder app)
95
+ {
96
+ app.UseAuthentication();
97
+ app.UseAuthorization();
98
+ return app;
99
+ }
100
+ }
101
+
102
+ // ==============================================================================
103
+ // APPSETTINGS EXAMPLE
104
+ // ==============================================================================
105
+
106
+ /*
107
+ {
108
+ "NeonAuth": {
109
+ "BaseUrl": "https://ep-xxx.neonauth.us-east-2.aws.neon.build/neondb/auth"
110
+ }
111
+ }
112
+ */
113
+
114
+ // ==============================================================================
115
+ // PROGRAM.CS EXAMPLE
116
+ // ==============================================================================
117
+
118
+ /*
119
+ var builder = WebApplication.CreateBuilder(args);
120
+
121
+ // Add Neon Auth authentication
122
+ builder.Services.AddNeonAuthentication(builder.Configuration);
123
+ builder.Services.AddHttpContextAccessor();
124
+ builder.Services.AddScoped<ICurrentUserService, CurrentUserService>();
125
+
126
+ var app = builder.Build();
127
+
128
+ app.UseNeonAuthentication();
129
+
130
+ app.MapControllers().RequireAuthorization();
131
+
132
+ app.Run();
133
+ */
@@ -63,7 +63,7 @@ proposal.md, design-system.md, mockups.md, components.md, flows.md, spec.md, con
63
63
 
64
64
  ## Exemplos
65
65
  - "Sistema de relatórios com jobs agendados Hangfire"
66
- - "Autenticação completa com Clerk (login, signup, OAuth)"
66
+ - "Autenticação completa com Neon Auth (login, signup, OAuth)"
67
67
  - "Dashboard com gráficos, tabelas e filtros complexos"
68
68
  - "RAG pipeline com AI Search e embeddings"
69
69
  - "Infraestrutura completa com Docker/Easypanel"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "4.17.0",
3
+ "version": "4.18.0",
4
4
  "description": "MORPH-SPEC: AI-First development framework with validation pipeline and multi-stack support",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -74,8 +74,8 @@ export function detectProject(targetPath, opts = {}) {
74
74
  if (depNames.includes('@neondatabase/serverless') || depNames.includes('postgres') || depNames.includes('pg')) {
75
75
  structure.integrations.push('neon');
76
76
  }
77
- if (depNames.includes('@clerk/nextjs') || depNames.includes('@clerk/clerk-sdk-node')) {
78
- structure.integrations.push('clerk');
77
+ if (depNames.includes('@neondatabase/auth')) {
78
+ structure.integrations.push('neon-auth');
79
79
  }
80
80
  if (depNames.includes('stripe')) {
81
81
  structure.integrations.push('stripe');
@@ -223,7 +223,7 @@ export async function scanIntegrations(projectPath) {
223
223
  );
224
224
 
225
225
  const knownServices = {
226
- 'Clerk': 'auth',
226
+ 'NeonAuth': 'auth',
227
227
  'AsaaS': 'payment',
228
228
  'Resend': 'email',
229
229
  'Hangfire': 'background-jobs',
@@ -266,8 +266,7 @@ export async function scanIntegrations(projectPath) {
266
266
 
267
267
  // Scan .env files for known prefixes
268
268
  const envPrefixes = {
269
- 'NEXT_PUBLIC_CLERK': 'Clerk',
270
- 'CLERK_': 'Clerk',
269
+ 'NEON_AUTH_': 'NeonAuth',
271
270
  'DATABASE_URL': 'Neon',
272
271
  'NEON_': 'Neon',
273
272
  'RESEND_': 'Resend',
@@ -1,109 +0,0 @@
1
- ---
2
- name: clerk-auth
3
- description: Clerk Auth specialist for Clerk SDK integration, social login, JWT session management, and user management in Next.js and .NET projects. Use when integrating Clerk authentication, implementing social login flows, managing user sessions with Clerk JWT, or protecting routes with Clerk middleware.
4
- allowed-tools: Read, Write, Edit, Bash, Glob, Grep
5
- stacks:
6
- - clerk
7
- color: teal
8
- effort: medium
9
- ---
10
-
11
- # Clerk Auth
12
-
13
- Autenticação SaaS com Clerk para .NET e Next.js. SDK: `Clerk.Net.AspNetCore.Security` (.NET) / `@clerk/nextjs` (Next.js).
14
-
15
- ## Setup
16
-
17
- ```csharp
18
- // appsettings.json
19
- { "Clerk": { "SecretKey": "${CLERK_SECRET_KEY}", "PublishableKey": "pk_test_xxx" } }
20
-
21
- // Program.cs
22
- builder.Services.AddClerk(builder.Configuration);
23
- builder.Services.AddAuthentication(ClerkAuthenticationDefaults.AuthenticationScheme)
24
- .AddClerk(o => { o.Authority = "https://clerk.{instance}.com"; o.ValidAudiences = ["your-app-id"]; });
25
- builder.Services.AddAuthorization();
26
- app.UseAuthentication();
27
- app.UseAuthorization();
28
- ```
29
-
30
- ## Protected Endpoints
31
-
32
- ```csharp
33
- // Minimal API
34
- app.MapGet("/api/profile", async (ClaimsPrincipal user, IClerkClient clerk) =>
35
- {
36
- var userId = user.FindFirstValue(ClaimTypes.NameIdentifier);
37
- if (userId is null) return Results.Unauthorized();
38
- var u = await clerk.Users.GetUserAsync(userId);
39
- return Results.Ok(new { u.Id, Email = u.EmailAddresses.FirstOrDefault()?.EmailAddress });
40
- }).RequireAuthorization();
41
-
42
- // Controller: same pattern with [Authorize] + User.FindFirstValue()
43
- // Role-based: [Authorize(Roles = "admin")]
44
- ```
45
-
46
- ## Next.js Integration
47
-
48
- ```tsx
49
- // middleware.ts
50
- import { clerkMiddleware } from '@clerk/nextjs/server';
51
- export default clerkMiddleware();
52
- export const config = { matcher: ['/((?!.*\\..*|_next).*)', '/'] };
53
-
54
- // Protected page
55
- import { auth } from '@clerk/nextjs/server';
56
- export default async function DashboardPage() {
57
- const { userId } = await auth();
58
- if (!userId) redirect('/sign-in');
59
- return <Dashboard />;
60
- }
61
-
62
- // Client component
63
- 'use client';
64
- import { useUser } from '@clerk/nextjs';
65
- const { user, isLoaded } = useUser();
66
- ```
67
-
68
- ## Client Operations (.NET)
69
-
70
- ```csharp
71
- var user = await _clerk.Users.GetUserAsync(userId); // Get
72
- var users = await _clerk.Users.GetUserListAsync(new() { Limit = 10 }); // List
73
- await _clerk.Users.UpdateUserMetadataAsync(userId, new() // Update metadata
74
- { PublicMetadata = new Dictionary<string, object> { ["plan"] = "pro" } });
75
- await _clerk.Users.DeleteUserAsync(userId); // Delete
76
- ```
77
-
78
- ## Webhooks
79
-
80
- ```csharp
81
- [ApiController, Route("api/webhooks/clerk")]
82
- public class ClerkWebhookController(IUserService users) : ControllerBase
83
- {
84
- [HttpPost]
85
- public async Task<IActionResult> Handle([FromBody] ClerkWebhookPayload payload)
86
- {
87
- switch (payload.Type)
88
- {
89
- case "user.created": await users.SyncUserAsync(payload.Data); break;
90
- case "user.updated": await users.UpdateUserAsync(payload.Data); break;
91
- case "user.deleted": await users.DeleteUserAsync(payload.Data.Id); break;
92
- }
93
- return Ok();
94
- }
95
- }
96
- ```
97
-
98
- ## Checklist
99
-
100
- - [ ] Secret Key in environment variables (not hardcoded)
101
- - [ ] Authentication scheme configured
102
- - [ ] Authorization policies defined
103
- - [ ] Webhook endpoint + signature validation
104
- - [ ] Redirect after login configured
105
- - [ ] Error handling for expired sessions
106
-
107
- ---
108
-
109
- *MORPH-SPEC by Polymorphism Tech*
@@ -1,13 +0,0 @@
1
- ---
2
- paths:
3
- - "**/Auth/**"
4
- - "**/auth/**"
5
- - "**/Identity/**"
6
- - "**/Clerk/**"
7
- stacks:
8
- - dotnet
9
- ---
10
-
11
- # Clerk Authentication Standards
12
-
13
- @.morph/framework/standards/backend/integrations/clerk/clerk-auth.md
@@ -1,292 +0,0 @@
1
- # Clerk Authentication Integration Standard
2
-
3
- > **Scope:** universal
4
- > **Layer:** 2 (on keyword)
5
- > **Keywords:** clerk, auth, authentication, nextjs, user management
6
- > **Load When:** clerk authentication keywords detected
7
-
8
- Modern authentication and user management for Next.js applications.
9
-
10
- ---
11
-
12
- ## Overview
13
-
14
- Clerk provides:
15
- - Pre-built UI components (SignIn, SignUp, UserProfile)
16
- - Social auth (Google, GitHub, etc.)
17
- - Multi-factor authentication
18
- - Session management
19
- - User metadata and organizations
20
-
21
- **Primary Use Case:** Next.js 15 + App Router
22
-
23
- ---
24
-
25
- ## Core Principles
26
-
27
- 1. **Server-First**: Use server-side auth checks with `auth()` helper
28
- 2. **Route Protection**: Middleware-based protection for private routes
29
- 3. **Type Safety**: Use Clerk's TypeScript types
30
- 4. **Edge Compatible**: Works with Edge Runtime
31
-
32
- ---
33
-
34
- ## Installation & Setup
35
-
36
- ### Install Packages
37
-
38
- ```bash
39
- npm install @clerk/nextjs
40
- ```
41
-
42
- ### Environment Variables
43
-
44
- ```bash
45
- # .env.local
46
- NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
47
- CLERK_SECRET_KEY=sk_test_...
48
- NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
49
- NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
50
- NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard
51
- NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/onboarding
52
- ```
53
-
54
- ### Root Layout Wrapper
55
-
56
- ```typescript
57
- // app/layout.tsx
58
- import { ClerkProvider } from '@clerk/nextjs';
59
-
60
- export default function RootLayout({ children }: { children: React.ReactNode }) {
61
- return (
62
- <ClerkProvider>
63
- <html lang="en">
64
- <body>{children}</body>
65
- </html>
66
- </ClerkProvider>
67
- );
68
- }
69
- ```
70
-
71
- ### Middleware Protection
72
-
73
- ```typescript
74
- // middleware.ts
75
- import { authMiddleware } from '@clerk/nextjs';
76
-
77
- export default authMiddleware({
78
- publicRoutes: ['/', '/api/webhooks/clerk'],
79
- ignoredRoutes: ['/api/public']
80
- });
81
-
82
- export const config = {
83
- matcher: ['/((?!.+\\.[\\w]+$|_next).*)', '/', '/(api|trpc)(.*)'],
84
- };
85
- ```
86
-
87
- ---
88
-
89
- ## Common Patterns
90
-
91
- ### Sign In Page
92
-
93
- ```typescript
94
- // app/sign-in/[[...sign-in]]/page.tsx
95
- import { SignIn } from '@clerk/nextjs';
96
-
97
- export default function SignInPage() {
98
- return (
99
- <div className="flex items-center justify-center min-h-screen">
100
- <SignIn />
101
- </div>
102
- );
103
- }
104
- ```
105
-
106
- ### Server-Side Auth Check
107
-
108
- ```typescript
109
- // app/dashboard/page.tsx
110
- import { auth } from '@clerk/nextjs';
111
- import { redirect } from 'next/navigation';
112
-
113
- export default async function DashboardPage() {
114
- const { userId } = auth();
115
-
116
- if (!userId) {
117
- redirect('/sign-in');
118
- }
119
-
120
- return <div>Dashboard for user {userId}</div>;
121
- }
122
- ```
123
-
124
- ### Client Component with User Data
125
-
126
- ```typescript
127
- // components/UserProfile.tsx
128
- 'use client';
129
- import { useUser } from '@clerk/nextjs';
130
-
131
- export function UserProfile() {
132
- const { user, isLoaded, isSignedIn } = useUser();
133
-
134
- if (!isLoaded) return <div>Loading...</div>;
135
- if (!isSignedIn) return <div>Not signed in</div>;
136
-
137
- return (
138
- <div>
139
- <p>Welcome, {user.firstName}!</p>
140
- <p>Email: {user.primaryEmailAddress?.emailAddress}</p>
141
- </div>
142
- );
143
- }
144
- ```
145
-
146
- ### API Route Protection
147
-
148
- ```typescript
149
- // app/api/protected/route.ts
150
- import { auth } from '@clerk/nextjs';
151
-
152
- export async function GET() {
153
- const { userId } = auth();
154
-
155
- if (!userId) {
156
- return new Response('Unauthorized', { status: 401 });
157
- }
158
-
159
- // Fetch user-specific data
160
- const data = await fetchUserData(userId);
161
-
162
- return Response.json(data);
163
- }
164
- ```
165
-
166
- ---
167
-
168
- ## Webhook Integration
169
-
170
- ### Setup Webhook Endpoint
171
-
172
- ```typescript
173
- // app/api/webhooks/clerk/route.ts
174
- import { Webhook } from 'svix';
175
- import { headers } from 'next/headers';
176
-
177
- export async function POST(req: Request) {
178
- const WEBHOOK_SECRET = process.env.CLERK_WEBHOOK_SECRET!;
179
-
180
- const headerPayload = headers();
181
- const svix_id = headerPayload.get('svix-id');
182
- const svix_timestamp = headerPayload.get('svix-timestamp');
183
- const svix_signature = headerPayload.get('svix-signature');
184
-
185
- if (!svix_id || !svix_timestamp || !svix_signature) {
186
- return new Response('Missing svix headers', { status: 400 });
187
- }
188
-
189
- const payload = await req.json();
190
- const body = JSON.stringify(payload);
191
-
192
- const wh = new Webhook(WEBHOOK_SECRET);
193
-
194
- let evt;
195
- try {
196
- evt = wh.verify(body, {
197
- 'svix-id': svix_id,
198
- 'svix-timestamp': svix_timestamp,
199
- 'svix-signature': svix_signature,
200
- });
201
- } catch (err) {
202
- return new Response('Invalid signature', { status: 400 });
203
- }
204
-
205
- // Handle events
206
- switch (evt.type) {
207
- case 'user.created':
208
- await handleUserCreated(evt.data);
209
- break;
210
- case 'user.updated':
211
- await handleUserUpdated(evt.data);
212
- break;
213
- case 'user.deleted':
214
- await handleUserDeleted(evt.data);
215
- break;
216
- }
217
-
218
- return new Response('OK');
219
- }
220
- ```
221
-
222
- ---
223
-
224
- ## Neon Integration
225
-
226
- ### Sync Users to Neon PostgreSQL (via EF Core / Npgsql)
227
-
228
- ```csharp
229
- // Services/ClerkUserSyncService.cs
230
- public sealed class ClerkUserSyncService(IDbContextFactory<AppDbContext> dbFactory)
231
- {
232
- public async Task HandleUserCreatedAsync(ClerkUserData userData, CancellationToken ct)
233
- {
234
- await using var db = await dbFactory.CreateDbContextAsync(ct);
235
-
236
- db.Profiles.Add(new Profile
237
- {
238
- ClerkUserId = userData.Id,
239
- Email = userData.EmailAddresses[0].EmailAddress,
240
- FirstName = userData.FirstName,
241
- LastName = userData.LastName,
242
- AvatarUrl = userData.ImageUrl
243
- });
244
-
245
- await db.SaveChangesAsync(ct);
246
- }
247
- }
248
- ```
249
-
250
- ---
251
-
252
- ## Best Practices
253
-
254
- ### Custom Claims
255
-
256
- ```typescript
257
- // Add custom claims in Clerk Dashboard or via API
258
- const { sessionClaims } = auth();
259
- const role = sessionClaims?.metadata?.role as string;
260
-
261
- if (role !== 'admin') {
262
- return new Response('Forbidden', { status: 403 });
263
- }
264
- ```
265
-
266
- ### Organizations
267
-
268
- ```typescript
269
- import { auth } from '@clerk/nextjs';
270
-
271
- const { orgId, orgRole } = auth();
272
-
273
- if (!orgId) {
274
- redirect('/create-organization');
275
- }
276
-
277
- if (orgRole !== 'admin') {
278
- return <div>Admin access required</div>;
279
- }
280
- ```
281
-
282
- ---
283
-
284
- ## References
285
-
286
- - [Clerk Next.js Documentation](https://clerk.com/docs/nextjs)
287
- - [Clerk API Reference](https://clerk.com/docs/reference/backend-api)
288
- - [Webhooks Guide](https://clerk.com/docs/integrations/webhooks)
289
-
290
- ---
291
-
292
- *MORPH-SPEC by Polymorphism Tech*