claudecode-omc 5.11.0 → 5.13.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/.local/skills/prompt-pilot/SKILL.md +258 -0
- package/bundled/manifest.json +3 -3
- package/bundled/upstream/anthropic-skills/.omc-source/bundle.json +2 -2
- package/bundled/upstream/anthropic-skills/.omc-source/provenance.json +394 -390
- package/bundled/upstream/anthropic-skills/skills/claude-api/SKILL.md +60 -29
- package/bundled/upstream/anthropic-skills/skills/claude-api/csharp/claude-api.md +46 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/curl/examples.md +2 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/curl/managed-agents.md +3 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/go/claude-api.md +23 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/java/claude-api.md +32 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/php/claude-api.md +27 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/README.md +123 -7
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/batches.md +13 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/files-api.md +7 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/claude-api/streaming.md +18 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/python/managed-agents/README.md +9 -7
- package/bundled/upstream/anthropic-skills/skills/claude-api/ruby/claude-api.md +27 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/agent-design.md +1 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/anthropic-cli.md +246 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/claude-platform-on-aws.md +59 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/error-codes.md +24 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/live-sources.md +8 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-api-reference.md +48 -4
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-client-patterns.md +3 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-core.md +15 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-environments.md +10 -6
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-events.md +25 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-onboarding.md +48 -18
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-overview.md +8 -5
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-scheduled-deployments.md +144 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-self-hosted-sandboxes.md +2 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/managed-agents-tools.md +46 -9
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/model-migration.md +259 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/models.md +17 -9
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/prompt-caching.md +55 -3
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/token-counting.md +56 -0
- package/bundled/upstream/anthropic-skills/skills/claude-api/shared/tool-use-concepts.md +22 -2
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/README.md +45 -6
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/claude-api/streaming.md +1 -1
- package/bundled/upstream/anthropic-skills/skills/claude-api/typescript/managed-agents/README.md +10 -12
- package/bundled/upstream/anthropic-skills/skills/frontend-design/SKILL.md +39 -26
- package/bundled/upstream/ecc/.omc-source/bundle.json +2 -2
- package/bundled/upstream/ecc/.omc-source/manifests/.claude-plugin/marketplace.json +2 -2
- package/bundled/upstream/ecc/.omc-source/provenance.json +602 -550
- package/bundled/upstream/ecc/agents/agent-evaluator.md +206 -0
- package/bundled/upstream/ecc/agents/performance-optimizer.md +9 -9
- package/bundled/upstream/ecc/agents/php-reviewer.md +109 -0
- package/bundled/upstream/ecc/agents/spec-miner.md +217 -0
- package/bundled/upstream/ecc/agents/vue-reviewer.md +206 -0
- package/bundled/upstream/ecc/commands/cost-report.md +58 -84
- package/bundled/upstream/ecc/commands/epic-claim.md +26 -0
- package/bundled/upstream/ecc/commands/epic-decompose.md +23 -0
- package/bundled/upstream/ecc/commands/epic-publish.md +23 -0
- package/bundled/upstream/ecc/commands/epic-review.md +23 -0
- package/bundled/upstream/ecc/commands/epic-sync.md +23 -0
- package/bundled/upstream/ecc/commands/epic-unblock.md +22 -0
- package/bundled/upstream/ecc/commands/epic-validate.md +22 -0
- package/bundled/upstream/ecc/commands/instinct-status.md +8 -8
- package/bundled/upstream/ecc/commands/multi-backend.md +2 -0
- package/bundled/upstream/ecc/commands/multi-execute.md +2 -0
- package/bundled/upstream/ecc/commands/multi-frontend.md +2 -0
- package/bundled/upstream/ecc/commands/multi-plan.md +2 -0
- package/bundled/upstream/ecc/commands/multi-workflow.md +2 -0
- package/bundled/upstream/ecc/commands/orch-add-feature.md +36 -0
- package/bundled/upstream/ecc/commands/orch-build-mvp.md +36 -0
- package/bundled/upstream/ecc/commands/orch-change-feature.md +38 -0
- package/bundled/upstream/ecc/commands/orch-fix-defect.md +38 -0
- package/bundled/upstream/ecc/commands/orch-refine-code.md +39 -0
- package/bundled/upstream/ecc/commands/quality-gate.md +34 -16
- package/bundled/upstream/ecc/commands/vue-review.md +174 -0
- package/bundled/upstream/ecc/skills/accessibility/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agent-architecture-audit/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agent-eval/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agent-harness-construction/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agent-introspection-debugging/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agent-payment-x402/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agent-self-evaluation/SKILL.md +182 -0
- package/bundled/upstream/ecc/skills/agent-self-evaluation/examples/high-score-example.md +87 -0
- package/bundled/upstream/ecc/skills/agent-self-evaluation/examples/low-score-example.md +86 -0
- package/bundled/upstream/ecc/skills/agent-self-evaluation/references/evaluation-criteria.md +71 -0
- package/bundled/upstream/ecc/skills/agent-self-evaluation/references/hook-integration.md +64 -0
- package/bundled/upstream/ecc/skills/agent-self-evaluation/scripts/evaluate.py +408 -0
- package/bundled/upstream/ecc/skills/agent-self-evaluation/templates/evaluation-report.md +86 -0
- package/bundled/upstream/ecc/skills/agent-sort/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agentic-engineering/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/agentic-os/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ai-first-engineering/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ai-regression-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/android-clean-architecture/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/angular-developer/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/api-connector-builder/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/api-design/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/architecture-decision-records/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/article-writing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/automation-audit-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/autonomous-agent-harness/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/autonomous-loops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/backend-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/benchmark/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/benchmark-methodology/SKILL.md +190 -0
- package/bundled/upstream/ecc/skills/benchmark-optimization-loop/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/blender-motion-state-inspection/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/blueprint/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/brand-discovery/SKILL.md +145 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/10_purpose-why.md +40 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/20_positioning.md +44 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/30_audience-niche.md +52 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/40_personality-archetype.md +57 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/50_voice-tone.md +59 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/60_narrative-story.md +50 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/70_founder-tension.md +49 -0
- package/bundled/upstream/ecc/skills/brand-discovery/references/90_SYNTHESIS.md +133 -0
- package/bundled/upstream/ecc/skills/brand-voice/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/browser-qa/SKILL.md +22 -4
- package/bundled/upstream/ecc/skills/bun-runtime/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/canary-watch/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/carrier-relationship-management/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/cisco-ios-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ck/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/claude-devfleet/SKILL.md +11 -2
- package/bundled/upstream/ecc/skills/click-path-audit/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/clickhouse-io/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/code-tour/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/codebase-onboarding/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/codehealth-mcp/SKILL.md +167 -0
- package/bundled/upstream/ecc/skills/coding-standards/SKILL.md +4 -2
- package/bundled/upstream/ecc/skills/competitive-platform-analysis/SKILL.md +214 -0
- package/bundled/upstream/ecc/skills/competitive-report-structure/SKILL.md +162 -0
- package/bundled/upstream/ecc/skills/compose-multiplatform-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/config-gc/SKILL.md +120 -0
- package/bundled/upstream/ecc/skills/configure-ecc/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/connections-optimizer/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/content-engine/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/content-hash-cache-pattern/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/context-budget/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/continuous-agent-loop/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/continuous-learning/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/continuous-learning-v2/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/continuous-learning-v2/agents/observer-loop.sh +14 -1
- package/bundled/upstream/ecc/skills/continuous-learning-v2/hooks/observe.sh +31 -7
- package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/instinct-cli.py +90 -2
- package/bundled/upstream/ecc/skills/continuous-learning-v2/scripts/test_parse_instinct.py +27 -0
- package/bundled/upstream/ecc/skills/cost-aware-llm-pipeline/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/cost-tracking/SKILL.md +58 -108
- package/bundled/upstream/ecc/skills/council/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/cpp-coding-standards/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/cpp-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/crosspost/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/csharp-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/customer-billing-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/customs-trade-compliance/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/dart-flutter-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/dashboard-builder/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/data-scraper-agent/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/data-throughput-accelerator/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/database-migrations/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/deep-research/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/defi-amm-security/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/deployment-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/design-system/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/django-celery/SKILL.md +3 -2
- package/bundled/upstream/ecc/skills/django-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/django-security/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/django-tdd/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/django-verification/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/dmux-workflows/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/docker-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/documentation-lookup/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/dotnet-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/dynamic-workflow-mode/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/e2e-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ecc-guide/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ecc-tools-cost-audit/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/email-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/energy-procurement/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/enterprise-agent-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/error-handling/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/eval-harness/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/evm-token-decimals/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/exa-search/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/fal-ai-media/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/fastapi-patterns/SKILL.md +375 -188
- package/bundled/upstream/ecc/skills/finance-billing-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/flox-environments/SKILL.md +3 -2
- package/bundled/upstream/ecc/skills/flutter-dart-code-review/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/frontend-a11y/SKILL.md +3 -3
- package/bundled/upstream/ecc/skills/frontend-design-direction/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/frontend-patterns/SKILL.md +23 -8
- package/bundled/upstream/ecc/skills/frontend-slides/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/frontend-slides/scripts/export-pdf.sh +1 -1
- package/bundled/upstream/ecc/skills/fsharp-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/gan-style-harness/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/gateguard/SKILL.md +9 -1
- package/bundled/upstream/ecc/skills/generating-python-installer/SKILL.md +820 -0
- package/bundled/upstream/ecc/skills/git-workflow/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/github-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/golang-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/golang-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/google-workspace-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/healthcare-cdss-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/healthcare-emr-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/healthcare-eval-harness/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/healthcare-phi-compliance/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/hermes-imports/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/hexagonal-architecture/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/hipaa-compliance/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/homelab-network-readiness/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/homelab-network-setup/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/homelab-pihole-dns/SKILL.md +10 -9
- package/bundled/upstream/ecc/skills/homelab-vlan-segmentation/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/homelab-wireguard-vpn/SKILL.md +4 -3
- package/bundled/upstream/ecc/skills/inherit-legacy-style/SKILL.md +157 -0
- package/bundled/upstream/ecc/skills/intent-driven-development/SKILL.md +360 -0
- package/bundled/upstream/ecc/skills/inventory-demand-planning/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/investor-materials/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/investor-outreach/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ios-icon-gen/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/iterative-retrieval/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ito-basket-compare/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ito-data-atlas-agent/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ito-market-intelligence/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ito-trade-planner/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/java-coding-standards/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/jira-integration/SKILL.md +17 -7
- package/bundled/upstream/ecc/skills/jpa-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/knowledge-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/kotlin-coroutines-flows/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/kotlin-exposed-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/kotlin-ktor-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/kotlin-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/kotlin-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/kubernetes-patterns/SKILL.md +756 -0
- package/bundled/upstream/ecc/skills/laravel-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/laravel-plugin-discovery/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/laravel-security/SKILL.md +826 -163
- package/bundled/upstream/ecc/skills/laravel-tdd/SKILL.md +541 -149
- package/bundled/upstream/ecc/skills/laravel-verification/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/latency-critical-systems/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/lead-intelligence/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/llm-trading-agent-security/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/logistics-exception-management/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/make-interfaces-feel-better/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/manim-video/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/market-research/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/marketing-campaign/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/mcp-server-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/messages-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ml-adoption-playbook/SKILL.md +57 -0
- package/bundled/upstream/ecc/skills/mle-workflow/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/motion-patterns/SKILL.md +1 -2
- package/bundled/upstream/ecc/skills/motion-ui/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/mysql-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/nanoclaw-repl/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/nestjs-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/netmiko-ssh-automation/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/network-bgp-diagnostics/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/network-config-validation/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/network-interface-health/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/nextjs-turbopack/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/nodejs-keccak256/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/nutrient-document-processing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/nuxt4-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/openclaw-persona-forge/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/opensource-pipeline/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/orch-add-feature/SKILL.md +45 -0
- package/bundled/upstream/ecc/skills/orch-build-mvp/SKILL.md +49 -0
- package/bundled/upstream/ecc/skills/orch-change-feature/SKILL.md +43 -0
- package/bundled/upstream/ecc/skills/orch-fix-defect/SKILL.md +43 -0
- package/bundled/upstream/ecc/skills/orch-pipeline/SKILL.md +121 -0
- package/bundled/upstream/ecc/skills/orch-refine-code/SKILL.md +44 -0
- package/bundled/upstream/ecc/skills/parallel-execution-optimizer/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/perl-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/perl-security/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/perl-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/plan-orchestrate/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/plankton-code-quality/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/postgres-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/prediction-market-oracle-research/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/prediction-market-risk-review/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/prisma-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/product-capability/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/product-lens/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/production-audit/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/production-scheduling/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/project-flow-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/prompt-optimizer/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/python-patterns/SKILL.md +4 -3
- package/bundled/upstream/ecc/skills/python-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/pytorch-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/quality-nonconformance/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/quarkus-patterns/SKILL.md +51 -50
- package/bundled/upstream/ecc/skills/quarkus-security/SKILL.md +25 -24
- package/bundled/upstream/ecc/skills/quarkus-tdd/SKILL.md +73 -72
- package/bundled/upstream/ecc/skills/quarkus-verification/SKILL.md +8 -7
- package/bundled/upstream/ecc/skills/ralphinho-rfc-pipeline/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/react-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/react-performance/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/react-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/recsys-pipeline-architect/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/recursive-decision-ledger/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/redis-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/regex-vs-llm-structured-text/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/repo-scan/SKILL.md +64 -63
- package/bundled/upstream/ecc/skills/research-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/returns-reverse-logistics/SKILL.md +1 -1
- package/bundled/upstream/ecc/skills/rules-distill/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/rust-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/rust-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/safety-guard/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/santa-method/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/scientific-db-pubmed-database/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/scientific-db-uspto-database/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/scientific-pkg-gget/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/scientific-thinking-literature-review/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/scientific-thinking-scholar-evaluation/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/search-first/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/security-bounty-hunter/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/security-review/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/security-scan/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/seo/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/skill-comply/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/skill-comply/scripts/runner.py +8 -0
- package/bundled/upstream/ecc/skills/skill-scout/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/skill-stocktake/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/social-graph-ranker/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/social-publisher/SKILL.md +17 -2
- package/bundled/upstream/ecc/skills/springboot-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/springboot-security/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/springboot-tdd/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/springboot-verification/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/strategic-compact/SKILL.md +10 -5
- package/bundled/upstream/ecc/skills/swift-actor-persistence/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/swift-protocol-di-testing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/taste/SKILL.md +264 -0
- package/bundled/upstream/ecc/skills/taste/references/genre-taxonomy.md +87 -0
- package/bundled/upstream/ecc/skills/tdd-workflow/SKILL.md +64 -1
- package/bundled/upstream/ecc/skills/team-agent-orchestration/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/team-builder/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/terminal-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/tinystruct-patterns/SKILL.md +77 -1
- package/bundled/upstream/ecc/skills/token-budget-advisor/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ui-demo/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/ui-to-vue/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/uncloud/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/unified-notifications-ops/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/verification-loop/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/video-editing/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/videodb/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/vite-patterns/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/vue-patterns/SKILL.md +471 -0
- package/bundled/upstream/ecc/skills/windows-desktop-e2e/SKILL.md +9 -8
- package/bundled/upstream/ecc/skills/workspace-surface-audit/SKILL.md +2 -1
- package/bundled/upstream/ecc/skills/x-api/SKILL.md +2 -1
- package/bundled/upstream/impeccable/.omc-source/bundle.json +2 -2
- package/bundled/upstream/impeccable/.omc-source/provenance.json +30 -25
- package/bundled/upstream/impeccable/skills/impeccable/SKILL.md +2 -2
- package/bundled/upstream/impeccable/skills/impeccable/reference/hooks.md +10 -8
- package/bundled/upstream/impeccable/skills/impeccable/reference/live.md +1 -1
- package/bundled/upstream/impeccable/skills/impeccable/scripts/context.mjs +707 -26
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/browser/injected/index.mjs +202 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/cli/main.mjs +57 -11
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/design-system.mjs +750 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +231 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/detect-antipatterns.mjs +7 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +29 -4
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +20 -4
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +2 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +27 -1
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/registry/antipatterns.mjs +29 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/detector/shared/inline-ignores.mjs +148 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/hook-admin.mjs +135 -48
- package/bundled/upstream/impeccable/skills/impeccable/scripts/hook-before-edit.mjs +5 -2
- package/bundled/upstream/impeccable/skills/impeccable/scripts/hook-lib.mjs +375 -29
- package/bundled/upstream/impeccable/skills/impeccable/scripts/lib/design-parser.mjs +8 -1
- package/bundled/upstream/impeccable/skills/impeccable/scripts/lib/impeccable-config.mjs +638 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/lib/impeccable-paths.mjs +37 -35
- package/bundled/upstream/impeccable/skills/impeccable/scripts/lib/target-args.mjs +42 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/live-browser.js +159 -72
- package/bundled/upstream/impeccable/skills/impeccable/scripts/live-poll.mjs +16 -11
- package/bundled/upstream/impeccable/skills/impeccable/scripts/live-server.mjs +9 -8
- package/bundled/upstream/impeccable/skills/impeccable/scripts/live-target.mjs +30 -0
- package/bundled/upstream/impeccable/skills/impeccable/scripts/live-wrap.mjs +1 -1
- package/bundled/upstream/impeccable/skills/impeccable/scripts/live.mjs +72 -21
- package/bundled/upstream/oh-my-claudecode/.omc-source/bundle.json +2 -2
- package/bundled/upstream/oh-my-claudecode/.omc-source/provenance.json +103 -103
- package/bundled/upstream/oh-my-claudecode/agents/analyst.md +6 -0
- package/bundled/upstream/oh-my-claudecode/agents/architect.md +6 -0
- package/bundled/upstream/oh-my-claudecode/agents/code-reviewer.md +6 -0
- package/bundled/upstream/oh-my-claudecode/agents/critic.md +6 -0
- package/bundled/upstream/oh-my-claudecode/agents/debugger.md +6 -0
- package/bundled/upstream/oh-my-claudecode/agents/security-reviewer.md +6 -0
- package/bundled/upstream/oh-my-claudecode/agents/tracer.md +6 -0
- package/bundled/upstream/oh-my-claudecode/agents/verifier.md +7 -0
- package/bundled/upstream/oh-my-claudecode/hooks/hooks.json +9 -2
- package/bundled/upstream/oh-my-claudecode/skills/ask/SKILL.md +15 -4
- package/bundled/upstream/oh-my-claudecode/skills/autopilot/SKILL.md +30 -1
- package/bundled/upstream/oh-my-claudecode/skills/cancel/SKILL.md +29 -35
- package/bundled/upstream/oh-my-claudecode/skills/ccg/SKILL.md +20 -9
- package/bundled/upstream/oh-my-claudecode/skills/configure-notifications/SKILL.md +2 -2
- package/bundled/upstream/oh-my-claudecode/skills/omc-reference/SKILL.md +6 -4
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/02-configure.md +1 -1
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/03-integrations.md +2 -1
- package/bundled/upstream/oh-my-claudecode/skills/omc-setup/phases/04-welcome.md +2 -2
- package/bundled/upstream/oh-my-claudecode/skills/omc-teams/SKILL.md +29 -18
- package/bundled/upstream/oh-my-claudecode/skills/team/SKILL.md +127 -165
- package/bundled/upstream/superpowers/.omc-source/bundle.json +2 -2
- package/bundled/upstream/superpowers/.omc-source/provenance.json +59 -52
- package/bundled/upstream/superpowers/hooks/hooks-codex.json +16 -0
- package/bundled/upstream/superpowers/hooks/session-start +4 -12
- package/bundled/upstream/superpowers/hooks/session-start-codex +26 -0
- package/bundled/upstream/superpowers/skills/brainstorming/SKILL.md +5 -10
- package/bundled/upstream/superpowers/skills/brainstorming/scripts/frame-template.html +25 -26
- package/bundled/upstream/superpowers/skills/brainstorming/scripts/helper.js +101 -22
- package/bundled/upstream/superpowers/skills/brainstorming/scripts/server.cjs +399 -30
- package/bundled/upstream/superpowers/skills/brainstorming/scripts/start-server.sh +70 -9
- package/bundled/upstream/superpowers/skills/brainstorming/scripts/stop-server.sh +66 -2
- package/bundled/upstream/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +1 -1
- package/bundled/upstream/superpowers/skills/brainstorming/visual-companion.md +33 -22
- package/bundled/upstream/superpowers/skills/dispatching-parallel-agents/SKILL.md +9 -6
- package/bundled/upstream/superpowers/skills/executing-plans/SKILL.md +2 -2
- package/bundled/upstream/superpowers/skills/finishing-a-development-branch/SKILL.md +2 -12
- package/bundled/upstream/superpowers/skills/receiving-code-review/SKILL.md +2 -2
- package/bundled/upstream/superpowers/skills/requesting-code-review/SKILL.md +2 -2
- package/bundled/upstream/superpowers/skills/requesting-code-review/code-reviewer.md +15 -11
- package/bundled/upstream/superpowers/skills/subagent-driven-development/SKILL.md +206 -67
- package/bundled/upstream/superpowers/skills/subagent-driven-development/implementer-prompt.md +30 -4
- package/bundled/upstream/superpowers/skills/subagent-driven-development/scripts/review-package +44 -0
- package/bundled/upstream/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +22 -0
- package/bundled/upstream/superpowers/skills/subagent-driven-development/scripts/task-brief +40 -0
- package/bundled/upstream/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +188 -0
- package/bundled/upstream/superpowers/skills/systematic-debugging/SKILL.md +1 -1
- package/bundled/upstream/superpowers/skills/test-driven-development/SKILL.md +1 -1
- package/bundled/upstream/superpowers/skills/using-git-worktrees/SKILL.md +9 -22
- package/bundled/upstream/superpowers/skills/using-superpowers/SKILL.md +19 -15
- package/bundled/upstream/superpowers/skills/using-superpowers/references/antigravity-tools.md +96 -0
- package/bundled/upstream/superpowers/skills/using-superpowers/references/claude-code-tools.md +50 -0
- package/bundled/upstream/superpowers/skills/using-superpowers/references/codex-tools.md +25 -12
- package/bundled/upstream/superpowers/skills/using-superpowers/references/copilot-tools.md +27 -20
- package/bundled/upstream/superpowers/skills/using-superpowers/references/gemini-tools.md +44 -32
- package/bundled/upstream/superpowers/skills/using-superpowers/references/pi-tools.md +28 -0
- package/bundled/upstream/superpowers/skills/writing-plans/SKILL.md +22 -0
- package/bundled/upstream/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +1 -1
- package/bundled/upstream/superpowers/skills/writing-skills/SKILL.md +52 -18
- package/bundled/upstream/superpowers/skills/writing-skills/anthropic-best-practices.md +88 -88
- package/bundled/upstream/superpowers/skills/writing-skills/persuasion-principles.md +3 -3
- package/package.json +1 -1
- package/bundled/upstream/superpowers/skills/subagent-driven-development/code-quality-reviewer-prompt.md +0 -25
- package/bundled/upstream/superpowers/skills/subagent-driven-development/spec-reviewer-prompt.md +0 -61
|
@@ -1,327 +1,514 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: fastapi-patterns
|
|
3
|
-
description: FastAPI
|
|
4
|
-
|
|
3
|
+
description: FastAPI best practices covering project structure, Pydantic v2 schemas, dependency injection, async handlers, authentication, authorization, transactional service layers, and testing with httpx and pytest.
|
|
4
|
+
metadata:
|
|
5
|
+
origin: ECC
|
|
5
6
|
---
|
|
6
7
|
|
|
7
8
|
# FastAPI Patterns
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
Modern, production-grade FastAPI development: project layout, Pydantic v2 schemas, dependency injection, async patterns, auth, transactional service methods, and testing.
|
|
10
11
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
- Building or reviewing a FastAPI app.
|
|
14
|
-
- Splitting routers, schemas, dependencies, and database access.
|
|
15
|
-
- Writing async endpoints that call a database or external service.
|
|
16
|
-
- Adding authentication, authorization, OpenAPI docs, tests, or deployment settings.
|
|
17
|
-
- Checking a FastAPI PR for copy-pasteable examples and production risks.
|
|
18
|
-
|
|
19
|
-
## How It Works
|
|
20
|
-
|
|
21
|
-
Treat the FastAPI app as a thin HTTP layer over explicit dependencies and service code:
|
|
22
|
-
|
|
23
|
-
- `main.py` owns app construction, middleware, exception handlers, and router registration.
|
|
24
|
-
- `schemas/` owns Pydantic request and response models.
|
|
25
|
-
- `dependencies.py` owns database, auth, pagination, and request-scoped dependencies.
|
|
26
|
-
- `services/` or `crud/` owns business and persistence operations.
|
|
27
|
-
- `tests/` overrides dependencies instead of opening production resources.
|
|
28
|
-
|
|
29
|
-
Prefer small routers and explicit `response_model` declarations. Keep raw ORM objects, secrets, and framework globals out of response schemas.
|
|
30
|
-
|
|
31
|
-
## Project Layout
|
|
12
|
+
## Project Structure
|
|
32
13
|
|
|
33
14
|
```text
|
|
34
|
-
|
|
35
|
-
|--
|
|
36
|
-
|--
|
|
37
|
-
|--
|
|
38
|
-
|--
|
|
39
|
-
|--
|
|
40
|
-
|
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
44
|
-
| |--
|
|
45
|
-
| `--
|
|
46
|
-
|
|
47
|
-
|
|
|
48
|
-
|
|
49
|
-
|--
|
|
50
|
-
|
|
51
|
-
|
|
15
|
+
my_app/
|
|
16
|
+
|-- app/
|
|
17
|
+
| |-- main.py # App factory, lifespan, middleware
|
|
18
|
+
| |-- config.py # Settings via pydantic-settings
|
|
19
|
+
| |-- dependencies.py # Shared FastAPI dependencies
|
|
20
|
+
| |-- database.py # SQLAlchemy engine + session
|
|
21
|
+
| |-- routers/
|
|
22
|
+
| | `-- users.py
|
|
23
|
+
| |-- models/ # SQLAlchemy ORM models
|
|
24
|
+
| | `-- user.py
|
|
25
|
+
| |-- schemas/ # Pydantic request/response schemas
|
|
26
|
+
| | `-- user.py
|
|
27
|
+
| `-- services/ # Business logic layer
|
|
28
|
+
| `-- user_service.py
|
|
29
|
+
|-- tests/
|
|
30
|
+
| |-- conftest.py
|
|
31
|
+
| `-- test_users.py
|
|
32
|
+
|-- pyproject.toml
|
|
33
|
+
`-- .env
|
|
52
34
|
```
|
|
53
35
|
|
|
54
|
-
|
|
36
|
+
---
|
|
55
37
|
|
|
56
|
-
|
|
38
|
+
## App Factory and Lifespan
|
|
57
39
|
|
|
58
40
|
```python
|
|
41
|
+
# app/main.py
|
|
59
42
|
from contextlib import asynccontextmanager
|
|
60
|
-
|
|
61
43
|
from fastapi import FastAPI
|
|
62
44
|
from fastapi.middleware.cors import CORSMiddleware
|
|
63
45
|
|
|
64
|
-
from app.api.routes import health, users
|
|
65
46
|
from app.config import settings
|
|
66
|
-
from app.
|
|
67
|
-
from app.
|
|
47
|
+
from app.database import engine, Base
|
|
48
|
+
from app.routers import users
|
|
68
49
|
|
|
69
50
|
|
|
70
51
|
@asynccontextmanager
|
|
71
52
|
async def lifespan(app: FastAPI):
|
|
72
|
-
|
|
53
|
+
# Automatically create tables on startup for ease of use in dev/demo environments.
|
|
54
|
+
# For strict production applications, manage schemas via Alembic migrations instead.
|
|
55
|
+
async with engine.begin() as conn:
|
|
56
|
+
await conn.run_sync(Base.metadata.create_all)
|
|
73
57
|
yield
|
|
74
|
-
|
|
58
|
+
# Shutdown: close pooled resources.
|
|
59
|
+
await engine.dispose()
|
|
75
60
|
|
|
76
61
|
|
|
77
62
|
def create_app() -> FastAPI:
|
|
78
63
|
app = FastAPI(
|
|
79
|
-
title=settings.
|
|
80
|
-
version=settings.
|
|
64
|
+
title=settings.app_name,
|
|
65
|
+
version=settings.app_version,
|
|
81
66
|
lifespan=lifespan,
|
|
82
67
|
)
|
|
83
68
|
|
|
84
69
|
app.add_middleware(
|
|
85
70
|
CORSMiddleware,
|
|
86
|
-
allow_origins=settings.
|
|
87
|
-
allow_credentials=
|
|
88
|
-
allow_methods=
|
|
89
|
-
allow_headers=
|
|
71
|
+
allow_origins=settings.allowed_origins,
|
|
72
|
+
allow_credentials=settings.allow_credentials,
|
|
73
|
+
allow_methods=settings.allowed_methods,
|
|
74
|
+
allow_headers=settings.allowed_headers,
|
|
90
75
|
)
|
|
91
76
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
app.include_router(users.router, prefix="/api/v1/users", tags=["users"])
|
|
77
|
+
app.include_router(users.router, prefix="/users", tags=["users"])
|
|
78
|
+
|
|
95
79
|
return app
|
|
96
80
|
|
|
97
81
|
|
|
98
82
|
app = create_app()
|
|
99
83
|
```
|
|
100
84
|
|
|
101
|
-
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Configuration with pydantic-settings
|
|
102
88
|
|
|
103
|
-
|
|
89
|
+
```python
|
|
90
|
+
# app/config.py
|
|
91
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
104
92
|
|
|
105
|
-
|
|
93
|
+
|
|
94
|
+
class Settings(BaseSettings):
|
|
95
|
+
model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
|
|
96
|
+
|
|
97
|
+
app_name: str = "My App"
|
|
98
|
+
app_version: str = "0.1.0"
|
|
99
|
+
debug: bool = False
|
|
100
|
+
|
|
101
|
+
database_url: str
|
|
102
|
+
secret_key: str
|
|
103
|
+
algorithm: str = "HS256"
|
|
104
|
+
access_token_expire_minutes: int = 30
|
|
105
|
+
|
|
106
|
+
# Pydantic-settings v2 safely evaluates mutable list literals directly
|
|
107
|
+
allowed_origins: list[str] = ["http://localhost:3000"]
|
|
108
|
+
allowed_methods: list[str] = ["GET", "POST", "PATCH", "DELETE", "OPTIONS"]
|
|
109
|
+
allowed_headers: list[str] = ["Authorization", "Content-Type"]
|
|
110
|
+
allow_credentials: bool = True
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
settings = Settings()
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Pydantic Schemas (v2)
|
|
106
119
|
|
|
107
120
|
```python
|
|
121
|
+
# app/schemas/user.py
|
|
108
122
|
from datetime import datetime
|
|
109
|
-
from
|
|
110
|
-
from uuid import UUID
|
|
111
|
-
|
|
112
|
-
from pydantic import BaseModel, ConfigDict, EmailStr, Field
|
|
123
|
+
from pydantic import BaseModel, EmailStr, Field, model_validator
|
|
113
124
|
|
|
114
125
|
|
|
115
126
|
class UserBase(BaseModel):
|
|
116
127
|
email: EmailStr
|
|
117
|
-
|
|
128
|
+
username: str = Field(min_length=3, max_length=50)
|
|
118
129
|
|
|
119
130
|
|
|
120
131
|
class UserCreate(UserBase):
|
|
121
|
-
password:
|
|
132
|
+
password: str = Field(min_length=8)
|
|
133
|
+
password_confirm: str
|
|
134
|
+
|
|
135
|
+
@model_validator(mode="after")
|
|
136
|
+
def passwords_match(self) -> "UserCreate":
|
|
137
|
+
if self.password != self.password_confirm:
|
|
138
|
+
raise ValueError("Passwords do not match")
|
|
139
|
+
return self
|
|
122
140
|
|
|
123
141
|
|
|
124
142
|
class UserUpdate(BaseModel):
|
|
143
|
+
username: str | None = Field(default=None, min_length=3, max_length=50)
|
|
125
144
|
email: EmailStr | None = None
|
|
126
|
-
full_name: Annotated[str | None, Field(min_length=1, max_length=100)] = None
|
|
127
145
|
|
|
128
146
|
|
|
129
147
|
class UserResponse(UserBase):
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
id: UUID
|
|
148
|
+
id: int
|
|
149
|
+
is_active: bool
|
|
133
150
|
created_at: datetime
|
|
134
|
-
updated_at: datetime
|
|
135
|
-
```
|
|
136
151
|
|
|
137
|
-
|
|
152
|
+
model_config = {"from_attributes": True}
|
|
138
153
|
|
|
139
|
-
## Dependencies
|
|
140
154
|
|
|
141
|
-
|
|
155
|
+
class UserListResponse(BaseModel):
|
|
156
|
+
total: int
|
|
157
|
+
items: list[UserResponse]
|
|
158
|
+
```
|
|
142
159
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Dependency Injection
|
|
146
163
|
|
|
164
|
+
```python
|
|
165
|
+
# app/dependencies.py
|
|
166
|
+
from typing import Annotated, AsyncGenerator
|
|
147
167
|
from fastapi import Depends, HTTPException, status
|
|
148
168
|
from fastapi.security import OAuth2PasswordBearer
|
|
169
|
+
from jose import JWTError, jwt
|
|
149
170
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
150
171
|
|
|
151
|
-
from app.
|
|
152
|
-
from app.
|
|
172
|
+
from app.config import settings
|
|
173
|
+
from app.database import AsyncSessionLocal
|
|
153
174
|
from app.models.user import User
|
|
154
175
|
|
|
155
|
-
|
|
156
|
-
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login")
|
|
176
|
+
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/users/token")
|
|
157
177
|
|
|
158
178
|
|
|
159
|
-
async def get_db() ->
|
|
160
|
-
async with
|
|
179
|
+
async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
|
180
|
+
async with AsyncSessionLocal() as session:
|
|
161
181
|
try:
|
|
162
182
|
yield session
|
|
163
|
-
await session.commit()
|
|
164
183
|
except Exception:
|
|
165
184
|
await session.rollback()
|
|
166
185
|
raise
|
|
167
186
|
|
|
168
187
|
|
|
169
188
|
async def get_current_user(
|
|
170
|
-
token: str
|
|
171
|
-
db: AsyncSession
|
|
189
|
+
token: Annotated[str, Depends(oauth2_scheme)],
|
|
190
|
+
db: Annotated[AsyncSession, Depends(get_db)],
|
|
172
191
|
) -> User:
|
|
173
|
-
|
|
174
|
-
|
|
192
|
+
credentials_exception = HTTPException(
|
|
193
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
194
|
+
detail="Could not validate credentials",
|
|
195
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
196
|
+
)
|
|
197
|
+
try:
|
|
198
|
+
payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm])
|
|
199
|
+
subject = payload.get("sub")
|
|
200
|
+
if subject is None:
|
|
201
|
+
raise credentials_exception
|
|
202
|
+
user_id = int(subject)
|
|
203
|
+
except (JWTError, TypeError, ValueError):
|
|
204
|
+
raise credentials_exception
|
|
205
|
+
|
|
175
206
|
user = await db.get(User, user_id)
|
|
176
207
|
if user is None:
|
|
177
|
-
raise
|
|
208
|
+
raise credentials_exception
|
|
178
209
|
return user
|
|
179
|
-
```
|
|
180
210
|
|
|
181
|
-
Avoid creating sessions, clients, or credentials inline inside route handlers.
|
|
182
211
|
|
|
183
|
-
|
|
212
|
+
async def get_current_active_user(
|
|
213
|
+
current_user: Annotated[User, Depends(get_current_user)],
|
|
214
|
+
) -> User:
|
|
215
|
+
if not current_user.is_active:
|
|
216
|
+
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Inactive user")
|
|
217
|
+
return current_user
|
|
184
218
|
|
|
185
|
-
Keep route handlers async when they perform I/O, and use async libraries inside them.
|
|
186
219
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
220
|
+
DbDep = Annotated[AsyncSession, Depends(get_db)]
|
|
221
|
+
CurrentUserDep = Annotated[User, Depends(get_current_user)]
|
|
222
|
+
ActiveUserDep = Annotated[User, Depends(get_current_active_user)]
|
|
223
|
+
```
|
|
191
224
|
|
|
192
|
-
|
|
193
|
-
from app.models.user import User
|
|
194
|
-
from app.schemas.user import UserResponse
|
|
225
|
+
---
|
|
195
226
|
|
|
227
|
+
## Router and Endpoint Design
|
|
196
228
|
|
|
197
|
-
|
|
229
|
+
```python
|
|
230
|
+
# app/routers/users.py
|
|
231
|
+
from typing import Annotated
|
|
232
|
+
from fastapi import APIRouter, HTTPException, Query, status
|
|
233
|
+
from fastapi.security import OAuth2PasswordRequestForm
|
|
198
234
|
|
|
235
|
+
from app.dependencies import ActiveUserDep, DbDep
|
|
236
|
+
from app.schemas.user import UserCreate, UserResponse, UserUpdate, UserListResponse
|
|
237
|
+
from app.services.user_service import DuplicateUserError, UserService
|
|
199
238
|
|
|
200
|
-
|
|
201
|
-
async def list_users(
|
|
202
|
-
limit: int = Query(default=50, ge=1, le=100),
|
|
203
|
-
offset: int = Query(default=0, ge=0),
|
|
204
|
-
db: AsyncSession = Depends(get_db),
|
|
205
|
-
current_user: User = Depends(get_current_user),
|
|
206
|
-
):
|
|
207
|
-
result = await db.execute(
|
|
208
|
-
select(User).order_by(User.created_at.desc()).limit(limit).offset(offset)
|
|
209
|
-
)
|
|
210
|
-
return result.scalars().all()
|
|
211
|
-
```
|
|
239
|
+
router = APIRouter()
|
|
212
240
|
|
|
213
|
-
Use `httpx.AsyncClient` for external HTTP calls from async handlers. Do not call `requests` in an async route.
|
|
214
241
|
|
|
215
|
-
|
|
242
|
+
@router.post("/", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
|
|
243
|
+
async def create_user(payload: UserCreate, db: DbDep) -> UserResponse:
|
|
244
|
+
service = UserService(db)
|
|
245
|
+
try:
|
|
246
|
+
return await service.create(payload)
|
|
247
|
+
except DuplicateUserError:
|
|
248
|
+
raise HTTPException(status_code=400, detail="Email already registered")
|
|
216
249
|
|
|
217
|
-
Centralize domain exceptions and keep response shapes stable.
|
|
218
250
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
251
|
+
@router.get("/me", response_model=UserResponse)
|
|
252
|
+
async def get_me(current_user: ActiveUserDep) -> UserResponse:
|
|
253
|
+
return current_user
|
|
222
254
|
|
|
223
255
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
256
|
+
@router.get("/", response_model=UserListResponse)
|
|
257
|
+
async def list_users(
|
|
258
|
+
db: DbDep,
|
|
259
|
+
current_user: ActiveUserDep,
|
|
260
|
+
skip: Annotated[int, Query(ge=0)] = 0,
|
|
261
|
+
limit: Annotated[int, Query(ge=1, le=100)] = 20,
|
|
262
|
+
) -> UserListResponse:
|
|
263
|
+
service = UserService(db)
|
|
264
|
+
users, total = await service.list(skip=skip, limit=limit)
|
|
265
|
+
return UserListResponse(total=total, items=users)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@router.patch("/{user_id}", response_model=UserResponse)
|
|
269
|
+
async def update_user(
|
|
270
|
+
user_id: int,
|
|
271
|
+
payload: UserUpdate,
|
|
272
|
+
db: DbDep,
|
|
273
|
+
current_user: ActiveUserDep,
|
|
274
|
+
) -> UserResponse:
|
|
275
|
+
if current_user.id != user_id:
|
|
276
|
+
raise HTTPException(status_code=403, detail="Not authorized")
|
|
277
|
+
service = UserService(db)
|
|
278
|
+
try:
|
|
279
|
+
user = await service.update(user_id, payload)
|
|
280
|
+
except DuplicateUserError:
|
|
281
|
+
raise HTTPException(status_code=400, detail="Email already registered")
|
|
282
|
+
if user is None:
|
|
283
|
+
raise HTTPException(status_code=404, detail="User not found")
|
|
284
|
+
return user
|
|
229
285
|
|
|
230
286
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
287
|
+
@router.post("/token")
|
|
288
|
+
async def login(
|
|
289
|
+
form_data: Annotated[OAuth2PasswordRequestForm, Depends()],
|
|
290
|
+
db: DbDep,
|
|
291
|
+
) -> dict[str, str]:
|
|
292
|
+
service = UserService(db)
|
|
293
|
+
token = await service.authenticate(form_data.username, form_data.password)
|
|
294
|
+
if token is None:
|
|
295
|
+
raise HTTPException(
|
|
296
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
|
297
|
+
detail="Incorrect username or password",
|
|
298
|
+
headers={"WWW-Authenticate": "Bearer"},
|
|
237
299
|
)
|
|
300
|
+
return {"access_token": token, "token_type": "bearer"}
|
|
238
301
|
```
|
|
239
302
|
|
|
240
|
-
|
|
303
|
+
---
|
|
241
304
|
|
|
242
|
-
|
|
305
|
+
## Service Layer
|
|
243
306
|
|
|
244
307
|
```python
|
|
245
|
-
|
|
246
|
-
from
|
|
308
|
+
# app/services/user_service.py
|
|
309
|
+
from datetime import datetime, timedelta, timezone
|
|
247
310
|
|
|
311
|
+
from jose import jwt
|
|
312
|
+
from passlib.context import CryptContext
|
|
313
|
+
from sqlalchemy import func, select
|
|
314
|
+
from sqlalchemy.exc import IntegrityError
|
|
315
|
+
from sqlalchemy.ext.asyncio import AsyncSession
|
|
248
316
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return app.openapi_schema
|
|
317
|
+
from app.config import settings
|
|
318
|
+
from app.models.user import User
|
|
319
|
+
from app.schemas.user import UserCreate, UserUpdate
|
|
320
|
+
|
|
321
|
+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
class DuplicateUserError(Exception):
|
|
325
|
+
"""Raised when a unique user field conflicts with an existing row."""
|
|
259
326
|
|
|
260
|
-
|
|
327
|
+
|
|
328
|
+
class UserService:
|
|
329
|
+
def __init__(self, db: AsyncSession) -> None:
|
|
330
|
+
self.db = db
|
|
331
|
+
|
|
332
|
+
async def get_by_email(self, email: str) -> User | None:
|
|
333
|
+
result = await self.db.execute(select(User).where(User.email == email))
|
|
334
|
+
return result.scalar_one_or_none()
|
|
335
|
+
|
|
336
|
+
async def create(self, payload: UserCreate) -> User:
|
|
337
|
+
user = User(
|
|
338
|
+
email=payload.email,
|
|
339
|
+
username=payload.username,
|
|
340
|
+
hashed_password=pwd_context.hash(payload.password),
|
|
341
|
+
)
|
|
342
|
+
self.db.add(user)
|
|
343
|
+
try:
|
|
344
|
+
# Rely on atomic DB constraints rather than race-prone application-level prechecks
|
|
345
|
+
await self.db.commit()
|
|
346
|
+
except IntegrityError as exc:
|
|
347
|
+
await self.db.rollback()
|
|
348
|
+
raise DuplicateUserError from exc
|
|
349
|
+
await self.db.refresh(user)
|
|
350
|
+
return user
|
|
351
|
+
|
|
352
|
+
async def list(self, skip: int = 0, limit: int = 20) -> tuple[list[User], int]:
|
|
353
|
+
total_result = await self.db.execute(select(func.count(User.id)))
|
|
354
|
+
total = total_result.scalar_one()
|
|
355
|
+
# Enforce explicit deterministic ordering to ensure reliable pagination
|
|
356
|
+
result = await self.db.execute(
|
|
357
|
+
select(User).order_by(User.id).offset(skip).limit(limit)
|
|
358
|
+
)
|
|
359
|
+
return list(result.scalars()), total
|
|
360
|
+
|
|
361
|
+
async def update(self, user_id: int, payload: UserUpdate) -> User | None:
|
|
362
|
+
user = await self.db.get(User, user_id)
|
|
363
|
+
if user is None:
|
|
364
|
+
return None
|
|
365
|
+
for field, value in payload.model_dump(exclude_unset=True).items():
|
|
366
|
+
setattr(user, field, value)
|
|
367
|
+
try:
|
|
368
|
+
await self.db.commit()
|
|
369
|
+
except IntegrityError as exc:
|
|
370
|
+
await self.db.rollback()
|
|
371
|
+
raise DuplicateUserError from exc
|
|
372
|
+
await self.db.refresh(user)
|
|
373
|
+
return user
|
|
374
|
+
|
|
375
|
+
async def authenticate(self, email: str, password: str) -> str | None:
|
|
376
|
+
user = await self.get_by_email(email)
|
|
377
|
+
if user is None or not pwd_context.verify(password, user.hashed_password):
|
|
378
|
+
return None
|
|
379
|
+
expire = datetime.now(timezone.utc) + timedelta(
|
|
380
|
+
minutes=settings.access_token_expire_minutes
|
|
381
|
+
)
|
|
382
|
+
return jwt.encode(
|
|
383
|
+
{"sub": str(user.id), "exp": expire},
|
|
384
|
+
settings.secret_key,
|
|
385
|
+
algorithm=settings.algorithm,
|
|
386
|
+
)
|
|
261
387
|
```
|
|
262
388
|
|
|
263
|
-
|
|
389
|
+
> **Note on Database Design:** Application-level unique handling requires an underlying unique database index (e.g., `unique=True` on your SQLAlchemy mapping attributes). Without underlying constraints, application layer error-catching cannot safely prevent concurrent race conditions.
|
|
390
|
+
|
|
391
|
+
---
|
|
264
392
|
|
|
265
|
-
|
|
393
|
+
## Testing with httpx and pytest
|
|
266
394
|
|
|
267
395
|
```python
|
|
268
|
-
|
|
396
|
+
# tests/conftest.py
|
|
397
|
+
import pytest_asyncio
|
|
269
398
|
from httpx import ASGITransport, AsyncClient
|
|
270
|
-
from sqlalchemy.ext.asyncio import AsyncSession
|
|
399
|
+
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
|
271
400
|
|
|
401
|
+
from app.database import Base
|
|
272
402
|
from app.dependencies import get_db
|
|
273
403
|
from app.main import create_app
|
|
274
404
|
|
|
405
|
+
TEST_DATABASE_URL = "sqlite+aiosqlite:///:memory:"
|
|
406
|
+
|
|
407
|
+
engine = create_async_engine(TEST_DATABASE_URL)
|
|
408
|
+
TestingSessionLocal = async_sessionmaker(engine, expire_on_commit=False)
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
@pytest_asyncio.fixture(autouse=True)
|
|
412
|
+
async def setup_db():
|
|
413
|
+
async with engine.begin() as conn:
|
|
414
|
+
await conn.run_sync(Base.metadata.create_all)
|
|
415
|
+
yield
|
|
416
|
+
async with engine.begin() as conn:
|
|
417
|
+
await conn.run_sync(Base.metadata.drop_all)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
@pytest_asyncio.fixture
|
|
421
|
+
async def db_session():
|
|
422
|
+
async with TestingSessionLocal() as session:
|
|
423
|
+
yield session
|
|
424
|
+
await session.rollback()
|
|
425
|
+
|
|
275
426
|
|
|
276
|
-
@
|
|
277
|
-
async def client(
|
|
427
|
+
@pytest_asyncio.fixture
|
|
428
|
+
async def client(db_session: AsyncSession):
|
|
278
429
|
app = create_app()
|
|
279
430
|
|
|
280
431
|
async def override_get_db():
|
|
281
|
-
yield
|
|
432
|
+
yield db_session
|
|
282
433
|
|
|
283
434
|
app.dependency_overrides[get_db] = override_get_db
|
|
435
|
+
|
|
284
436
|
async with AsyncClient(
|
|
285
|
-
transport=ASGITransport(app=app),
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
437
|
+
transport=ASGITransport(app=app), base_url="http://test"
|
|
438
|
+
) as ac:
|
|
439
|
+
yield ac
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
@pytest_asyncio.fixture
|
|
443
|
+
async def registered_user(client: AsyncClient) -> dict:
|
|
444
|
+
resp = await client.post("/users/", json={
|
|
445
|
+
"email": "test@example.com",
|
|
446
|
+
"username": "testuser",
|
|
447
|
+
"password": "securepass1",
|
|
448
|
+
"password_confirm": "securepass1",
|
|
449
|
+
})
|
|
450
|
+
assert resp.status_code == 201
|
|
451
|
+
return resp.json()
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
@pytest_asyncio.fixture
|
|
455
|
+
async def auth_token(client: AsyncClient, registered_user: dict) -> str:
|
|
456
|
+
resp = await client.post("/users/token", data={
|
|
457
|
+
"username": "test@example.com",
|
|
458
|
+
"password": "securepass1",
|
|
459
|
+
})
|
|
460
|
+
assert resp.status_code == 200
|
|
461
|
+
return resp.json()["access_token"]
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
@pytest_asyncio.fixture
|
|
465
|
+
async def auth_client(client: AsyncClient, auth_token: str) -> AsyncClient:
|
|
466
|
+
client.headers.update({"Authorization": f"Bearer {auth_token}"})
|
|
467
|
+
return client
|
|
290
468
|
```
|
|
291
469
|
|
|
292
|
-
|
|
470
|
+
---
|
|
293
471
|
|
|
294
|
-
|
|
295
|
-
- Validate JWT issuer, audience, expiry, and signing algorithm.
|
|
296
|
-
- Keep CORS origins environment-specific.
|
|
297
|
-
- Put rate limits on auth and write-heavy endpoints.
|
|
298
|
-
- Use Pydantic models for all request bodies.
|
|
299
|
-
- Use ORM parameter binding or SQLAlchemy Core expressions; never build SQL with f-strings.
|
|
300
|
-
- Redact tokens, authorization headers, cookies, and passwords from logs.
|
|
301
|
-
- Run dependency audit tooling in CI.
|
|
472
|
+
## Anti-Patterns
|
|
302
473
|
|
|
303
|
-
|
|
474
|
+
```python
|
|
475
|
+
# Bad: business logic inside route handlers.
|
|
476
|
+
@router.post("/users/")
|
|
477
|
+
async def create_user(payload: UserCreate, db: DbDep):
|
|
478
|
+
hashed = bcrypt.hash(payload.password)
|
|
479
|
+
user = User(email=payload.email, hashed_password=hashed)
|
|
480
|
+
db.add(user)
|
|
481
|
+
await db.commit()
|
|
482
|
+
return user
|
|
304
483
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
484
|
+
# Good: thin route, transactional service handling.
|
|
485
|
+
@router.post("/users/", response_model=UserResponse, status_code=201)
|
|
486
|
+
async def create_user(payload: UserCreate, db: DbDep):
|
|
487
|
+
try:
|
|
488
|
+
return await UserService(db).create(payload)
|
|
489
|
+
except DuplicateUserError:
|
|
490
|
+
raise HTTPException(status_code=400, detail="Email already registered")
|
|
311
491
|
|
|
312
|
-
## Examples
|
|
313
492
|
|
|
314
|
-
|
|
493
|
+
# Bad: sync DB calls in async routes block the event loop.
|
|
494
|
+
@router.get("/items/")
|
|
495
|
+
async def list_items(db: Session = Depends(get_db)):
|
|
496
|
+
return db.query(Item).all()
|
|
315
497
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
498
|
+
# Good: use async SQLAlchemy executions.
|
|
499
|
+
@router.get("/items/")
|
|
500
|
+
async def list_items(db: AsyncSession = Depends(get_db)):
|
|
501
|
+
result = await db.execute(select(Item))
|
|
502
|
+
return result.scalars().all()
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
---
|
|
320
506
|
|
|
321
|
-
##
|
|
507
|
+
## Best Practices
|
|
322
508
|
|
|
323
|
-
-
|
|
324
|
-
-
|
|
325
|
-
-
|
|
326
|
-
-
|
|
327
|
-
-
|
|
509
|
+
- Always declare a typed `response_model` to prevent accidental PII/data leaks and output clean OpenAPI schemas.
|
|
510
|
+
- Consolidate standard middleware dependency injections via type-aliasing: `DbDep = Annotated[AsyncSession, Depends(get_db)]`.
|
|
511
|
+
- Wrap database mutation boundaries gracefully within transactions inside your service layer, catching structural database errors directly.
|
|
512
|
+
- Parse JWT parameters defensively, expecting potential string/integer cast mismatches from modern payload variations.
|
|
513
|
+
- Enforce deterministic sorting (e.g., `.order_by(Model.id)`) on all offset/limit paginated endpoints to avoid data skips.
|
|
514
|
+
- Isolate authorization checks from core authentication dependencies to provide precise REST status signals (`401` vs `403`).
|