@polymorphism-tech/morph-spec 7.9.3 → 7.9.4
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/README.md +2 -2
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +1 -1
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +1 -1
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/standards/STANDARDS.json +7 -2
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +45 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> Spec-driven development framework for multi-stack projects. Turns feature requests into implementation-ready code through structured, AI-orchestrated phases.
|
|
4
4
|
|
|
5
5
|
**Package:** `@polymorphism-tech/morph-spec`
|
|
6
|
-
**Version:** 7.9.
|
|
6
|
+
**Version:** 7.9.4
|
|
7
7
|
**Requires:** Node.js 22+, Claude Code
|
|
8
8
|
|
|
9
9
|
---
|
|
@@ -365,4 +365,4 @@ Code generated by morph-spec (contracts, templates, implementation output) belon
|
|
|
365
365
|
|
|
366
366
|
---
|
|
367
367
|
|
|
368
|
-
*morph-spec v7.9.
|
|
368
|
+
*morph-spec v7.9.4 by [Polymorphism Tech](https://polymorphism.tech)*
|
package/claude-plugin.json
CHANGED
package/docs/CHEATSHEET.md
CHANGED
package/docs/QUICKSTART.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Guia a criação de uma landing page nova ponta-a-ponta a partir do
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar um novo projeto de LP com o template Umbraco genérico
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# create-umbraco-lp
|
|
@@ -4,7 +4,7 @@ description: Migra uma landing page existente (React/Vite, Next.js estático ou
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /migrate-lp-to-umbraco {projeto}" do usuário, ou quando o usuário descrever necessidade de migrar uma LP para Umbraco
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# migrate-lp-to-umbraco
|
|
@@ -4,7 +4,7 @@ description: Orquestra a execução autônoma de tasks de uma feature morph-spec
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: após Gate 2 aprovado, ao receber instrução "use /morph-apply" ou "implementar feature"
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-apply
|
|
@@ -4,7 +4,7 @@ description: Entende o negócio, os usuários e a arquitetura antes de qualquer
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber um novo request de feature, antes de morph-plan
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-brainstorming
|
|
@@ -4,7 +4,7 @@ description: Avalia a qualidade de uma tarefa ou fase com rubricas graduadas 0-1
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao completar uma tarefa ou ao finalizar uma fase de implementação
|
|
6
6
|
user-invokable: false
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-eval
|
|
@@ -4,7 +4,7 @@ description: Guia a produção dos três artefatos de planejamento de uma featur
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase plan de uma feature, após o Gate 1 (proposal aprovado)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-plan
|
|
@@ -4,7 +4,7 @@ description: Orquestra a fase de proposta+plano de uma feature morph-spec. Encad
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao receber instrução "use /morph-proposal" do usuário, ou ao iniciar uma nova feature
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-proposal
|
|
@@ -4,7 +4,7 @@ description: Conduz a fase de revisão e produz o review-report.md para o Gate 3
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar a fase review, após todas as tasks de tasks.json estarem com status `done`
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-review
|
|
@@ -4,7 +4,7 @@ description: Varre o codebase existente, detecta stack atual, compara com o stac
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: ao iniciar uma feature em projeto brownfield (codebase já existente)
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-stack-scan
|
|
@@ -4,7 +4,7 @@ description: Localiza e carrega um standard específico do STANDARDS.json sob de
|
|
|
4
4
|
version: core
|
|
5
5
|
when-to-invoke: quando precisar consultar um standard específico durante a implementação
|
|
6
6
|
user-invokable: true
|
|
7
|
-
cliVersion: "7.9.
|
|
7
|
+
cliVersion: "7.9.4"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# morph-standards
|
|
@@ -941,10 +941,15 @@
|
|
|
941
941
|
"signature validator",
|
|
942
942
|
"jwks",
|
|
943
943
|
"middleware runtime",
|
|
944
|
-
"api prefix"
|
|
944
|
+
"api prefix",
|
|
945
|
+
"data api",
|
|
946
|
+
"postgrest",
|
|
947
|
+
"bypass backend",
|
|
948
|
+
"direct database access"
|
|
945
949
|
],
|
|
946
950
|
"anchors": {
|
|
947
951
|
"setup": "#installation--setup",
|
|
952
|
+
"data-access-boundary": "#data-access-boundary--backend-first-by-default",
|
|
948
953
|
"onboarding": "#onboarding-checklist--do-this-before-testing-login-mandatory",
|
|
949
954
|
"middleware": "#route-protection-middleware",
|
|
950
955
|
"api-prefix": "#api-prefix-convention--server-direct-vs-client-proxy",
|
|
@@ -952,7 +957,7 @@
|
|
|
952
957
|
"rls": "#row-level-security-integration",
|
|
953
958
|
"postmortem": "#known-failure-modes-postmortem"
|
|
954
959
|
},
|
|
955
|
-
"digest": "Use @neondatabase/auth SDK for Next.js. Auth data lives in neon_auth schema — no external provider, no webhooks. Server: createNeonAuth() with NEON_AUTH_BASE_URL + NEON_AUTH_COOKIE_SECRET. Client: createAuthClient(). Pages: AuthView component. Protection: auth.middleware() with runtime='nodejs' (Edge times out minting the session cookie). Register every dev/preview origin in trusted_origins before testing login. Two named prefix constants (BACKEND_API_PREFIX / PROXY_API_PREFIX) — never share one between server-direct and client-proxy calls. .NET: tokens are EdDSA/Ed25519 (OKP) — Microsoft.IdentityModel.Tokens can't verify OKP keys and there's no OIDC discovery; fetch+cache the JWKS yourself and verify signatures manually via BouncyCastle.Cryptography + TokenValidationParameters.SignatureValidator (must return Microsoft.IdentityModel.JsonWebTokens.JsonWebToken, not JwtSecurityToken — else IDX10506). NeonAuth:BaseUrl is mandatory in appsettings.Development.json (public value). RLS: auth.user_id() via pg_session_jwt."
|
|
960
|
+
"digest": "Use @neondatabase/auth SDK for Next.js. Auth data lives in neon_auth schema — no external provider, no webhooks. Server: createNeonAuth() with NEON_AUTH_BASE_URL + NEON_AUTH_COOKIE_SECRET. Client: createAuthClient(). Pages: AuthView component. Protection: auth.middleware() with runtime='nodejs' (Edge times out minting the session cookie). Register every dev/preview origin in trusted_origins before testing login. Two named prefix constants (BACKEND_API_PREFIX / PROXY_API_PREFIX) — never share one between server-direct and client-proxy calls. Frontend never queries Neon directly for business data by default — only its own auth/session SDK; a Data API bypass requires a decisions.md ADR. .NET: tokens are EdDSA/Ed25519 (OKP) — Microsoft.IdentityModel.Tokens can't verify OKP keys and there's no OIDC discovery; fetch+cache the JWKS yourself and verify signatures manually via BouncyCastle.Cryptography + TokenValidationParameters.SignatureValidator (must return Microsoft.IdentityModel.JsonWebTokens.JsonWebToken, not JwtSecurityToken — else IDX10506). NeonAuth:BaseUrl is mandatory in appsettings.Development.json (public value). RLS: auth.user_id() via pg_session_jwt."
|
|
956
961
|
},
|
|
957
962
|
{
|
|
958
963
|
"id": "backend-integrations-hangfire-hangfire-jobs",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> **Scope:** universal
|
|
4
4
|
> **Layer:** 2 (on keyword)
|
|
5
|
-
> **Keywords:** neon auth, better auth, authentication, nextjs, user management, session, JWT, trusted origins, EdDSA, Ed25519, BouncyCastle, signature validator, jwks, middleware runtime, api prefix
|
|
5
|
+
> **Keywords:** neon auth, better auth, authentication, nextjs, user management, session, JWT, trusted origins, EdDSA, Ed25519, BouncyCastle, signature validator, jwks, middleware runtime, api prefix, data api, postgrest, bypass backend, direct database access
|
|
6
6
|
> **Load When:** neon auth or authentication keywords detected
|
|
7
7
|
|
|
8
8
|
**Verified against:** Neon Auth — @neondatabase/auth + @neondatabase/auth-ui (Better Auth). Last-verified: 2026-07-13.
|
|
@@ -37,13 +37,42 @@ Neon Auth provides:
|
|
|
37
37
|
1. **Database-First**: Auth data lives in `neon_auth` schema — no external service to sync
|
|
38
38
|
2. **Branch Isolation**: Each Neon branch gets isolated users, sessions, and auth config
|
|
39
39
|
3. **Server-First**: Use server-side auth checks with `auth.getSession()`
|
|
40
|
-
4. **JWT for RLS**: Tokens contain `sub` (user ID), `email`, `role: "authenticated"` for database
|
|
40
|
+
4. **JWT for RLS**: Tokens contain `sub` (user ID), `email`, `role: "authenticated"` for database
|
|
41
|
+
policies — used only inside the justified Data API exception path, not by default (see
|
|
42
|
+
[Data Access Boundary](#data-access-boundary--backend-first-by-default))
|
|
41
43
|
5. **No OIDC discovery**: Neon Auth does **not** expose `/.well-known/openid-configuration` — only the
|
|
42
44
|
raw `/.well-known/jwks.json`. Never assume `options.Authority` alone gives you working discovery on
|
|
43
45
|
the .NET side (see [.NET Backend Integration](#net-backend-integration)).
|
|
44
46
|
|
|
45
47
|
---
|
|
46
48
|
|
|
49
|
+
## Data Access Boundary — Backend-First by Default
|
|
50
|
+
|
|
51
|
+
The Next.js frontend has exactly one inherent reason to talk to Neon directly: Neon Auth's own
|
|
52
|
+
client SDK (`authClient`, `useSession`, `auth.getSession()`) — that's Better Auth's session/JWT
|
|
53
|
+
mechanism, not a business-data call. Every read or write of application/business data goes through
|
|
54
|
+
the .NET backend instead, either as a server-direct fetch or a client-via-proxy call (see
|
|
55
|
+
[API Prefix Convention](#api-prefix-convention--server-direct-vs-client-proxy) for the mechanics).
|
|
56
|
+
|
|
57
|
+
**Rule:** the frontend does not query Neon directly for business data — not via a Neon Data API
|
|
58
|
+
(REST-over-Postgres) endpoint, not via a browser-held connection string, not via any other bypass
|
|
59
|
+
of the .NET backend. The .NET backend is the sole gateway to business data, for the same reason
|
|
60
|
+
`architecture/vertical-slice/vertical-slice.md` makes the backend the sole gateway to the database
|
|
61
|
+
in general: handler-level authorization, no business rules duplicated on two sides of the wire, one
|
|
62
|
+
place to audit.
|
|
63
|
+
|
|
64
|
+
**The exception process:** a feature that genuinely needs the frontend to reach Neon directly for
|
|
65
|
+
business data (for example, via the Neon MCP `provision_neon_data_api` tool) is an exception, not a
|
|
66
|
+
default — treat it exactly like vertical-slice.md's "Stores dedicados (exceção justificada)" clause:
|
|
67
|
+
document the justification in the feature's `decisions.md` before writing the code. A tool being
|
|
68
|
+
available is not, by itself, justification.
|
|
69
|
+
|
|
70
|
+
See [Row-Level Security Integration](#row-level-security-integration) for how to constrain a
|
|
71
|
+
Data-API-exception session once one exists — those RLS policies are not a signal that the frontend
|
|
72
|
+
should have direct access by default.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
47
76
|
## Installation & Setup
|
|
48
77
|
|
|
49
78
|
### Install Packages
|
|
@@ -299,6 +328,10 @@ export async function GET() {
|
|
|
299
328
|
|
|
300
329
|
## API Prefix Convention — Server-Direct vs Client-Proxy
|
|
301
330
|
|
|
331
|
+
> Assumes the [Data Access Boundary](#data-access-boundary--backend-first-by-default) rule: all
|
|
332
|
+
> business data routes through the backend by default. This section covers only the *mechanics* of
|
|
333
|
+
> doing so from each render context.
|
|
334
|
+
|
|
302
335
|
A Next.js app talking to a Neon-Auth-protected .NET backend fetches from **two different places**
|
|
303
336
|
depending on where the code runs:
|
|
304
337
|
|
|
@@ -616,7 +649,13 @@ app.Run();
|
|
|
616
649
|
|
|
617
650
|
## Row-Level Security Integration
|
|
618
651
|
|
|
619
|
-
|
|
652
|
+
> Defense-in-depth on a JWT-scoped Postgres session — the Data API exception above, not a directive
|
|
653
|
+
> to call Neon from the browser for business data by default. See
|
|
654
|
+
> [Data Access Boundary](#data-access-boundary--backend-first-by-default).
|
|
655
|
+
|
|
656
|
+
When a Data API endpoint is provisioned (the justified exception above), Neon Auth JWT tokens are
|
|
657
|
+
automatically validated by it. The `auth.user_id()` function (via `pg_session_jwt` extension)
|
|
658
|
+
exposes the authenticated user ID from the JWT `sub` claim to any RLS policy on that session.
|
|
620
659
|
|
|
621
660
|
```sql
|
|
622
661
|
-- Enable RLS
|
|
@@ -673,6 +712,9 @@ Each Neon branch gets its own isolated auth data. This means:
|
|
|
673
712
|
service silently becomes a phantom `[FromBody]` parameter and crashes the app at startup
|
|
674
713
|
10. **On .NET, never rely on `options.Authority` alone** — Neon Auth has no OIDC discovery document;
|
|
675
714
|
fetch and cache the JWKS yourself and verify EdDSA signatures manually (BouncyCastle)
|
|
715
|
+
11. **Route business data through the .NET backend by default** — the frontend's only inherent
|
|
716
|
+
reason to talk to Neon directly is its own auth/session SDK; a direct Data API call needs a
|
|
717
|
+
`decisions.md` ADR (see [Data Access Boundary](#data-access-boundary--backend-first-by-default))
|
|
676
718
|
|
|
677
719
|
---
|
|
678
720
|
|