groundwork-method 0.0.1 → 0.10.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/CHANGELOG.md +781 -0
- package/LICENSE +21 -0
- package/README.md +44 -29
- package/bin/groundwork.js +1654 -0
- package/dist/src/generators/add-capability/generator.d.ts +8 -0
- package/dist/src/generators/add-capability/generator.js +60 -0
- package/dist/src/generators/add-capability/generator.js.map +1 -0
- package/dist/src/generators/cli-app/generator.d.ts +9 -0
- package/dist/src/generators/cli-app/generator.js +140 -0
- package/dist/src/generators/cli-app/generator.js.map +1 -0
- package/dist/src/generators/docs-site/generator.d.ts +5 -0
- package/dist/src/generators/docs-site/generator.js +441 -0
- package/dist/src/generators/docs-site/generator.js.map +1 -0
- package/dist/src/generators/electron-app/generator.d.ts +6 -0
- package/dist/src/generators/electron-app/generator.js +261 -0
- package/dist/src/generators/electron-app/generator.js.map +1 -0
- package/dist/src/generators/flutter-app/generator.d.ts +6 -0
- package/dist/src/generators/flutter-app/generator.js +314 -0
- package/dist/src/generators/flutter-app/generator.js.map +1 -0
- package/dist/src/generators/go-microservice/generator.d.ts +8 -0
- package/dist/src/generators/go-microservice/generator.js +232 -0
- package/dist/src/generators/go-microservice/generator.js.map +1 -0
- package/dist/src/generators/nextjs-app/generator.d.ts +8 -0
- package/dist/src/generators/nextjs-app/generator.js +294 -0
- package/dist/src/generators/nextjs-app/generator.js.map +1 -0
- package/dist/src/generators/python-microservice/generator.d.ts +13 -0
- package/dist/src/generators/python-microservice/generator.js +265 -0
- package/dist/src/generators/python-microservice/generator.js.map +1 -0
- package/dist/src/generators/shared/brand-tokens.d.ts +89 -0
- package/dist/src/generators/shared/brand-tokens.js +308 -0
- package/dist/src/generators/shared/brand-tokens.js.map +1 -0
- package/dist/src/generators/shared/capabilities.d.ts +101 -0
- package/dist/src/generators/shared/capabilities.js +279 -0
- package/dist/src/generators/shared/capabilities.js.map +1 -0
- package/dist/src/generators/shared/provenance.d.ts +2 -0
- package/dist/src/generators/shared/provenance.js +85 -0
- package/dist/src/generators/shared/provenance.js.map +1 -0
- package/dist/src/generators/shared/scaffold-helpers.d.ts +72 -0
- package/dist/src/generators/shared/scaffold-helpers.js +309 -0
- package/dist/src/generators/shared/scaffold-helpers.js.map +1 -0
- package/dist/src/generators/system-test-runner/generator.d.ts +23 -0
- package/dist/src/generators/system-test-runner/generator.js +125 -0
- package/dist/src/generators/system-test-runner/generator.js.map +1 -0
- package/dist/src/generators/workspace-dev-cli/generator.d.ts +7 -0
- package/dist/src/generators/workspace-dev-cli/generator.js +138 -0
- package/dist/src/generators/workspace-dev-cli/generator.js.map +1 -0
- package/generators.json +57 -0
- package/lib/repo-map/grammars/tree-sitter-c.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-cpp.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-csharp.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-dart.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-go.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-java.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-javascript.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-kotlin.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-lua.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-php.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-python.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-ruby.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-rust.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-scala.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-swift.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-tsx.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-typescript.wasm +0 -0
- package/lib/repo-map/index.js +386 -0
- package/lib/repo-map/languages.js +514 -0
- package/lib/repo-map/pagerank.js +59 -0
- package/migrations/README.md +60 -0
- package/migrations/_template/cli-migration.js +27 -0
- package/migrations/gw-bet-prose-redesign.js +105 -0
- package/migrations/gw-drop-test-manifest.js +37 -0
- package/migrations/gw-register-serena-mcp.js +42 -0
- package/migrations/gw-relocate-hidden-skills.js +40 -0
- package/migrations/gw-seed-config-toml.js +24 -0
- package/migrations/index.json +40 -0
- package/package.json +70 -6
- package/src/AGENTS.md +36 -0
- package/src/config/config.toml +30 -0
- package/src/config/groundwork-state.json +5 -0
- package/src/docs/llms.txt +72 -0
- package/src/docs/principles/ai-native/agent-native-systems.md +90 -0
- package/src/docs/principles/ai-native/agentic-systems.md +78 -0
- package/src/docs/principles/ai-native/ai-engineering.md +100 -0
- package/src/docs/principles/ai-native/ai-native-product.md +76 -0
- package/src/docs/principles/delivery/cost-engineering.md +89 -0
- package/src/docs/principles/delivery/day-2-operational-baseline.md +57 -0
- package/src/docs/principles/delivery/devex.md +88 -0
- package/src/docs/principles/delivery/platform.md +101 -0
- package/src/docs/principles/delivery/progressive-delivery.md +92 -0
- package/src/docs/principles/design/ai-native-design.md +73 -0
- package/src/docs/principles/design/design-foundations.md +80 -0
- package/src/docs/principles/design/design-systems-and-tokens.md +72 -0
- package/src/docs/principles/design/interaction-and-motion.md +69 -0
- package/src/docs/principles/design/layout-and-space.md +72 -0
- package/src/docs/principles/design/usability-and-ux.md +68 -0
- package/src/docs/principles/design/visual-design.md +84 -0
- package/src/docs/principles/foundations/code-craft.md +86 -0
- package/src/docs/principles/foundations/continuous-discovery.md +75 -0
- package/src/docs/principles/foundations/documentation.md +102 -0
- package/src/docs/principles/foundations/prioritization-and-appetite.md +78 -0
- package/src/docs/principles/foundations/product-engineering.md +90 -0
- package/src/docs/principles/foundations/product-risks.md +89 -0
- package/src/docs/principles/foundations/requirements-and-specs.md +80 -0
- package/src/docs/principles/foundations/success-metrics.md +66 -0
- package/src/docs/principles/foundations/testing.md +82 -0
- package/src/docs/principles/index.md +23 -0
- package/src/docs/principles/quality/accessibility.md +88 -0
- package/src/docs/principles/quality/observability.md +84 -0
- package/src/docs/principles/quality/performance.md +84 -0
- package/src/docs/principles/quality/privacy.md +92 -0
- package/src/docs/principles/quality/reliability.md +89 -0
- package/src/docs/principles/quality/security.md +78 -0
- package/src/docs/principles/stack/postgres.md +100 -0
- package/src/docs/principles/system-design/api-design.md +86 -0
- package/src/docs/principles/system-design/architecture-decisions.md +81 -0
- package/src/docs/principles/system-design/code-structure.md +104 -0
- package/src/docs/principles/system-design/data-engineering.md +87 -0
- package/src/docs/principles/system-design/durable-execution.md +89 -0
- package/src/docs/principles/system-design/evolutionary-architecture.md +81 -0
- package/src/docs/principles/system-design/identity-and-access.md +76 -0
- package/src/docs/principles/system-design/integration-patterns.md +84 -0
- package/src/docs/principles/system-design/real-time.md +83 -0
- package/src/docs/principles/system-design/surface-architecture.md +74 -0
- package/src/docs/ways-of-working/documentation.md +69 -0
- package/src/docs/ways-of-working/how-we-work.md +76 -0
- package/src/docs/ways-of-working/units-of-work.md +40 -0
- package/src/engineer-skills/groundwork-electron-engineer/SKILL.md +118 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/ipc-contracts.md +138 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/packaging-and-updates.md +82 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/process-model.md +94 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/security.md +107 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/testing-and-smoke.md +107 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/theming-and-tokens.md +74 -0
- package/src/engineer-skills/groundwork-electron-engineer/sync-anchor.md +14 -0
- package/src/engineer-skills/groundwork-flutter-engineer/SKILL.md +108 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/accessibility.md +92 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/architecture.md +189 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/data-and-contracts.md +136 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/navigation.md +122 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/platform-channels.md +93 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/releases-and-distribution.md +84 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/state-management.md +166 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/testing.md +135 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/theming-and-design-tokens.md +109 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/widgets-and-composition.md +123 -0
- package/src/engineer-skills/groundwork-flutter-engineer/sync-anchor.md +15 -0
- package/src/engineer-skills/groundwork-go-engineer/SKILL.md +171 -0
- package/src/engineer-skills/groundwork-go-engineer/references/api-design.md +82 -0
- package/src/engineer-skills/groundwork-go-engineer/references/architecture.md +42 -0
- package/src/engineer-skills/groundwork-go-engineer/references/capability-ports.md +50 -0
- package/src/engineer-skills/groundwork-go-engineer/references/code-craft-security.md +34 -0
- package/src/engineer-skills/groundwork-go-engineer/references/concurrency.md +108 -0
- package/src/engineer-skills/groundwork-go-engineer/references/go-services.md +77 -0
- package/src/engineer-skills/groundwork-go-engineer/references/http-handlers.md +172 -0
- package/src/engineer-skills/groundwork-go-engineer/references/implementation-patterns.md +156 -0
- package/src/engineer-skills/groundwork-go-engineer/references/integration-realtime-data.md +57 -0
- package/src/engineer-skills/groundwork-go-engineer/references/observability.md +49 -0
- package/src/engineer-skills/groundwork-go-engineer/references/postgres.md +41 -0
- package/src/engineer-skills/groundwork-go-engineer/references/reliability-performance.md +105 -0
- package/src/engineer-skills/groundwork-go-engineer/references/testing.md +139 -0
- package/src/engineer-skills/groundwork-go-engineer/sync-anchor.md +11 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/SKILL.md +107 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/architecture.md +323 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/data-fetching.md +458 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/documentation.md +324 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/error-boundaries.md +383 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/mutations-and-forms.md +396 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/performance-and-deployment.md +947 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/routing-and-navigation.md +405 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/server-components.md +394 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/tailwind-and-styling.md +134 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/testing.md +433 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/type-system.md +368 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/ux-principles.md +278 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/visual-language.md +69 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/sync-anchor.md +9 -0
- package/src/engineer-skills/groundwork-python-engineer/SKILL.md +196 -0
- package/src/engineer-skills/groundwork-python-engineer/references/api-standards.md +88 -0
- package/src/engineer-skills/groundwork-python-engineer/references/architecture.md +57 -0
- package/src/engineer-skills/groundwork-python-engineer/references/async-patterns.md +103 -0
- package/src/engineer-skills/groundwork-python-engineer/references/capability-ports.md +44 -0
- package/src/engineer-skills/groundwork-python-engineer/references/database.md +88 -0
- package/src/engineer-skills/groundwork-python-engineer/references/documentation-mcp.md +167 -0
- package/src/engineer-skills/groundwork-python-engineer/references/implementation-patterns.md +166 -0
- package/src/engineer-skills/groundwork-python-engineer/references/ml-pipelines.md +119 -0
- package/src/engineer-skills/groundwork-python-engineer/references/ml-systems-ai-engineering.md +74 -0
- package/src/engineer-skills/groundwork-python-engineer/references/observability.md +57 -0
- package/src/engineer-skills/groundwork-python-engineer/references/resilience.md +126 -0
- package/src/engineer-skills/groundwork-python-engineer/references/testing.md +177 -0
- package/src/engineer-skills/groundwork-python-engineer/sync-anchor.md +13 -0
- package/src/generators/add-capability/generator.ts +70 -0
- package/src/generators/add-capability/schema.json +30 -0
- package/src/generators/capabilities/llm/capability.json +28 -0
- package/src/generators/capabilities/llm/providers/anthropic/footprint.json +13 -0
- package/src/generators/capabilities/llm/providers/anthropic/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/anthropic/stacks/python/src/__packageName__/adapters/llm.py.template +61 -0
- package/src/generators/capabilities/llm/providers/local/footprint.json +13 -0
- package/src/generators/capabilities/llm/providers/local/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/local/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
- package/src/generators/capabilities/llm/providers/localai/footprint.json +29 -0
- package/src/generators/capabilities/llm/providers/localai/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/localai/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
- package/src/generators/capabilities/llm/providers/none/footprint.json +9 -0
- package/src/generators/capabilities/llm/providers/none/stacks/go/internal/llm/llm.go.template +35 -0
- package/src/generators/capabilities/llm/providers/none/stacks/python/src/__packageName__/adapters/llm.py.template +25 -0
- package/src/generators/capabilities/llm/providers/ollama/footprint.json +20 -0
- package/src/generators/capabilities/llm/providers/ollama/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/ollama/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
- package/src/generators/capabilities/llm/providers/openai/footprint.json +13 -0
- package/src/generators/capabilities/llm/providers/openai/stacks/go/internal/llm/llm.go.template +98 -0
- package/src/generators/capabilities/llm/providers/openai/stacks/python/src/__packageName__/adapters/llm.py.template +60 -0
- package/src/generators/capabilities/llm/stacks/go/internal/core/service/llm.go.template +12 -0
- package/src/generators/capabilities/llm/stacks/go/internal/llm/llm_test.go.template +33 -0
- package/src/generators/capabilities/llm/stacks/python/src/__packageName__/core/llm.py.template +15 -0
- package/src/generators/capabilities/llm/stacks/python/tests/contracts/test_llm.py.template +37 -0
- package/src/generators/cli-app/files/README.md.template +76 -0
- package/src/generators/cli-app/files/build.mjs.template +15 -0
- package/src/generators/cli-app/files/package.json.template +21 -0
- package/src/generators/cli-app/files/src/cli.ts.template +67 -0
- package/src/generators/cli-app/files/src/commands/hello.ts.template +17 -0
- package/src/generators/cli-app/files/src/commands/status.ts.template +23 -0
- package/src/generators/cli-app/files/src/core/client.test.ts.template +80 -0
- package/src/generators/cli-app/files/src/core/client.ts.template +64 -0
- package/src/generators/cli-app/files/src/registry.test.ts.template +35 -0
- package/src/generators/cli-app/files/src/registry.ts.template +31 -0
- package/src/generators/cli-app/files/tsconfig.json.template +16 -0
- package/src/generators/cli-app/files/tsconfig.test.json.template +11 -0
- package/src/generators/cli-app/generator.ts +138 -0
- package/src/generators/cli-app/schema.json +24 -0
- package/src/generators/docs-site/files/.gitignore.ejs +40 -0
- package/src/generators/docs-site/files/app/docs/__slug__/page.tsx +101 -0
- package/src/generators/docs-site/files/app/docs/layout.tsx +14 -0
- package/src/generators/docs-site/files/app/docs.css +43 -0
- package/src/generators/docs-site/files/app/layout.tsx +24 -0
- package/src/generators/docs-site/files/app/page.tsx +135 -0
- package/src/generators/docs-site/files/app/source.ts +8 -0
- package/src/generators/docs-site/files/components/mermaid.tsx +67 -0
- package/src/generators/docs-site/files/next.config.mjs +10 -0
- package/src/generators/docs-site/files/package.json +32 -0
- package/src/generators/docs-site/files/pnpm-workspace.yaml +7 -0
- package/src/generators/docs-site/files/postcss.config.mjs +6 -0
- package/src/generators/docs-site/files/source.config.ts +77 -0
- package/src/generators/docs-site/files/tailwind.config.js +10 -0
- package/src/generators/docs-site/files/tsconfig.json +27 -0
- package/src/generators/docs-site/generator.ts +476 -0
- package/src/generators/docs-site/schema.json +17 -0
- package/src/generators/electron-app/docs/principles/stack/electron/index.md +47 -0
- package/src/generators/electron-app/docs/principles/stack/electron/ipc-contracts.md +71 -0
- package/src/generators/electron-app/docs/principles/stack/electron/packaging-and-updates.md +59 -0
- package/src/generators/electron-app/docs/principles/stack/electron/process-model.md +53 -0
- package/src/generators/electron-app/docs/principles/stack/electron/security.md +70 -0
- package/src/generators/electron-app/docs/principles/stack/typescript/frontend.md +65 -0
- package/src/generators/electron-app/files/.gitignore.template +20 -0
- package/src/generators/electron-app/files/README.md.template +125 -0
- package/src/generators/electron-app/files/electron.vite.config.ts +31 -0
- package/src/generators/electron-app/files/eslint.config.mjs +92 -0
- package/src/generators/electron-app/files/forge.config.ts.template +44 -0
- package/src/generators/electron-app/files/package.json.template +54 -0
- package/src/generators/electron-app/files/playwright.config.ts +18 -0
- package/src/generators/electron-app/files/project.json.template +65 -0
- package/src/generators/electron-app/files/src/main/core-client.test.ts +81 -0
- package/src/generators/electron-app/files/src/main/core-client.ts +55 -0
- package/src/generators/electron-app/files/src/main/index.ts +157 -0
- package/src/generators/electron-app/files/src/main/ipc.ts +52 -0
- package/src/generators/electron-app/files/src/main/policy.test.ts +71 -0
- package/src/generators/electron-app/files/src/main/policy.ts +73 -0
- package/src/generators/electron-app/files/src/preload/index.ts +23 -0
- package/src/generators/electron-app/files/src/renderer/index.html.template +20 -0
- package/src/generators/electron-app/files/src/renderer/src/App.test.tsx +61 -0
- package/src/generators/electron-app/files/src/renderer/src/App.tsx.template +43 -0
- package/src/generators/electron-app/files/src/renderer/src/assets/main.css +40 -0
- package/src/generators/electron-app/files/src/renderer/src/env.d.ts +14 -0
- package/src/generators/electron-app/files/src/renderer/src/main.tsx +25 -0
- package/src/generators/electron-app/files/src/shared/ipc.ts +54 -0
- package/src/generators/electron-app/files/tests/smoke/app.spec.ts.template +68 -0
- package/src/generators/electron-app/files/tool/electron_exec.sh.template +83 -0
- package/src/generators/electron-app/files/tsconfig.json +7 -0
- package/src/generators/electron-app/files/tsconfig.node.json +27 -0
- package/src/generators/electron-app/files/tsconfig.web.json +22 -0
- package/src/generators/electron-app/files/vitest.config.ts +32 -0
- package/src/generators/electron-app/files/vitest.setup.ts +1 -0
- package/src/generators/electron-app/generator.ts +288 -0
- package/src/generators/electron-app/schema.json +23 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/architecture.md +78 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/index.md +38 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/platform-channels.md +51 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/releases-and-distribution.md +59 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/state-management.md +85 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/testing.md +74 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/widgets-and-composition.md +69 -0
- package/src/generators/flutter-app/files/.gitignore.template +30 -0
- package/src/generators/flutter-app/files/README.md.template +100 -0
- package/src/generators/flutter-app/files/analysis_options.yaml.template +18 -0
- package/src/generators/flutter-app/files/integration_test/app_test.dart.template +30 -0
- package/src/generators/flutter-app/files/lib/app.dart.template +24 -0
- package/src/generators/flutter-app/files/lib/config/app_config.dart +15 -0
- package/src/generators/flutter-app/files/lib/data/repositories/status_repository.dart +36 -0
- package/src/generators/flutter-app/files/lib/data/services/api_client.dart +71 -0
- package/src/generators/flutter-app/files/lib/domain/models/health_status.dart +23 -0
- package/src/generators/flutter-app/files/lib/main.dart +11 -0
- package/src/generators/flutter-app/files/lib/router.dart +23 -0
- package/src/generators/flutter-app/files/lib/ui/core/theme/app_theme.dart +110 -0
- package/src/generators/flutter-app/files/lib/ui/home/home_view.dart +89 -0
- package/src/generators/flutter-app/files/lib/ui/home/home_view_model.dart.template +38 -0
- package/src/generators/flutter-app/files/project.json.template +51 -0
- package/src/generators/flutter-app/files/pubspec.yaml.template +47 -0
- package/src/generators/flutter-app/files/test/api_client_test.dart.template +63 -0
- package/src/generators/flutter-app/files/test/fakes/fake_status_repository.dart.template +19 -0
- package/src/generators/flutter-app/files/test/home_view_test.dart.template +58 -0
- package/src/generators/flutter-app/files/tool/flutter_exec.sh.template +60 -0
- package/src/generators/flutter-app/generator.ts +362 -0
- package/src/generators/flutter-app/schema.json +23 -0
- package/src/generators/go-microservice/docs/principles/stack/go/concurrency.md +123 -0
- package/src/generators/go-microservice/docs/principles/stack/go/index.md +70 -0
- package/src/generators/go-microservice/docs/principles/stack/go/testing.md +152 -0
- package/src/generators/go-microservice/files/.air.toml.template +38 -0
- package/src/generators/go-microservice/files/.env.template +4 -0
- package/src/generators/go-microservice/files/.golangci.yml.template +82 -0
- package/src/generators/go-microservice/files/Dockerfile.dev.template +12 -0
- package/src/generators/go-microservice/files/asyncapi-pubsub.yaml.template +33 -0
- package/src/generators/go-microservice/files/asyncapi-ws.yaml.template +34 -0
- package/src/generators/go-microservice/files/cmd/api/main.go.template +149 -0
- package/src/generators/go-microservice/files/cmd/api/main_test.go.template +99 -0
- package/src/generators/go-microservice/files/cmd/worker/cleanup/main.go.template +39 -0
- package/src/generators/go-microservice/files/db/schema.sql.template +24 -0
- package/src/generators/go-microservice/files/go.mod.template +39 -0
- package/src/generators/go-microservice/files/internal/config/config.go.template +52 -0
- package/src/generators/go-microservice/files/internal/config/otel.go.template +93 -0
- package/src/generators/go-microservice/files/internal/core/domain/errors.go.template +16 -0
- package/src/generators/go-microservice/files/internal/core/domain/model.go.template +28 -0
- package/src/generators/go-microservice/files/internal/core/domain/user.go.template +13 -0
- package/src/generators/go-microservice/files/internal/core/pagination.go.template +16 -0
- package/src/generators/go-microservice/files/internal/core/service/app_service.go.template +79 -0
- package/src/generators/go-microservice/files/internal/core/service/event_hub.go.template +9 -0
- package/src/generators/go-microservice/files/internal/core/service/message_queue.go.template +10 -0
- package/src/generators/go-microservice/files/internal/core/service/outbox_repository.go.template +31 -0
- package/src/generators/go-microservice/files/internal/core/service/repository.go.template +23 -0
- package/src/generators/go-microservice/files/internal/core/service/user_repository.go.template +15 -0
- package/src/generators/go-microservice/files/internal/core/service/user_service.go.template +43 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/app_handler.go.template +108 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/auth_middleware_test.go.template +52 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook.go.template +202 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook_test.go.template +82 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/health_handler.go.template +80 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware.go.template +87 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware_test.go.template +76 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/repository.go.template +37 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_auth.go.template +40 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_loadshed.go.template +38 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_logging.go.template +40 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_ratelimit.go.template +48 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_test.go.template +81 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/router.go.template +105 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/types.go.template +70 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/websocket_handler.go.template +39 -0
- package/src/generators/go-microservice/files/internal/httpclient/http_client.go.template +87 -0
- package/src/generators/go-microservice/files/internal/kafka/kafka.go.template +34 -0
- package/src/generators/go-microservice/files/internal/postgres/postgres.go.template +195 -0
- package/src/generators/go-microservice/files/internal/postgres/postgres_test.go.template +156 -0
- package/src/generators/go-microservice/files/internal/postgres/user_repository.go.template +56 -0
- package/src/generators/go-microservice/files/internal/pubsub/gcp_pubsub.go.template +35 -0
- package/src/generators/go-microservice/files/internal/websocket/client.go.template +151 -0
- package/src/generators/go-microservice/files/internal/websocket/hub.go.template +261 -0
- package/src/generators/go-microservice/files/scripts/apply-schema.sh.template +21 -0
- package/src/generators/go-microservice/files/tools/tools.go.template +10 -0
- package/src/generators/go-microservice/generator.ts +240 -0
- package/src/generators/go-microservice/schema.json +63 -0
- package/src/generators/nextjs-app/docs/principles/stack/typescript/frontend.md +65 -0
- package/src/generators/nextjs-app/files/.dockerignore.template +7 -0
- package/src/generators/nextjs-app/files/.env.example.template +24 -0
- package/src/generators/nextjs-app/files/.gitignore.template +5 -0
- package/src/generators/nextjs-app/files/Dockerfile +53 -0
- package/src/generators/nextjs-app/files/app/(auth)/sign-in/__sign-in__/page.tsx.template +9 -0
- package/src/generators/nextjs-app/files/app/(auth)/sign-up/__sign-up__/page.tsx.template +9 -0
- package/src/generators/nextjs-app/files/app/api/config/route.ts.template +39 -0
- package/src/generators/nextjs-app/files/app/api/healthz/route.test.ts +15 -0
- package/src/generators/nextjs-app/files/app/api/healthz/route.ts +5 -0
- package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.test.ts.template +55 -0
- package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.ts.template +126 -0
- package/src/generators/nextjs-app/files/app/error.tsx +39 -0
- package/src/generators/nextjs-app/files/app/global-error.tsx +68 -0
- package/src/generators/nextjs-app/files/app/globals.css +105 -0
- package/src/generators/nextjs-app/files/app/layout.tsx +59 -0
- package/src/generators/nextjs-app/files/app/loading.tsx +13 -0
- package/src/generators/nextjs-app/files/app/not-found.tsx +30 -0
- package/src/generators/nextjs-app/files/app/page.tsx +20 -0
- package/src/generators/nextjs-app/files/components/providers/default.tsx +19 -0
- package/src/generators/nextjs-app/files/components/providers/production.tsx +32 -0
- package/src/generators/nextjs-app/files/components/providers/telemetry.tsx +76 -0
- package/src/generators/nextjs-app/files/components/render-smoke.test.tsx +29 -0
- package/src/generators/nextjs-app/files/components/theme-provider.tsx +11 -0
- package/src/generators/nextjs-app/files/components.json +21 -0
- package/src/generators/nextjs-app/files/eslint.config.mjs +120 -0
- package/src/generators/nextjs-app/files/hooks/use-toast.ts +7 -0
- package/src/generators/nextjs-app/files/instrumentation.ts +90 -0
- package/src/generators/nextjs-app/files/lib/api/fetcher.ts.template +130 -0
- package/src/generators/nextjs-app/files/lib/config.ts +21 -0
- package/src/generators/nextjs-app/files/lib/logger.ts +29 -0
- package/src/generators/nextjs-app/files/lib/schemas/index.ts +19 -0
- package/src/generators/nextjs-app/files/lib/utils.ts +6 -0
- package/src/generators/nextjs-app/files/next.config.mjs +9 -0
- package/src/generators/nextjs-app/files/package.json +70 -0
- package/src/generators/nextjs-app/files/postcss.config.mjs +8 -0
- package/src/generators/nextjs-app/files/proxy.test.ts.template +30 -0
- package/src/generators/nextjs-app/files/proxy.ts +31 -0
- package/src/generators/nextjs-app/files/public/.gitkeep +1 -0
- package/src/generators/nextjs-app/files/tsconfig.json +42 -0
- package/src/generators/nextjs-app/files/vitest.config.mts +15 -0
- package/src/generators/nextjs-app/files/vitest.setup.ts +7 -0
- package/src/generators/nextjs-app/generator.ts +307 -0
- package/src/generators/nextjs-app/schema.json +44 -0
- package/src/generators/python-microservice/docs/principles/stack/python/async.md +168 -0
- package/src/generators/python-microservice/docs/principles/stack/python/documentation.md +240 -0
- package/src/generators/python-microservice/docs/principles/stack/python/mcp.md +147 -0
- package/src/generators/python-microservice/docs/principles/stack/python/resilience.md +193 -0
- package/src/generators/python-microservice/docs/principles/stack/python/testing.md +281 -0
- package/src/generators/python-microservice/files/.env.example.template +30 -0
- package/src/generators/python-microservice/files/Dockerfile.template +36 -0
- package/src/generators/python-microservice/files/db/schema.sql.template +19 -0
- package/src/generators/python-microservice/files/pyproject.toml.template +76 -0
- package/src/generators/python-microservice/files/scripts/apply-schema.sh.template +25 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/comfyui.py.template +87 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/config.py.template +48 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/database.py.template +21 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/message_queue.py.template +29 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/repository.py.template +130 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/telemetry.py.template +68 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/websocket_hub.py.template +36 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/domain/entities.py.template +22 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/domain/exceptions.py.template +43 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/ports.py.template +42 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/service/example_service.py.template +68 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/dependencies.py.template +50 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/middleware.py.template +131 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/router.py.template +37 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/websocket_handler.py.template +20 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/cleanup.py.template +35 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/worker.py.template +28 -0
- package/src/generators/python-microservice/files/src/__packageName__/main.py.template +108 -0
- package/src/generators/python-microservice/files/tests/test_main.py.template +74 -0
- package/src/generators/python-microservice/files/tests/test_middleware.py.template +109 -0
- package/src/generators/python-microservice/files/tests/test_worker.py.template +16 -0
- package/src/generators/python-microservice/generator.ts +286 -0
- package/src/generators/python-microservice/schema.json +86 -0
- package/src/generators/shared/brand-tokens.ts +301 -0
- package/src/generators/shared/capabilities.ts +349 -0
- package/src/generators/shared/provenance.ts +61 -0
- package/src/generators/shared/scaffold-helpers.ts +309 -0
- package/src/generators/system-test-runner/files/tests/bets/.gitkeep +0 -0
- package/src/generators/system-test-runner/files/tests/bets/_archive/.gitkeep +0 -0
- package/src/generators/system-test-runner/files/tests/conftest.py.template +503 -0
- package/src/generators/system-test-runner/files/tests/pyproject.toml.template +20 -0
- package/src/generators/system-test-runner/files/tests/system/pages/__init__.py.template +9 -0
- package/src/generators/system-test-runner/files/tests/system/pages/base_page.py.template +36 -0
- package/src/generators/system-test-runner/files/tests/system/test_a11y_smoke.py.template +132 -0
- package/src/generators/system-test-runner/files/tests/system/test_contract_conformance.py.template +140 -0
- package/src/generators/system-test-runner/files/tests/system/test_layout_geometry.py.template +109 -0
- package/src/generators/system-test-runner/files/tests/system/test_render_smoke.py.template +227 -0
- package/src/generators/system-test-runner/files/tests/system/test_system.py.template +158 -0
- package/src/generators/system-test-runner/files/tests/system/test_token_conformance.py.template +206 -0
- package/src/generators/system-test-runner/files/tests/system/test_visual_regression.py.template +104 -0
- package/src/generators/system-test-runner/generator.ts +142 -0
- package/src/generators/system-test-runner/schema.json +24 -0
- package/src/generators/workspace-dev-cli/cli-src/build.mjs +42 -0
- package/src/generators/workspace-dev-cli/cli-src/dist/dev-bundle.js +2168 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/bet.ts +442 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/completion.ts +87 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/doctor.ts +139 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/lifecycle.ts +548 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/quality.ts +127 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/surface.ts +214 -0
- package/src/generators/workspace-dev-cli/cli-src/src/index.ts +127 -0
- package/src/generators/workspace-dev-cli/cli-src/src/registry.ts +194 -0
- package/src/generators/workspace-dev-cli/cli-src/src/theme/color.ts +130 -0
- package/src/generators/workspace-dev-cli/cli-src/src/theme/render.ts +158 -0
- package/src/generators/workspace-dev-cli/cli-src/src/theme/tokens.ts +122 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/context.ts +43 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/extensions.ts +99 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/paths.ts +46 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/proc.ts +106 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/prompt.ts +108 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/runners.ts +70 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/services.ts +221 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/version.ts +21 -0
- package/src/generators/workspace-dev-cli/cli-src/tsconfig.json +16 -0
- package/src/generators/workspace-dev-cli/files/.agents/skills/workspace-cli/SKILL.md.template +74 -0
- package/src/generators/workspace-dev-cli/files/dev.template +16 -0
- package/src/generators/workspace-dev-cli/files/docker-compose.yml.template +20 -0
- package/src/generators/workspace-dev-cli/files/scripts/cli/templates/milestone-test.pytmpl.template +46 -0
- package/src/generators/workspace-dev-cli/files/scripts/cli/templates/slice-test.pytmpl.template +38 -0
- package/src/generators/workspace-dev-cli/generator.ts +136 -0
- package/src/generators/workspace-dev-cli/schema.json +22 -0
- package/src/hidden-skills/code-intelligence.md +129 -0
- package/src/hidden-skills/groundwork-architect/SKILL.md +114 -0
- package/src/hidden-skills/groundwork-architect/references/agentic-systems.md +44 -0
- package/src/hidden-skills/groundwork-architect/references/ai-native-architecture.md +37 -0
- package/src/hidden-skills/groundwork-architect/references/api-and-contracts.md +45 -0
- package/src/hidden-skills/groundwork-architect/references/core-and-boundaries.md +45 -0
- package/src/hidden-skills/groundwork-architect/references/data-architecture.md +33 -0
- package/src/hidden-skills/groundwork-architect/references/decision-records.md +34 -0
- package/src/hidden-skills/groundwork-architect/references/durable-execution.md +45 -0
- package/src/hidden-skills/groundwork-architect/references/evolutionary-architecture.md +37 -0
- package/src/hidden-skills/groundwork-architect/references/identity-and-access.md +41 -0
- package/src/hidden-skills/groundwork-architect/references/integration-patterns.md +39 -0
- package/src/hidden-skills/groundwork-architect/references/observability.md +36 -0
- package/src/hidden-skills/groundwork-architect/references/performance-and-scale.md +41 -0
- package/src/hidden-skills/groundwork-architect/references/platform-and-delivery.md +47 -0
- package/src/hidden-skills/groundwork-architect/references/realtime-and-async.md +28 -0
- package/src/hidden-skills/groundwork-architect/references/reliability.md +31 -0
- package/src/hidden-skills/groundwork-architect/references/security-and-trust.md +47 -0
- package/src/hidden-skills/groundwork-architect/references/surface-architecture.md +40 -0
- package/src/hidden-skills/groundwork-architect/sync-anchor.md +34 -0
- package/src/hidden-skills/groundwork-architecture/architecture-template.md +50 -0
- package/src/hidden-skills/groundwork-architecture/instructions.md +139 -0
- package/src/hidden-skills/groundwork-architecture/phases/01-context-ingestion.md +18 -0
- package/src/hidden-skills/groundwork-architecture/phases/02-technical-constraints.md +27 -0
- package/src/hidden-skills/groundwork-architecture/phases/03-service-design.md +19 -0
- package/src/hidden-skills/groundwork-architecture/phases/04-data-flow-communication.md +23 -0
- package/src/hidden-skills/groundwork-architecture/phases/05-component-boundaries-contracts.md +17 -0
- package/src/hidden-skills/groundwork-architecture/phases/06-draft-review-present.md +38 -0
- package/src/hidden-skills/groundwork-architecture/phases/07-commit.md +33 -0
- package/src/hidden-skills/groundwork-architecture/templates/architecture-cache.md +43 -0
- package/src/hidden-skills/groundwork-architecture-extract/instructions.md +163 -0
- package/src/hidden-skills/groundwork-architecture-extract/templates/architecture-extract-cache.md +21 -0
- package/src/hidden-skills/groundwork-bet/briefs/slice-worker.md +191 -0
- package/src/hidden-skills/groundwork-bet/instructions.md +88 -0
- package/src/hidden-skills/groundwork-bet/templates/bet-progress-test.md +126 -0
- package/src/hidden-skills/groundwork-bet/templates/change-proposal.md +38 -0
- package/src/hidden-skills/groundwork-bet/templates/decomposition/meta.json +4 -0
- package/src/hidden-skills/groundwork-bet/templates/decomposition/milestone-index.md +35 -0
- package/src/hidden-skills/groundwork-bet/templates/decomposition/slice.md +35 -0
- package/src/hidden-skills/groundwork-bet/templates/pitch.md +45 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/01-ui-design.md +51 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/02-data-flows.md +36 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/03-api-design.md +90 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/04-data-design.md +29 -0
- package/src/hidden-skills/groundwork-bet/workflows/01-discovery.md +198 -0
- package/src/hidden-skills/groundwork-bet/workflows/02-design.md +168 -0
- package/src/hidden-skills/groundwork-bet/workflows/03-decomposition.md +246 -0
- package/src/hidden-skills/groundwork-bet/workflows/04-delivery.md +193 -0
- package/src/hidden-skills/groundwork-bet/workflows/05-validation.md +199 -0
- package/src/hidden-skills/groundwork-design-system/instructions.md +125 -0
- package/src/hidden-skills/groundwork-design-system/templates/brand-tokens.md +182 -0
- package/src/hidden-skills/groundwork-design-system/templates/design-system-cache.md +64 -0
- package/src/hidden-skills/groundwork-design-system/tracks/_foundation.md +136 -0
- package/src/hidden-skills/groundwork-design-system/tracks/agentic-protocol.md +269 -0
- package/src/hidden-skills/groundwork-design-system/tracks/cli.md +355 -0
- package/src/hidden-skills/groundwork-design-system/tracks/graphical-ui.md +330 -0
- package/src/hidden-skills/groundwork-design-system-extract/instructions.md +124 -0
- package/src/hidden-skills/groundwork-design-system-extract/templates/design-system-extract-cache.md +19 -0
- package/src/hidden-skills/groundwork-designer/SKILL.md +108 -0
- package/src/hidden-skills/groundwork-designer/references/accessibility.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/ai-native-design.md +37 -0
- package/src/hidden-skills/groundwork-designer/references/design-review.md +29 -0
- package/src/hidden-skills/groundwork-designer/references/design-systems-and-tokens.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/interaction-and-motion.md +37 -0
- package/src/hidden-skills/groundwork-designer/references/layout-and-space.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/usability-and-ux.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/visual-craft.md +49 -0
- package/src/hidden-skills/groundwork-designer/sync-anchor.md +20 -0
- package/src/hidden-skills/groundwork-doc-sync/instructions.md +100 -0
- package/src/hidden-skills/groundwork-elicit/instructions.md +66 -0
- package/src/hidden-skills/groundwork-elicit/methods.md +65 -0
- package/src/hidden-skills/groundwork-infra-adopt/instructions.md +168 -0
- package/src/hidden-skills/groundwork-infra-adopt/templates/infra-adopt-cache.md +21 -0
- package/src/hidden-skills/groundwork-mvp/instructions.md +223 -0
- package/src/hidden-skills/groundwork-mvp/templates/mvp-cache.md +9 -0
- package/src/hidden-skills/groundwork-patch/instructions.md +40 -0
- package/src/hidden-skills/groundwork-persona/instructions.md +54 -0
- package/src/hidden-skills/groundwork-product/SKILL.md +102 -0
- package/src/hidden-skills/groundwork-product/references/ai-native-product.md +45 -0
- package/src/hidden-skills/groundwork-product/references/discovery-and-opportunity.md +38 -0
- package/src/hidden-skills/groundwork-product/references/product-risks.md +52 -0
- package/src/hidden-skills/groundwork-product/references/requirements-and-specs.md +39 -0
- package/src/hidden-skills/groundwork-product/references/scope-and-sequencing.md +35 -0
- package/src/hidden-skills/groundwork-product/references/shaping-and-appetite.md +48 -0
- package/src/hidden-skills/groundwork-product/references/success-metrics-and-signals.md +37 -0
- package/src/hidden-skills/groundwork-product/sync-anchor.md +19 -0
- package/src/hidden-skills/groundwork-product-brief/instructions.md +231 -0
- package/src/hidden-skills/groundwork-product-brief-extract/instructions.md +139 -0
- package/src/hidden-skills/groundwork-product-brief-extract/templates/product-brief-extract-cache.md +17 -0
- package/src/hidden-skills/groundwork-review/checklists/architecture.md +93 -0
- package/src/hidden-skills/groundwork-review/checklists/bet-pitch.md +94 -0
- package/src/hidden-skills/groundwork-review/checklists/decomposition.md +135 -0
- package/src/hidden-skills/groundwork-review/checklists/design-system.md +85 -0
- package/src/hidden-skills/groundwork-review/checklists/domain-entity.md +66 -0
- package/src/hidden-skills/groundwork-review/checklists/implementation-readiness.md +46 -0
- package/src/hidden-skills/groundwork-review/checklists/infrastructure.md +68 -0
- package/src/hidden-skills/groundwork-review/checklists/maturity.md +71 -0
- package/src/hidden-skills/groundwork-review/checklists/product-brief.md +69 -0
- package/src/hidden-skills/groundwork-review/checklists/technical-design.md +112 -0
- package/src/hidden-skills/groundwork-review/instructions.md +181 -0
- package/src/hidden-skills/groundwork-scaffold/instructions.md +254 -0
- package/src/hidden-skills/groundwork-scaffold/phases/01-ingestion-service-mapping.md +87 -0
- package/src/hidden-skills/groundwork-scaffold/phases/02-scaffolding-execution.md +15 -0
- package/src/hidden-skills/groundwork-scaffold/phases/03-service-documentation-api-stubs.md +100 -0
- package/src/hidden-skills/groundwork-scaffold/phases/04-infrastructure-verification.md +17 -0
- package/src/hidden-skills/groundwork-scaffold/phases/05-draft-review.md +19 -0
- package/src/hidden-skills/groundwork-scaffold/phases/06-commit.md +19 -0
- package/src/hidden-skills/groundwork-scaffold/templates/scaffold-cache.md +23 -0
- package/src/hidden-skills/groundwork-scan/instructions.md +164 -0
- package/src/hidden-skills/groundwork-scan/references/digest-schema.md +66 -0
- package/src/hidden-skills/groundwork-scan/references/exclusions.md +44 -0
- package/src/hidden-skills/groundwork-scan/templates/architecture-findings.md +42 -0
- package/src/hidden-skills/groundwork-scan/templates/design-findings.md +23 -0
- package/src/hidden-skills/groundwork-scan/templates/overview.md +26 -0
- package/src/hidden-skills/groundwork-scan/templates/product-findings.md +23 -0
- package/src/hidden-skills/groundwork-scan/templates/scan-state.json +19 -0
- package/src/hidden-skills/groundwork-stack-forge/instructions.md +150 -0
- package/src/hidden-skills/groundwork-stack-forge/references/authoring-engineer-skills.md +107 -0
- package/src/hidden-skills/groundwork-surface-activation/instructions.md +138 -0
- package/src/hidden-skills/groundwork-update/briefs/reconcile-worker.md +196 -0
- package/src/hidden-skills/groundwork-update/instructions.md +200 -0
- package/src/hidden-skills/groundwork-writer/SKILL.md +278 -0
- package/src/hidden-skills/maturity-model.md +125 -0
- package/src/hidden-skills/operating-contract.md +400 -0
- package/src/hidden-skills/repo-map-schema.md +90 -0
- package/src/hidden-skills/templates/adr.md +57 -0
- package/src/hidden-skills/templates/capability-ports.md +71 -0
- package/src/hidden-skills/templates/discovery-notes.md +33 -0
- package/src/hidden-skills/templates/domain-entity.md +80 -0
- package/src/hidden-skills/templates/gap-ledger.md +21 -0
- package/src/hidden-skills/templates/handoff.md +37 -0
- package/src/hidden-skills/templates/maturity.md +39 -0
- package/src/hidden-skills/templates/surfaces.md +207 -0
- package/src/skills/groundwork-check/SKILL.md +56 -0
- package/src/skills/groundwork-check/instructions.md +70 -0
- package/src/skills/groundwork-orchestrator/SKILL.md +176 -0
- package/src/skills/groundwork-orchestrator/workflow-index.md +50 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Visual Language & Surfaces
|
|
2
|
+
|
|
3
|
+
This reference is about **technique** — how to consume the design system and how the surface layer composes depth. It carries **no fixed palette, type, or surface catalogue**. Every concrete value (colours, type scale, shadow stacks, blur radii, gradients, surface treatments) is a per-app decision that lives in `docs/design-system.md` and is projected from `.groundwork/config/brand-tokens.json` into `app/brand.css` and surfaced through `app/globals.css` as token utilities. Read the design system before any visual work; never invent values here.
|
|
4
|
+
|
|
5
|
+
## Where the values live
|
|
6
|
+
|
|
7
|
+
The nextjs-app generator projects the design system's `visual` block into `app/brand.css` (regenerated, never hand-edited). `app/globals.css` maps those values into Tailwind token utilities and surface classes. The chain:
|
|
8
|
+
|
|
9
|
+
| Layer | Owns | You touch |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| `docs/design-system.md` | The human source of truth — palette, type, elevation, surfaces, motion, at the depth standard | Read it |
|
|
12
|
+
| `.groundwork/config/brand-tokens.json` `visual` block | The machine projection of those decisions | Read it; never hand-edit |
|
|
13
|
+
| `app/brand.css` (generated) | `--gw-*` values + the shadcn structural vars, light and dark | Never hand-edit |
|
|
14
|
+
| `app/globals.css` | Token-utility mappings (`@theme`) + surface classes | Extend structure only, never bake values |
|
|
15
|
+
| Your components | Consume token utilities and surface classes | Here |
|
|
16
|
+
|
|
17
|
+
**Consume tokens, never literals.** A raw hex/length/shadow/blur/gradient in a component bypasses the design system and fails the token-conformance lint (`eslint.config.mjs`). If you need a raw value, reference the projected custom property (`var(--gw-shadow-mid)`, or the Tailwind var form `shadow-(--gw-shadow-mid)`) — never a literal recipe.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Colour (OKLCH)
|
|
22
|
+
|
|
23
|
+
The design system defines colour in OKLCH — perceptually uniform lightness, so a colour at `L=0.7` reads equally bright across hues (unlike HSL). **Hex, RGB, and HSL literals are forbidden in components.**
|
|
24
|
+
|
|
25
|
+
Consume colour through the projected token utilities — `bg-background`, `text-foreground`, `bg-primary`, `text-muted-foreground`, `border-border`, `bg-destructive`, the `chart-*` roles — all backed by the brand's palette in `brand.css`. The semantic role of each (which hue means success, error, accent) is the design system's call, recorded there; honour it rather than reaching for a generic "green."
|
|
26
|
+
|
|
27
|
+
**Dynamic opacity** — derive a translucent variant of any token without a new variable, via the relative colour function:
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
/* technique, not a value: any projected colour var works */
|
|
31
|
+
background-color: oklch(from var(--background) l c h / 0.72);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This keeps one source of truth per colour while allowing per-surface translucency.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Typography
|
|
39
|
+
|
|
40
|
+
The design system commits a full type scale (families, and per-role size, line-height, weight, tracking) at `docs/design-system.md`; the per-role micro is projected into `--gw-text-<role>-{size,line,weight,tracking}`. Consume the scale through the project's type utilities or those custom properties. Do not invent ad-hoc font sizes — if content does not fit a role, the layout needs adjustment, not a new size. Where figures must align in columns, use the projected tabular-numerals treatment rather than the proportional default.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Spacing (8pt grid)
|
|
45
|
+
|
|
46
|
+
The design system's spacing scale derives from an 8px base (4px is the optical sub-grid). Consume it through the spacing-scale utilities (`p-4`, `gap-6`, `px-8`) — arbitrary length values (`p-[12px]`) fail lint. Reserve the 4px sub-grid step for optical alignment (icon centring, badge offsets, hairline adjustments), not general spacing. Related elements sit closer than unrelated ones: internal spacing is always tighter than the gap between groups.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Surface depth — the technique
|
|
51
|
+
|
|
52
|
+
High-end surfaces read as modelled material, not flat boxes. Four techniques compose that depth. The design system decides the *values*; you apply them through the projected tokens and surface classes.
|
|
53
|
+
|
|
54
|
+
- **Multi-layer shadow.** A single drop shadow reads flat. Depth comes from stacking several shadows — a tight contact layer, a mid ambient layer, a wide diffuse layer — with alpha tapering as each widens, tinted toward the background rather than pure black. The stacks are projected as `--gw-shadow-low/mid/high` and surfaced as the `shadow-low/mid/high` utilities (theme-aware: the dark theme carries deeper variants).
|
|
55
|
+
- **Backdrop blur.** Translucent surfaces over content need `backdrop-filter: blur(...)` (always paired with the `-webkit-` prefix). Blur radii are projected as `--gw-blur-subtle/standard/heavy` and the `backdrop-blur-*` utilities.
|
|
56
|
+
- **Concentric radii.** When nesting rounded elements, keep curves harmonious: `inner radius = outer radius − padding`. Use the radius tokens (`rounded-lg`, `rounded-xl`), not literal pixel radii.
|
|
57
|
+
- **Ambient gradient.** A barely-perceptible mesh/aurora gradient (opacity well under ~0.15, fading to transparent, layered over a solid fallback) adds warmth to large surfaces. Recipes are projected as gradient tokens; the hero surface composes one.
|
|
58
|
+
|
|
59
|
+
### Surface utilities
|
|
60
|
+
|
|
61
|
+
The per-app surface vocabulary — the glass/elevated/hero treatments that used to be a fixed catalogue — is projected from the design system's `surface` tokens into composite classes in `globals.css`. Apply them; do not re-author the recipe:
|
|
62
|
+
|
|
63
|
+
| Class | For | Composes |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| `.surface-glass` | Regular content cards, panels, list items | standard blur + glass tint + hairline border + `shadow-mid` |
|
|
66
|
+
| `.surface-elevated` | Modals, dialogs, command palette, popovers | heavy blur + denser tint + border + `shadow-high` |
|
|
67
|
+
| `.surface-hero` | Dashboard hero metric, key insight, primary KPI | standard blur + hero tint + ambient gradient + `shadow-high` |
|
|
68
|
+
|
|
69
|
+
Need a surface the project has not defined? Compose it from the same tokens (`var(--gw-shadow-*)`, `var(--gw-blur-*)`, the palette vars) or add the treatment to the design system and regenerate — never hardcode a one-off stack in a component.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Sync Anchor
|
|
2
|
+
|
|
3
|
+
This file pins the principle files this skill embeds. When any listed file
|
|
4
|
+
changes, this skill must be reviewed in the same commit. CI verifies the
|
|
5
|
+
hashes match.
|
|
6
|
+
|
|
7
|
+
| Principle file | SHA-256 | Last reviewed |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| src/generators/nextjs-app/docs/principles/stack/typescript/frontend.md | 98232d067ad03c08d6c1ca5f2caec30e7c3400da55c3afb7754482bc121d7554 | 2026-05-26 |
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: groundwork-python-engineer
|
|
3
|
+
description: >
|
|
4
|
+
Implement and review Python service changes using self-contained engineering
|
|
5
|
+
references and the current repository as the source of truth. Use for Python
|
|
6
|
+
backend handlers, services, providers, domain models, ML pipelines, FastAPI
|
|
7
|
+
routes, async patterns, dependency injection, tests, resilience, or service
|
|
8
|
+
architecture. This skill is the execution router for Python backend work: it
|
|
9
|
+
loads reference docs selectively, preserves core/edge boundaries and the
|
|
10
|
+
inward dependency rule, coordinates with adjacent skills, and verifies
|
|
11
|
+
changes against contracts and tests. Use
|
|
12
|
+
this skill whenever the user works in a Python service directory or asks about
|
|
13
|
+
Python backend / ML engineering, even if they do not explicitly ask for a
|
|
14
|
+
"python engineer."
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Python Engineer
|
|
18
|
+
|
|
19
|
+
Python backend execution router for service repositories. Durable engineering guidance lives in `references/`; this skill decides what to load, how to route the task, what repository facts to verify, and which safety gates apply.
|
|
20
|
+
|
|
21
|
+
## Operating Contract
|
|
22
|
+
|
|
23
|
+
1. Load reference docs from `references/` for architectural and implementation guidance. Treat the current repository's code, specs, and generated contracts as the source of truth for naming, structure, and behavior.
|
|
24
|
+
2. Inspect the current repository before naming packages, commands, import paths, schemas, or generated files.
|
|
25
|
+
3. Load the smallest reference set that explains the task. Add more context only when the task crosses a boundary.
|
|
26
|
+
4. Preserve the service's dependency direction and public contracts. Code implements OpenAPI, database migrations, event schemas, and documented architecture — it does not invent them.
|
|
27
|
+
5. Coordinate with adjacent skills when another skill owns the primary decision surface.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Code intelligence (repo map + Serena)
|
|
32
|
+
|
|
33
|
+
GroundWork gives you a deterministic **repo map** (`npx groundwork-method repo-map` — tree-sitter import edges + PageRank centrality, cached to `.groundwork/cache/repo-map.json`) and the **Serena** MCP server (LSP-backed symbol navigation and editing), registered at init. Orient before reading widely: refresh the map, read its `centrality` ranking to find the hubs, then use Serena to navigate them (`get_symbols_overview` / `find_symbol` / `find_referencing_symbols`) and make reference-aware edits (`replace_symbol_body` / `rename`). Full workflow and the graceful-degradation contract live in `.groundwork/skills/code-intelligence.md`; fall back to ordinary reads and edits when they are unavailable.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Required First Checks
|
|
38
|
+
|
|
39
|
+
Before non-trivial Python implementation or review work:
|
|
40
|
+
|
|
41
|
+
| Check | Why |
|
|
42
|
+
|---|---|
|
|
43
|
+
| Service package layout and nearby examples for the touched layer | Prevents inventing structure that already has a convention |
|
|
44
|
+
| `pyproject.toml` for Python version and dependencies | Avoids version-specific advice that contradicts the project |
|
|
45
|
+
| OpenAPI spec (if HTTP behavior changes) | HTTP contracts are generated — code must match the spec |
|
|
46
|
+
| Pydantic models for domain and request/response types | Boundary validation is the code; must not be duplicated |
|
|
47
|
+
| Event specs (AsyncAPI, Protobuf) for async behavior | Event types drive code generation downstream |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Context Routing
|
|
52
|
+
|
|
53
|
+
Load only the rows relevant to the current task. Reference files are in the skill's `references/` directory.
|
|
54
|
+
|
|
55
|
+
| Task shape | Reference to load |
|
|
56
|
+
|---|---|
|
|
57
|
+
| Any non-trivial service change | `architecture.md`, `implementation-patterns.md` |
|
|
58
|
+
| Async, event loop, TaskGroup, lifespan, background tasks | `async-patterns.md` |
|
|
59
|
+
| Layer placement, new boundary, dependency direction | `architecture.md` |
|
|
60
|
+
| FastAPI endpoint, route handler, inbound defenses | `architecture.md`, `api-standards.md` |
|
|
61
|
+
| Idempotency, pagination, CORS, load shedding | `api-standards.md` |
|
|
62
|
+
| Database schemas, migrations, test isolation, DB sessions | `database.md` |
|
|
63
|
+
| ML pipeline, inference, embedding, RAG, streaming | `ml-pipelines.md` |
|
|
64
|
+
| ML systems architecture, model serving, evals, prompts | `ml-systems-ai-engineering.md` |
|
|
65
|
+
| AI engineering, context design, agent architecture | `ml-systems-ai-engineering.md` |
|
|
66
|
+
| MCP server, tool/resource design, agent interfaces | `documentation-mcp.md` |
|
|
67
|
+
| Resilience — timeouts, retries, circuit breakers, health probes | `resilience.md` |
|
|
68
|
+
| Graceful shutdown, degradation, lifespan management | `resilience.md`, `async-patterns.md` |
|
|
69
|
+
| Observability — tracing, structured logging, metrics | `observability.md` |
|
|
70
|
+
| Tests, quality gates, coverage strategy, fixture design | `testing.md` |
|
|
71
|
+
| Code documentation, docstrings, Pydantic Field docs | `documentation-mcp.md` |
|
|
72
|
+
| Error handling, exception hierarchy, domain errors | `implementation-patterns.md` |
|
|
73
|
+
| Dependency injection, Protocol ports, wiring | `implementation-patterns.md`, `architecture.md`, `database.md` |
|
|
74
|
+
| Capability port + provider (LLM etc.), generated adapter shape, bare-port bet, `add-capability` | `capability-ports.md`, `architecture.md` |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Skill Handoffs
|
|
79
|
+
|
|
80
|
+
Use the smallest collaborating set. Keep the Python engineer as lead when the work is mainly Python implementation inside a service directory.
|
|
81
|
+
|
|
82
|
+
| Condition | Hand off to |
|
|
83
|
+
|---|---|
|
|
84
|
+
| Endpoint shape, OpenAPI, error envelope, pagination, idempotency | API architect / API design skill |
|
|
85
|
+
| Schema, migrations, indexes, query plans, vector search | Database / Postgres design skill |
|
|
86
|
+
| Streaming, Pub/Sub, WebSockets, event schemas, fan-out | Real-time / event architecture skill |
|
|
87
|
+
| Test strategy, CI quality gates, contract tests, flake reduction | Test architecture skill |
|
|
88
|
+
| Deployment, Cloud Run, Docker, CI/CD, observability infra | Platform engineering skill |
|
|
89
|
+
| Go backend coordination, inter-service contracts | Go engineer skill |
|
|
90
|
+
|
|
91
|
+
If the collaborating skill does not exist in the project, handle the concern inline but flag it as outside this skill's primary scope.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Execution Checklist
|
|
96
|
+
|
|
97
|
+
1. **Identify the touched contract surface** — domain behavior, HTTP contract, event contract, ML pipeline, or tests.
|
|
98
|
+
2. **Load minimal routed references** and inspect nearby code before designing.
|
|
99
|
+
3. **State important inferences** when guidance comes from general Python knowledge rather than project-specific docs or code.
|
|
100
|
+
4. **Implement within existing conventions** — do not create new layer boundaries without evidence from docs or existing code.
|
|
101
|
+
5. **Run targeted tests/checks** when feasible. If not feasible, explain the blocker and name the exact command to run later.
|
|
102
|
+
6. **Summarize** references consulted, files changed, verification performed, and residual risks.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Safety Gates
|
|
107
|
+
|
|
108
|
+
### Naming and Boundaries
|
|
109
|
+
- Do not invent package paths, command names, contract files, or service boundaries. Verify them in the repository first.
|
|
110
|
+
- Do not create new layer boundaries without evidence from docs or existing code.
|
|
111
|
+
|
|
112
|
+
### Layer Discipline
|
|
113
|
+
- Do not put business decisions in entrypoints, adapters, or middleware when the architecture expects them in service code.
|
|
114
|
+
- Do not leak adapter-specific types across the core/edge boundary. If an SDK response type appears in a core port, the architecture is broken.
|
|
115
|
+
- FastAPI `Depends`, `Request`, `Session` objects never enter the Service or Domain layers.
|
|
116
|
+
- Always use `pydantic-settings` to validate configuration at startup.
|
|
117
|
+
|
|
118
|
+
### Inbound Defenses & API Standards
|
|
119
|
+
- Do not use offset/limit pagination for collections; enforce cursor-based pagination.
|
|
120
|
+
- Do not allow mutating endpoints (POST/PATCH) without an `Idempotency-Key` implementation to prevent duplicate side-effects.
|
|
121
|
+
- Do not omit inbound concurrency limits (load shedding); shed load rather than queuing indefinitely.
|
|
122
|
+
- Never use wildcard CORS (`allow_origins=["*"]`).
|
|
123
|
+
|
|
124
|
+
### Error Handling
|
|
125
|
+
- Do not log and re-raise the same error at multiple layers. Wrap errors with domain exceptions at the adapter boundary and handle at the entrypoint.
|
|
126
|
+
- Map SDK errors to domain exception types before retrying.
|
|
127
|
+
|
|
128
|
+
### Async Discipline
|
|
129
|
+
- Do not block the event loop. Use `asyncio.to_thread` for synchronous operations.
|
|
130
|
+
- Do not use bare `asyncio.create_task`. Use `asyncio.TaskGroup`.
|
|
131
|
+
- Do not initialise async resources at module level. Use FastAPI `lifespan`.
|
|
132
|
+
|
|
133
|
+
### Contract & Data Integrity
|
|
134
|
+
- Do not change HTTP behavior without checking the OpenAPI source.
|
|
135
|
+
- Do not change Pydantic models that are part of the public API without checking downstream consumers.
|
|
136
|
+
- Do not add or modify event types without updating the corresponding event spec.
|
|
137
|
+
- Do not use manual UP/DOWN migrations; enforce declarative schema management (e.g., `schema.sql` + diffing engine).
|
|
138
|
+
|
|
139
|
+
### ML Pipeline Integrity
|
|
140
|
+
- Do not trust model outputs without boundary validation (shape, length, content).
|
|
141
|
+
- Do not hardcode confidence thresholds — use configuration.
|
|
142
|
+
- Do not embed one item at a time — batch API calls.
|
|
143
|
+
- Prompts are code. They live in version control and are covered by evals.
|
|
144
|
+
|
|
145
|
+
### Generation
|
|
146
|
+
- Do not run code generation manually outside documented generation flows.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Quick Reference
|
|
151
|
+
|
|
152
|
+
### Domain Error Pattern
|
|
153
|
+
|
|
154
|
+
| Exception | HTTP | Use |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `NotFoundError` | 404 | Resource lookup miss |
|
|
157
|
+
| `UnauthorizedError` | 401 | Missing/invalid auth |
|
|
158
|
+
| `ForbiddenError` | 403 | Valid auth, insufficient permission |
|
|
159
|
+
| `ConflictError` | 409 | Duplicate resource |
|
|
160
|
+
| `ValidationError` | 422 | Field-level validation |
|
|
161
|
+
| `TransientInferenceError` | 503 | Retriable provider failure |
|
|
162
|
+
| `PermanentInferenceError` | 400/500 | Non-retriable provider failure |
|
|
163
|
+
|
|
164
|
+
### Test Strategy
|
|
165
|
+
|
|
166
|
+
| Tier | What | Infrastructure |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| Service test (default) | HTTP → Service → Adapter | Testcontainers + `dependency_overrides` |
|
|
169
|
+
| Unit test (reserved) | Complex domain logic | None |
|
|
170
|
+
| System test (minimal) | Bootstrap + golden path | Full live stack |
|
|
171
|
+
|
|
172
|
+
### Dependency Injection
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
# Port — in src/<package>/core/ports.py
|
|
176
|
+
class Processor(Protocol):
|
|
177
|
+
async def process(self, uri: str) -> Result: ...
|
|
178
|
+
|
|
179
|
+
# Adapter — in src/<package>/adapters/
|
|
180
|
+
class ConcreteProcessor:
|
|
181
|
+
async def process(self, uri: str) -> Result: ...
|
|
182
|
+
|
|
183
|
+
# Wiring — in entrypoints/ or dependencies.py, typed as the port
|
|
184
|
+
def get_service() -> ProcessingService:
|
|
185
|
+
return ProcessingService(processor=ConcreteProcessor())
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Output Expectations
|
|
191
|
+
|
|
192
|
+
- Name the references or source files that informed non-obvious decisions.
|
|
193
|
+
- Separate verified repository facts from recommendations based on general Python knowledge.
|
|
194
|
+
- Provide concrete verification commands and results.
|
|
195
|
+
- For code reviews: findings first, ordered by severity, with file references and missing-test risks.
|
|
196
|
+
- For implementation work: changed files, behavior, tests, and follow-up risks.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# API Standards & Inbound Defenses
|
|
2
|
+
|
|
3
|
+
Every Python service must expose a hardened, predictable API surface. Implement these Day-2 operational requirements at the FastAPI entrypoint layer.
|
|
4
|
+
|
|
5
|
+
## 1. Idempotency
|
|
6
|
+
|
|
7
|
+
Mutating endpoints (`POST`, `PATCH`) must be idempotent to allow safe client retries; `PUT` is idempotent by HTTP semantics and needs no key.
|
|
8
|
+
|
|
9
|
+
- Require an `Idempotency-Key` header on mutating requests.
|
|
10
|
+
- Intercept the key in middleware or a FastAPI dependency before business logic executes.
|
|
11
|
+
- Store the intent and the final response in a fast, persistent store (e.g., Redis).
|
|
12
|
+
- If a request arrives with a known key and is `IN_PROGRESS`, return `409 Conflict`.
|
|
13
|
+
- If a request arrives with a known key and is `COMPLETED`, return the cached response immediately.
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from fastapi import Header, Depends
|
|
17
|
+
|
|
18
|
+
async def verify_idempotency(
|
|
19
|
+
idempotency_key: str = Header(..., min_length=16)
|
|
20
|
+
):
|
|
21
|
+
# Check Redis/DB. If completed, raise a custom exception that
|
|
22
|
+
# an exception handler catches to return the cached response.
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
@router.post("/items")
|
|
26
|
+
async def create_item(
|
|
27
|
+
body: ItemCreate,
|
|
28
|
+
_: None = Depends(verify_idempotency)
|
|
29
|
+
) -> ItemResponse:
|
|
30
|
+
# Business logic executes only once per key
|
|
31
|
+
pass
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 2. Cursor-Based Pagination
|
|
35
|
+
|
|
36
|
+
Never use offset/limit pagination for collections. Offset pagination scales poorly (O(N) database scans) and skips/duplicates items if the underlying dataset changes during iteration.
|
|
37
|
+
|
|
38
|
+
- Always return a `cursor` (usually a base64-encoded string representing the last seen ID and sort column).
|
|
39
|
+
- Include `has_next` boolean.
|
|
40
|
+
- Use generic Pydantic wrappers for paginated responses.
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from typing import Generic, TypeVar
|
|
44
|
+
from pydantic import BaseModel
|
|
45
|
+
|
|
46
|
+
T = TypeVar("T")
|
|
47
|
+
|
|
48
|
+
class PaginatedList(BaseModel, Generic[T]):
|
|
49
|
+
items: list[T]
|
|
50
|
+
next_cursor: str | None
|
|
51
|
+
has_next: bool
|
|
52
|
+
|
|
53
|
+
@router.get("/items")
|
|
54
|
+
async def list_items(cursor: str | None = None, limit: int = 50) -> PaginatedList[ItemResponse]:
|
|
55
|
+
# Pass cursor down to the repository port
|
|
56
|
+
pass
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 3. Load Shedding & Concurrency Limits
|
|
60
|
+
|
|
61
|
+
Do not allow an API to queue requests indefinitely until memory is exhausted or timeouts cascade.
|
|
62
|
+
|
|
63
|
+
- Implement an inbound concurrency limit (e.g., using a FastAPI middleware that acquires an `asyncio.Semaphore`).
|
|
64
|
+
- When the semaphore is exhausted, immediately shed load by returning `503 Service Unavailable`.
|
|
65
|
+
- This ensures the service remains responsive for health checks and active requests, rather than becoming a black hole.
|
|
66
|
+
|
|
67
|
+
## 4. CORS Configuration
|
|
68
|
+
|
|
69
|
+
Configure `CORSMiddleware` explicitly. Never use `allow_origins=["*"]` in production.
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
73
|
+
|
|
74
|
+
app.add_middleware(
|
|
75
|
+
CORSMiddleware,
|
|
76
|
+
allow_origins=settings.CORS_ALLOWED_ORIGINS, # Loaded from env
|
|
77
|
+
allow_credentials=True,
|
|
78
|
+
allow_methods=["GET", "POST", "PATCH", "DELETE"],
|
|
79
|
+
allow_headers=["Authorization", "Content-Type", "Idempotency-Key"],
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Anti-Patterns
|
|
84
|
+
|
|
85
|
+
- **Offset pagination.** `?limit=50&offset=1000` requires the database to scan and discard 1,000 rows.
|
|
86
|
+
- **Ignoring idempotency keys.** Clients will retry on timeouts, causing duplicate side effects (e.g., double charges, duplicate records).
|
|
87
|
+
- **Queuing without bounds.** A service processing 10 req/sec should reject the 100th concurrent request rather than queuing it for 10 seconds.
|
|
88
|
+
- **Wildcard CORS.** Leaks cross-origin data. Always restrict to known frontends.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# A Pure Core, Swappable Edges (Python)
|
|
2
|
+
|
|
3
|
+
## Dependency Rule
|
|
4
|
+
|
|
5
|
+
Dependencies flow inward. The core never imports from the edge. `import-linter` (a `[tool.importlinter]` contract in `pyproject.toml`) makes this a real gate: it forbids `<package>.core` (and `<package>.core.*`) from importing `<package>.adapters`, `<package>.entrypoints`, `fastapi`, or `sqlalchemy`, and a `<package>.core` → `<package>.adapters` import fails `lint-imports`.
|
|
6
|
+
|
|
7
|
+
## Where code lives
|
|
8
|
+
|
|
9
|
+
`src/` holds the importable package `src/<package>/` (src-layout); `<package>` is the service name in snake_case. The pieces (paths relative to `src/<package>/`):
|
|
10
|
+
|
|
11
|
+
| Zone | Location | Depends on | Contains |
|
|
12
|
+
|---|---|---|---|
|
|
13
|
+
| **Domain** | `src/<package>/core/domain` | Nothing (stdlib + Pydantic only) | Pydantic/dataclass entities, value objects, exceptions, constants |
|
|
14
|
+
| **Ports** | `src/<package>/core/ports.py` (+ per-capability modules like `src/<package>/core/llm.py`) | Domain only | `typing.Protocol` (default) or `abc.ABC` definitions describing the capabilities the core consumes |
|
|
15
|
+
| **Services** | `src/<package>/core/service` | Domain + Ports | Use-case orchestration, workflow coordination |
|
|
16
|
+
| **Adapters** | `src/<package>/adapters/` | Domain + Ports | Concrete implementations (Postgres, external APIs, message brokers) |
|
|
17
|
+
| **Entrypoints** | `src/<package>/entrypoints/` | Domain + Services | FastAPI routes, CLI, Pub/Sub consumers, MCP servers |
|
|
18
|
+
|
|
19
|
+
## Structural Invariants
|
|
20
|
+
|
|
21
|
+
- The Domain imports no framework, no SDK, no database driver, no HTTP library. Pydantic and stdlib only.
|
|
22
|
+
- Ports define _what_ (e.g., `store`, `transcribe`), never _how_. Signatures use Domain entities exclusively.
|
|
23
|
+
- Ports use domain names: `publish(msg: Message)`, not `send_to_sqs(msg: Message)`.
|
|
24
|
+
- Services depend on ports (Protocols), not concrete adapters. Return concrete Domain objects.
|
|
25
|
+
- Adapters map external SDK responses into Domain entities. Catch library-specific errors and raise Domain exceptions.
|
|
26
|
+
- Entrypoints validate inputs, map request schemas to Domain objects, and delegate all business decisions to Services.
|
|
27
|
+
- All concrete adapter-to-service wiring happens at the outermost edge (entrypoint startup or a dedicated `dependencies.py` / `container.py`).
|
|
28
|
+
|
|
29
|
+
## Dependency Injection
|
|
30
|
+
|
|
31
|
+
- **Constructor injection** via `__init__` for all dependencies.
|
|
32
|
+
- **Explicit lifecycles**: initialise database clients in FastAPI's `lifespan` context manager, not at module level.
|
|
33
|
+
- **No DI frameworks**: wiring is manual, explicit, and visible at the composition root.
|
|
34
|
+
|
|
35
|
+
## Integrity Testing
|
|
36
|
+
|
|
37
|
+
### Bootstrap Verification
|
|
38
|
+
A test in `tests/system/test_bootstrap.py` initialises the full dependency tree. Catches missing env vars and wiring failures before production.
|
|
39
|
+
|
|
40
|
+
### Golden Path System Tests
|
|
41
|
+
Run a live instance against real infrastructure via Testcontainers. Zero mocks. Verify the critical success paths end-to-end.
|
|
42
|
+
|
|
43
|
+
## Engineering Standards
|
|
44
|
+
|
|
45
|
+
1. **Pydantic everywhere.** Use Pydantic for all data boundaries (request/response and domain).
|
|
46
|
+
2. **Structured logging.** Use `structlog` or equivalent — never bare `print`.
|
|
47
|
+
3. **Acyclic dependencies.** Import cycles are an immediate signal of leaked layer responsibilities.
|
|
48
|
+
4. **Strict boundaries.** FastAPI `Depends`, `Request`, `Session` objects never enter the Service or Domain layers.
|
|
49
|
+
5. **Clean containers.** Always call `container.stop()` or equivalent in pytest fixtures.
|
|
50
|
+
|
|
51
|
+
## Anti-Patterns
|
|
52
|
+
|
|
53
|
+
- **Framework-coupled domain.** If the core imports FastAPI or SQLAlchemy, it is broken.
|
|
54
|
+
- **Leaky ports.** A port with SDK types in its signature is an adapter in disguise.
|
|
55
|
+
- **Anaemic domain models.** Data structs with no behaviour and a thick service.
|
|
56
|
+
- **Over-layering.** Five layers of DTO translation. Adapters are thin.
|
|
57
|
+
- **Layer-skipping.** Entrypoints talking directly to adapters.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Async Patterns
|
|
2
|
+
|
|
3
|
+
## The One Rule: Never Block the Event Loop
|
|
4
|
+
|
|
5
|
+
Any synchronous call longer than ~1ms inside an `async def` stalls every other coroutine. Symptoms: random, unrelated timeouts across the service.
|
|
6
|
+
|
|
7
|
+
Blocking calls — file I/O, model loading, `time.sleep`, synchronous SDK methods — must run in a thread:
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
import asyncio
|
|
11
|
+
|
|
12
|
+
result = await asyncio.to_thread(blocking_function, arg1, arg2)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Structured Concurrency with TaskGroup
|
|
16
|
+
|
|
17
|
+
`asyncio.TaskGroup` is the only primitive that guarantees all tasks complete — or are cancelled — before control returns to the caller:
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
async def process_item(item_id: str) -> ProcessedResult:
|
|
21
|
+
async with asyncio.TaskGroup() as tg:
|
|
22
|
+
primary_task = tg.create_task(primary_process(item_id))
|
|
23
|
+
secondary_task = tg.create_task(secondary_process(item_id))
|
|
24
|
+
|
|
25
|
+
return ProcessedResult(
|
|
26
|
+
primary=primary_task.result(),
|
|
27
|
+
secondary=secondary_task.result(),
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
If either task raises, `TaskGroup` cancels the sibling and re-raises. No orphaned tasks, no leaked resources.
|
|
32
|
+
|
|
33
|
+
**Never use bare `asyncio.create_task`.** The event loop holds only a weak reference — if the caller exits, the task is garbage collected mid-execution:
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
# Wrong — task may be silently dropped
|
|
37
|
+
asyncio.create_task(publish_event(event))
|
|
38
|
+
|
|
39
|
+
# Correct — task lifetime bound to TaskGroup scope
|
|
40
|
+
async with asyncio.TaskGroup() as tg:
|
|
41
|
+
tg.create_task(publish_event(event))
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Route Handlers
|
|
45
|
+
|
|
46
|
+
All route handlers are `async def`. Synchronous `def` handlers are threaded by FastAPI's executor — this makes the async/sync boundary invisible and causes subtle performance issues.
|
|
47
|
+
|
|
48
|
+
## Background Tasks
|
|
49
|
+
|
|
50
|
+
Use FastAPI's `BackgroundTasks` for post-response work:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from fastapi import BackgroundTasks
|
|
54
|
+
|
|
55
|
+
@router.post("/process")
|
|
56
|
+
async def process_endpoint(
|
|
57
|
+
request: ProcessRequest,
|
|
58
|
+
background_tasks: BackgroundTasks,
|
|
59
|
+
) -> ProcessResponse:
|
|
60
|
+
result = await service.process(request.input_url)
|
|
61
|
+
background_tasks.add_task(publish_completed_event, result.id)
|
|
62
|
+
return ProcessResponse.from_domain(result)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Application Lifespan
|
|
66
|
+
|
|
67
|
+
Initialise shared resources in the FastAPI `lifespan` context manager:
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from contextlib import asynccontextmanager
|
|
71
|
+
from fastapi import FastAPI
|
|
72
|
+
|
|
73
|
+
@asynccontextmanager
|
|
74
|
+
async def lifespan(app: FastAPI):
|
|
75
|
+
db_pool = await create_db_pool()
|
|
76
|
+
app.state.db = db_pool
|
|
77
|
+
yield
|
|
78
|
+
await db_pool.close()
|
|
79
|
+
|
|
80
|
+
app = FastAPI(lifespan=lifespan)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Never initialise clients at module level.** Module-level runs at import time, before env vars load, and cannot be awaited.
|
|
84
|
+
|
|
85
|
+
## Toolchain
|
|
86
|
+
|
|
87
|
+
`uv` manages all Python tooling:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uv run pytest # Run tests
|
|
91
|
+
uv add httpx # Add a dependency
|
|
92
|
+
uv sync # Sync from lockfile
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The lockfile (`uv.lock`) is committed. Every developer and CI run resolves identical trees.
|
|
96
|
+
|
|
97
|
+
## Anti-Patterns
|
|
98
|
+
|
|
99
|
+
- **Blocking the event loop.** Use `asyncio.to_thread` for blocking operations.
|
|
100
|
+
- **Bare `asyncio.create_task`.** Creates untracked tasks that can be silently dropped.
|
|
101
|
+
- **Synchronous `def` route handlers.** Write `async def` so the boundary is explicit.
|
|
102
|
+
- **Module-level async initialisation.** `asyncio.run()` at import time conflicts with FastAPI's loop.
|
|
103
|
+
- **`asyncio.sleep` as retry delay.** Use `tenacity` with async backoff.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Capability Ports & Providers
|
|
2
|
+
|
|
3
|
+
GroundWork scaffolds external capabilities (LLM inference, and the same pattern for any future capability) as **a port the core owns plus a selectable provider that satisfies it**. When you read or hand-write one of these, match the generated shape exactly — the generator and your code are the same contract.
|
|
4
|
+
|
|
5
|
+
## The model
|
|
6
|
+
|
|
7
|
+
- A **capability** is a port: a `Protocol` the core owns, in `src/<package>/core/` (e.g. `src/<package>/core/llm.py`).
|
|
8
|
+
- A **provider** is the vendor that satisfies the capability; its implementation is the adapter, in `src/<package>/adapters/` (e.g. `src/<package>/adapters/llm.py`). Choosing a provider selects the adapter wired in at the edge; the port and its callers never change.
|
|
9
|
+
- Each provider declares a **footprint** — exactly one of `env`, `compose-service`, `runner`, `none` — which is the only thing that varies the operational cost. Infrastructure is a consequence of the provider, not a default.
|
|
10
|
+
|
|
11
|
+
| Footprint | Means | Materializes as |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| `env` | config only (a hosted API) | env vars in `.env.example`, no infra |
|
|
14
|
+
| `compose-service` | a container (a self-hosted server) | a service in `docker-compose.yml` |
|
|
15
|
+
| `runner` | a host process | an entry in `.dev/dev.config.json` runners |
|
|
16
|
+
| `none` | the bare port — a bet | port + stub + conformance test, nothing else |
|
|
17
|
+
|
|
18
|
+
## Generated shape (LLM reference family)
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
src/<package>/core/llm.py # the port — a runtime_checkable Protocol, core-owned
|
|
22
|
+
src/<package>/adapters/llm.py # the adapter — one provider's implementation
|
|
23
|
+
tests/contracts/test_llm.py # the contract test
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **Port** — a `@runtime_checkable` `Protocol`, no SDK type in its signature. It lives in its own module (`src/<package>/core/llm.py`), separate from the shared `src/<package>/core/ports.py`, so `add-capability` can generate it independently.
|
|
27
|
+
```python
|
|
28
|
+
@runtime_checkable
|
|
29
|
+
class TextGenerator(Protocol):
|
|
30
|
+
async def generate_text(self, prompt: str, max_tokens: int = 100) -> str: ...
|
|
31
|
+
```
|
|
32
|
+
- **Adapter** — `LLMClient` in `src/<package>/adapters/llm.py`, implements the protocol structurally (no `class LLMClient(TextGenerator)` inheritance needed). Reads config from `settings`, wraps calls in `tenacity` retry + a circuit breaker, raises the domain's `TransientInferenceError` / `PermanentInferenceError`. A hosted provider adds its SDK to `pyproject.toml`; a self-hosted one uses the OpenAI-compatible client.
|
|
33
|
+
- **Wiring** — provide `LLMClient()` from your composition root (e.g. `dependencies.py get_text_generator`) typed as the `TextGenerator` port from `core.llm`. Never let a service depend on the concrete adapter.
|
|
34
|
+
|
|
35
|
+
## The `none` bare port (a bet)
|
|
36
|
+
|
|
37
|
+
`--provider none` ships the port, a stub adapter that raises `NotImplementedError`, and a **strict-xfail** contract test. The test is kept `@pytest.mark.xfail(strict=True)` so a fresh scaffold stays green *and* flips red the moment the adapter starts working — that is the open-bet marker: the contract is fixed, the implementation is owed. Implement the adapter behind the existing port to cash it, then drop the xfail. The conformance check is `issubclass(LLMClient, TextGenerator)` — no construction, no network.
|
|
38
|
+
|
|
39
|
+
## Rules when you touch one of these
|
|
40
|
+
|
|
41
|
+
- Add a capability to an existing service with `nx g add-capability --service <svc> --capability llm --provider <p>` — it runs the same injector the scaffold does, idempotently.
|
|
42
|
+
- Swapping providers swaps only the adapter file, its dependency, and the footprint. If a change forces the port or a caller to change, the port was leaky — fix the port, not the callers.
|
|
43
|
+
- Surfaces and frontends do **not** embed an adapter; they call this service's port over its API (keys stay server-side, one owner per capability).
|
|
44
|
+
- A hand-written adapter must pass the same `issubclass(...)` conformance test the generator emits.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Database & Schema Management
|
|
2
|
+
|
|
3
|
+
## 1. Declarative Schema
|
|
4
|
+
|
|
5
|
+
Manual `UP`/`DOWN` migrations (e.g., standard Alembic versions) cause merge conflicts in distributed teams and make the "target state" of the database impossible to read without executing scripts.
|
|
6
|
+
|
|
7
|
+
We use **declarative schema management**.
|
|
8
|
+
- The source of truth is a single `schema.sql` file (or equivalent Prisma/SQLAlchemy models).
|
|
9
|
+
- We use a diffing engine (e.g., `atlas` or `alembic revision --autogenerate`) to compute the migration dynamically.
|
|
10
|
+
- Migrations are applied automatically during deployment, or generated purely as a verification step in CI.
|
|
11
|
+
|
|
12
|
+
## 2. Session Management & Dependency Injection
|
|
13
|
+
|
|
14
|
+
The database session lifecycle is managed at the entrypoint layer (FastAPI), not within the Domain or Service layers.
|
|
15
|
+
|
|
16
|
+
### The FastAPI Dependency
|
|
17
|
+
|
|
18
|
+
Use a FastAPI dependency to yield a session and ensure it is closed after the request completes.
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from typing import AsyncGenerator
|
|
22
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
23
|
+
from <package>.adapters.database import async_session_maker
|
|
24
|
+
|
|
25
|
+
async def get_db_session() -> AsyncGenerator[AsyncSession, None]:
|
|
26
|
+
async with async_session_maker() as session:
|
|
27
|
+
yield session
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Injecting into Adapters
|
|
31
|
+
|
|
32
|
+
Inject the `AsyncSession` into the concrete adapter. **Never pass the session into the Service or Domain layers.**
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from fastapi import Depends
|
|
36
|
+
from <package>.core.ports import OrderRepository
|
|
37
|
+
from <package>.adapters.repository import PostgresOrderRepository
|
|
38
|
+
|
|
39
|
+
def get_order_repository(
|
|
40
|
+
session: AsyncSession = Depends(get_db_session)
|
|
41
|
+
) -> OrderRepository:
|
|
42
|
+
# PostgresOrderRepository implements the OrderRepository port
|
|
43
|
+
return PostgresOrderRepository(session=session)
|
|
44
|
+
|
|
45
|
+
def get_order_service(
|
|
46
|
+
repository: OrderRepository = Depends(get_order_repository)
|
|
47
|
+
) -> OrderService:
|
|
48
|
+
return OrderService(repository=repository)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The dependency is typed as the **port** (the `OrderRepository` Protocol from `<package>.core.ports`), not the concrete `PostgresOrderRepository` — the seam stays on the port.
|
|
52
|
+
|
|
53
|
+
## 3. Transaction Boundaries
|
|
54
|
+
|
|
55
|
+
By default, the `get_db_session` dependency provides an open transaction if the SQLAlchemy engine is configured correctly. However, explicit transaction boundaries (commit/rollback) belong in the Provider or the Service, depending on the isolation requirement.
|
|
56
|
+
|
|
57
|
+
If the Service coordinates multiple repository calls that must be transactional, use a generic "Unit of Work" (UoW) pattern rather than leaking `session.commit()` into the Service.
|
|
58
|
+
|
|
59
|
+
## 4. The shape of the persistence port
|
|
60
|
+
|
|
61
|
+
By default the SQLAlchemy `AsyncSession` already is a unit of work and a collection-like store — a thin CRUD service can use it directly rather than defining its own port. Introduce a persistence port (a domain-named repository Protocol in `src/<package>/core/ports.py`) only when a rich domain aggregate must stay storage-ignorant. When you do:
|
|
62
|
+
|
|
63
|
+
- **One port per aggregate root, named in the domain's language** (`OrderRepository.get`, `.save`) — never a generic `Repository[T]` / `Generic[T]` CRUD base. Its "generic" is unproven from a single implementation, and a uniform CRUD surface leaks the store's shape into the core (the very leak it was meant to prevent).
|
|
64
|
+
- **Define the port as a narrow `Protocol` or ABC in the core**, exposing only the methods the service calls. A good size check: if an in-memory fake of the port is awkward to write, the port is too broad.
|
|
65
|
+
- When query variety grows, reach for a query object / specification — not more methods on the port or a leaked SQLAlchemy `Select`.
|
|
66
|
+
- Integration-test the adapter against a real Postgres (Testcontainers); never mock the port or the database.
|
|
67
|
+
|
|
68
|
+
## 5. Test Isolation
|
|
69
|
+
|
|
70
|
+
Never mock the database. Use Testcontainers for a real Postgres instance.
|
|
71
|
+
Between tests, isolate state by truncating tables rather than recreating the schema, as truncation is significantly faster.
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import pytest
|
|
75
|
+
from sqlalchemy import text
|
|
76
|
+
|
|
77
|
+
@pytest.fixture(autouse=True)
|
|
78
|
+
async def clear_database(db_session: AsyncSession):
|
|
79
|
+
"""Truncates all tables between tests."""
|
|
80
|
+
await db_session.execute(text("TRUNCATE TABLE orders, users CASCADE;"))
|
|
81
|
+
await db_session.commit()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Anti-Patterns
|
|
85
|
+
|
|
86
|
+
- **Leaking sessions.** Passing `AsyncSession` directly into the Domain or Service layer breaks the Dependency Inversion Principle.
|
|
87
|
+
- **Manual migration scripts.** Writing manual `ALTER TABLE` statements causes drift. Use a declarative engine.
|
|
88
|
+
- **Mocking the database.** Use Testcontainers. Mocks hide SQL syntax errors and constraint violations.
|