@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.
- package/CLAUDE.md +36 -0
- package/README.md +2 -2
- package/bin/morph-spec.js +3 -0
- package/bin/task-manager.js +999 -962
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/agents/ai-agents/vector-search-expert.md +247 -233
- package/framework/agents/backend/ms-agent-expert.md +1 -1
- package/framework/agents/backend/neon-expert.md +379 -0
- package/framework/agents/frontend/gsap-animator.md +131 -0
- package/framework/agents/integrations/neon-auth.md +151 -0
- package/framework/agents.json +1183 -1085
- package/framework/commands/morph-preflight.md +200 -192
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +1 -1
- package/framework/rules/gsap-standards.md +13 -0
- package/framework/rules/neon-auth-standards.md +13 -0
- package/framework/rules/neon-standards.md +26 -0
- package/framework/skills/level-0-meta/mcp-registry.json +1 -1
- package/framework/skills/level-0-meta/morph-agent-teams/SKILL.md +472 -472
- package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +1 -1
- package/framework/skills/level-0-meta/morph-init/SKILL.md +12 -12
- package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +5 -5
- package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +5 -5
- package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +7 -7
- package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +24 -24
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +12 -12
- package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +9 -9
- package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +143 -143
- package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +197 -116
- package/framework/standards/ai-agents/production.md +1 -0
- package/framework/standards/ai-agents/setup.md +3 -2
- package/framework/standards/ai-agents/workflows.md +1 -0
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +4 -4
- package/framework/standards/backend/database/postgresql/database.md +63 -83
- package/framework/standards/backend/dotnet/scalar-ui.md +172 -172
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +274 -274
- package/framework/standards/backend/integrations/asaas/asaas-api.md +2 -2
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +364 -0
- package/framework/standards/frontend/design-system/animations.md +9 -0
- package/framework/standards/frontend/gsap/gsap-core.md +463 -0
- package/framework/standards/frontend/gsap/gsap-plugins.md +294 -0
- package/framework/standards/frontend/gsap/gsap-scrolltrigger.md +318 -0
- package/framework/standards/frontend/nextjs/motion-patterns.md +1 -0
- package/framework/standards/frontend/nextjs/nextjs-patterns.md +47 -37
- package/framework/standards/infrastructure/docker/easypanel-deploy.md +4 -8
- package/framework/standards/infrastructure/neon/neon-pgrag.md +239 -0
- package/framework/standards/infrastructure/neon/neon-pgvector.md +236 -0
- package/framework/standards/infrastructure/neon/neon-semantic-kernel.md +310 -0
- package/framework/standards/infrastructure/neon/neon-setup.md +186 -0
- package/framework/standards/integration/mcp/mcp-tools.md +32 -34
- package/framework/templates/README.md +20 -20
- package/framework/templates/REGISTRY.json +54 -101
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/backend/repository.cs +148 -148
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
- package/framework/templates/code/dotnet/database/vector-entity.cs +93 -0
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +1 -1
- package/framework/templates/code/sql/{supabase-migration.sql → postgresql-migration.sql} +12 -21
- package/framework/templates/code/sql/{supabase-migration.template.sql → postgresql-migration.template.sql} +13 -18
- package/framework/templates/code/sql/{rls-policy.sql → postgresql-rls-policy.sql} +6 -9
- package/framework/templates/code/typescript/contracts.ts +167 -168
- package/framework/templates/context/CONTEXT.md +3 -3
- package/framework/templates/docs/proposal.md +6 -6
- package/framework/templates/docs/ui-components.md +1 -1
- package/framework/templates/feature/decisions.md +122 -121
- package/framework/templates/feature/recap.md +145 -145
- package/framework/templates/feature/tasks.md +199 -199
- package/framework/templates/frontend/nextjs/gsap-scroll-section.tsx.hbs +44 -0
- package/framework/templates/infrastructure/docker/docker-compose.template.yml +50 -67
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/docker/easypanel.template.json +46 -54
- package/framework/templates/infrastructure/github/README.md +56 -56
- package/framework/templates/integrations/neon-auth-config.cs +133 -0
- package/framework/templates/integrations/semantic-kernel-neon.cs +125 -0
- package/framework/workflows/README.md +1 -1
- package/framework/workflows/docs/full-morph.md +69 -69
- package/package.json +1 -1
- package/src/commands/agents/dispatch-agents.js +19 -15
- package/src/commands/state/advance-phase.js +5 -0
- package/src/commands/tasks/task.js +3 -0
- package/src/core/state/state-manager.js +45 -1
- package/src/core/templates/template-registry.js +1 -66
- package/src/lib/detectors/index.js +4 -4
- package/src/lib/generators/architecture-scanner.js +639 -640
- package/src/lib/installers/mcp-installer.js +1 -1
- package/src/lib/tasks/task-classifier.js +15 -1
- package/src/lib/tasks/test-runner.js +5 -1
- package/src/lib/validators/content/content-validator.js +9 -10
- package/src/lib/validators/validation-runner.js +7 -5
- package/framework/agents/backend/supabase-expert.md +0 -256
- package/framework/agents/integrations/clerk-auth.md +0 -109
- package/framework/rules/clerk-standards.md +0 -13
- package/framework/rules/supabase-standards.md +0 -29
- package/framework/standards/backend/integrations/clerk/clerk-auth.md +0 -290
- package/framework/standards/infrastructure/supabase/mcp-setup.md +0 -142
- package/framework/standards/infrastructure/supabase/supabase-auth.md +0 -176
- package/framework/standards/infrastructure/supabase/supabase-custom-jwt.md +0 -206
- package/framework/standards/infrastructure/supabase/supabase-pgvector.md +0 -169
- package/framework/standards/infrastructure/supabase/supabase-rls.md +0 -184
- package/framework/standards/infrastructure/supabase/supabase-storage.md +0 -153
- package/framework/templates/integrations/clerk-config.cs +0 -217
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Neon PostgreSQL Database Standards
|
|
2
2
|
|
|
3
|
-
> **Scope:** nextjs-
|
|
3
|
+
> **Scope:** nextjs-neon
|
|
4
4
|
> **Layer:** 2 (on keyword)
|
|
5
|
-
> **Keywords:** postgresql, postgres, sql,
|
|
6
|
-
> **Load When:**
|
|
5
|
+
> **Keywords:** postgresql, postgres, sql, neon, database schema
|
|
6
|
+
> **Load When:** neon or postgresql keywords detected
|
|
7
7
|
|
|
8
|
-
Database schema design, migrations, and Row Level Security (RLS) patterns for
|
|
8
|
+
Database schema design, migrations, and Row Level Security (RLS) patterns for Neon PostgreSQL.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -68,7 +68,7 @@ alter table public.profiles enable row level security;
|
|
|
68
68
|
```sql
|
|
69
69
|
create policy "Users can view own profile"
|
|
70
70
|
on public.profiles for select
|
|
71
|
-
using (auth.
|
|
71
|
+
using (auth.user_id() = user_id);
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
#### User can update own profile
|
|
@@ -76,8 +76,8 @@ create policy "Users can view own profile"
|
|
|
76
76
|
```sql
|
|
77
77
|
create policy "Users can update own profile"
|
|
78
78
|
on public.profiles for update
|
|
79
|
-
using (auth.
|
|
80
|
-
with check (auth.
|
|
79
|
+
using (auth.user_id() = user_id)
|
|
80
|
+
with check (auth.user_id() = user_id);
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
#### User can insert own profile
|
|
@@ -85,7 +85,7 @@ create policy "Users can update own profile"
|
|
|
85
85
|
```sql
|
|
86
86
|
create policy "Users can insert own profile"
|
|
87
87
|
on public.profiles for insert
|
|
88
|
-
with check (auth.
|
|
88
|
+
with check (auth.user_id() = user_id);
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
#### Admin can do anything
|
|
@@ -96,7 +96,7 @@ create policy "Admins have full access"
|
|
|
96
96
|
using (
|
|
97
97
|
exists (
|
|
98
98
|
select 1 from public.user_roles
|
|
99
|
-
where user_id = auth.
|
|
99
|
+
where user_id = auth.user_id() and role = 'admin'
|
|
100
100
|
)
|
|
101
101
|
);
|
|
102
102
|
```
|
|
@@ -113,16 +113,20 @@ create policy "Public profiles are viewable by everyone"
|
|
|
113
113
|
|
|
114
114
|
## Migrations
|
|
115
115
|
|
|
116
|
-
### Migration
|
|
116
|
+
### Migration Management (EF Core)
|
|
117
117
|
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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
|
|
123
127
|
```
|
|
124
128
|
|
|
125
|
-
### Migration Template
|
|
129
|
+
### Migration Template (SQL for manual migrations)
|
|
126
130
|
|
|
127
131
|
```sql
|
|
128
132
|
-- Create table
|
|
@@ -250,89 +254,65 @@ create trigger users_soft_delete
|
|
|
250
254
|
|
|
251
255
|
---
|
|
252
256
|
|
|
253
|
-
##
|
|
257
|
+
## Database Queries (EF Core / SQL)
|
|
254
258
|
|
|
255
|
-
### Select
|
|
259
|
+
### Select (EF Core)
|
|
256
260
|
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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);
|
|
264
268
|
```
|
|
265
269
|
|
|
266
|
-
### Insert
|
|
270
|
+
### Insert (EF Core)
|
|
267
271
|
|
|
268
|
-
```
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
.select()
|
|
273
|
-
.single()
|
|
272
|
+
```csharp
|
|
273
|
+
var user = new User { Name = "John", Email = "john@example.com" };
|
|
274
|
+
db.Users.Add(user);
|
|
275
|
+
await db.SaveChangesAsync(ct);
|
|
274
276
|
```
|
|
275
277
|
|
|
276
|
-
### Update
|
|
278
|
+
### Update (EF Core)
|
|
277
279
|
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
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
|
+
}
|
|
285
287
|
```
|
|
286
288
|
|
|
287
|
-
### Delete
|
|
289
|
+
### Delete (EF Core)
|
|
288
290
|
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
.from('users')
|
|
292
|
-
.delete()
|
|
293
|
-
.eq('id', userId)
|
|
291
|
+
```csharp
|
|
292
|
+
await db.Users.Where(u => u.Id == userId).ExecuteDeleteAsync(ct);
|
|
294
293
|
```
|
|
295
294
|
|
|
296
|
-
### Joins (
|
|
295
|
+
### Joins (Navigation Properties)
|
|
297
296
|
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
)
|
|
309
|
-
`)
|
|
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);
|
|
310
307
|
```
|
|
311
308
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
## Realtime Subscriptions
|
|
315
|
-
|
|
316
|
-
### Listen to Changes
|
|
309
|
+
### Direct SQL via Npgsql (Next.js / serverless)
|
|
317
310
|
|
|
318
311
|
```typescript
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
{
|
|
324
|
-
event: '*', // or 'INSERT', 'UPDATE', 'DELETE'
|
|
325
|
-
schema: 'public',
|
|
326
|
-
table: 'posts'
|
|
327
|
-
},
|
|
328
|
-
(payload) => {
|
|
329
|
-
console.log('Change received!', payload)
|
|
330
|
-
}
|
|
331
|
-
)
|
|
332
|
-
.subscribe()
|
|
333
|
-
|
|
334
|
-
// Cleanup
|
|
335
|
-
supabase.removeChannel(channel)
|
|
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`;
|
|
336
316
|
```
|
|
337
317
|
|
|
338
318
|
---
|
|
@@ -349,4 +329,4 @@ supabase.removeChannel(channel)
|
|
|
349
329
|
|
|
350
330
|
---
|
|
351
331
|
|
|
352
|
-
*
|
|
332
|
+
*Neon PostgreSQL Database Standards - MORPH-SPEC by Polymorphism Tech*
|
|
@@ -1,172 +1,172 @@
|
|
|
1
|
-
# Scalar.AspNetCore — API Documentation UI
|
|
2
|
-
|
|
3
|
-
> **Scope:** dotnet-vsa
|
|
4
|
-
> **Layer:** 0 (always load)
|
|
5
|
-
> **Keywords:** scalar, openapi, swagger, api-docs, documentation
|
|
6
|
-
> **Load When:** dotnet VSA projects
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
Scalar replaces Swagger UI as the API documentation frontend. It provides a modern UI with built-in request testing, client code generation, and dark themes. Works with ASP.NET Core's native OpenAPI support (`Microsoft.AspNetCore.OpenApi`).
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Package Setup
|
|
15
|
-
|
|
16
|
-
```xml
|
|
17
|
-
<!-- .csproj -->
|
|
18
|
-
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
|
|
19
|
-
<PackageReference Include="Scalar.AspNetCore" Version="2.12.40" />
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
No Swashbuckle needed. ASP.NET Core 9+ has built-in OpenAPI document generation.
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## Program.cs Configuration
|
|
27
|
-
|
|
28
|
-
```csharp
|
|
29
|
-
using Scalar.AspNetCore;
|
|
30
|
-
|
|
31
|
-
var builder = WebApplication.CreateBuilder(args);
|
|
32
|
-
|
|
33
|
-
// Enable OpenAPI document generation
|
|
34
|
-
builder.Services.AddOpenApi();
|
|
35
|
-
|
|
36
|
-
var app = builder.Build();
|
|
37
|
-
|
|
38
|
-
// Map the OpenAPI JSON endpoint (dev only)
|
|
39
|
-
if (app.Environment.IsDevelopment())
|
|
40
|
-
{
|
|
41
|
-
app.MapOpenApi();
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Map Scalar UI at /scalar/v1
|
|
45
|
-
app.MapScalarApiReference(options =>
|
|
46
|
-
{
|
|
47
|
-
options.WithTheme(ScalarTheme.DeepSpace);
|
|
48
|
-
|
|
49
|
-
// Enable Developer Tools (request + client code panel)
|
|
50
|
-
options.WithDefaultHttpClient(
|
|
51
|
-
ScalarTarget.CSharp,
|
|
52
|
-
ScalarClient.HttpClient);
|
|
53
|
-
});
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
**Access URL:** `https://localhost:{port}/scalar/v1`
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
## Available Themes
|
|
61
|
-
|
|
62
|
-
| Theme | Description |
|
|
63
|
-
|-------|-------------|
|
|
64
|
-
| `ScalarTheme.Default` | Light theme |
|
|
65
|
-
| `ScalarTheme.DeepSpace` | Dark blue (recommended) |
|
|
66
|
-
| `ScalarTheme.Purple` | Purple accent |
|
|
67
|
-
| `ScalarTheme.Moon` | Dark grey |
|
|
68
|
-
| `ScalarTheme.Saturn` | Warm dark |
|
|
69
|
-
| `ScalarTheme.Mars` | Red accent |
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## ApiTags Organization
|
|
74
|
-
|
|
75
|
-
Group endpoints by feature using a constants class and `.WithTags()`:
|
|
76
|
-
|
|
77
|
-
```csharp
|
|
78
|
-
// Constants/ApiTags.cs
|
|
79
|
-
public static class ApiTags
|
|
80
|
-
{
|
|
81
|
-
public const string Books = "books";
|
|
82
|
-
public const string Authors = "authors";
|
|
83
|
-
public const string Orders = "orders";
|
|
84
|
-
}
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Apply tags in endpoints:
|
|
88
|
-
|
|
89
|
-
```csharp
|
|
90
|
-
internal sealed class CreateBookEndpoint : IApiEndpoint
|
|
91
|
-
{
|
|
92
|
-
public void MapEndpoint(
|
|
93
|
-
{
|
|
94
|
-
app.MapPost("books", async (
|
|
95
|
-
IHandler<CreateBookRequest, Result<CreateBookResponse>> handler,
|
|
96
|
-
CreateBookRequest command,
|
|
97
|
-
CancellationToken cancellationToken) =>
|
|
98
|
-
{
|
|
99
|
-
var result = await handler.HandleAsync(command, cancellationToken);
|
|
100
|
-
return result.Match(
|
|
101
|
-
onSuccess: () => Results.Ok(result.Value),
|
|
102
|
-
onFailure: error => Results.BadRequest(error));
|
|
103
|
-
})
|
|
104
|
-
.WithTags(ApiTags.Books)
|
|
105
|
-
.Produces<CreateBookResponse>(StatusCodes.Status200OK)
|
|
106
|
-
.Produces(StatusCodes.Status400BadRequest);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## Endpoint Metadata
|
|
114
|
-
|
|
115
|
-
Use `.Produces<T>()` to document response types for OpenAPI:
|
|
116
|
-
|
|
117
|
-
```csharp
|
|
118
|
-
app.MapGet("books/{id:guid}", async (...) => { ... })
|
|
119
|
-
.WithTags(ApiTags.Books)
|
|
120
|
-
.WithName("GetBookById")
|
|
121
|
-
.WithSummary("Get a book by its unique identifier")
|
|
122
|
-
.Produces<GetBookResponse>(StatusCodes.Status200OK)
|
|
123
|
-
.Produces(StatusCodes.Status404NotFound);
|
|
124
|
-
|
|
125
|
-
app.MapDelete("books/{id:guid}", async (...) => { ... })
|
|
126
|
-
.WithTags(ApiTags.Books)
|
|
127
|
-
.Produces(StatusCodes.Status204NoContent)
|
|
128
|
-
.Produces(StatusCodes.Status404NotFound);
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Common Metadata Methods
|
|
132
|
-
|
|
133
|
-
| Method | Purpose |
|
|
134
|
-
|--------|---------|
|
|
135
|
-
| `.WithTags("tag")` | Group in Scalar sidebar |
|
|
136
|
-
| `.WithName("OperationId")` | Unique operation identifier |
|
|
137
|
-
| `.WithSummary("...")` | Short description in endpoint list |
|
|
138
|
-
| `.WithDescription("...")` | Long description in detail panel |
|
|
139
|
-
| `.Produces<T>(statusCode)` | Document success response type |
|
|
140
|
-
| `.Produces(statusCode)` | Document error response (no body) |
|
|
141
|
-
| `.ProducesProblem(statusCode)` | Document ProblemDetails response |
|
|
142
|
-
| `.RequireAuthorization()` | Marks as requiring auth in docs |
|
|
143
|
-
|
|
144
|
-
---
|
|
145
|
-
|
|
146
|
-
## Client Code Generation
|
|
147
|
-
|
|
148
|
-
Scalar auto-generates client code for API calls. The `WithDefaultHttpClient` option selects the default language:
|
|
149
|
-
|
|
150
|
-
| Target | Client | Description |
|
|
151
|
-
|--------|--------|-------------|
|
|
152
|
-
| `ScalarTarget.CSharp` | `ScalarClient.HttpClient` | .NET HttpClient |
|
|
153
|
-
| `ScalarTarget.JavaScript` | `ScalarClient.Fetch` | Browser fetch() |
|
|
154
|
-
| `ScalarTarget.Python` | `ScalarClient.Requests` | Python requests |
|
|
155
|
-
| `ScalarTarget.Shell` | `ScalarClient.Curl` | cURL command |
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## Anti-Patterns
|
|
160
|
-
|
|
161
|
-
| Do NOT | Do Instead |
|
|
162
|
-
|--------|------------|
|
|
163
|
-
| Install Swashbuckle | Use `Microsoft.AspNetCore.OpenApi` + `Scalar.AspNetCore` |
|
|
164
|
-
| Expose OpenAPI in production | Guard with `IsDevelopment()` check |
|
|
165
|
-
| Skip `.WithTags()` on endpoints | Every endpoint needs a tag for organized docs |
|
|
166
|
-
| Skip `.Produces<T>()` | Always document response types for accurate API docs |
|
|
167
|
-
| Use magic strings for tags | Define tags in `Constants/ApiTags.cs` |
|
|
168
|
-
| Map Scalar before `MapOpenApi()` | `MapOpenApi()` first, then `MapScalarApiReference()` |
|
|
169
|
-
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
*MORPH-SPEC by Polymorphism Tech*
|
|
1
|
+
# Scalar.AspNetCore — API Documentation UI
|
|
2
|
+
|
|
3
|
+
> **Scope:** dotnet-vsa
|
|
4
|
+
> **Layer:** 0 (always load)
|
|
5
|
+
> **Keywords:** scalar, openapi, swagger, api-docs, documentation
|
|
6
|
+
> **Load When:** dotnet VSA projects
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Scalar replaces Swagger UI as the API documentation frontend. It provides a modern UI with built-in request testing, client code generation, and dark themes. Works with ASP.NET Core's native OpenAPI support (`Microsoft.AspNetCore.OpenApi`).
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Package Setup
|
|
15
|
+
|
|
16
|
+
```xml
|
|
17
|
+
<!-- .csproj -->
|
|
18
|
+
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
|
|
19
|
+
<PackageReference Include="Scalar.AspNetCore" Version="2.12.40" />
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
No Swashbuckle needed. ASP.NET Core 9+ has built-in OpenAPI document generation.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Program.cs Configuration
|
|
27
|
+
|
|
28
|
+
```csharp
|
|
29
|
+
using Scalar.AspNetCore;
|
|
30
|
+
|
|
31
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
32
|
+
|
|
33
|
+
// Enable OpenAPI document generation
|
|
34
|
+
builder.Services.AddOpenApi();
|
|
35
|
+
|
|
36
|
+
var app = builder.Build();
|
|
37
|
+
|
|
38
|
+
// Map the OpenAPI JSON endpoint (dev only)
|
|
39
|
+
if (app.Environment.IsDevelopment())
|
|
40
|
+
{
|
|
41
|
+
app.MapOpenApi();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Map Scalar UI at /scalar/v1
|
|
45
|
+
app.MapScalarApiReference(options =>
|
|
46
|
+
{
|
|
47
|
+
options.WithTheme(ScalarTheme.DeepSpace);
|
|
48
|
+
|
|
49
|
+
// Enable Developer Tools (request + client code panel)
|
|
50
|
+
options.WithDefaultHttpClient(
|
|
51
|
+
ScalarTarget.CSharp,
|
|
52
|
+
ScalarClient.HttpClient);
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Access URL:** `https://localhost:{port}/scalar/v1`
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Available Themes
|
|
61
|
+
|
|
62
|
+
| Theme | Description |
|
|
63
|
+
|-------|-------------|
|
|
64
|
+
| `ScalarTheme.Default` | Light theme |
|
|
65
|
+
| `ScalarTheme.DeepSpace` | Dark blue (recommended) |
|
|
66
|
+
| `ScalarTheme.Purple` | Purple accent |
|
|
67
|
+
| `ScalarTheme.Moon` | Dark grey |
|
|
68
|
+
| `ScalarTheme.Saturn` | Warm dark |
|
|
69
|
+
| `ScalarTheme.Mars` | Red accent |
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## ApiTags Organization
|
|
74
|
+
|
|
75
|
+
Group endpoints by feature using a constants class and `.WithTags()`:
|
|
76
|
+
|
|
77
|
+
```csharp
|
|
78
|
+
// Constants/ApiTags.cs
|
|
79
|
+
public static class ApiTags
|
|
80
|
+
{
|
|
81
|
+
public const string Books = "books";
|
|
82
|
+
public const string Authors = "authors";
|
|
83
|
+
public const string Orders = "orders";
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Apply tags in endpoints:
|
|
88
|
+
|
|
89
|
+
```csharp
|
|
90
|
+
internal sealed class CreateBookEndpoint : IApiEndpoint
|
|
91
|
+
{
|
|
92
|
+
public void MapEndpoint(IEndpointRouteBuilder app)
|
|
93
|
+
{
|
|
94
|
+
app.MapPost("books", async (
|
|
95
|
+
IHandler<CreateBookRequest, Result<CreateBookResponse>> handler,
|
|
96
|
+
CreateBookRequest command,
|
|
97
|
+
CancellationToken cancellationToken) =>
|
|
98
|
+
{
|
|
99
|
+
var result = await handler.HandleAsync(command, cancellationToken);
|
|
100
|
+
return result.Match(
|
|
101
|
+
onSuccess: () => Results.Ok(result.Value),
|
|
102
|
+
onFailure: error => Results.BadRequest(error));
|
|
103
|
+
})
|
|
104
|
+
.WithTags(ApiTags.Books)
|
|
105
|
+
.Produces<CreateBookResponse>(StatusCodes.Status200OK)
|
|
106
|
+
.Produces(StatusCodes.Status400BadRequest);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Endpoint Metadata
|
|
114
|
+
|
|
115
|
+
Use `.Produces<T>()` to document response types for OpenAPI:
|
|
116
|
+
|
|
117
|
+
```csharp
|
|
118
|
+
app.MapGet("books/{id:guid}", async (...) => { ... })
|
|
119
|
+
.WithTags(ApiTags.Books)
|
|
120
|
+
.WithName("GetBookById")
|
|
121
|
+
.WithSummary("Get a book by its unique identifier")
|
|
122
|
+
.Produces<GetBookResponse>(StatusCodes.Status200OK)
|
|
123
|
+
.Produces(StatusCodes.Status404NotFound);
|
|
124
|
+
|
|
125
|
+
app.MapDelete("books/{id:guid}", async (...) => { ... })
|
|
126
|
+
.WithTags(ApiTags.Books)
|
|
127
|
+
.Produces(StatusCodes.Status204NoContent)
|
|
128
|
+
.Produces(StatusCodes.Status404NotFound);
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Common Metadata Methods
|
|
132
|
+
|
|
133
|
+
| Method | Purpose |
|
|
134
|
+
|--------|---------|
|
|
135
|
+
| `.WithTags("tag")` | Group in Scalar sidebar |
|
|
136
|
+
| `.WithName("OperationId")` | Unique operation identifier |
|
|
137
|
+
| `.WithSummary("...")` | Short description in endpoint list |
|
|
138
|
+
| `.WithDescription("...")` | Long description in detail panel |
|
|
139
|
+
| `.Produces<T>(statusCode)` | Document success response type |
|
|
140
|
+
| `.Produces(statusCode)` | Document error response (no body) |
|
|
141
|
+
| `.ProducesProblem(statusCode)` | Document ProblemDetails response |
|
|
142
|
+
| `.RequireAuthorization()` | Marks as requiring auth in docs |
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Client Code Generation
|
|
147
|
+
|
|
148
|
+
Scalar auto-generates client code for API calls. The `WithDefaultHttpClient` option selects the default language:
|
|
149
|
+
|
|
150
|
+
| Target | Client | Description |
|
|
151
|
+
|--------|--------|-------------|
|
|
152
|
+
| `ScalarTarget.CSharp` | `ScalarClient.HttpClient` | .NET HttpClient |
|
|
153
|
+
| `ScalarTarget.JavaScript` | `ScalarClient.Fetch` | Browser fetch() |
|
|
154
|
+
| `ScalarTarget.Python` | `ScalarClient.Requests` | Python requests |
|
|
155
|
+
| `ScalarTarget.Shell` | `ScalarClient.Curl` | cURL command |
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Anti-Patterns
|
|
160
|
+
|
|
161
|
+
| Do NOT | Do Instead |
|
|
162
|
+
|--------|------------|
|
|
163
|
+
| Install Swashbuckle | Use `Microsoft.AspNetCore.OpenApi` + `Scalar.AspNetCore` |
|
|
164
|
+
| Expose OpenAPI in production | Guard with `IsDevelopment()` check |
|
|
165
|
+
| Skip `.WithTags()` on endpoints | Every endpoint needs a tag for organized docs |
|
|
166
|
+
| Skip `.Produces<T>()` | Always document response types for accurate API docs |
|
|
167
|
+
| Use magic strings for tags | Define tags in `Constants/ApiTags.cs` |
|
|
168
|
+
| Map Scalar before `MapOpenApi()` | `MapOpenApi()` first, then `MapScalarApiReference()` |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
*MORPH-SPEC by Polymorphism Tech*
|