@polymorphism-tech/morph-spec 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +279 -0
  2. package/bin/morph-spec.js +53 -0
  3. package/content/.claude/commands/morph-apply.md +66 -0
  4. package/content/.claude/commands/morph-archive.md +79 -0
  5. package/content/.claude/commands/morph-costs.md +206 -0
  6. package/content/.claude/commands/morph-infra.md +209 -0
  7. package/content/.claude/commands/morph-proposal.md +60 -0
  8. package/content/.claude/commands/morph-status.md +71 -0
  9. package/content/.claude/settings.local.json +15 -0
  10. package/content/.claude/skills/infra/bicep-architect.md +419 -0
  11. package/content/.claude/skills/infra/container-specialist.md +437 -0
  12. package/content/.claude/skills/infra/devops-engineer.md +405 -0
  13. package/content/.claude/skills/integrations/asaas-financial.md +333 -0
  14. package/content/.claude/skills/integrations/azure-identity.md +309 -0
  15. package/content/.claude/skills/integrations/clerk-auth.md +290 -0
  16. package/content/.claude/skills/specialists/azure-architect.md +142 -0
  17. package/content/.claude/skills/specialists/cost-guardian.md +110 -0
  18. package/content/.claude/skills/specialists/ef-modeler.md +200 -0
  19. package/content/.claude/skills/specialists/hangfire-orchestrator.md +245 -0
  20. package/content/.claude/skills/specialists/ms-agent-expert.md +209 -0
  21. package/content/.claude/skills/specialists/po-pm-advisor.md +197 -0
  22. package/content/.claude/skills/specialists/standards-architect.md +78 -0
  23. package/content/.claude/skills/specialists/ui-ux-designer.md +325 -0
  24. package/content/.claude/skills/stacks/dotnet-blazor.md +352 -0
  25. package/content/.claude/skills/stacks/dotnet-nextjs.md +402 -0
  26. package/content/.claude/skills/stacks/shopify.md +445 -0
  27. package/content/.morph/archive/.gitkeep +25 -0
  28. package/content/.morph/config/agents.json +149 -0
  29. package/content/.morph/config/config.template.json +96 -0
  30. package/content/.morph/examples/api-nextjs/README.md +241 -0
  31. package/content/.morph/examples/api-nextjs/contracts.ts +307 -0
  32. package/content/.morph/examples/api-nextjs/spec.md +399 -0
  33. package/content/.morph/examples/api-nextjs/tasks.md +168 -0
  34. package/content/.morph/examples/micro-saas/README.md +125 -0
  35. package/content/.morph/examples/micro-saas/contracts.cs +358 -0
  36. package/content/.morph/examples/micro-saas/decisions.md +246 -0
  37. package/content/.morph/examples/micro-saas/spec.md +236 -0
  38. package/content/.morph/examples/micro-saas/tasks.md +150 -0
  39. package/content/.morph/examples/multi-agent/README.md +309 -0
  40. package/content/.morph/examples/multi-agent/contracts.cs +433 -0
  41. package/content/.morph/examples/multi-agent/spec.md +479 -0
  42. package/content/.morph/examples/multi-agent/tasks.md +185 -0
  43. package/content/.morph/features/.gitkeep +25 -0
  44. package/content/.morph/project.md +159 -0
  45. package/content/.morph/specs/.gitkeep +20 -0
  46. package/content/.morph/standards/architecture.md +190 -0
  47. package/content/.morph/standards/azure.md +184 -0
  48. package/content/.morph/standards/coding.md +342 -0
  49. package/content/.morph/templates/agent.cs +172 -0
  50. package/content/.morph/templates/component.razor +239 -0
  51. package/content/.morph/templates/contracts.cs +217 -0
  52. package/content/.morph/templates/decisions.md +106 -0
  53. package/content/.morph/templates/infra/app-insights.bicep +63 -0
  54. package/content/.morph/templates/infra/container-app-env.bicep +49 -0
  55. package/content/.morph/templates/infra/container-app.bicep +156 -0
  56. package/content/.morph/templates/infra/key-vault.bicep +91 -0
  57. package/content/.morph/templates/infra/main.bicep +155 -0
  58. package/content/.morph/templates/infra/parameters.dev.json +23 -0
  59. package/content/.morph/templates/infra/parameters.prod.json +23 -0
  60. package/content/.morph/templates/infra/sql-database.bicep +103 -0
  61. package/content/.morph/templates/infra/storage.bicep +106 -0
  62. package/content/.morph/templates/integrations/asaas-client.cs +387 -0
  63. package/content/.morph/templates/integrations/asaas-webhook.cs +351 -0
  64. package/content/.morph/templates/integrations/azure-identity-config.cs +288 -0
  65. package/content/.morph/templates/integrations/clerk-config.cs +258 -0
  66. package/content/.morph/templates/job.cs +171 -0
  67. package/content/.morph/templates/migration.cs +83 -0
  68. package/content/.morph/templates/proposal.md +155 -0
  69. package/content/.morph/templates/recap.md +105 -0
  70. package/content/.morph/templates/repository.cs +141 -0
  71. package/content/.morph/templates/saas/subscription.cs +347 -0
  72. package/content/.morph/templates/saas/tenant.cs +338 -0
  73. package/content/.morph/templates/service.cs +139 -0
  74. package/content/.morph/templates/spec.md +147 -0
  75. package/content/.morph/templates/tasks.md +235 -0
  76. package/content/.morph/templates/test.cs +239 -0
  77. package/content/CLAUDE.md +318 -0
  78. package/package.json +50 -0
  79. package/src/commands/doctor.js +132 -0
  80. package/src/commands/init.js +121 -0
  81. package/src/commands/update.js +84 -0
  82. package/src/utils/file-copier.js +50 -0
  83. package/src/utils/logger.js +32 -0
