@polymorphism-tech/morph-spec 3.1.0 → 4.2.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 +882 -3
- package/README.md +79 -18
- package/bin/detect-agents.js +1 -1
- package/bin/morph-spec.js +163 -26
- package/bin/task-manager.cjs +101 -7
- package/bin/validate.js +1 -1
- package/docs/cli-auto-detection.md +219 -0
- package/docs/getting-started.md +0 -5
- package/docs/llm-interaction-config.md +735 -0
- package/docs/troubleshooting.md +269 -0
- package/docs/v3.0/AGENTS.md +521 -0
- package/docs/v3.0/ANALYSIS.md +555 -0
- package/docs/v3.0/ARCHITECTURE.md +436 -0
- package/docs/v3.0/EXECUTION-FLOW.md +1304 -0
- package/docs/v3.0/FEATURES.md +688 -0
- package/docs/v3.0/README.md +231 -0
- package/docs/v3.0/ROADMAP.md +801 -0
- package/docs/validation-checklist.md +0 -1
- package/package.json +5 -1
- package/src/commands/agents/index.js +4 -0
- package/src/commands/agents/spawn-team.js +172 -0
- package/src/commands/{create-story.js → feature/create-story.js} +357 -354
- package/src/commands/feature/index.js +6 -0
- package/src/commands/{shard-spec.js → feature/shard-spec.js} +2 -2
- package/src/commands/{sprint-status.js → feature/sprint-status.js} +1 -1
- package/src/commands/{generate-context.js → generation/generate-context.js} +40 -40
- package/src/commands/{generate.js → generation/generate.js} +130 -3
- package/src/commands/generation/index.js +5 -0
- package/src/commands/index.js +16 -0
- package/src/commands/learning/capture-pattern.js +121 -0
- package/src/commands/learning/index.js +5 -0
- package/src/commands/learning/search-patterns.js +126 -0
- package/src/commands/{detect-agents.js → project/detect-agents.js} +178 -178
- package/src/commands/project/detect-workflow.js +174 -0
- package/src/commands/{detect.js → project/detect.js} +104 -104
- package/src/commands/{doctor.js → project/doctor.js} +356 -356
- package/src/commands/project/index.js +10 -0
- package/src/commands/{init.js → project/init.js} +305 -258
- package/src/commands/{sync.js → project/sync.js} +167 -167
- package/src/commands/{update.js → project/update.js} +240 -204
- package/src/commands/{advance-phase.js → state/advance-phase.js} +416 -266
- package/src/commands/state/approve.js +221 -0
- package/src/commands/state/index.js +8 -0
- package/src/commands/{rollback-phase.js → state/rollback-phase.js} +185 -185
- package/src/commands/{state.js → state/state.js} +334 -334
- package/src/commands/{validate-phase.js → state/validate-phase.js} +221 -221
- package/src/commands/tasks/index.js +4 -0
- package/src/commands/{task.js → tasks/task.js} +78 -78
- package/src/commands/templates/index.js +8 -0
- package/src/commands/templates/template-customize.js +101 -0
- package/src/commands/templates/template-list.js +128 -0
- package/src/commands/templates/template-render.js +95 -0
- package/src/commands/templates/template-show.js +131 -0
- package/src/commands/templates/template-validate.js +91 -0
- package/src/commands/utils/index.js +7 -0
- package/src/commands/utils/migrate-state.js +158 -0
- package/src/commands/{session-summary.js → utils/session-summary.js} +291 -291
- package/src/commands/{troubleshoot.js → utils/troubleshoot.js} +222 -222
- package/src/commands/utils/upgrade.js +346 -0
- package/src/commands/{analyze-blazor-concurrency.js → validation/analyze-blazor-concurrency.js} +193 -193
- package/src/commands/validation/index.js +8 -0
- package/src/commands/{lint-fluent.js → validation/lint-fluent.js} +352 -352
- package/src/commands/{validate-blazor-state.js → validation/validate-blazor-state.js} +210 -210
- package/src/commands/{validate-blazor.js → validation/validate-blazor.js} +156 -156
- package/src/commands/{validate-css.js → validation/validate-css.js} +84 -84
- package/src/core/index.js +10 -0
- package/src/core/registry/command-registry.js +302 -0
- package/src/core/registry/index.js +8 -0
- package/src/core/registry/validator-registry.js +204 -0
- package/src/core/state/index.js +8 -0
- package/src/core/state/phase-state-machine.js +214 -0
- package/src/{lib → core/state}/state-manager.js +572 -414
- package/src/core/templates/index.js +9 -0
- package/src/core/templates/template-data-sources.js +325 -0
- package/src/core/templates/template-registry.js +335 -0
- package/src/core/templates/template-renderer.js +477 -0
- package/src/core/templates/template-validator.js +296 -0
- package/src/core/workflows/index.js +7 -0
- package/src/core/workflows/workflow-detector.js +354 -0
- package/src/generator/config-generator.js +206 -0
- package/src/generator/templates/config.json.template +40 -0
- package/src/generator/templates/project.md.template +67 -0
- package/src/lib/{complexity-analyzer.js → analysis/complexity-analyzer.js} +441 -441
- package/src/lib/analysis/index.js +7 -0
- package/src/lib/checkpoints/checkpoint-hooks.js +258 -0
- package/src/lib/checkpoints/index.js +7 -0
- package/src/lib/detectors/config-detector.js +223 -223
- package/src/lib/detectors/conversation-analyzer.js +163 -163
- package/src/lib/{design-system-detector.js → detectors/design-system-detector.js} +187 -187
- package/src/lib/detectors/index.js +87 -84
- package/src/lib/detectors/standards-generator.js +275 -275
- package/src/lib/detectors/structure-detector.js +245 -245
- package/src/lib/{context-generator.js → generators/context-generator.js} +526 -516
- package/src/lib/generators/index.js +10 -0
- package/src/lib/generators/metadata-extractor.js +387 -0
- package/src/lib/{recap-generator.js → generators/recap-generator.js} +205 -205
- package/src/lib/learning/index.js +7 -0
- package/src/lib/orchestration/index.js +7 -0
- package/src/lib/{team-orchestrator.js → orchestration/team-orchestrator.js} +323 -323
- package/src/lib/stacks/index.js +7 -0
- package/src/lib/{stack-resolver.js → stacks/stack-resolver.js} +180 -148
- package/src/lib/standards/index.js +7 -0
- package/src/lib/{standards-context-injector.js → standards/standards-context-injector.js} +298 -288
- package/src/lib/troubleshooting/index.js +8 -0
- package/src/lib/{troubleshoot-grep.js → troubleshooting/troubleshoot-grep.js} +204 -204
- package/src/lib/{troubleshoot-index.js → troubleshooting/troubleshoot-index.js} +144 -144
- package/src/lib/validators/architecture/architecture-validator.js +387 -0
- package/src/lib/validators/architecture/index.js +7 -0
- package/src/lib/validators/architecture-validator.js +40 -367
- package/src/lib/{blazor-concurrency-analyzer.js → validators/blazor/blazor-concurrency-analyzer.js} +277 -288
- package/src/lib/{blazor-state-validator.js → validators/blazor/blazor-state-validator.js} +279 -291
- package/src/lib/{blazor-validator.js → validators/blazor/blazor-validator.js} +369 -374
- package/src/lib/validators/blazor/index.js +9 -0
- package/src/lib/validators/content/content-validator.js +351 -0
- package/src/lib/validators/content/index.js +7 -0
- package/src/lib/validators/content-validator.js +164 -0
- package/src/lib/validators/{contract-compliance-validator.js → contracts/contract-compliance-validator.js} +273 -273
- package/src/lib/validators/contracts/index.js +7 -0
- package/src/lib/{css-validator.js → validators/css/css-validator.js} +352 -352
- package/src/lib/validators/css/index.js +7 -0
- package/src/lib/validators/{design-system-validator.js → design-system/design-system-validator.js} +231 -231
- package/src/lib/validators/design-system/index.js +7 -0
- package/src/lib/validators/package-validator.js +41 -340
- package/src/lib/validators/packages/index.js +7 -0
- package/src/lib/validators/packages/package-validator.js +360 -0
- package/src/lib/validators/shared/index.js +12 -0
- package/src/lib/validators/shared/issue-counter.js +18 -0
- package/src/lib/validators/shared/result-formatter.js +124 -0
- package/src/lib/{spec-validator.js → validators/spec-validator.js} +258 -258
- package/src/lib/validators/ui/index.js +7 -0
- package/src/lib/validators/ui/ui-contrast-validator.js +422 -0
- package/src/lib/validators/ui-contrast-validator.js +31 -409
- package/src/lib/{validation-runner.js → validators/validation-runner.js} +286 -284
- package/src/llm/analyzer.js +215 -0
- package/src/llm/environment-detector.js +43 -0
- package/src/llm/few-shot-examples.js +216 -0
- package/src/llm/project-config-schema.json +188 -0
- package/src/llm/prompt-builder.js +96 -0
- package/src/orchestrator.js +206 -0
- package/src/sanitizer/context-sanitizer.js +221 -0
- package/src/sanitizer/patterns.js +163 -0
- package/src/scanner/project-scanner.js +242 -0
- package/src/ui/diff-display.js +91 -0
- package/src/ui/interactive-wizard.js +96 -0
- package/src/ui/user-review.js +211 -0
- package/src/ui/wizard-questions.js +188 -0
- package/src/utils/color-utils.js +70 -0
- package/src/utils/file-copier.js +188 -189
- package/src/utils/process-handler.js +97 -0
- package/src/writer/file-writer.js +86 -0
- package/stacks/blazor-azure/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +3 -3
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/api-designer.md +59 -0
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/dotnet-senior.md +45 -255
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ef-modeler.md +33 -88
- package/stacks/blazor-azure/.claude/skills/level-2-domains/backend/ms-agent-expert.md +25 -89
- package/stacks/blazor-azure/.claude/skills/level-2-domains/integrations/hangfire-orchestrator.md +64 -0
- package/stacks/blazor-azure/.morph/config/agents.json +879 -764
- package/stacks/blazor-azure/.morph/hooks/{pre-commit-tests.sh → pre-commit/tests-csharp.sh} +3 -2
- package/stacks/blazor-azure/.morph/templates/.gitkeep +0 -0
- package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs +41 -0
- package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/cd-staging.yml.hbs +24 -0
- package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs +23 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-apply.md +221 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-archive.md +79 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-deploy.md +529 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-infra.md +209 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-preflight.md +227 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-proposal.md +122 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-status.md +86 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-troubleshoot.md +122 -0
- package/stacks/nextjs-supabase/.claude/settings.local.json +6 -0
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +30 -150
- package/stacks/nextjs-supabase/.morph/config/agents.json +345 -345
- package/stacks/nextjs-supabase/.morph/hooks/pre-commit/tests-typescript.sh +61 -0
- package/stacks/nextjs-supabase/.morph/templates/.gitkeep +0 -0
- package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs +22 -0
- package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-staging.yml.hbs +22 -0
- package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs +35 -0
- package/stacks/nextjs-supabase/README.md +6 -15
- package/bin/render-template.js +0 -303
- package/bin/semantic-detect-agents.js +0 -247
- package/bin/validate-agents-skills.js +0 -257
- package/bin/validate-agents.js +0 -70
- package/bin/validate-phase.js +0 -263
- package/docs/examples.md +0 -328
- package/scripts/reorganize-skills.cjs +0 -175
- package/scripts/validate-agents-structure.cjs +0 -52
- package/scripts/validate-skills.cjs +0 -180
- package/src/commands/deploy.js +0 -780
- package/src/lib/continuous-validator.js +0 -421
- package/src/lib/decision-constraint-loader.js +0 -109
- package/src/lib/design-system-scaffolder.js +0 -299
- package/src/lib/hook-executor.js +0 -257
- package/src/lib/mockup-generator.js +0 -366
- package/src/lib/ui-detector.js +0 -350
- package/stacks/blazor-azure/.azure/README.md +0 -293
- package/stacks/blazor-azure/.azure/docs/azure-devops-setup.md +0 -454
- package/stacks/blazor-azure/.azure/docs/branch-strategy.md +0 -398
- package/stacks/blazor-azure/.azure/docs/local-development.md +0 -515
- package/stacks/blazor-azure/.azure/pipelines/pipeline-variables.yml +0 -34
- package/stacks/blazor-azure/.azure/pipelines/prod-pipeline.yml +0 -319
- package/stacks/blazor-azure/.azure/pipelines/staging-pipeline.yml +0 -234
- package/stacks/blazor-azure/.azure/pipelines/templates/build-dotnet.yml +0 -75
- package/stacks/blazor-azure/.azure/pipelines/templates/deploy-app-service.yml +0 -94
- package/stacks/blazor-azure/.azure/pipelines/templates/deploy-container-app.yml +0 -120
- package/stacks/blazor-azure/.azure/pipelines/templates/infra-deploy.yml +0 -90
- package/stacks/blazor-azure/.claude/settings.local.json +0 -15
- package/stacks/blazor-azure/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +0 -392
- package/stacks/blazor-azure/.morph/docs/workflows/design-impl.md +0 -37
- package/stacks/blazor-azure/.morph/docs/workflows/enforcement-pipeline.md +0 -668
- package/stacks/blazor-azure/.morph/docs/workflows/fast-track.md +0 -29
- package/stacks/blazor-azure/.morph/docs/workflows/full-morph.md +0 -76
- package/stacks/blazor-azure/.morph/docs/workflows/standard.md +0 -44
- package/stacks/blazor-azure/.morph/docs/workflows/ui-refresh.md +0 -39
- package/stacks/blazor-azure/.morph/examples/api-nextjs/README.md +0 -241
- package/stacks/blazor-azure/.morph/examples/api-nextjs/contracts.ts +0 -307
- package/stacks/blazor-azure/.morph/examples/api-nextjs/spec.md +0 -399
- package/stacks/blazor-azure/.morph/examples/api-nextjs/tasks.md +0 -168
- package/stacks/blazor-azure/.morph/examples/micro-saas/README.md +0 -125
- package/stacks/blazor-azure/.morph/examples/micro-saas/contracts.cs +0 -358
- package/stacks/blazor-azure/.morph/examples/micro-saas/decisions.md +0 -246
- package/stacks/blazor-azure/.morph/examples/micro-saas/spec.md +0 -236
- package/stacks/blazor-azure/.morph/examples/micro-saas/tasks.md +0 -150
- package/stacks/blazor-azure/.morph/examples/multi-agent/README.md +0 -309
- package/stacks/blazor-azure/.morph/examples/multi-agent/contracts.cs +0 -433
- package/stacks/blazor-azure/.morph/examples/multi-agent/spec.md +0 -479
- package/stacks/blazor-azure/.morph/examples/multi-agent/tasks.md +0 -185
- package/stacks/blazor-azure/.morph/examples/scheduled-reports/decisions.md +0 -158
- package/stacks/blazor-azure/.morph/examples/scheduled-reports/proposal.md +0 -95
- package/stacks/blazor-azure/.morph/examples/scheduled-reports/spec.md +0 -267
- package/stacks/blazor-azure/.morph/examples/state-v3.json +0 -188
- package/stacks/blazor-azure/.morph/hooks/README.md +0 -348
- package/stacks/blazor-azure/.morph/hooks/pre-commit-agents.sh +0 -24
- package/stacks/blazor-azure/.morph/hooks/pre-commit-all.sh +0 -48
- package/stacks/blazor-azure/.morph/hooks/pre-commit-specs.sh +0 -49
- package/stacks/blazor-azure/.morph/hooks/task-completed.js +0 -73
- package/stacks/blazor-azure/.morph/hooks/teammate-idle.js +0 -68
- package/stacks/blazor-azure/.morph/standards/agent-framework-blazor-ui.md +0 -359
- package/stacks/blazor-azure/.morph/standards/agent-framework-production.md +0 -410
- package/stacks/blazor-azure/.morph/standards/agent-framework-setup.md +0 -413
- package/stacks/blazor-azure/.morph/standards/agent-framework-workflows.md +0 -349
- package/stacks/blazor-azure/.morph/standards/agent-teams-workflow.md +0 -474
- package/stacks/blazor-azure/.morph/standards/architecture.md +0 -325
- package/stacks/blazor-azure/.morph/standards/azure.md +0 -605
- package/stacks/blazor-azure/.morph/standards/coding.md +0 -377
- package/stacks/blazor-azure/.morph/standards/dotnet10-migration.md +0 -520
- package/stacks/blazor-azure/.morph/standards/fluent-ui-setup.md +0 -590
- package/stacks/blazor-azure/.morph/standards/migration-guide.md +0 -514
- package/stacks/blazor-azure/.morph/standards/passkeys-auth.md +0 -423
- package/stacks/blazor-azure/.morph/standards/vector-search-rag.md +0 -536
- package/stacks/blazor-azure/.morph/templates/CONTEXT-FEATURE.md +0 -276
- package/stacks/blazor-azure/.morph/templates/CONTEXT.md +0 -170
- package/stacks/blazor-azure/.morph/templates/FluentDesignTheme.cs +0 -149
- package/stacks/blazor-azure/.morph/templates/MudTheme.cs +0 -281
- package/stacks/blazor-azure/.morph/templates/agent.cs +0 -163
- package/stacks/blazor-azure/.morph/templates/clarify-questions.md +0 -159
- package/stacks/blazor-azure/.morph/templates/component.razor +0 -239
- package/stacks/blazor-azure/.morph/templates/contracts/Commands.cs +0 -74
- package/stacks/blazor-azure/.morph/templates/contracts/Entities.cs +0 -25
- package/stacks/blazor-azure/.morph/templates/contracts/Queries.cs +0 -74
- package/stacks/blazor-azure/.morph/templates/contracts/README.md +0 -74
- package/stacks/blazor-azure/.morph/templates/contracts.cs +0 -217
- package/stacks/blazor-azure/.morph/templates/decisions.md +0 -123
- package/stacks/blazor-azure/.morph/templates/design-system.css +0 -226
- package/stacks/blazor-azure/.morph/templates/infra/.dockerignore.example +0 -89
- package/stacks/blazor-azure/.morph/templates/infra/Dockerfile.example +0 -82
- package/stacks/blazor-azure/.morph/templates/infra/README.md +0 -286
- package/stacks/blazor-azure/.morph/templates/infra/app-insights.bicep +0 -63
- package/stacks/blazor-azure/.morph/templates/infra/app-service.bicep +0 -164
- package/stacks/blazor-azure/.morph/templates/infra/azure-pipelines-deploy.yml +0 -480
- package/stacks/blazor-azure/.morph/templates/infra/container-app-env.bicep +0 -49
- package/stacks/blazor-azure/.morph/templates/infra/container-app.bicep +0 -156
- package/stacks/blazor-azure/.morph/templates/infra/deploy-checklist.md +0 -426
- package/stacks/blazor-azure/.morph/templates/infra/deploy.ps1 +0 -229
- package/stacks/blazor-azure/.morph/templates/infra/deploy.sh +0 -208
- package/stacks/blazor-azure/.morph/templates/infra/key-vault.bicep +0 -91
- package/stacks/blazor-azure/.morph/templates/infra/main.bicep +0 -189
- package/stacks/blazor-azure/.morph/templates/infra/parameters.dev.json +0 -29
- package/stacks/blazor-azure/.morph/templates/infra/parameters.prod.json +0 -29
- package/stacks/blazor-azure/.morph/templates/infra/parameters.staging.json +0 -29
- package/stacks/blazor-azure/.morph/templates/infra/sql-database.bicep +0 -103
- package/stacks/blazor-azure/.morph/templates/infra/storage.bicep +0 -106
- package/stacks/blazor-azure/.morph/templates/integrations/asaas-client.cs +0 -387
- package/stacks/blazor-azure/.morph/templates/integrations/asaas-webhook.cs +0 -351
- package/stacks/blazor-azure/.morph/templates/integrations/azure-identity-config.cs +0 -288
- package/stacks/blazor-azure/.morph/templates/integrations/clerk-config.cs +0 -258
- package/stacks/blazor-azure/.morph/templates/job.cs +0 -171
- package/stacks/blazor-azure/.morph/templates/migration.cs +0 -83
- package/stacks/blazor-azure/.morph/templates/proposal.md +0 -141
- package/stacks/blazor-azure/.morph/templates/recap.md +0 -94
- package/stacks/blazor-azure/.morph/templates/repository.cs +0 -141
- package/stacks/blazor-azure/.morph/templates/saas/subscription.cs +0 -347
- package/stacks/blazor-azure/.morph/templates/saas/tenant.cs +0 -338
- package/stacks/blazor-azure/.morph/templates/service.cs +0 -139
- package/stacks/blazor-azure/.morph/templates/simulation.md +0 -353
- package/stacks/blazor-azure/.morph/templates/spec.md +0 -149
- package/stacks/blazor-azure/.morph/templates/sprint-status.yaml +0 -68
- package/stacks/blazor-azure/.morph/templates/state.template.json +0 -222
- package/stacks/blazor-azure/.morph/templates/story.md +0 -143
- package/stacks/blazor-azure/.morph/templates/tasks.md +0 -257
- package/stacks/blazor-azure/.morph/templates/test.cs +0 -239
- package/stacks/blazor-azure/.morph/templates/ui-components.md +0 -362
- package/stacks/blazor-azure/.morph/templates/ui-design-system.md +0 -286
- package/stacks/blazor-azure/.morph/templates/ui-flows.md +0 -336
- package/stacks/blazor-azure/.morph/templates/ui-mockups.md +0 -133
- package/stacks/nextjs-supabase/.morph/docs/easypanel-setup.md +0 -169
- package/stacks/nextjs-supabase/.morph/docs/supabase-mcp-setup.md +0 -247
- package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/README.md +0 -697
- package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/spec.md +0 -85
- package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/tasks.md +0 -86
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/README.md +0 -498
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/decisions.md +0 -121
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/spec.md +0 -138
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/tasks.md +0 -162
- package/stacks/nextjs-supabase/.morph/standards/easypanel-deploy.md +0 -191
- package/stacks/nextjs-supabase/.morph/standards/nextjs-patterns.md +0 -193
- package/stacks/nextjs-supabase/.morph/standards/supabase-auth.md +0 -171
- package/stacks/nextjs-supabase/.morph/standards/supabase-pgvector.md +0 -164
- package/stacks/nextjs-supabase/.morph/standards/supabase-rls.md +0 -179
- package/stacks/nextjs-supabase/.morph/standards/supabase-storage.md +0 -148
- package/stacks/nextjs-supabase/.morph/templates/contracts.cs +0 -173
- package/stacks/nextjs-supabase/.morph/templates/contracts.ts +0 -168
- package/stacks/nextjs-supabase/.morph/templates/decisions.md +0 -115
- package/stacks/nextjs-supabase/.morph/templates/dockerfile-api.dockerfile +0 -38
- package/stacks/nextjs-supabase/.morph/templates/dockerfile-web.dockerfile +0 -48
- package/stacks/nextjs-supabase/.morph/templates/proposal.md +0 -145
- package/stacks/nextjs-supabase/.morph/templates/recap.md +0 -134
- package/stacks/nextjs-supabase/.morph/templates/rls-policy.sql +0 -57
- package/stacks/nextjs-supabase/.morph/templates/spec.md +0 -231
- package/stacks/nextjs-supabase/.morph/templates/supabase-migration.sql +0 -100
- package/stacks/nextjs-supabase/.morph/templates/tasks.md +0 -257
- /package/src/lib/{design-system-generator.js → generators/design-system-generator.js} +0 -0
- /package/src/lib/{learning-system.js → learning/learning-system.js} +0 -0
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# Supabase Storage Standard
|
|
2
|
-
|
|
3
|
-
> Stack: Next.js 15 + Supabase + .NET Backend
|
|
4
|
-
|
|
5
|
-
## Core Rules
|
|
6
|
-
|
|
7
|
-
- ALWAYS use RLS policies on storage.objects for access control
|
|
8
|
-
- NEVER serve private files without signed URLs
|
|
9
|
-
- ALWAYS validate file type and size before upload
|
|
10
|
-
- Public buckets: anyone can read, still need auth for write
|
|
11
|
-
- Private buckets: require signed URLs or authenticated access
|
|
12
|
-
|
|
13
|
-
## Bucket Configuration
|
|
14
|
-
|
|
15
|
-
```sql
|
|
16
|
-
-- Public bucket (avatars, logos)
|
|
17
|
-
INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
|
|
18
|
-
VALUES ('avatars', 'avatars', true, 2097152, ARRAY['image/jpeg','image/png','image/webp']);
|
|
19
|
-
|
|
20
|
-
-- Private bucket (documents, reports)
|
|
21
|
-
INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types)
|
|
22
|
-
VALUES ('documents', 'documents', false, 10485760, ARRAY['application/pdf','image/jpeg','image/png']);
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
| Setting | Public Bucket | Private Bucket |
|
|
26
|
-
|---------|--------------|----------------|
|
|
27
|
-
| Read access | Anyone via URL | Signed URL or auth required |
|
|
28
|
-
| Write access | RLS policy required | RLS policy required |
|
|
29
|
-
| Use case | Avatars, public images | Documents, reports |
|
|
30
|
-
|
|
31
|
-
## Storage RLS Policies
|
|
32
|
-
|
|
33
|
-
```sql
|
|
34
|
-
-- Users upload/view/delete in their own folder
|
|
35
|
-
CREATE POLICY "user_upload" ON storage.objects FOR INSERT
|
|
36
|
-
WITH CHECK (bucket_id = 'documents' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
37
|
-
|
|
38
|
-
CREATE POLICY "user_select" ON storage.objects FOR SELECT
|
|
39
|
-
USING (bucket_id = 'documents' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
40
|
-
|
|
41
|
-
CREATE POLICY "user_delete" ON storage.objects FOR DELETE
|
|
42
|
-
USING (bucket_id = 'documents' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
43
|
-
|
|
44
|
-
-- Public bucket: anyone reads, auth users upload to own folder
|
|
45
|
-
CREATE POLICY "public_read" ON storage.objects FOR SELECT
|
|
46
|
-
USING (bucket_id = 'avatars');
|
|
47
|
-
|
|
48
|
-
CREATE POLICY "auth_upload_avatar" ON storage.objects FOR INSERT
|
|
49
|
-
WITH CHECK (bucket_id = 'avatars' AND (storage.foldername(name))[1] = auth.uid()::text);
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Path Naming Convention
|
|
53
|
-
|
|
54
|
-
```
|
|
55
|
-
{bucket}/{user_id}/{category}/{filename}
|
|
56
|
-
avatars/{user_id}/profile.webp
|
|
57
|
-
documents/{user_id}/invoices/2026-01-invoice.pdf
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
First folder segment = user_id (enables simple RLS). Use lowercase, hyphens, include extension.
|
|
61
|
-
|
|
62
|
-
## Upload Patterns
|
|
63
|
-
|
|
64
|
-
### Browser Upload (Next.js)
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
async function uploadFile(file: File, userId: string) {
|
|
68
|
-
if (file.size > 10 * 1024 * 1024) throw new Error("File too large");
|
|
69
|
-
const allowedTypes = ["application/pdf", "image/jpeg", "image/png"];
|
|
70
|
-
if (!allowedTypes.includes(file.type)) throw new Error("Invalid type");
|
|
71
|
-
|
|
72
|
-
const path = `${userId}/uploads/${Date.now()}-${file.name}`;
|
|
73
|
-
const { data, error } = await supabase.storage
|
|
74
|
-
.from("documents")
|
|
75
|
-
.upload(path, file, { cacheControl: "3600", upsert: false, contentType: file.type });
|
|
76
|
-
if (error) throw error;
|
|
77
|
-
return data.path;
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Server Upload (.NET)
|
|
82
|
-
|
|
83
|
-
```csharp
|
|
84
|
-
public sealed class StorageService(Supabase.Client client, ILogger<StorageService> logger)
|
|
85
|
-
{
|
|
86
|
-
private static readonly string[] AllowedTypes = ["application/pdf", "image/jpeg", "image/png"];
|
|
87
|
-
|
|
88
|
-
public async Task<string> UploadAsync(
|
|
89
|
-
string bucket, string path, Stream stream,
|
|
90
|
-
string contentType, CancellationToken ct = default)
|
|
91
|
-
{
|
|
92
|
-
if (!AllowedTypes.Contains(contentType))
|
|
93
|
-
throw new ValidationException($"Invalid content type: {contentType}");
|
|
94
|
-
var response = await client.Storage.From(bucket)
|
|
95
|
-
.Upload(stream, path, new FileOptions { ContentType = contentType, Upsert = false });
|
|
96
|
-
return response;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## Download and Signed URLs
|
|
102
|
-
|
|
103
|
-
```ts
|
|
104
|
-
// Public bucket: direct URL
|
|
105
|
-
const { data } = supabase.storage.from("avatars").getPublicUrl("user-id/profile.webp");
|
|
106
|
-
|
|
107
|
-
// Private bucket: signed URL (time-limited)
|
|
108
|
-
const { data } = await supabase.storage
|
|
109
|
-
.from("documents").createSignedUrl("user-id/report.pdf", 3600); // 1 hour
|
|
110
|
-
|
|
111
|
-
// Download file content (returns Blob)
|
|
112
|
-
const { data } = await supabase.storage.from("documents").download("user-id/report.pdf");
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
## Image Transformations
|
|
116
|
-
|
|
117
|
-
```ts
|
|
118
|
-
const { data } = supabase.storage.from("avatars").getPublicUrl("user-id/photo.jpg", {
|
|
119
|
-
transform: { width: 200, height: 200, resize: "cover", quality: 80 },
|
|
120
|
-
});
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
| Parameter | Options | Default |
|
|
124
|
-
|-----------|---------|---------|
|
|
125
|
-
| `width` / `height` | 1-2500 px | original |
|
|
126
|
-
| `resize` | cover, contain, fill | cover |
|
|
127
|
-
| `quality` | 20-100 | 80 |
|
|
128
|
-
| `format` | origin, avif, webp | origin |
|
|
129
|
-
|
|
130
|
-
## File Validation
|
|
131
|
-
|
|
132
|
-
| Check | Client-Side | Server-Side | Bucket Config |
|
|
133
|
-
|-------|------------|-------------|---------------|
|
|
134
|
-
| File size | `file.size` | Stream length | `file_size_limit` |
|
|
135
|
-
| MIME type | `file.type` | Content-Type | `allowed_mime_types` |
|
|
136
|
-
| Extension | File name | File name | -- |
|
|
137
|
-
|
|
138
|
-
Always validate at all three levels. Client-side can be bypassed.
|
|
139
|
-
|
|
140
|
-
## Common Mistakes
|
|
141
|
-
|
|
142
|
-
| Wrong | Right | Why |
|
|
143
|
-
|-------|-------|-----|
|
|
144
|
-
| No RLS on storage.objects | Policies for each bucket | Anyone can read/write without policies |
|
|
145
|
-
| Private files via public URL | `createSignedUrl()` | Private bucket returns 403 without auth |
|
|
146
|
-
| User-provided filename as-is | Sanitize + timestamp prefix | Path traversal attacks, collisions |
|
|
147
|
-
| `upsert: true` by default | `upsert: false` | Prevents accidental file overwrites |
|
|
148
|
-
| Files without user folder | `{user_id}/...` path pattern | Cannot write simple RLS policies |
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// CONTRACTS: {{FEATURE_NAME_TITLE}}
|
|
3
|
-
// Stack: Next.js + Supabase + .NET API
|
|
4
|
-
// Generated by MORPH Framework
|
|
5
|
-
// Date: {{DATE}}
|
|
6
|
-
// ============================================================
|
|
7
|
-
|
|
8
|
-
#region Usings
|
|
9
|
-
|
|
10
|
-
using System;
|
|
11
|
-
using System.Collections.Generic;
|
|
12
|
-
using System.Threading;
|
|
13
|
-
using System.Threading.Tasks;
|
|
14
|
-
|
|
15
|
-
#endregion
|
|
16
|
-
|
|
17
|
-
namespace {{NAMESPACE}}.Application.Features.{{FEATURE_NAME_PASCAL}};
|
|
18
|
-
|
|
19
|
-
#region Configuration
|
|
20
|
-
|
|
21
|
-
/// <summary>
|
|
22
|
-
/// Supabase configuration options.
|
|
23
|
-
/// Bind from appsettings.json "Supabase" section.
|
|
24
|
-
/// </summary>
|
|
25
|
-
public sealed record SupabaseConfig
|
|
26
|
-
{
|
|
27
|
-
public required string Url { get; init; }
|
|
28
|
-
public required string AnonKey { get; init; }
|
|
29
|
-
public required string ServiceRoleKey { get; init; }
|
|
30
|
-
public required string JwtSecret { get; init; }
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
#endregion
|
|
34
|
-
|
|
35
|
-
#region Pagination
|
|
36
|
-
|
|
37
|
-
/// <summary>
|
|
38
|
-
/// Pagination query parameters. Use with [AsParameters] in Minimal API.
|
|
39
|
-
/// </summary>
|
|
40
|
-
public sealed record PaginationQuery(
|
|
41
|
-
int Page = 1,
|
|
42
|
-
int PageSize = 20)
|
|
43
|
-
{
|
|
44
|
-
public int Offset => (Page - 1) * PageSize;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/// <summary>
|
|
48
|
-
/// Paginated result wrapper.
|
|
49
|
-
/// </summary>
|
|
50
|
-
public sealed record PagedResult<T>(
|
|
51
|
-
List<T> Items,
|
|
52
|
-
int TotalCount,
|
|
53
|
-
int Page,
|
|
54
|
-
int PageSize)
|
|
55
|
-
{
|
|
56
|
-
public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize);
|
|
57
|
-
public bool HasNext => Page < TotalPages;
|
|
58
|
-
public bool HasPrevious => Page > 1;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
#endregion
|
|
62
|
-
|
|
63
|
-
#region Repository Interfaces
|
|
64
|
-
|
|
65
|
-
/// <summary>
|
|
66
|
-
/// Generic repository interface for Supabase/PostgreSQL data access via Dapper.
|
|
67
|
-
/// </summary>
|
|
68
|
-
public interface IRepository<T, TId>
|
|
69
|
-
{
|
|
70
|
-
Task<T?> GetByIdAsync(TId id, CancellationToken cancellationToken = default);
|
|
71
|
-
Task<List<T>> GetAllAsync(CancellationToken cancellationToken = default);
|
|
72
|
-
Task<PagedResult<T>> GetPagedAsync(PaginationQuery query, CancellationToken cancellationToken = default);
|
|
73
|
-
Task<TId> CreateAsync(T entity, CancellationToken cancellationToken = default);
|
|
74
|
-
Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
|
|
75
|
-
Task DeleteAsync(TId id, CancellationToken cancellationToken = default);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
#endregion
|
|
79
|
-
|
|
80
|
-
#region Service Interfaces
|
|
81
|
-
|
|
82
|
-
/// <summary>
|
|
83
|
-
/// Service for managing {{FEATURE_NAME_PASCAL}} operations.
|
|
84
|
-
/// </summary>
|
|
85
|
-
public interface I{{FEATURE_NAME_PASCAL}}Service
|
|
86
|
-
{
|
|
87
|
-
/// <summary>
|
|
88
|
-
/// Gets a {{FEATURE_NAME_PASCAL}} by its identifier.
|
|
89
|
-
/// </summary>
|
|
90
|
-
Task<{{FEATURE_NAME_PASCAL}}Dto?> GetByIdAsync(Guid id, CancellationToken cancellationToken = default);
|
|
91
|
-
|
|
92
|
-
/// <summary>
|
|
93
|
-
/// Gets paginated list of {{FEATURE_NAME_PASCAL}} items.
|
|
94
|
-
/// </summary>
|
|
95
|
-
Task<PagedResult<{{FEATURE_NAME_PASCAL}}Dto>> GetPagedAsync(PaginationQuery query, Guid userId, CancellationToken cancellationToken = default);
|
|
96
|
-
|
|
97
|
-
/// <summary>
|
|
98
|
-
/// Creates a new {{FEATURE_NAME_PASCAL}}.
|
|
99
|
-
/// </summary>
|
|
100
|
-
Task<{{FEATURE_NAME_PASCAL}}Dto> CreateAsync(Create{{FEATURE_NAME_PASCAL}}Request request, Guid userId, CancellationToken cancellationToken = default);
|
|
101
|
-
|
|
102
|
-
/// <summary>
|
|
103
|
-
/// Updates an existing {{FEATURE_NAME_PASCAL}}.
|
|
104
|
-
/// </summary>
|
|
105
|
-
Task UpdateAsync(Guid id, Update{{FEATURE_NAME_PASCAL}}Request request, Guid userId, CancellationToken cancellationToken = default);
|
|
106
|
-
|
|
107
|
-
/// <summary>
|
|
108
|
-
/// Deletes a {{FEATURE_NAME_PASCAL}}.
|
|
109
|
-
/// </summary>
|
|
110
|
-
Task DeleteAsync(Guid id, Guid userId, CancellationToken cancellationToken = default);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
#endregion
|
|
114
|
-
|
|
115
|
-
#region DTOs
|
|
116
|
-
|
|
117
|
-
/// <summary>
|
|
118
|
-
/// Data transfer object for {{FEATURE_NAME_PASCAL}}.
|
|
119
|
-
/// </summary>
|
|
120
|
-
public sealed record {{FEATURE_NAME_PASCAL}}Dto(
|
|
121
|
-
Guid Id,
|
|
122
|
-
string Name,
|
|
123
|
-
Guid UserId,
|
|
124
|
-
{{FEATURE_NAME_PASCAL}}Status Status,
|
|
125
|
-
DateTime CreatedAt,
|
|
126
|
-
DateTime? UpdatedAt
|
|
127
|
-
);
|
|
128
|
-
|
|
129
|
-
/// <summary>
|
|
130
|
-
/// Request to create a new {{FEATURE_NAME_PASCAL}}.
|
|
131
|
-
/// </summary>
|
|
132
|
-
public sealed record Create{{FEATURE_NAME_PASCAL}}Request(
|
|
133
|
-
string Name
|
|
134
|
-
// Add other required fields
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
/// <summary>
|
|
138
|
-
/// Request to update an existing {{FEATURE_NAME_PASCAL}}.
|
|
139
|
-
/// </summary>
|
|
140
|
-
public sealed record Update{{FEATURE_NAME_PASCAL}}Request(
|
|
141
|
-
string Name
|
|
142
|
-
// Add other updatable fields
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
#endregion
|
|
146
|
-
|
|
147
|
-
#region Enums
|
|
148
|
-
|
|
149
|
-
/// <summary>
|
|
150
|
-
/// Status of a {{FEATURE_NAME_PASCAL}}.
|
|
151
|
-
/// </summary>
|
|
152
|
-
public enum {{FEATURE_NAME_PASCAL}}Status
|
|
153
|
-
{
|
|
154
|
-
Draft = 0,
|
|
155
|
-
Active = 1,
|
|
156
|
-
Completed = 2,
|
|
157
|
-
Archived = 3,
|
|
158
|
-
// Error states
|
|
159
|
-
Failed = 100,
|
|
160
|
-
Cancelled = 101
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
#endregion
|
|
164
|
-
|
|
165
|
-
#region Exceptions
|
|
166
|
-
|
|
167
|
-
public sealed class {{FEATURE_NAME_PASCAL}}NotFoundException(Guid id)
|
|
168
|
-
: Exception($"{{FEATURE_NAME_PASCAL}} with ID {id} was not found.");
|
|
169
|
-
|
|
170
|
-
public sealed class {{FEATURE_NAME_PASCAL}}AccessDeniedException(Guid id, Guid userId)
|
|
171
|
-
: Exception($"User {userId} does not have access to {{FEATURE_NAME_PASCAL}} {id}.");
|
|
172
|
-
|
|
173
|
-
#endregion
|
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// CONTRACTS: {{FEATURE_NAME_TITLE}}
|
|
3
|
-
// Stack: Next.js + Supabase
|
|
4
|
-
// Generated by MORPH Framework
|
|
5
|
-
// Date: {{DATE}}
|
|
6
|
-
// ============================================================
|
|
7
|
-
|
|
8
|
-
// ----- Supabase Config -----
|
|
9
|
-
|
|
10
|
-
export interface SupabaseConfig {
|
|
11
|
-
url: string;
|
|
12
|
-
anonKey: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// ----- API Client Types -----
|
|
16
|
-
|
|
17
|
-
export interface ApiClientConfig {
|
|
18
|
-
baseUrl: string;
|
|
19
|
-
getAccessToken: () => Promise<string | null>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ApiError {
|
|
23
|
-
message: string;
|
|
24
|
-
code: string;
|
|
25
|
-
statusCode: number;
|
|
26
|
-
details?: Record<string, string[]>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export type ApiResult<T> =
|
|
30
|
-
| { success: true; data: T }
|
|
31
|
-
| { success: false; error: ApiError };
|
|
32
|
-
|
|
33
|
-
// ----- Pagination -----
|
|
34
|
-
|
|
35
|
-
export interface PaginationQuery {
|
|
36
|
-
page?: number;
|
|
37
|
-
pageSize?: number;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface PagedResult<T> {
|
|
41
|
-
items: T[];
|
|
42
|
-
totalCount: number;
|
|
43
|
-
page: number;
|
|
44
|
-
pageSize: number;
|
|
45
|
-
totalPages: number;
|
|
46
|
-
hasNext: boolean;
|
|
47
|
-
hasPrevious: boolean;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// ----- Supabase Client Type Aliases -----
|
|
51
|
-
// Generated by: supabase gen types typescript --project-id <id> > types/database.ts
|
|
52
|
-
|
|
53
|
-
export type Tables<T extends keyof Database["public"]["Tables"]> =
|
|
54
|
-
Database["public"]["Tables"][T]["Row"];
|
|
55
|
-
|
|
56
|
-
export type Insertable<T extends keyof Database["public"]["Tables"]> =
|
|
57
|
-
Database["public"]["Tables"][T]["Insert"];
|
|
58
|
-
|
|
59
|
-
export type Updatable<T extends keyof Database["public"]["Tables"]> =
|
|
60
|
-
Database["public"]["Tables"][T]["Update"];
|
|
61
|
-
|
|
62
|
-
// ----- Database Schema (placeholder - replace with generated types) -----
|
|
63
|
-
|
|
64
|
-
export interface Database {
|
|
65
|
-
public: {
|
|
66
|
-
Tables: {
|
|
67
|
-
{{FEATURE_NAME}}: {
|
|
68
|
-
Row: {
|
|
69
|
-
id: string;
|
|
70
|
-
name: string;
|
|
71
|
-
user_id: string;
|
|
72
|
-
status: {{FEATURE_NAME_PASCAL}}Status;
|
|
73
|
-
created_at: string;
|
|
74
|
-
updated_at: string | null;
|
|
75
|
-
};
|
|
76
|
-
Insert: {
|
|
77
|
-
id?: string;
|
|
78
|
-
name: string;
|
|
79
|
-
user_id?: string;
|
|
80
|
-
status?: {{FEATURE_NAME_PASCAL}}Status;
|
|
81
|
-
created_at?: string;
|
|
82
|
-
updated_at?: string | null;
|
|
83
|
-
};
|
|
84
|
-
Update: {
|
|
85
|
-
id?: string;
|
|
86
|
-
name?: string;
|
|
87
|
-
user_id?: string;
|
|
88
|
-
status?: {{FEATURE_NAME_PASCAL}}Status;
|
|
89
|
-
created_at?: string;
|
|
90
|
-
updated_at?: string | null;
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
Views: Record<string, never>;
|
|
95
|
-
Functions: Record<string, never>;
|
|
96
|
-
Enums: {
|
|
97
|
-
{{FEATURE_NAME}}_status: {{FEATURE_NAME_PASCAL}}Status;
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// ----- Feature Types -----
|
|
103
|
-
|
|
104
|
-
export type {{FEATURE_NAME_PASCAL}}Status =
|
|
105
|
-
| "draft"
|
|
106
|
-
| "active"
|
|
107
|
-
| "completed"
|
|
108
|
-
| "archived"
|
|
109
|
-
| "failed"
|
|
110
|
-
| "cancelled";
|
|
111
|
-
|
|
112
|
-
export interface {{FEATURE_NAME_PASCAL}} {
|
|
113
|
-
id: string;
|
|
114
|
-
name: string;
|
|
115
|
-
userId: string;
|
|
116
|
-
status: {{FEATURE_NAME_PASCAL}}Status;
|
|
117
|
-
createdAt: string;
|
|
118
|
-
updatedAt: string | null;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export interface Create{{FEATURE_NAME_PASCAL}}Input {
|
|
122
|
-
name: string;
|
|
123
|
-
// Add other required fields
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export interface Update{{FEATURE_NAME_PASCAL}}Input {
|
|
127
|
-
name?: string;
|
|
128
|
-
// Add other updatable fields
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ----- Storage Types -----
|
|
132
|
-
|
|
133
|
-
export interface StorageUpload {
|
|
134
|
-
bucket: string;
|
|
135
|
-
path: string;
|
|
136
|
-
file: File;
|
|
137
|
-
contentType?: string;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
export interface StorageFile {
|
|
141
|
-
id: string;
|
|
142
|
-
name: string;
|
|
143
|
-
bucket: string;
|
|
144
|
-
path: string;
|
|
145
|
-
publicUrl: string;
|
|
146
|
-
size: number;
|
|
147
|
-
contentType: string;
|
|
148
|
-
createdAt: string;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ----- Auth Types -----
|
|
152
|
-
|
|
153
|
-
export interface AuthUser {
|
|
154
|
-
id: string;
|
|
155
|
-
email: string;
|
|
156
|
-
displayName: string | null;
|
|
157
|
-
avatarUrl: string | null;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export interface AuthSession {
|
|
161
|
-
user: AuthUser;
|
|
162
|
-
accessToken: string;
|
|
163
|
-
expiresAt: number;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// ----- Form Schemas (use with zod) -----
|
|
167
|
-
// Define zod schemas in component files, not here.
|
|
168
|
-
// This file is for type definitions only.
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
# Architecture Decision Records - {{FEATURE_NAME_TITLE}}
|
|
2
|
-
|
|
3
|
-
## ADR-001: {Decision Title}
|
|
4
|
-
|
|
5
|
-
**Date:** {{DATE}}
|
|
6
|
-
**Status:** Proposed | Accepted | Deprecated | Superseded
|
|
7
|
-
**Deciders:** MORPH Agents, Developer
|
|
8
|
-
|
|
9
|
-
### Context
|
|
10
|
-
|
|
11
|
-
{Describe the context and problem that led to this decision}
|
|
12
|
-
|
|
13
|
-
### Decision
|
|
14
|
-
|
|
15
|
-
{Describe the decision made}
|
|
16
|
-
|
|
17
|
-
### Consequences
|
|
18
|
-
|
|
19
|
-
**Pros:**
|
|
20
|
-
- {Positive consequence 1}
|
|
21
|
-
- {Positive consequence 2}
|
|
22
|
-
|
|
23
|
-
**Cons:**
|
|
24
|
-
- {Negative consequence 1}
|
|
25
|
-
|
|
26
|
-
**Risks:**
|
|
27
|
-
- {Identified risk}
|
|
28
|
-
|
|
29
|
-
### Alternatives Considered
|
|
30
|
-
|
|
31
|
-
#### Option A: {Name}
|
|
32
|
-
- Pros: {advantages}
|
|
33
|
-
- Cons: {disadvantages}
|
|
34
|
-
- **Rejected because:** {reason}
|
|
35
|
-
|
|
36
|
-
#### Option B: {Name}
|
|
37
|
-
- Pros: {advantages}
|
|
38
|
-
- Cons: {disadvantages}
|
|
39
|
-
- **Rejected because:** {reason}
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## ADR-002: Database Access Strategy
|
|
44
|
-
|
|
45
|
-
**Date:** {{DATE}}
|
|
46
|
-
**Status:** Accepted
|
|
47
|
-
|
|
48
|
-
### Context
|
|
49
|
-
|
|
50
|
-
Need to decide how the .NET API accesses Supabase PostgreSQL.
|
|
51
|
-
|
|
52
|
-
### Decision
|
|
53
|
-
|
|
54
|
-
Use Dapper with Npgsql for direct SQL queries. No EF Core.
|
|
55
|
-
|
|
56
|
-
### Consequences
|
|
57
|
-
|
|
58
|
-
**Pros:**
|
|
59
|
-
- Full control over SQL queries
|
|
60
|
-
- Better performance (no ORM overhead)
|
|
61
|
-
- Direct access to PostgreSQL features (jsonb, pgvector, functions)
|
|
62
|
-
- RLS policies apply naturally through connection
|
|
63
|
-
|
|
64
|
-
**Cons:**
|
|
65
|
-
- No automatic migrations (use Supabase CLI instead)
|
|
66
|
-
- Manual SQL query writing
|
|
67
|
-
- No change tracking
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## ADR-003: Auth Strategy
|
|
72
|
-
|
|
73
|
-
**Date:** {{DATE}}
|
|
74
|
-
**Status:** Accepted
|
|
75
|
-
|
|
76
|
-
### Context
|
|
77
|
-
|
|
78
|
-
Need authentication for both Next.js frontend and .NET API.
|
|
79
|
-
|
|
80
|
-
### Decision
|
|
81
|
-
|
|
82
|
-
Use Supabase Auth with @supabase/ssr on frontend. Validate JWT tokens in .NET API middleware.
|
|
83
|
-
|
|
84
|
-
### Consequences
|
|
85
|
-
|
|
86
|
-
**Pros:**
|
|
87
|
-
- Single auth provider for both layers
|
|
88
|
-
- RLS policies work automatically with auth.uid()
|
|
89
|
-
- Built-in social login, magic links, email/password
|
|
90
|
-
- No separate auth service to maintain
|
|
91
|
-
|
|
92
|
-
**Cons:**
|
|
93
|
-
- Coupled to Supabase ecosystem
|
|
94
|
-
- JWT secret must be shared with .NET API
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## Template for New ADRs
|
|
99
|
-
|
|
100
|
-
```markdown
|
|
101
|
-
## ADR-XXX: {Title}
|
|
102
|
-
|
|
103
|
-
**Date:**
|
|
104
|
-
**Status:** Proposed | Accepted | Deprecated | Superseded
|
|
105
|
-
|
|
106
|
-
### Context
|
|
107
|
-
{Why is this decision needed?}
|
|
108
|
-
|
|
109
|
-
### Decision
|
|
110
|
-
{What was decided?}
|
|
111
|
-
|
|
112
|
-
### Consequences
|
|
113
|
-
**Pros:** {list}
|
|
114
|
-
**Cons:** {list}
|
|
115
|
-
```
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# ============================================================
|
|
2
|
-
# Dockerfile: .NET 10 API ({{FEATURE_NAME_TITLE}})
|
|
3
|
-
# Stack: Next.js + Supabase + .NET API
|
|
4
|
-
# Generated by MORPH Framework
|
|
5
|
-
# ============================================================
|
|
6
|
-
|
|
7
|
-
# Stage 1: Build
|
|
8
|
-
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
|
9
|
-
WORKDIR /src
|
|
10
|
-
|
|
11
|
-
# Copy project file and restore dependencies
|
|
12
|
-
COPY *.csproj .
|
|
13
|
-
RUN dotnet restore
|
|
14
|
-
|
|
15
|
-
# Copy source code and publish
|
|
16
|
-
COPY . .
|
|
17
|
-
RUN dotnet publish -c Release -o /app/publish --no-restore
|
|
18
|
-
|
|
19
|
-
# Stage 2: Runtime
|
|
20
|
-
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime
|
|
21
|
-
WORKDIR /app
|
|
22
|
-
|
|
23
|
-
# Copy published output
|
|
24
|
-
COPY --from=build /app/publish .
|
|
25
|
-
|
|
26
|
-
# Configuration
|
|
27
|
-
ENV ASPNETCORE_URLS=http://+:8080
|
|
28
|
-
ENV ASPNETCORE_ENVIRONMENT=Production
|
|
29
|
-
|
|
30
|
-
# Expose port
|
|
31
|
-
EXPOSE 8080
|
|
32
|
-
|
|
33
|
-
# Health check
|
|
34
|
-
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
35
|
-
CMD curl -f http://localhost:8080/health || exit 1
|
|
36
|
-
|
|
37
|
-
# Entrypoint
|
|
38
|
-
ENTRYPOINT ["dotnet", "Api.dll"]
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# ============================================================
|
|
2
|
-
# Dockerfile: Next.js Frontend ({{FEATURE_NAME_TITLE}})
|
|
3
|
-
# Stack: Next.js + Supabase
|
|
4
|
-
# Generated by MORPH Framework
|
|
5
|
-
# Requires: output: "standalone" in next.config.ts
|
|
6
|
-
# ============================================================
|
|
7
|
-
|
|
8
|
-
# Stage 1: Install dependencies
|
|
9
|
-
FROM node:22-alpine AS deps
|
|
10
|
-
WORKDIR /app
|
|
11
|
-
COPY package.json package-lock.json ./
|
|
12
|
-
RUN npm ci --omit=dev
|
|
13
|
-
|
|
14
|
-
# Stage 2: Build application
|
|
15
|
-
FROM node:22-alpine AS builder
|
|
16
|
-
WORKDIR /app
|
|
17
|
-
COPY --from=deps /app/node_modules ./node_modules
|
|
18
|
-
COPY . .
|
|
19
|
-
ENV NEXT_TELEMETRY_DISABLED=1
|
|
20
|
-
RUN npm run build
|
|
21
|
-
|
|
22
|
-
# Stage 3: Production runtime
|
|
23
|
-
FROM node:22-alpine AS runner
|
|
24
|
-
WORKDIR /app
|
|
25
|
-
|
|
26
|
-
ENV NODE_ENV=production
|
|
27
|
-
ENV NEXT_TELEMETRY_DISABLED=1
|
|
28
|
-
|
|
29
|
-
# Create non-root user
|
|
30
|
-
RUN addgroup --system --gid 1001 nodejs && \
|
|
31
|
-
adduser --system --uid 1001 nextjs
|
|
32
|
-
|
|
33
|
-
# Copy build output
|
|
34
|
-
COPY --from=builder /app/public ./public
|
|
35
|
-
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
36
|
-
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
37
|
-
|
|
38
|
-
# Switch to non-root user
|
|
39
|
-
USER nextjs
|
|
40
|
-
|
|
41
|
-
# Expose port
|
|
42
|
-
EXPOSE 3000
|
|
43
|
-
|
|
44
|
-
ENV PORT=3000
|
|
45
|
-
ENV HOSTNAME="0.0.0.0"
|
|
46
|
-
|
|
47
|
-
# Start server
|
|
48
|
-
CMD ["node", "server.js"]
|