proagents 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/bin/proagents.js +90 -0
- package/lib/commands/feature.js +125 -0
- package/lib/commands/fix.js +60 -0
- package/lib/commands/help.js +76 -0
- package/lib/commands/init.js +64 -0
- package/lib/commands/status.js +91 -0
- package/lib/index.js +28 -0
- package/package.json +52 -0
- package/proagents/.learning/global/common-patterns.json +77 -0
- package/proagents/.learning/global/user-preferences.json +76 -0
- package/proagents/.learning/projects/example-project/corrections.json +99 -0
- package/proagents/.learning/projects/example-project/feedback.json +109 -0
- package/proagents/.learning/projects/example-project/metrics.json +101 -0
- package/proagents/.learning/projects/example-project/patterns.json +102 -0
- package/proagents/.learning/schemas/README.md +48 -0
- package/proagents/.learning/schemas/corrections-schema.json +100 -0
- package/proagents/.learning/schemas/feedback-schema.json +144 -0
- package/proagents/.learning/schemas/metrics-schema.json +96 -0
- package/proagents/.learning/schemas/patterns-schema.json +82 -0
- package/proagents/.learning/schemas/project-patterns-schema.json +125 -0
- package/proagents/.learning/schemas/user-preferences-schema.json +136 -0
- package/proagents/GETTING-STARTED-STORY.md +708 -0
- package/proagents/README.md +99 -0
- package/proagents/WORKFLOW.md +1234 -0
- package/proagents/active-features/.gitkeep +0 -0
- package/proagents/active-features/README.md +176 -0
- package/proagents/active-features/_index.json +74 -0
- package/proagents/active-features/feature-user-auth/dependencies.json +81 -0
- package/proagents/active-features/feature-user-auth/files-modified.json +126 -0
- package/proagents/active-features/feature-user-auth/status.json +122 -0
- package/proagents/active-features/schemas/dependencies-schema.json +119 -0
- package/proagents/active-features/schemas/feature-schema.json +132 -0
- package/proagents/active-features/schemas/files-schema.json +100 -0
- package/proagents/active-features/schemas/index-schema.json +95 -0
- package/proagents/adr/README.md +302 -0
- package/proagents/adr/examples/api-versioning.md +297 -0
- package/proagents/adr/examples/database-choice.md +264 -0
- package/proagents/adr/template.md +273 -0
- package/proagents/ai-models/README.md +141 -0
- package/proagents/ai-models/cost-management.md +362 -0
- package/proagents/ai-models/fallbacks.md +342 -0
- package/proagents/ai-models/model-config.md +318 -0
- package/proagents/ai-models/task-routing.md +503 -0
- package/proagents/ai-training/README.md +155 -0
- package/proagents/ai-training/continuous-learning.md +413 -0
- package/proagents/ai-training/domain-knowledge.md +378 -0
- package/proagents/ai-training/pattern-learning.md +455 -0
- package/proagents/ai-training/training-data.md +337 -0
- package/proagents/ai-training/user-preferences.md +346 -0
- package/proagents/api-versioning/README.md +257 -0
- package/proagents/api-versioning/changelog-template.md +225 -0
- package/proagents/api-versioning/deprecation-workflow.md +470 -0
- package/proagents/api-versioning/versioning-strategy.md +291 -0
- package/proagents/approval-workflows/README.md +146 -0
- package/proagents/approval-workflows/approval-config.md +332 -0
- package/proagents/approval-workflows/approval-stages.md +503 -0
- package/proagents/approval-workflows/emergency-bypass.md +351 -0
- package/proagents/approval-workflows/examples.md +859 -0
- package/proagents/approval-workflows/notifications.md +320 -0
- package/proagents/automation/README.md +38 -0
- package/proagents/automation/ai-behavior-rules.md +339 -0
- package/proagents/automation/ai-prompt-injection.md +331 -0
- package/proagents/automation/auto-decisions.md +535 -0
- package/proagents/automation/decision-defaults.yaml +317 -0
- package/proagents/cache/README.md +110 -0
- package/proagents/cache/analysis-metadata.json +76 -0
- package/proagents/cache/conventions.json +125 -0
- package/proagents/cache/dependencies.json +85 -0
- package/proagents/cache/features.json +115 -0
- package/proagents/cache/patterns.json +105 -0
- package/proagents/cache/schemas/conventions-schema.json +138 -0
- package/proagents/cache/schemas/dependencies-schema.json +95 -0
- package/proagents/cache/schemas/features-schema.json +104 -0
- package/proagents/cache/schemas/metadata-schema.json +83 -0
- package/proagents/cache/schemas/patterns-schema.json +136 -0
- package/proagents/cache/schemas/structure-schema.json +72 -0
- package/proagents/cache/structure.json +109 -0
- package/proagents/changelog/2024/01/2024-01-10-api-url-config.md +41 -0
- package/proagents/changelog/2024/01/2024-01-12-login-bug-fix.md +69 -0
- package/proagents/changelog/2024/01/2024-01-15-user-auth-feature.md +99 -0
- package/proagents/changelog/CHANGELOG.md +82 -0
- package/proagents/changelog/README.md +327 -0
- package/proagents/changelog/entry-template.md +283 -0
- package/proagents/checklists/README.md +261 -0
- package/proagents/checklists/code-quality.md +137 -0
- package/proagents/checklists/code-review.md +148 -0
- package/proagents/checklists/pr-checklist.md +78 -0
- package/proagents/checklists/pre-deployment.md +132 -0
- package/proagents/checklists/pre-implementation.md +80 -0
- package/proagents/checklists/testing.md +120 -0
- package/proagents/cicd/README.md +338 -0
- package/proagents/cicd/azure-devops.md +267 -0
- package/proagents/cicd/github-actions.md +375 -0
- package/proagents/cicd/gitlab-ci.md +278 -0
- package/proagents/cicd/jenkins.md +317 -0
- package/proagents/cli/README.md +392 -0
- package/proagents/cli/commands-reference.md +893 -0
- package/proagents/cli/ide-integration.md +584 -0
- package/proagents/cli/shortcuts.md +394 -0
- package/proagents/cli/slash-commands.md +507 -0
- package/proagents/collaboration/README.md +143 -0
- package/proagents/collaboration/roles.md +248 -0
- package/proagents/collaboration/sessions.md +390 -0
- package/proagents/collaboration/sync.md +358 -0
- package/proagents/compliance/README.md +206 -0
- package/proagents/compliance/access-control.md +310 -0
- package/proagents/compliance/audit-logging.md +444 -0
- package/proagents/compliance/compliance-frameworks.md +429 -0
- package/proagents/compliance/reports.md +491 -0
- package/proagents/compliance/retention-policies.md +454 -0
- package/proagents/config/README.md +181 -0
- package/proagents/config/integrations/README.md +68 -0
- package/proagents/config/integrations/github.yaml +211 -0
- package/proagents/config/integrations/jira.yaml +144 -0
- package/proagents/config/integrations/linear.yaml +157 -0
- package/proagents/config/integrations/notion.yaml +203 -0
- package/proagents/config/integrations/slack.yaml +230 -0
- package/proagents/config/rules/README.md +73 -0
- package/proagents/config/rules/custom-rules.template.yaml +188 -0
- package/proagents/config/rules/validation-rules.template.yaml +177 -0
- package/proagents/config/standards/README.md +58 -0
- package/proagents/config/standards/architecture-rules.template.md +124 -0
- package/proagents/config/standards/coding-standards.template.md +107 -0
- package/proagents/config/standards/naming-conventions.template.md +114 -0
- package/proagents/config/standards/testing-standards.template.md +213 -0
- package/proagents/config/templates/README.md +74 -0
- package/proagents/config/templates/api-route.template.ts +142 -0
- package/proagents/config/templates/component.template.tsx +55 -0
- package/proagents/config/templates/hook.template.ts +93 -0
- package/proagents/config/templates/test.template.ts +171 -0
- package/proagents/config-versioning/README.md +120 -0
- package/proagents/config-versioning/changelog.md +300 -0
- package/proagents/config-versioning/rollback.md +283 -0
- package/proagents/config-versioning/versioning.md +330 -0
- package/proagents/contract-testing/README.md +223 -0
- package/proagents/contract-testing/contract-testing.md +614 -0
- package/proagents/contract-testing/pact-integration.md +507 -0
- package/proagents/contract-testing/schema-validation.md +565 -0
- package/proagents/cost/README.md +48 -0
- package/proagents/cost/cost-template.md +283 -0
- package/proagents/cost/estimation-framework.md +287 -0
- package/proagents/database/README.md +72 -0
- package/proagents/database/examples/001-create-users.sql +129 -0
- package/proagents/database/examples/002-add-preferences.sql +94 -0
- package/proagents/database/examples/003-add-index.sql +105 -0
- package/proagents/database/examples/004-rename-column.sql +122 -0
- package/proagents/database/examples/005-add-foreign-key.sql +142 -0
- package/proagents/database/examples/006-data-migration.sql +196 -0
- package/proagents/database/examples/007-drop-column.sql +163 -0
- package/proagents/database/examples/README.md +89 -0
- package/proagents/database/migration-workflow.md +478 -0
- package/proagents/database/rollback-scripts.md +487 -0
- package/proagents/database/safety-checks.md +447 -0
- package/proagents/dependency-management/README.md +140 -0
- package/proagents/dependency-management/automation.md +363 -0
- package/proagents/dependency-management/compatibility.md +319 -0
- package/proagents/dependency-management/security-scanning.md +413 -0
- package/proagents/dependency-management/update-policies.md +374 -0
- package/proagents/disaster-recovery/README.md +247 -0
- package/proagents/disaster-recovery/automation.md +366 -0
- package/proagents/disaster-recovery/backup-recovery.md +571 -0
- package/proagents/disaster-recovery/incident-response.md +565 -0
- package/proagents/disaster-recovery/rollback-procedures.md +499 -0
- package/proagents/disaster-recovery/runbooks.md +603 -0
- package/proagents/disaster-recovery/scenarios.md +892 -0
- package/proagents/disaster-recovery/testing.md +438 -0
- package/proagents/environments/README.md +244 -0
- package/proagents/environments/configuration.md +437 -0
- package/proagents/environments/promotion.md +434 -0
- package/proagents/environments/setup.md +420 -0
- package/proagents/examples/README.md +55 -0
- package/proagents/examples/backend-nodejs/README.md +188 -0
- package/proagents/examples/backend-nodejs/complete-conversation.md +601 -0
- package/proagents/examples/backend-nodejs/proagents.config.yaml +415 -0
- package/proagents/examples/backend-nodejs/workflow-example.md +909 -0
- package/proagents/examples/fullstack-nextjs/README.md +155 -0
- package/proagents/examples/fullstack-nextjs/complete-conversation.md +604 -0
- package/proagents/examples/fullstack-nextjs/proagents.config.yaml +287 -0
- package/proagents/examples/fullstack-nextjs/workflow-example.md +553 -0
- package/proagents/examples/mobile-react-native/README.md +171 -0
- package/proagents/examples/mobile-react-native/complete-conversation.md +825 -0
- package/proagents/examples/mobile-react-native/proagents.config.yaml +330 -0
- package/proagents/examples/mobile-react-native/workflow-example.md +723 -0
- package/proagents/examples/web-frontend-react/README.md +125 -0
- package/proagents/examples/web-frontend-react/complete-conversation.md +556 -0
- package/proagents/examples/web-frontend-react/proagents.config.yaml +183 -0
- package/proagents/examples/web-frontend-react/workflow-example.md +603 -0
- package/proagents/existing-projects/README.md +65 -0
- package/proagents/existing-projects/challenges.md +861 -0
- package/proagents/existing-projects/coexistence-mode.md +483 -0
- package/proagents/existing-projects/compatibility-assessment.md +541 -0
- package/proagents/existing-projects/gradual-adoption.md +515 -0
- package/proagents/existing-projects/migration-strategies.md +788 -0
- package/proagents/existing-projects/pattern-reconciliation.md +489 -0
- package/proagents/existing-projects/team-onboarding.md +617 -0
- package/proagents/existing-projects/technical-debt-handling.md +644 -0
- package/proagents/feature-flags/README.md +263 -0
- package/proagents/feature-flags/ab-testing.md +413 -0
- package/proagents/feature-flags/configuration.md +420 -0
- package/proagents/feature-flags/kill-switches.md +444 -0
- package/proagents/feature-flags/rollout-strategies.md +392 -0
- package/proagents/getting-started/README.md +60 -0
- package/proagents/getting-started/ai-training-setup.md +380 -0
- package/proagents/getting-started/ide-setup.md +195 -0
- package/proagents/getting-started/mcp-setup.md +239 -0
- package/proagents/getting-started/pm-integration.md +336 -0
- package/proagents/getting-started/prompt-engineering.md +478 -0
- package/proagents/getting-started/team-onboarding.md +236 -0
- package/proagents/git/README.md +68 -0
- package/proagents/git/branch-strategy.md +164 -0
- package/proagents/git/commit-conventions.md +241 -0
- package/proagents/git/pr-workflow.md +286 -0
- package/proagents/git/rollback-procedures.md +416 -0
- package/proagents/i18n/README.md +133 -0
- package/proagents/i18n/extraction.md +433 -0
- package/proagents/i18n/tms-integration.md +332 -0
- package/proagents/i18n/translation-workflow.md +413 -0
- package/proagents/i18n/validation.md +355 -0
- package/proagents/ide-integration/README.md +124 -0
- package/proagents/ide-integration/cline-config.md +429 -0
- package/proagents/ide-integration/continue-config.md +380 -0
- package/proagents/ide-integration/cursor-rules.md +280 -0
- package/proagents/ide-integration/github-copilot.md +384 -0
- package/proagents/ide-integration/windsurf-rules.md +314 -0
- package/proagents/integrations/README.md +97 -0
- package/proagents/integrations/pm/README.md +344 -0
- package/proagents/learning/README.md +136 -0
- package/proagents/learning/adaptation.md +305 -0
- package/proagents/learning/data-collection.md +283 -0
- package/proagents/learning/implementation-guide.md +865 -0
- package/proagents/learning/reports.md +306 -0
- package/proagents/logging/README.md +276 -0
- package/proagents/logging/aggregation.md +475 -0
- package/proagents/logging/log-levels.md +376 -0
- package/proagents/logging/sensitive-data.md +423 -0
- package/proagents/logging/structured-logging.md +406 -0
- package/proagents/mcp/README.md +133 -0
- package/proagents/mcp/context-providers.md +442 -0
- package/proagents/mcp/server-config.md +306 -0
- package/proagents/mcp/tools-definition.md +513 -0
- package/proagents/metrics/README.md +174 -0
- package/proagents/metrics/code-quality-kpis.md +461 -0
- package/proagents/metrics/deployment-metrics.md +517 -0
- package/proagents/metrics/developer-productivity.md +368 -0
- package/proagents/metrics/learning-effectiveness.md +478 -0
- package/proagents/migrations/README.md +77 -0
- package/proagents/migrations/from-claude-projects.md +312 -0
- package/proagents/migrations/from-cursor-rules.md +345 -0
- package/proagents/migrations/from-custom-workflows.md +410 -0
- package/proagents/monitoring/README.md +308 -0
- package/proagents/monitoring/alerting.md +449 -0
- package/proagents/monitoring/dashboards.md +454 -0
- package/proagents/monitoring/health-checks.md +436 -0
- package/proagents/monitoring/metrics.md +434 -0
- package/proagents/multi-project/README.md +170 -0
- package/proagents/multi-project/coordinated-deploy.md +510 -0
- package/proagents/multi-project/cross-project-deps.md +395 -0
- package/proagents/multi-project/unified-changelog.md +477 -0
- package/proagents/multi-project/walkthroughs/monorepo-setup.md +787 -0
- package/proagents/multi-project/workspace-config.md +408 -0
- package/proagents/notifications/README.md +151 -0
- package/proagents/notifications/channels.md +457 -0
- package/proagents/notifications/preferences.md +415 -0
- package/proagents/notifications/routing.md +449 -0
- package/proagents/notifications/scheduling.md +425 -0
- package/proagents/notifications/templates.md +446 -0
- package/proagents/offline-mode/README.md +145 -0
- package/proagents/offline-mode/caching.md +344 -0
- package/proagents/offline-mode/offline-operations.md +312 -0
- package/proagents/offline-mode/queue-specifications.md +679 -0
- package/proagents/offline-mode/sync.md +475 -0
- package/proagents/parallel-features/README.md +85 -0
- package/proagents/parallel-features/conflict-detection.md +226 -0
- package/proagents/parallel-features/dependency-management.md +392 -0
- package/proagents/parallel-features/merge-coordination.md +506 -0
- package/proagents/parallel-features/tracking-system.md +416 -0
- package/proagents/patterns/README.md +305 -0
- package/proagents/patterns/api-errors.md +453 -0
- package/proagents/patterns/async-errors.md +521 -0
- package/proagents/patterns/error-types.md +437 -0
- package/proagents/patterns/ui-errors.md +595 -0
- package/proagents/performance/README.md +59 -0
- package/proagents/performance/bundle-analysis.md +375 -0
- package/proagents/performance/load-testing.md +563 -0
- package/proagents/performance/runtime-metrics.md +489 -0
- package/proagents/performance/web-vitals.md +425 -0
- package/proagents/plugins/README.md +139 -0
- package/proagents/plugins/creating-plugins.md +504 -0
- package/proagents/plugins/plugin-api.md +467 -0
- package/proagents/plugins/plugin-registry.md +276 -0
- package/proagents/pm-integration/README.md +151 -0
- package/proagents/pm-integration/asana.md +346 -0
- package/proagents/pm-integration/github-issues.md +308 -0
- package/proagents/pm-integration/gitlab-issues.md +482 -0
- package/proagents/pm-integration/jira.md +364 -0
- package/proagents/pm-integration/linear.md +409 -0
- package/proagents/pm-integration/notion.md +275 -0
- package/proagents/pm-integration/sync-config.md +533 -0
- package/proagents/pm-integration/trello.md +159 -0
- package/proagents/proagents.config.yaml +213 -0
- package/proagents/prompts/00-init-wizard.md +426 -0
- package/proagents/prompts/00-init.md +219 -0
- package/proagents/prompts/01-analysis.md +244 -0
- package/proagents/prompts/02-requirements.md +399 -0
- package/proagents/prompts/03-ui-design.md +493 -0
- package/proagents/prompts/04-planning.md +505 -0
- package/proagents/prompts/05-implementation.md +518 -0
- package/proagents/prompts/06-testing.md +620 -0
- package/proagents/prompts/06.5-code-review.md +512 -0
- package/proagents/prompts/07-documentation.md +673 -0
- package/proagents/prompts/08-deployment.md +539 -0
- package/proagents/prompts/09-rollback.md +554 -0
- package/proagents/prompts/README.md +51 -0
- package/proagents/prompts/accessibility/README.md +146 -0
- package/proagents/prompts/accessibility/aria.md +276 -0
- package/proagents/prompts/accessibility/audit.md +233 -0
- package/proagents/prompts/accessibility/keyboard.md +392 -0
- package/proagents/prompts/accessibility/wcag.md +189 -0
- package/proagents/prompts/debugging/README.md +51 -0
- package/proagents/prompts/debugging/error-analysis.md +385 -0
- package/proagents/prompts/debugging/performance-debug.md +381 -0
- package/proagents/prompts/debugging/systematic.md +270 -0
- package/proagents/prompts/performance/README.md +47 -0
- package/proagents/prompts/performance/analyze.md +265 -0
- package/proagents/prompts/performance/optimize.md +347 -0
- package/proagents/prompts/refactoring/README.md +51 -0
- package/proagents/prompts/refactoring/architecture.md +531 -0
- package/proagents/prompts/refactoring/code-smells.md +174 -0
- package/proagents/prompts/refactoring/patterns.md +516 -0
- package/proagents/prompts/security-audit/README.md +197 -0
- package/proagents/prompts/security-audit/code-review.md +260 -0
- package/proagents/prompts/security-audit/vulnerability-scan.md +288 -0
- package/proagents/reporting/README.md +158 -0
- package/proagents/reporting/dashboards.md +366 -0
- package/proagents/reporting/exports.md +524 -0
- package/proagents/reporting/quality-metrics.md +385 -0
- package/proagents/reporting/templates/README.md +56 -0
- package/proagents/reporting/templates/dashboard-config.json +187 -0
- package/proagents/reporting/templates/metrics-queries.md +427 -0
- package/proagents/reporting/templates/react-dashboard.tsx +544 -0
- package/proagents/reporting/templates/widgets.md +451 -0
- package/proagents/reporting/velocity-metrics.md +340 -0
- package/proagents/reverse-engineering/README.md +151 -0
- package/proagents/reverse-engineering/architecture-extraction.md +325 -0
- package/proagents/reverse-engineering/code-analysis.md +377 -0
- package/proagents/reverse-engineering/dependency-mapping.md +567 -0
- package/proagents/reverse-engineering/diagram-generation.md +586 -0
- package/proagents/reverse-engineering/documentation-generation.md +468 -0
- package/proagents/reverse-engineering/pattern-detection.md +569 -0
- package/proagents/reverse-engineering/quality-assessment.md +733 -0
- package/proagents/rules/README.md +179 -0
- package/proagents/rules/custom-rules-template.yaml +286 -0
- package/proagents/rules/custom-rules.md +754 -0
- package/proagents/rules/validation-rules-template.yaml +517 -0
- package/proagents/runbooks/README.md +219 -0
- package/proagents/runbooks/dependency-vulnerability.md +505 -0
- package/proagents/runbooks/incident-response.md +451 -0
- package/proagents/runbooks/performance-degradation.md +584 -0
- package/proagents/runbooks/production-debugging.md +489 -0
- package/proagents/scaffolding/README.md +64 -0
- package/proagents/scaffolding/nextjs/README.md +578 -0
- package/proagents/scaffolding/nextjs/templates/api-route.ts.template +185 -0
- package/proagents/scaffolding/nextjs/templates/page.tsx.template +109 -0
- package/proagents/scaffolding/nextjs/templates/server-action.ts.template +204 -0
- package/proagents/scaffolding/nodejs/README.md +558 -0
- package/proagents/scaffolding/nodejs/templates/controller.ts.template +167 -0
- package/proagents/scaffolding/nodejs/templates/repository.ts.template +155 -0
- package/proagents/scaffolding/nodejs/templates/service.ts.template +207 -0
- package/proagents/scaffolding/project-types.md +401 -0
- package/proagents/scaffolding/react/README.md +399 -0
- package/proagents/scaffolding/react/templates/component.tsx.template +88 -0
- package/proagents/scaffolding/react/templates/hook.ts.template +127 -0
- package/proagents/scaffolding/react/templates/service.ts.template +155 -0
- package/proagents/scaffolding/react/templates/test.tsx.template +149 -0
- package/proagents/scaffolding/react-native/README.md +476 -0
- package/proagents/scaffolding/react-native/templates/hook.ts.template +226 -0
- package/proagents/scaffolding/react-native/templates/screen.tsx.template +247 -0
- package/proagents/secrets/README.md +278 -0
- package/proagents/secrets/access-control.md +443 -0
- package/proagents/secrets/rotation.md +403 -0
- package/proagents/secrets/scanning.md +487 -0
- package/proagents/secrets/storage.md +394 -0
- package/proagents/security/README.md +71 -0
- package/proagents/security/owasp-checklist.md +390 -0
- package/proagents/security/sast-guide.md +473 -0
- package/proagents/security/security-report-template.md +343 -0
- package/proagents/security/vulnerability-scanning.md +329 -0
- package/proagents/slash-commands.json +161 -0
- package/proagents/standards/README.md +120 -0
- package/proagents/standards/architecture-patterns.md +728 -0
- package/proagents/standards/architecture-rules-template.md +489 -0
- package/proagents/standards/coding-standards-template.md +489 -0
- package/proagents/standards/examples/README.md +61 -0
- package/proagents/standards/examples/nodejs-api.md +560 -0
- package/proagents/standards/examples/react-nextjs.md +428 -0
- package/proagents/standards/naming-conventions-template.md +526 -0
- package/proagents/standards/override-system.md +717 -0
- package/proagents/standards/testing-standards-template.md +220 -0
- package/proagents/team/README.md +256 -0
- package/proagents/team/code-ownership.md +306 -0
- package/proagents/team/communication-templates.md +441 -0
- package/proagents/team/handoff-protocol.md +380 -0
- package/proagents/team/ide-setup/README.md +103 -0
- package/proagents/team/ide-setup/cursor.md +276 -0
- package/proagents/team/ide-setup/jetbrains.md +330 -0
- package/proagents/team/ide-setup/neovim.md +640 -0
- package/proagents/team/ide-setup/vscode.md +348 -0
- package/proagents/team/onboarding.md +278 -0
- package/proagents/templates/README.md +57 -0
- package/proagents/templates/code-review-report.md +255 -0
- package/proagents/templates/codebase-analysis-report.md +315 -0
- package/proagents/templates/deployment-checklist.md +277 -0
- package/proagents/templates/feature-requirements.md +142 -0
- package/proagents/templates/feature-status.md +231 -0
- package/proagents/templates/implementation-plan.md +373 -0
- package/proagents/templates/rollback-plan.md +331 -0
- package/proagents/templates/test-plan.md +336 -0
- package/proagents/templates/ui-specification.md +431 -0
- package/proagents/testing-standards/README.md +229 -0
- package/proagents/testing-standards/coverage-requirements.md +198 -0
- package/proagents/testing-standards/mocking-guidelines.md +478 -0
- package/proagents/testing-standards/test-naming.md +485 -0
- package/proagents/testing-standards/test-patterns.md +488 -0
- package/proagents/troubleshooting/README.md +730 -0
- package/proagents/troubleshooting/ai-issues.md +601 -0
- package/proagents/troubleshooting/workflow-issues.md +571 -0
- package/proagents/ui-integration/README.md +77 -0
- package/proagents/ui-integration/figma-guide.md +217 -0
- package/proagents/ui-integration/manual-export-guide.md +358 -0
- package/proagents/ui-integration/sketch-interpretation.md +471 -0
- package/proagents/webhooks/README.md +126 -0
- package/proagents/webhooks/endpoints.md +298 -0
- package/proagents/webhooks/events.md +316 -0
- package/proagents/webhooks/payloads.md +325 -0
- package/proagents/webhooks/reliability.md +363 -0
- package/proagents/webhooks/security.md +380 -0
- package/proagents/workflow-modes/README.md +136 -0
- package/proagents/workflow-modes/deferred-tracking.md +405 -0
- package/proagents/workflow-modes/entry-modes.md +397 -0
- package/proagents/workflow-modes/guardrails.md +405 -0
- package/proagents/workflow-modes/mode-detection.md +358 -0
- package/proagents/workflow-modes/mode-switching.md +372 -0
|
@@ -0,0 +1,909 @@
|
|
|
1
|
+
# Node.js Backend API Workflow Example
|
|
2
|
+
|
|
3
|
+
A complete walkthrough of building an API feature using ProAgents workflow.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Scenario
|
|
8
|
+
|
|
9
|
+
**Feature:** Add product inventory management API
|
|
10
|
+
**Project:** Existing Node.js + Express + TypeScript + PostgreSQL application
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Phase 0: Initialization
|
|
15
|
+
|
|
16
|
+
### Start Feature
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
User: /feature-start "Product Inventory API"
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Context Gathered
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
Project: inventory-api
|
|
26
|
+
Type: Backend API (Node.js)
|
|
27
|
+
Branch: feature/product-inventory
|
|
28
|
+
|
|
29
|
+
Feature: Product Inventory API
|
|
30
|
+
- CRUD operations for products
|
|
31
|
+
- Inventory tracking (stock levels)
|
|
32
|
+
- Low stock alerts
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## Phase 1: Codebase Analysis
|
|
38
|
+
|
|
39
|
+
### Analysis Results
|
|
40
|
+
|
|
41
|
+
```markdown
|
|
42
|
+
## Codebase Analysis Summary
|
|
43
|
+
|
|
44
|
+
### Tech Stack
|
|
45
|
+
- Node.js 20.x
|
|
46
|
+
- Express 4.x
|
|
47
|
+
- TypeScript 5.x
|
|
48
|
+
- PostgreSQL 15
|
|
49
|
+
- Prisma ORM
|
|
50
|
+
- Zod for validation
|
|
51
|
+
- Jest for testing
|
|
52
|
+
|
|
53
|
+
### Directory Structure
|
|
54
|
+
src/
|
|
55
|
+
├── controllers/ # Route handlers
|
|
56
|
+
├── services/ # Business logic
|
|
57
|
+
├── repositories/ # Data access
|
|
58
|
+
├── middlewares/ # Auth, validation, error handling
|
|
59
|
+
├── utils/ # Helpers
|
|
60
|
+
├── types/ # TypeScript types
|
|
61
|
+
├── routes/ # Route definitions
|
|
62
|
+
└── app.ts # Express app
|
|
63
|
+
|
|
64
|
+
### Existing Patterns
|
|
65
|
+
- Repository pattern for data access
|
|
66
|
+
- Service layer for business logic
|
|
67
|
+
- Zod schemas for validation
|
|
68
|
+
- Custom error classes
|
|
69
|
+
- JWT authentication
|
|
70
|
+
|
|
71
|
+
### Database
|
|
72
|
+
- Existing tables: users, categories
|
|
73
|
+
- Prisma schema in prisma/schema.prisma
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Phase 2: Requirements
|
|
79
|
+
|
|
80
|
+
### API Requirements
|
|
81
|
+
|
|
82
|
+
```markdown
|
|
83
|
+
## Product Inventory API Requirements
|
|
84
|
+
|
|
85
|
+
### Endpoints
|
|
86
|
+
- POST /api/products - Create product
|
|
87
|
+
- GET /api/products - List products (with filters)
|
|
88
|
+
- GET /api/products/:id - Get product by ID
|
|
89
|
+
- PUT /api/products/:id - Update product
|
|
90
|
+
- DELETE /api/products/:id - Delete product
|
|
91
|
+
- PATCH /api/products/:id/inventory - Update inventory
|
|
92
|
+
|
|
93
|
+
### Business Rules
|
|
94
|
+
- SKU must be unique
|
|
95
|
+
- Initial stock can be 0 or greater
|
|
96
|
+
- Low stock threshold configurable per product
|
|
97
|
+
- Track inventory changes (audit log)
|
|
98
|
+
|
|
99
|
+
### Authentication
|
|
100
|
+
- All endpoints require authentication
|
|
101
|
+
- Admin role for create/update/delete
|
|
102
|
+
- Read access for all authenticated users
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Phase 3: Database Design
|
|
108
|
+
|
|
109
|
+
### Schema Design
|
|
110
|
+
|
|
111
|
+
```sql
|
|
112
|
+
-- Products table
|
|
113
|
+
CREATE TABLE products (
|
|
114
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
115
|
+
sku VARCHAR(50) NOT NULL UNIQUE,
|
|
116
|
+
name VARCHAR(255) NOT NULL,
|
|
117
|
+
description TEXT,
|
|
118
|
+
price DECIMAL(10, 2) NOT NULL,
|
|
119
|
+
category_id UUID REFERENCES categories(id),
|
|
120
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
121
|
+
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
-- Inventory table
|
|
125
|
+
CREATE TABLE inventory (
|
|
126
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
127
|
+
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
|
|
128
|
+
quantity INTEGER NOT NULL DEFAULT 0,
|
|
129
|
+
low_stock_threshold INTEGER NOT NULL DEFAULT 10,
|
|
130
|
+
last_restocked_at TIMESTAMP WITH TIME ZONE,
|
|
131
|
+
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
132
|
+
UNIQUE(product_id)
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
-- Inventory audit log
|
|
136
|
+
CREATE TABLE inventory_audit (
|
|
137
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
138
|
+
product_id UUID NOT NULL REFERENCES products(id),
|
|
139
|
+
change_type VARCHAR(20) NOT NULL, -- 'add', 'remove', 'adjust'
|
|
140
|
+
quantity_change INTEGER NOT NULL,
|
|
141
|
+
previous_quantity INTEGER NOT NULL,
|
|
142
|
+
new_quantity INTEGER NOT NULL,
|
|
143
|
+
reason TEXT,
|
|
144
|
+
performed_by UUID REFERENCES users(id),
|
|
145
|
+
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
CREATE INDEX idx_products_sku ON products(sku);
|
|
149
|
+
CREATE INDEX idx_products_category ON products(category_id);
|
|
150
|
+
CREATE INDEX idx_inventory_product ON inventory(product_id);
|
|
151
|
+
CREATE INDEX idx_inventory_low_stock ON inventory(quantity, low_stock_threshold);
|
|
152
|
+
CREATE INDEX idx_audit_product ON inventory_audit(product_id);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Phase 4: Implementation Plan
|
|
158
|
+
|
|
159
|
+
### File Plan
|
|
160
|
+
|
|
161
|
+
```markdown
|
|
162
|
+
## Files to Create
|
|
163
|
+
|
|
164
|
+
src/
|
|
165
|
+
├── modules/products/
|
|
166
|
+
│ ├── product.controller.ts
|
|
167
|
+
│ ├── product.service.ts
|
|
168
|
+
│ ├── product.repository.ts
|
|
169
|
+
│ ├── product.routes.ts
|
|
170
|
+
│ ├── product.validation.ts
|
|
171
|
+
│ ├── product.types.ts
|
|
172
|
+
│ └── __tests__/
|
|
173
|
+
│ ├── product.controller.test.ts
|
|
174
|
+
│ ├── product.service.test.ts
|
|
175
|
+
│ └── product.integration.test.ts
|
|
176
|
+
├── modules/inventory/
|
|
177
|
+
│ ├── inventory.controller.ts
|
|
178
|
+
│ ├── inventory.service.ts
|
|
179
|
+
│ ├── inventory.repository.ts
|
|
180
|
+
│ └── inventory.types.ts
|
|
181
|
+
|
|
182
|
+
prisma/
|
|
183
|
+
└── migrations/
|
|
184
|
+
└── XXXX_add_products_inventory.sql
|
|
185
|
+
|
|
186
|
+
## Files to Modify
|
|
187
|
+
- src/routes/index.ts - Add product routes
|
|
188
|
+
- prisma/schema.prisma - Add models
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Phase 5: Implementation
|
|
194
|
+
|
|
195
|
+
### Step 1: Database Migration
|
|
196
|
+
|
|
197
|
+
```prisma
|
|
198
|
+
// prisma/schema.prisma - Add to existing schema
|
|
199
|
+
|
|
200
|
+
model Product {
|
|
201
|
+
id String @id @default(uuid())
|
|
202
|
+
sku String @unique
|
|
203
|
+
name String
|
|
204
|
+
description String?
|
|
205
|
+
price Decimal @db.Decimal(10, 2)
|
|
206
|
+
categoryId String? @map("category_id")
|
|
207
|
+
category Category? @relation(fields: [categoryId], references: [id])
|
|
208
|
+
inventory Inventory?
|
|
209
|
+
createdAt DateTime @default(now()) @map("created_at")
|
|
210
|
+
updatedAt DateTime @updatedAt @map("updated_at")
|
|
211
|
+
|
|
212
|
+
@@map("products")
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
model Inventory {
|
|
216
|
+
id String @id @default(uuid())
|
|
217
|
+
productId String @unique @map("product_id")
|
|
218
|
+
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
|
|
219
|
+
quantity Int @default(0)
|
|
220
|
+
lowStockThreshold Int @default(10) @map("low_stock_threshold")
|
|
221
|
+
lastRestockedAt DateTime? @map("last_restocked_at")
|
|
222
|
+
updatedAt DateTime @updatedAt @map("updated_at")
|
|
223
|
+
|
|
224
|
+
@@map("inventory")
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
model InventoryAudit {
|
|
228
|
+
id String @id @default(uuid())
|
|
229
|
+
productId String @map("product_id")
|
|
230
|
+
changeType String @map("change_type")
|
|
231
|
+
quantityChange Int @map("quantity_change")
|
|
232
|
+
previousQuantity Int @map("previous_quantity")
|
|
233
|
+
newQuantity Int @map("new_quantity")
|
|
234
|
+
reason String?
|
|
235
|
+
performedBy String? @map("performed_by")
|
|
236
|
+
createdAt DateTime @default(now()) @map("created_at")
|
|
237
|
+
|
|
238
|
+
@@map("inventory_audit")
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Step 2: Types
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// src/modules/products/product.types.ts
|
|
246
|
+
export interface CreateProductDto {
|
|
247
|
+
sku: string;
|
|
248
|
+
name: string;
|
|
249
|
+
description?: string;
|
|
250
|
+
price: number;
|
|
251
|
+
categoryId?: string;
|
|
252
|
+
initialStock?: number;
|
|
253
|
+
lowStockThreshold?: number;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export interface UpdateProductDto {
|
|
257
|
+
name?: string;
|
|
258
|
+
description?: string;
|
|
259
|
+
price?: number;
|
|
260
|
+
categoryId?: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
export interface ProductFilters {
|
|
264
|
+
categoryId?: string;
|
|
265
|
+
search?: string;
|
|
266
|
+
lowStock?: boolean;
|
|
267
|
+
page?: number;
|
|
268
|
+
limit?: number;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export interface ProductWithInventory {
|
|
272
|
+
id: string;
|
|
273
|
+
sku: string;
|
|
274
|
+
name: string;
|
|
275
|
+
description: string | null;
|
|
276
|
+
price: number;
|
|
277
|
+
categoryId: string | null;
|
|
278
|
+
inventory: {
|
|
279
|
+
quantity: number;
|
|
280
|
+
lowStockThreshold: number;
|
|
281
|
+
isLowStock: boolean;
|
|
282
|
+
} | null;
|
|
283
|
+
createdAt: Date;
|
|
284
|
+
updatedAt: Date;
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Step 3: Validation
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
// src/modules/products/product.validation.ts
|
|
292
|
+
import { z } from 'zod';
|
|
293
|
+
|
|
294
|
+
export const createProductSchema = z.object({
|
|
295
|
+
body: z.object({
|
|
296
|
+
sku: z.string().min(1).max(50),
|
|
297
|
+
name: z.string().min(1).max(255),
|
|
298
|
+
description: z.string().optional(),
|
|
299
|
+
price: z.number().positive(),
|
|
300
|
+
categoryId: z.string().uuid().optional(),
|
|
301
|
+
initialStock: z.number().int().min(0).default(0),
|
|
302
|
+
lowStockThreshold: z.number().int().min(0).default(10),
|
|
303
|
+
}),
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
export const updateProductSchema = z.object({
|
|
307
|
+
params: z.object({
|
|
308
|
+
id: z.string().uuid(),
|
|
309
|
+
}),
|
|
310
|
+
body: z.object({
|
|
311
|
+
name: z.string().min(1).max(255).optional(),
|
|
312
|
+
description: z.string().optional(),
|
|
313
|
+
price: z.number().positive().optional(),
|
|
314
|
+
categoryId: z.string().uuid().nullable().optional(),
|
|
315
|
+
}),
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
export const updateInventorySchema = z.object({
|
|
319
|
+
params: z.object({
|
|
320
|
+
id: z.string().uuid(),
|
|
321
|
+
}),
|
|
322
|
+
body: z.object({
|
|
323
|
+
quantity: z.number().int(),
|
|
324
|
+
reason: z.string().optional(),
|
|
325
|
+
}),
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
export const listProductsSchema = z.object({
|
|
329
|
+
query: z.object({
|
|
330
|
+
categoryId: z.string().uuid().optional(),
|
|
331
|
+
search: z.string().optional(),
|
|
332
|
+
lowStock: z.coerce.boolean().optional(),
|
|
333
|
+
page: z.coerce.number().int().min(1).default(1),
|
|
334
|
+
limit: z.coerce.number().int().min(1).max(100).default(20),
|
|
335
|
+
}),
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Step 4: Repository
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// src/modules/products/product.repository.ts
|
|
343
|
+
import { PrismaClient, Product, Inventory } from '@prisma/client';
|
|
344
|
+
import type { CreateProductDto, UpdateProductDto, ProductFilters } from './product.types';
|
|
345
|
+
|
|
346
|
+
export class ProductRepository {
|
|
347
|
+
constructor(private prisma: PrismaClient) {}
|
|
348
|
+
|
|
349
|
+
async create(data: CreateProductDto): Promise<Product> {
|
|
350
|
+
return this.prisma.product.create({
|
|
351
|
+
data: {
|
|
352
|
+
sku: data.sku,
|
|
353
|
+
name: data.name,
|
|
354
|
+
description: data.description,
|
|
355
|
+
price: data.price,
|
|
356
|
+
categoryId: data.categoryId,
|
|
357
|
+
inventory: {
|
|
358
|
+
create: {
|
|
359
|
+
quantity: data.initialStock ?? 0,
|
|
360
|
+
lowStockThreshold: data.lowStockThreshold ?? 10,
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
include: { inventory: true },
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async findById(id: string): Promise<Product | null> {
|
|
369
|
+
return this.prisma.product.findUnique({
|
|
370
|
+
where: { id },
|
|
371
|
+
include: { inventory: true, category: true },
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
async findBySku(sku: string): Promise<Product | null> {
|
|
376
|
+
return this.prisma.product.findUnique({
|
|
377
|
+
where: { sku },
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
async findMany(filters: ProductFilters) {
|
|
382
|
+
const { categoryId, search, lowStock, page = 1, limit = 20 } = filters;
|
|
383
|
+
const skip = (page - 1) * limit;
|
|
384
|
+
|
|
385
|
+
const where = {
|
|
386
|
+
...(categoryId && { categoryId }),
|
|
387
|
+
...(search && {
|
|
388
|
+
OR: [
|
|
389
|
+
{ name: { contains: search, mode: 'insensitive' as const } },
|
|
390
|
+
{ sku: { contains: search, mode: 'insensitive' as const } },
|
|
391
|
+
],
|
|
392
|
+
}),
|
|
393
|
+
...(lowStock && {
|
|
394
|
+
inventory: {
|
|
395
|
+
quantity: { lte: this.prisma.inventory.fields.lowStockThreshold },
|
|
396
|
+
},
|
|
397
|
+
}),
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
const [products, total] = await Promise.all([
|
|
401
|
+
this.prisma.product.findMany({
|
|
402
|
+
where,
|
|
403
|
+
include: { inventory: true, category: true },
|
|
404
|
+
skip,
|
|
405
|
+
take: limit,
|
|
406
|
+
orderBy: { createdAt: 'desc' },
|
|
407
|
+
}),
|
|
408
|
+
this.prisma.product.count({ where }),
|
|
409
|
+
]);
|
|
410
|
+
|
|
411
|
+
return { products, total, page, limit };
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
async update(id: string, data: UpdateProductDto): Promise<Product> {
|
|
415
|
+
return this.prisma.product.update({
|
|
416
|
+
where: { id },
|
|
417
|
+
data,
|
|
418
|
+
include: { inventory: true },
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
async delete(id: string): Promise<void> {
|
|
423
|
+
await this.prisma.product.delete({ where: { id } });
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
async updateInventory(
|
|
427
|
+
productId: string,
|
|
428
|
+
quantityChange: number,
|
|
429
|
+
reason?: string,
|
|
430
|
+
performedBy?: string
|
|
431
|
+
): Promise<Inventory> {
|
|
432
|
+
return this.prisma.$transaction(async (tx) => {
|
|
433
|
+
const current = await tx.inventory.findUnique({
|
|
434
|
+
where: { productId },
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
if (!current) {
|
|
438
|
+
throw new Error('Inventory not found');
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const newQuantity = current.quantity + quantityChange;
|
|
442
|
+
|
|
443
|
+
if (newQuantity < 0) {
|
|
444
|
+
throw new Error('Insufficient inventory');
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Update inventory
|
|
448
|
+
const updated = await tx.inventory.update({
|
|
449
|
+
where: { productId },
|
|
450
|
+
data: {
|
|
451
|
+
quantity: newQuantity,
|
|
452
|
+
lastRestockedAt: quantityChange > 0 ? new Date() : undefined,
|
|
453
|
+
},
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// Create audit log
|
|
457
|
+
await tx.inventoryAudit.create({
|
|
458
|
+
data: {
|
|
459
|
+
productId,
|
|
460
|
+
changeType: quantityChange > 0 ? 'add' : 'remove',
|
|
461
|
+
quantityChange,
|
|
462
|
+
previousQuantity: current.quantity,
|
|
463
|
+
newQuantity,
|
|
464
|
+
reason,
|
|
465
|
+
performedBy,
|
|
466
|
+
},
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
return updated;
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
### Step 5: Service
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
// src/modules/products/product.service.ts
|
|
479
|
+
import { ProductRepository } from './product.repository';
|
|
480
|
+
import type { CreateProductDto, UpdateProductDto, ProductFilters } from './product.types';
|
|
481
|
+
import { NotFoundError, ConflictError, ValidationError } from '@/utils/errors';
|
|
482
|
+
|
|
483
|
+
export class ProductService {
|
|
484
|
+
constructor(private repository: ProductRepository) {}
|
|
485
|
+
|
|
486
|
+
async createProduct(data: CreateProductDto) {
|
|
487
|
+
// Check SKU uniqueness
|
|
488
|
+
const existing = await this.repository.findBySku(data.sku);
|
|
489
|
+
if (existing) {
|
|
490
|
+
throw new ConflictError(`Product with SKU ${data.sku} already exists`);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return this.repository.create(data);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async getProduct(id: string) {
|
|
497
|
+
const product = await this.repository.findById(id);
|
|
498
|
+
if (!product) {
|
|
499
|
+
throw new NotFoundError(`Product with ID ${id} not found`);
|
|
500
|
+
}
|
|
501
|
+
return this.formatProduct(product);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
async listProducts(filters: ProductFilters) {
|
|
505
|
+
const result = await this.repository.findMany(filters);
|
|
506
|
+
return {
|
|
507
|
+
data: result.products.map(this.formatProduct),
|
|
508
|
+
meta: {
|
|
509
|
+
total: result.total,
|
|
510
|
+
page: result.page,
|
|
511
|
+
limit: result.limit,
|
|
512
|
+
totalPages: Math.ceil(result.total / result.limit),
|
|
513
|
+
},
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
async updateProduct(id: string, data: UpdateProductDto) {
|
|
518
|
+
const existing = await this.repository.findById(id);
|
|
519
|
+
if (!existing) {
|
|
520
|
+
throw new NotFoundError(`Product with ID ${id} not found`);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return this.repository.update(id, data);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async deleteProduct(id: string) {
|
|
527
|
+
const existing = await this.repository.findById(id);
|
|
528
|
+
if (!existing) {
|
|
529
|
+
throw new NotFoundError(`Product with ID ${id} not found`);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
await this.repository.delete(id);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
async updateInventory(
|
|
536
|
+
productId: string,
|
|
537
|
+
quantityChange: number,
|
|
538
|
+
reason?: string,
|
|
539
|
+
performedBy?: string
|
|
540
|
+
) {
|
|
541
|
+
const product = await this.repository.findById(productId);
|
|
542
|
+
if (!product) {
|
|
543
|
+
throw new NotFoundError(`Product with ID ${productId} not found`);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
return this.repository.updateInventory(
|
|
547
|
+
productId,
|
|
548
|
+
quantityChange,
|
|
549
|
+
reason,
|
|
550
|
+
performedBy
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
private formatProduct(product: any) {
|
|
555
|
+
return {
|
|
556
|
+
id: product.id,
|
|
557
|
+
sku: product.sku,
|
|
558
|
+
name: product.name,
|
|
559
|
+
description: product.description,
|
|
560
|
+
price: Number(product.price),
|
|
561
|
+
categoryId: product.categoryId,
|
|
562
|
+
category: product.category,
|
|
563
|
+
inventory: product.inventory
|
|
564
|
+
? {
|
|
565
|
+
quantity: product.inventory.quantity,
|
|
566
|
+
lowStockThreshold: product.inventory.lowStockThreshold,
|
|
567
|
+
isLowStock:
|
|
568
|
+
product.inventory.quantity <= product.inventory.lowStockThreshold,
|
|
569
|
+
}
|
|
570
|
+
: null,
|
|
571
|
+
createdAt: product.createdAt,
|
|
572
|
+
updatedAt: product.updatedAt,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### Step 6: Controller
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
// src/modules/products/product.controller.ts
|
|
582
|
+
import { Request, Response, NextFunction } from 'express';
|
|
583
|
+
import { ProductService } from './product.service';
|
|
584
|
+
|
|
585
|
+
export class ProductController {
|
|
586
|
+
constructor(private service: ProductService) {}
|
|
587
|
+
|
|
588
|
+
create = async (req: Request, res: Response, next: NextFunction) => {
|
|
589
|
+
try {
|
|
590
|
+
const product = await this.service.createProduct(req.body);
|
|
591
|
+
res.status(201).json({ data: product });
|
|
592
|
+
} catch (error) {
|
|
593
|
+
next(error);
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
|
|
597
|
+
getById = async (req: Request, res: Response, next: NextFunction) => {
|
|
598
|
+
try {
|
|
599
|
+
const product = await this.service.getProduct(req.params.id);
|
|
600
|
+
res.json({ data: product });
|
|
601
|
+
} catch (error) {
|
|
602
|
+
next(error);
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
list = async (req: Request, res: Response, next: NextFunction) => {
|
|
607
|
+
try {
|
|
608
|
+
const result = await this.service.listProducts(req.query as any);
|
|
609
|
+
res.json(result);
|
|
610
|
+
} catch (error) {
|
|
611
|
+
next(error);
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
update = async (req: Request, res: Response, next: NextFunction) => {
|
|
616
|
+
try {
|
|
617
|
+
const product = await this.service.updateProduct(req.params.id, req.body);
|
|
618
|
+
res.json({ data: product });
|
|
619
|
+
} catch (error) {
|
|
620
|
+
next(error);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
delete = async (req: Request, res: Response, next: NextFunction) => {
|
|
625
|
+
try {
|
|
626
|
+
await this.service.deleteProduct(req.params.id);
|
|
627
|
+
res.status(204).send();
|
|
628
|
+
} catch (error) {
|
|
629
|
+
next(error);
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
|
|
633
|
+
updateInventory = async (req: Request, res: Response, next: NextFunction) => {
|
|
634
|
+
try {
|
|
635
|
+
const inventory = await this.service.updateInventory(
|
|
636
|
+
req.params.id,
|
|
637
|
+
req.body.quantity,
|
|
638
|
+
req.body.reason,
|
|
639
|
+
req.user?.id
|
|
640
|
+
);
|
|
641
|
+
res.json({ data: inventory });
|
|
642
|
+
} catch (error) {
|
|
643
|
+
next(error);
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
### Step 7: Routes
|
|
650
|
+
|
|
651
|
+
```typescript
|
|
652
|
+
// src/modules/products/product.routes.ts
|
|
653
|
+
import { Router } from 'express';
|
|
654
|
+
import { ProductController } from './product.controller';
|
|
655
|
+
import { ProductService } from './product.service';
|
|
656
|
+
import { ProductRepository } from './product.repository';
|
|
657
|
+
import { prisma } from '@/lib/prisma';
|
|
658
|
+
import { authenticate, authorize } from '@/middlewares/auth';
|
|
659
|
+
import { validate } from '@/middlewares/validate';
|
|
660
|
+
import {
|
|
661
|
+
createProductSchema,
|
|
662
|
+
updateProductSchema,
|
|
663
|
+
updateInventorySchema,
|
|
664
|
+
listProductsSchema,
|
|
665
|
+
} from './product.validation';
|
|
666
|
+
|
|
667
|
+
const router = Router();
|
|
668
|
+
|
|
669
|
+
// Setup dependencies
|
|
670
|
+
const repository = new ProductRepository(prisma);
|
|
671
|
+
const service = new ProductService(repository);
|
|
672
|
+
const controller = new ProductController(service);
|
|
673
|
+
|
|
674
|
+
// Routes
|
|
675
|
+
router.get(
|
|
676
|
+
'/',
|
|
677
|
+
authenticate,
|
|
678
|
+
validate(listProductsSchema),
|
|
679
|
+
controller.list
|
|
680
|
+
);
|
|
681
|
+
|
|
682
|
+
router.get(
|
|
683
|
+
'/:id',
|
|
684
|
+
authenticate,
|
|
685
|
+
controller.getById
|
|
686
|
+
);
|
|
687
|
+
|
|
688
|
+
router.post(
|
|
689
|
+
'/',
|
|
690
|
+
authenticate,
|
|
691
|
+
authorize('admin'),
|
|
692
|
+
validate(createProductSchema),
|
|
693
|
+
controller.create
|
|
694
|
+
);
|
|
695
|
+
|
|
696
|
+
router.put(
|
|
697
|
+
'/:id',
|
|
698
|
+
authenticate,
|
|
699
|
+
authorize('admin'),
|
|
700
|
+
validate(updateProductSchema),
|
|
701
|
+
controller.update
|
|
702
|
+
);
|
|
703
|
+
|
|
704
|
+
router.delete(
|
|
705
|
+
'/:id',
|
|
706
|
+
authenticate,
|
|
707
|
+
authorize('admin'),
|
|
708
|
+
controller.delete
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
router.patch(
|
|
712
|
+
'/:id/inventory',
|
|
713
|
+
authenticate,
|
|
714
|
+
authorize('admin'),
|
|
715
|
+
validate(updateInventorySchema),
|
|
716
|
+
controller.updateInventory
|
|
717
|
+
);
|
|
718
|
+
|
|
719
|
+
export { router as productRoutes };
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
## Phase 6: Testing
|
|
725
|
+
|
|
726
|
+
### Unit Tests
|
|
727
|
+
|
|
728
|
+
```typescript
|
|
729
|
+
// src/modules/products/__tests__/product.service.test.ts
|
|
730
|
+
import { ProductService } from '../product.service';
|
|
731
|
+
import { ProductRepository } from '../product.repository';
|
|
732
|
+
import { NotFoundError, ConflictError } from '@/utils/errors';
|
|
733
|
+
|
|
734
|
+
describe('ProductService', () => {
|
|
735
|
+
let service: ProductService;
|
|
736
|
+
let repository: jest.Mocked<ProductRepository>;
|
|
737
|
+
|
|
738
|
+
beforeEach(() => {
|
|
739
|
+
repository = {
|
|
740
|
+
create: jest.fn(),
|
|
741
|
+
findById: jest.fn(),
|
|
742
|
+
findBySku: jest.fn(),
|
|
743
|
+
findMany: jest.fn(),
|
|
744
|
+
update: jest.fn(),
|
|
745
|
+
delete: jest.fn(),
|
|
746
|
+
updateInventory: jest.fn(),
|
|
747
|
+
} as any;
|
|
748
|
+
service = new ProductService(repository);
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
describe('createProduct', () => {
|
|
752
|
+
it('should create product with unique SKU', async () => {
|
|
753
|
+
repository.findBySku.mockResolvedValue(null);
|
|
754
|
+
repository.create.mockResolvedValue({
|
|
755
|
+
id: '1',
|
|
756
|
+
sku: 'TEST-001',
|
|
757
|
+
name: 'Test Product',
|
|
758
|
+
} as any);
|
|
759
|
+
|
|
760
|
+
const result = await service.createProduct({
|
|
761
|
+
sku: 'TEST-001',
|
|
762
|
+
name: 'Test Product',
|
|
763
|
+
price: 99.99,
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
expect(result.sku).toBe('TEST-001');
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
it('should throw ConflictError for duplicate SKU', async () => {
|
|
770
|
+
repository.findBySku.mockResolvedValue({ id: '1' } as any);
|
|
771
|
+
|
|
772
|
+
await expect(
|
|
773
|
+
service.createProduct({
|
|
774
|
+
sku: 'EXISTING',
|
|
775
|
+
name: 'Test',
|
|
776
|
+
price: 99.99,
|
|
777
|
+
})
|
|
778
|
+
).rejects.toThrow(ConflictError);
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
describe('getProduct', () => {
|
|
783
|
+
it('should return product by ID', async () => {
|
|
784
|
+
repository.findById.mockResolvedValue({
|
|
785
|
+
id: '1',
|
|
786
|
+
name: 'Product',
|
|
787
|
+
inventory: { quantity: 10, lowStockThreshold: 5 },
|
|
788
|
+
} as any);
|
|
789
|
+
|
|
790
|
+
const result = await service.getProduct('1');
|
|
791
|
+
|
|
792
|
+
expect(result.inventory?.isLowStock).toBe(false);
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
it('should throw NotFoundError for missing product', async () => {
|
|
796
|
+
repository.findById.mockResolvedValue(null);
|
|
797
|
+
|
|
798
|
+
await expect(service.getProduct('999')).rejects.toThrow(NotFoundError);
|
|
799
|
+
});
|
|
800
|
+
});
|
|
801
|
+
});
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
### Integration Tests
|
|
805
|
+
|
|
806
|
+
```typescript
|
|
807
|
+
// src/modules/products/__tests__/product.integration.test.ts
|
|
808
|
+
import request from 'supertest';
|
|
809
|
+
import { app } from '@/app';
|
|
810
|
+
import { prisma } from '@/lib/prisma';
|
|
811
|
+
import { createTestUser, getAuthToken } from '@/test/helpers';
|
|
812
|
+
|
|
813
|
+
describe('Product API', () => {
|
|
814
|
+
let authToken: string;
|
|
815
|
+
let adminToken: string;
|
|
816
|
+
|
|
817
|
+
beforeAll(async () => {
|
|
818
|
+
const user = await createTestUser({ role: 'user' });
|
|
819
|
+
const admin = await createTestUser({ role: 'admin' });
|
|
820
|
+
authToken = getAuthToken(user);
|
|
821
|
+
adminToken = getAuthToken(admin);
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
afterAll(async () => {
|
|
825
|
+
await prisma.product.deleteMany();
|
|
826
|
+
await prisma.$disconnect();
|
|
827
|
+
});
|
|
828
|
+
|
|
829
|
+
describe('POST /api/products', () => {
|
|
830
|
+
it('should create product as admin', async () => {
|
|
831
|
+
const response = await request(app)
|
|
832
|
+
.post('/api/products')
|
|
833
|
+
.set('Authorization', `Bearer ${adminToken}`)
|
|
834
|
+
.send({
|
|
835
|
+
sku: 'TEST-001',
|
|
836
|
+
name: 'Test Product',
|
|
837
|
+
price: 99.99,
|
|
838
|
+
});
|
|
839
|
+
|
|
840
|
+
expect(response.status).toBe(201);
|
|
841
|
+
expect(response.body.data.sku).toBe('TEST-001');
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
it('should reject non-admin users', async () => {
|
|
845
|
+
const response = await request(app)
|
|
846
|
+
.post('/api/products')
|
|
847
|
+
.set('Authorization', `Bearer ${authToken}`)
|
|
848
|
+
.send({
|
|
849
|
+
sku: 'TEST-002',
|
|
850
|
+
name: 'Test',
|
|
851
|
+
price: 50,
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
expect(response.status).toBe(403);
|
|
855
|
+
});
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
describe('GET /api/products', () => {
|
|
859
|
+
it('should list products with pagination', async () => {
|
|
860
|
+
const response = await request(app)
|
|
861
|
+
.get('/api/products')
|
|
862
|
+
.set('Authorization', `Bearer ${authToken}`)
|
|
863
|
+
.query({ page: 1, limit: 10 });
|
|
864
|
+
|
|
865
|
+
expect(response.status).toBe(200);
|
|
866
|
+
expect(response.body.meta).toHaveProperty('total');
|
|
867
|
+
});
|
|
868
|
+
});
|
|
869
|
+
});
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
---
|
|
873
|
+
|
|
874
|
+
## Phase 8: Deployment
|
|
875
|
+
|
|
876
|
+
### Migration Command
|
|
877
|
+
|
|
878
|
+
```bash
|
|
879
|
+
npx prisma migrate deploy
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
### Git Commit
|
|
883
|
+
|
|
884
|
+
```bash
|
|
885
|
+
git commit -m "feat(products): add product inventory management API
|
|
886
|
+
|
|
887
|
+
- Add products and inventory tables
|
|
888
|
+
- Add CRUD endpoints for products
|
|
889
|
+
- Add inventory update with audit logging
|
|
890
|
+
- Add low stock filtering
|
|
891
|
+
- Add Zod validation
|
|
892
|
+
- Add unit and integration tests
|
|
893
|
+
|
|
894
|
+
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
---
|
|
898
|
+
|
|
899
|
+
## Summary
|
|
900
|
+
|
|
901
|
+
This example demonstrated building a complete Node.js backend API feature with:
|
|
902
|
+
|
|
903
|
+
- Database schema design with Prisma
|
|
904
|
+
- Layered architecture (controller → service → repository)
|
|
905
|
+
- Input validation with Zod
|
|
906
|
+
- Transaction support for inventory updates
|
|
907
|
+
- Audit logging
|
|
908
|
+
- Unit and integration testing
|
|
909
|
+
- Proper error handling
|