@@ -0,0 +1,402 @@
1
+ # .NET + Next.js Stack
2
+
3
+ Stack full-stack com .NET Web API no backend e Next.js no frontend.
4
+
5
+ ## Visão Geral
6
+
7
+ | Aspecto | Tecnologia |
8
+ |---------|------------|
9
+ | **Backend** | .NET 9+ Web API |
10
+ | **Frontend** | Next.js 15+ / React 19 |
11
+ | **Database** | Entity Framework Core + Azure SQL |
12
+ | **API** | REST + OpenAPI |
13
+ | **Hosting** | Azure Container Apps |
14
+
15
+ ## Triggers
16
+
17
+ Keywords: `nextjs`, `next.js`, `react`, `api`, `frontend`, `spa`, `typescript`
18
+
19
+ ## Estrutura de Projeto
20
+
21
+ ```
22
+ /
23
+ ├── backend/ # .NET Web API
24
+ │ ├── src/
25
+ │ │ ├── Api/
26
+ │ │ │ ├── Program.cs
27
+ │ │ │ ├── Controllers/
28
+ │ │ │ └── Endpoints/ # Minimal APIs
29
+ │ │ ├── Application/
30
+ │ │ │ ├── Services/
31
+ │ │ │ └── DTOs/
32
+ │ │ ├── Domain/
33
+ │ │ │ └── Entities/
34
+ │ │ └── Infrastructure/
35
+ │ │ └── Data/
36
+ │ ├── tests/
37
+ │ └── Backend.sln
38
+
39
+ ├── frontend/ # Next.js
40
+ │ ├── src/
41
+ │ │ ├── app/ # App Router
42
+ │ │ │ ├── layout.tsx
43
+ │ │ │ ├── page.tsx
44
+ │ │ │ └── (routes)/
45
+ │ │ ├── components/
46
+ │ │ ├── lib/
47
+ │ │ │ ├── api.ts # API client
48
+ │ │ │ └── types.ts # Generated from OpenAPI
49
+ │ │ └── hooks/
50
+ │ ├── package.json
51
+ │ └── next.config.js
52
+
53
+ ├── docker-compose.yml
54
+ └── infra/
55
+ └── main.bicep
56
+ ```
57
+
58
+ ## Backend (.NET API)
59
+
60
+ ### Program.cs (Minimal API)
61
+
62
+ ```csharp
63
+ var builder = WebApplication.CreateBuilder(args);
64
+
65
+ // OpenAPI
66
+ builder.Services.AddEndpointsApiExplorer();
67
+ builder.Services.AddSwaggerGen(c =>
68
+ {
69
+ c.SwaggerDoc("v1", new() { Title = "My API", Version = "v1" });
70
+ });
71
+
72
+ // CORS para Next.js
73
+ builder.Services.AddCors(options =>
74
+ {
75
+ options.AddPolicy("Frontend", policy =>
76
+ {
77
+ policy.WithOrigins(builder.Configuration["Frontend:Url"]!)
78
+ .AllowAnyHeader()
79
+ .AllowAnyMethod()
80
+ .AllowCredentials();
81
+ });
82
+ });
83
+
84
+ // Database
85
+ builder.Services.AddDbContext<AppDbContext>(options =>
86
+ options.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
87
+
88
+ // Services
89
+ builder.Services.AddScoped<IOrderService, OrderService>();
90
+
91
+ var app = builder.Build();
92
+
93
+ // Swagger (dev only)
94
+ if (app.Environment.IsDevelopment())
95
+ {
96
+ app.UseSwagger();
97
+ app.UseSwaggerUI();
98
+ }
99
+
100
+ app.UseHttpsRedirection();
101
+ app.UseCors("Frontend");
102
+ app.UseAuthentication();
103
+ app.UseAuthorization();
104
+
105
+ // Map endpoints
106
+ app.MapOrderEndpoints();
107
+
108
+ app.Run();
109
+ ```
110
+
111
+ ### Minimal API Endpoints
112
+
113
+ ```csharp
114
+ // Endpoints/OrderEndpoints.cs
115
+ public static class OrderEndpoints
116
+ {
117
+ public static void MapOrderEndpoints(this WebApplication app)
118
+ {
119
+ var group = app.MapGroup("/api/orders")
120
+ .WithTags("Orders")
121
+ .RequireAuthorization();
122
+
123
+ group.MapGet("/", GetAll);
124
+ group.MapGet("/{id:int}", GetById);
125
+ group.MapPost("/", Create);
126
+ group.MapPut("/{id:int}", Update);
127
+ group.MapDelete("/{id:int}", Delete);
128
+ }
129
+
130
+ private static async Task<IResult> GetAll(
131
+ IOrderService service,
132
+ [AsParameters] PaginationQuery query)
133
+ {
134
+ var result = await service.GetAllAsync(query);
135
+ return Results.Ok(result);
136
+ }
137
+
138
+ private static async Task<IResult> GetById(
139
+ int id,
140
+ IOrderService service)
141
+ {
142
+ var order = await service.GetByIdAsync(id);
143
+ return order is null ? Results.NotFound() : Results.Ok(order);
144
+ }
145
+
146
+ private static async Task<IResult> Create(
147
+ CreateOrderRequest request,
148
+ IOrderService service)
149
+ {
150
+ var order = await service.CreateAsync(request);
151
+ return Results.Created($"/api/orders/{order.Id}", order);
152
+ }
153
+
154
+ private static async Task<IResult> Update(
155
+ int id,
156
+ UpdateOrderRequest request,
157
+ IOrderService service)
158
+ {
159
+ await service.UpdateAsync(id, request);
160
+ return Results.NoContent();
161
+ }
162
+
163
+ private static async Task<IResult> Delete(
164
+ int id,
165
+ IOrderService service)
166
+ {
167
+ await service.DeleteAsync(id);
168
+ return Results.NoContent();
169
+ }
170
+ }
171
+ ```
172
+
173
+ ## Frontend (Next.js)
174
+
175
+ ### API Client
176
+
177
+ ```typescript
178
+ // lib/api.ts
179
+ const API_URL = process.env.NEXT_PUBLIC_API_URL!;
180
+
181
+ async function fetchApi<T>(
182
+ endpoint: string,
183
+ options?: RequestInit
184
+ ): Promise<T> {
185
+ const res = await fetch(`${API_URL}${endpoint}`, {
186
+ ...options,
187
+ headers: {
188
+ 'Content-Type': 'application/json',
189
+ ...options?.headers,
190
+ },
191
+ credentials: 'include',
192
+ });
193
+
194
+ if (!res.ok) {
195
+ throw new Error(`API error: ${res.status}`);
196
+ }
197
+
198
+ return res.json();
199
+ }
200
+
201
+ export const api = {
202
+ orders: {
203
+ getAll: (params?: { page?: number; pageSize?: number }) =>
204
+ fetchApi<PaginatedResult<Order>>(`/api/orders?${new URLSearchParams(params as any)}`),
205
+
206
+ getById: (id: number) =>
207
+ fetchApi<Order>(`/api/orders/${id}`),
208
+
209
+ create: (data: CreateOrderRequest) =>
210
+ fetchApi<Order>('/api/orders', {
211
+ method: 'POST',
212
+ body: JSON.stringify(data),
213
+ }),
214
+
215
+ update: (id: number, data: UpdateOrderRequest) =>
216
+ fetchApi<void>(`/api/orders/${id}`, {
217
+ method: 'PUT',
218
+ body: JSON.stringify(data),
219
+ }),
220
+
221
+ delete: (id: number) =>
222
+ fetchApi<void>(`/api/orders/${id}`, {
223
+ method: 'DELETE',
224
+ }),
225
+ },
226
+ };
227
+ ```
228
+
229
+ ### Types (gerado do OpenAPI)
230
+
231
+ ```typescript
232
+ // lib/types.ts
233
+ export interface Order {
234
+ id: number;
235
+ orderNumber: string;
236
+ customerId: number;
237
+ customerName: string;
238
+ total: number;
239
+ status: OrderStatus;
240
+ createdAt: string;
241
+ }
242
+
243
+ export type OrderStatus = 'Pending' | 'Processing' | 'Completed' | 'Cancelled';
244
+
245
+ export interface CreateOrderRequest {
246
+ customerId: number;
247
+ items: OrderItem[];
248
+ notes?: string;
249
+ }
250
+
251
+ export interface PaginatedResult<T> {
252
+ items: T[];
253
+ totalCount: number;
254
+ page: number;
255
+ pageSize: number;
256
+ totalPages: number;
257
+ }
258
+ ```
259
+
260
+ ### Server Component (App Router)
261
+
262
+ ```tsx
263
+ // app/orders/page.tsx
264
+ import { api } from '@/lib/api';
265
+ import { OrderList } from '@/components/orders/OrderList';
266
+
267
+ export default async function OrdersPage() {
268
+ const orders = await api.orders.getAll();
269
+
270
+ return (
271
+ <div className="container mx-auto p-4">
272
+ <div className="flex justify-between items-center mb-6">
273
+ <h1 className="text-2xl font-bold">Pedidos</h1>
274
+ <a href="/orders/new" className="btn btn-primary">
275
+ Novo Pedido
276
+ </a>
277
+ </div>
278
+
279
+ <OrderList initialOrders={orders} />
280
+ </div>
281
+ );
282
+ }
283
+ ```
284
+
285
+ ### Client Component
286
+
287
+ ```tsx
288
+ 'use client';
289
+
290
+ // components/orders/OrderList.tsx
291
+ import { useState } from 'react';
292
+ import { Order, PaginatedResult } from '@/lib/types';
293
+ import { api } from '@/lib/api';
294
+
295
+ interface Props {
296
+ initialOrders: PaginatedResult<Order>;
297
+ }
298
+
299
+ export function OrderList({ initialOrders }: Props) {
300
+ const [orders, setOrders] = useState(initialOrders);
301
+ const [loading, setLoading] = useState(false);
302
+
303
+ async function loadPage(page: number) {
304
+ setLoading(true);
305
+ try {
306
+ const result = await api.orders.getAll({ page });
307
+ setOrders(result);
308
+ } finally {
309
+ setLoading(false);
310
+ }
311
+ }
312
+
313
+ return (
314
+ <div>
315
+ <table className="w-full">
316
+ <thead>
317
+ <tr>
318
+ <th>Número</th>
319
+ <th>Cliente</th>
320
+ <th>Total</th>
321
+ <th>Status</th>
322
+ </tr>
323
+ </thead>
324
+ <tbody>
325
+ {orders.items.map((order) => (
326
+ <tr key={order.id}>
327
+ <td>{order.orderNumber}</td>
328
+ <td>{order.customerName}</td>
329
+ <td>{order.total.toLocaleString('pt-BR', { style: 'currency', currency: 'BRL' })}</td>
330
+ <td><StatusBadge status={order.status} /></td>
331
+ </tr>
332
+ ))}
333
+ </tbody>
334
+ </table>
335
+
336
+ <Pagination
337
+ currentPage={orders.page}
338
+ totalPages={orders.totalPages}
339
+ onPageChange={loadPage}
340
+ disabled={loading}
341
+ />
342
+ </div>
343
+ );
344
+ }
345
+ ```
346
+
347
+ ## Docker Compose
348
+
349
+ ```yaml
350
+ # docker-compose.yml
351
+ services:
352
+ backend:
353
+ build:
354
+ context: ./backend
355
+ dockerfile: Dockerfile
356
+ ports:
357
+ - "5000:8080"
358
+ environment:
359
+ - ConnectionStrings__Default=Server=db;Database=App;User=sa;Password=YourStrong!Passw0rd;TrustServerCertificate=true
360
+ - Frontend__Url=http://localhost:3000
361
+ depends_on:
362
+ - db
363
+
364
+ frontend:
365
+ build:
366
+ context: ./frontend
367
+ dockerfile: Dockerfile
368
+ ports:
369
+ - "3000:3000"
370
+ environment:
371
+ - NEXT_PUBLIC_API_URL=http://localhost:5000
372
+
373
+ db:
374
+ image: mcr.microsoft.com/mssql/server:2022-latest
375
+ environment:
376
+ - ACCEPT_EULA=Y
377
+ - SA_PASSWORD=YourStrong!Passw0rd
378
+ ports:
379
+ - "1433:1433"
380
+ ```
381
+
382
+ ## Documentação de Referência
383
+
384
+ - [Next.js Documentation](https://nextjs.org/docs)
385
+ - [ASP.NET Web API](https://learn.microsoft.com/en-us/aspnet/core/web-api/)
386
+ - [React Documentation](https://react.dev/)
387
+ - [Minimal APIs](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis)
388
+
389
+ ## Checklist de Projeto
390
+
391
+ - [ ] Backend com Minimal APIs
392
+ - [ ] OpenAPI/Swagger configurado
393
+ - [ ] CORS configurado para frontend
394
+ - [ ] Frontend com App Router (Next.js 15+)
395
+ - [ ] API client tipado
396
+ - [ ] Types gerados do OpenAPI
397
+ - [ ] Docker Compose para dev
398
+ - [ ] Environment variables configuradas
399
+
400
+ ---
401
+
402
+ *MORPH-SPEC by Polymorphism Tech*