blockmine 1.21.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/README.md +469 -0
- package/.claude/agents/auth-route-debugger.md +118 -0
- package/.claude/agents/auth-route-tester.md +93 -0
- package/.claude/agents/auto-error-resolver.md +97 -0
- package/.claude/agents/build-optimizer.md +236 -0
- package/.claude/agents/code-architecture-reviewer.md +83 -0
- package/.claude/agents/code-refactor-master.md +94 -0
- package/.claude/agents/cost-optimizer.md +134 -0
- package/.claude/agents/deployment-orchestrator.md +113 -0
- package/.claude/agents/documentation-architect.md +82 -0
- package/.claude/agents/frontend-error-fixer.md +77 -0
- package/.claude/agents/iac-code-generator.md +71 -0
- package/.claude/agents/incident-responder.md +346 -0
- package/.claude/agents/infrastructure-architect.md +31 -0
- package/.claude/agents/kubernetes-specialist.md +56 -0
- package/.claude/agents/migration-planner.md +181 -0
- package/.claude/agents/network-architect.md +196 -0
- package/.claude/agents/plan-reviewer.md +52 -0
- package/.claude/agents/refactor-planner.md +63 -0
- package/.claude/agents/security-scanner.md +102 -0
- package/.claude/agents/web-research-specialist.md +78 -0
- package/.claude/commands/cost-analysis.md +315 -0
- package/.claude/commands/dev-docs-update.md +55 -0
- package/.claude/commands/dev-docs.md +51 -0
- package/.claude/commands/incident-debug.md +247 -0
- package/.claude/commands/infra-plan.md +81 -0
- package/.claude/commands/migration-plan.md +478 -0
- package/.claude/commands/route-research-for-testing.md +37 -0
- package/.claude/commands/security-review.md +66 -0
- package/.claude/hooks/CONFIG.md +448 -0
- package/.claude/hooks/README.md +163 -0
- package/.claude/hooks/SKILL_ACTIVATION_COMPLETE.md +226 -0
- package/.claude/hooks/WINDOWS_HOOKS_README.md +151 -0
- package/.claude/hooks/add-skill-activation-banners.ts +132 -0
- package/.claude/hooks/comprehensive-skill-test.ts +1315 -0
- package/.claude/hooks/error-handling-reminder.sh +12 -0
- package/.claude/hooks/error-handling-reminder.ts +222 -0
- package/.claude/hooks/k8s-manifest-validator.sh +56 -0
- package/.claude/hooks/package-lock.json +556 -0
- package/.claude/hooks/package.json +16 -0
- package/.claude/hooks/post-tool-use-tracker.ps1 +174 -0
- package/.claude/hooks/post-tool-use-tracker.sh +183 -0
- package/.claude/hooks/security-policy-check.sh +247 -0
- package/.claude/hooks/skill-activation-prompt.ps1 +10 -0
- package/.claude/hooks/skill-activation-prompt.sh +10 -0
- package/.claude/hooks/skill-activation-prompt.ts +141 -0
- package/.claude/hooks/stop-build-check-enhanced.sh +130 -0
- package/.claude/hooks/terraform-validator.sh +53 -0
- package/.claude/hooks/test-input.json +7 -0
- package/.claude/hooks/test-skill-activation.ts +427 -0
- package/.claude/hooks/trigger-build-resolver.sh +79 -0
- package/.claude/hooks/tsc-check.sh +173 -0
- package/.claude/hooks/tsconfig.json +19 -0
- package/.claude/settings.json +55 -0
- package/.claude/settings.local.json +27 -14
- package/.claude/skills/README.md +507 -0
- package/.claude/skills/api-engineering/SKILL.md +63 -0
- package/.claude/skills/api-engineering/resources/api-versioning.md +88 -0
- package/.claude/skills/api-engineering/resources/graphql-patterns.md +106 -0
- package/.claude/skills/api-engineering/resources/rate-limiting.md +118 -0
- package/.claude/skills/api-engineering/resources/rest-api-design.md +105 -0
- package/.claude/skills/backend-dev-guidelines/SKILL.md +306 -0
- package/.claude/skills/backend-dev-guidelines/resources/architecture-overview.md +451 -0
- package/.claude/skills/backend-dev-guidelines/resources/async-and-errors.md +307 -0
- package/.claude/skills/backend-dev-guidelines/resources/complete-examples.md +638 -0
- package/.claude/skills/backend-dev-guidelines/resources/configuration.md +275 -0
- package/.claude/skills/backend-dev-guidelines/resources/database-patterns.md +224 -0
- package/.claude/skills/backend-dev-guidelines/resources/middleware-guide.md +213 -0
- package/.claude/skills/backend-dev-guidelines/resources/routing-and-controllers.md +756 -0
- package/.claude/skills/backend-dev-guidelines/resources/sentry-and-monitoring.md +336 -0
- package/.claude/skills/backend-dev-guidelines/resources/services-and-repositories.md +789 -0
- package/.claude/skills/backend-dev-guidelines/resources/testing-guide.md +235 -0
- package/.claude/skills/backend-dev-guidelines/resources/validation-patterns.md +754 -0
- package/.claude/skills/budget-and-cost-management/SKILL.md +850 -0
- package/.claude/skills/build-engineering/SKILL.md +431 -0
- package/.claude/skills/build-engineering/resources/artifact-repositories.md +72 -0
- package/.claude/skills/build-engineering/resources/build-caching.md +96 -0
- package/.claude/skills/build-engineering/resources/build-pipelines.md +105 -0
- package/.claude/skills/build-engineering/resources/build-security.md +95 -0
- package/.claude/skills/build-engineering/resources/build-systems.md +389 -0
- package/.claude/skills/build-engineering/resources/compilation-optimization.md +201 -0
- package/.claude/skills/build-engineering/resources/dependency-management.md +73 -0
- package/.claude/skills/build-engineering/resources/monorepo-builds.md +110 -0
- package/.claude/skills/build-engineering/resources/performance-optimization.md +113 -0
- package/.claude/skills/build-engineering/resources/reproducible-builds.md +82 -0
- package/.claude/skills/cloud-engineering/SKILL.md +675 -0
- package/.claude/skills/cloud-engineering/resources/aws-patterns.md +742 -0
- package/.claude/skills/cloud-engineering/resources/azure-patterns.md +714 -0
- package/.claude/skills/cloud-engineering/resources/cleared-cloud-environments.md +987 -0
- package/.claude/skills/cloud-engineering/resources/cloud-cost-optimization.md +757 -0
- package/.claude/skills/cloud-engineering/resources/cloud-networking.md +1058 -0
- package/.claude/skills/cloud-engineering/resources/cloud-security-tools.md +1530 -0
- package/.claude/skills/cloud-engineering/resources/cloud-security.md +990 -0
- package/.claude/skills/cloud-engineering/resources/gcp-patterns.md +758 -0
- package/.claude/skills/cloud-engineering/resources/migration-strategies.md +820 -0
- package/.claude/skills/cloud-engineering/resources/multi-cloud-strategies.md +670 -0
- package/.claude/skills/cloud-engineering/resources/oci-patterns.md +1198 -0
- package/.claude/skills/cloud-engineering/resources/serverless-patterns.md +795 -0
- package/.claude/skills/cloud-engineering/resources/well-architected-frameworks.md +966 -0
- package/.claude/skills/cybersecurity/SKILL.md +409 -0
- package/.claude/skills/cybersecurity/resources/security-architecture.md +266 -0
- package/.claude/skills/database-engineering/SKILL.md +61 -0
- package/.claude/skills/database-engineering/resources/backup-and-recovery.md +72 -0
- package/.claude/skills/database-engineering/resources/database-replication.md +63 -0
- package/.claude/skills/database-engineering/resources/postgresql-fundamentals.md +70 -0
- package/.claude/skills/database-engineering/resources/query-optimization.md +68 -0
- package/.claude/skills/devsecops/SKILL.md +374 -0
- package/.claude/skills/devsecops/resources/ci-cd-security.md +204 -0
- package/.claude/skills/devsecops/resources/compliance-automation.md +530 -0
- package/.claude/skills/devsecops/resources/compliance-frameworks.md +2322 -0
- package/.claude/skills/devsecops/resources/container-security.md +915 -0
- package/.claude/skills/devsecops/resources/cspm-integration.md +1440 -0
- package/.claude/skills/devsecops/resources/policy-enforcement.md +619 -0
- package/.claude/skills/devsecops/resources/secrets-management.md +755 -0
- package/.claude/skills/devsecops/resources/security-monitoring.md +146 -0
- package/.claude/skills/devsecops/resources/security-scanning.md +887 -0
- package/.claude/skills/devsecops/resources/security-testing.md +203 -0
- package/.claude/skills/devsecops/resources/supply-chain-security.md +518 -0
- package/.claude/skills/devsecops/resources/vulnerability-management.md +481 -0
- package/.claude/skills/devsecops/resources/zero-trust-architecture.md +177 -0
- package/.claude/skills/documentation-as-code/SKILL.md +323 -0
- package/.claude/skills/documentation-as-code/resources/api-documentation.md +90 -0
- package/.claude/skills/documentation-as-code/resources/changelog-management.md +79 -0
- package/.claude/skills/documentation-as-code/resources/diagram-generation.md +44 -0
- package/.claude/skills/documentation-as-code/resources/docs-as-code-workflow.md +99 -0
- package/.claude/skills/documentation-as-code/resources/documentation-automation.md +68 -0
- package/.claude/skills/documentation-as-code/resources/documentation-sites.md +79 -0
- package/.claude/skills/documentation-as-code/resources/markdown-best-practices.md +162 -0
- package/.claude/skills/documentation-as-code/resources/openapi-specification.md +77 -0
- package/.claude/skills/documentation-as-code/resources/readme-engineering.md +60 -0
- package/.claude/skills/documentation-as-code/resources/technical-writing-guide.md +202 -0
- package/.claude/skills/engineering-management/SKILL.md +356 -0
- package/.claude/skills/engineering-management/resources/career-ladders.md +609 -0
- package/.claude/skills/engineering-management/resources/hiring-and-assessment.md +555 -0
- package/.claude/skills/engineering-management/resources/one-on-one-guides.md +609 -0
- package/.claude/skills/engineering-management/resources/resource-planning.md +557 -0
- package/.claude/skills/engineering-management/resources/team-organization-patterns.md +491 -0
- package/.claude/skills/engineering-management/resources/technical-interviews.md +474 -0
- package/.claude/skills/engineering-operations-management/SKILL.md +817 -0
- package/.claude/skills/error-tracking/SKILL.md +379 -0
- package/.claude/skills/frontend-dev-guidelines/SKILL.md +403 -0
- package/.claude/skills/frontend-dev-guidelines/resources/common-patterns.md +331 -0
- package/.claude/skills/frontend-dev-guidelines/resources/complete-examples.md +872 -0
- package/.claude/skills/frontend-dev-guidelines/resources/component-patterns.md +502 -0
- package/.claude/skills/frontend-dev-guidelines/resources/data-fetching.md +767 -0
- package/.claude/skills/frontend-dev-guidelines/resources/file-organization.md +502 -0
- package/.claude/skills/frontend-dev-guidelines/resources/loading-and-error-states.md +501 -0
- package/.claude/skills/frontend-dev-guidelines/resources/performance.md +406 -0
- package/.claude/skills/frontend-dev-guidelines/resources/routing-guide.md +364 -0
- package/.claude/skills/frontend-dev-guidelines/resources/styling-guide.md +428 -0
- package/.claude/skills/frontend-dev-guidelines/resources/typescript-standards.md +418 -0
- package/.claude/skills/general-it-engineering/SKILL.md +393 -0
- package/.claude/skills/general-it-engineering/resources/asset-management.md +712 -0
- package/.claude/skills/general-it-engineering/resources/automation-orchestration.md +817 -0
- package/.claude/skills/general-it-engineering/resources/business-continuity.md +786 -0
- package/.claude/skills/general-it-engineering/resources/change-management.md +715 -0
- package/.claude/skills/general-it-engineering/resources/enterprise-monitoring.md +729 -0
- package/.claude/skills/general-it-engineering/resources/help-desk-operations.md +738 -0
- package/.claude/skills/general-it-engineering/resources/incident-service-management.md +834 -0
- package/.claude/skills/general-it-engineering/resources/it-governance.md +753 -0
- package/.claude/skills/general-it-engineering/resources/itil-framework.md +503 -0
- package/.claude/skills/general-it-engineering/resources/service-management.md +669 -0
- package/.claude/skills/infrastructure-architecture/SKILL.md +328 -0
- package/.claude/skills/infrastructure-architecture/resources/architecture-decision-records.md +505 -0
- package/.claude/skills/infrastructure-architecture/resources/architecture-patterns.md +528 -0
- package/.claude/skills/infrastructure-architecture/resources/capacity-planning.md +453 -0
- package/.claude/skills/infrastructure-architecture/resources/cleared-environment-architecture.md +773 -0
- package/.claude/skills/infrastructure-architecture/resources/cost-architecture.md +499 -0
- package/.claude/skills/infrastructure-architecture/resources/data-architecture.md +501 -0
- package/.claude/skills/infrastructure-architecture/resources/disaster-recovery.md +535 -0
- package/.claude/skills/infrastructure-architecture/resources/migration-architecture.md +512 -0
- package/.claude/skills/infrastructure-architecture/resources/multi-region-design.md +608 -0
- package/.claude/skills/infrastructure-architecture/resources/reference-architectures.md +562 -0
- package/.claude/skills/infrastructure-architecture/resources/security-architecture.md +538 -0
- package/.claude/skills/infrastructure-architecture/resources/system-design-principles.md +489 -0
- package/.claude/skills/infrastructure-architecture/resources/workload-classification.md +1000 -0
- package/.claude/skills/infrastructure-strategy/SKILL.md +924 -0
- package/.claude/skills/network-engineering/SKILL.md +385 -0
- package/.claude/skills/network-engineering/resources/dns-management.md +738 -0
- package/.claude/skills/network-engineering/resources/load-balancing.md +820 -0
- package/.claude/skills/network-engineering/resources/network-architecture.md +546 -0
- package/.claude/skills/network-engineering/resources/network-security.md +921 -0
- package/.claude/skills/network-engineering/resources/network-troubleshooting.md +749 -0
- package/.claude/skills/network-engineering/resources/routing-switching.md +373 -0
- package/.claude/skills/network-engineering/resources/sdn-networking.md +695 -0
- package/.claude/skills/network-engineering/resources/service-mesh-networking.md +777 -0
- package/.claude/skills/network-engineering/resources/tcp-ip-protocols.md +444 -0
- package/.claude/skills/network-engineering/resources/vpn-connectivity.md +672 -0
- package/.claude/skills/observability-engineering/SKILL.md +101 -0
- package/.claude/skills/observability-engineering/resources/apm-tools.md +97 -0
- package/.claude/skills/observability-engineering/resources/correlation-strategies.md +87 -0
- package/.claude/skills/observability-engineering/resources/distributed-tracing.md +98 -0
- package/.claude/skills/observability-engineering/resources/logs-aggregation.md +118 -0
- package/.claude/skills/observability-engineering/resources/observability-cost-optimization.md +141 -0
- package/.claude/skills/observability-engineering/resources/opentelemetry.md +110 -0
- package/.claude/skills/platform-engineering/SKILL.md +555 -0
- package/.claude/skills/platform-engineering/resources/architecture-overview.md +600 -0
- package/.claude/skills/platform-engineering/resources/container-orchestration.md +916 -0
- package/.claude/skills/platform-engineering/resources/cost-optimization.md +634 -0
- package/.claude/skills/platform-engineering/resources/developer-platforms.md +670 -0
- package/.claude/skills/platform-engineering/resources/gitops-automation.md +650 -0
- package/.claude/skills/platform-engineering/resources/infrastructure-as-code.md +778 -0
- package/.claude/skills/platform-engineering/resources/infrastructure-standards.md +708 -0
- package/.claude/skills/platform-engineering/resources/multi-tenancy.md +602 -0
- package/.claude/skills/platform-engineering/resources/platform-security.md +711 -0
- package/.claude/skills/platform-engineering/resources/resource-management.md +592 -0
- package/.claude/skills/platform-engineering/resources/service-mesh.md +628 -0
- package/.claude/skills/release-engineering/SKILL.md +393 -0
- package/.claude/skills/release-engineering/resources/artifact-management.md +108 -0
- package/.claude/skills/release-engineering/resources/build-optimization.md +84 -0
- package/.claude/skills/release-engineering/resources/ci-cd-pipelines.md +411 -0
- package/.claude/skills/release-engineering/resources/deployment-strategies.md +197 -0
- package/.claude/skills/release-engineering/resources/pipeline-security.md +62 -0
- package/.claude/skills/release-engineering/resources/progressive-delivery.md +83 -0
- package/.claude/skills/release-engineering/resources/release-automation.md +68 -0
- package/.claude/skills/release-engineering/resources/release-orchestration.md +77 -0
- package/.claude/skills/release-engineering/resources/rollback-strategies.md +66 -0
- package/.claude/skills/release-engineering/resources/versioning-strategies.md +59 -0
- package/.claude/skills/route-tester/SKILL.md +392 -0
- package/.claude/skills/skill-developer/ADVANCED.md +197 -0
- package/.claude/skills/skill-developer/HOOK_MECHANISMS.md +306 -0
- package/.claude/skills/skill-developer/PATTERNS_LIBRARY.md +152 -0
- package/.claude/skills/skill-developer/SKILL.md +430 -0
- package/.claude/skills/skill-developer/SKILL_RULES_REFERENCE.md +315 -0
- package/.claude/skills/skill-developer/TRIGGER_TYPES.md +305 -0
- package/.claude/skills/skill-developer/TROUBLESHOOTING.md +514 -0
- package/.claude/skills/skill-rules.json +2940 -0
- package/.claude/skills/sre/SKILL.md +464 -0
- package/.claude/skills/sre/resources/alerting-best-practices.md +282 -0
- package/.claude/skills/sre/resources/capacity-planning.md +226 -0
- package/.claude/skills/sre/resources/chaos-engineering.md +193 -0
- package/.claude/skills/sre/resources/disaster-recovery.md +232 -0
- package/.claude/skills/sre/resources/incident-management.md +436 -0
- package/.claude/skills/sre/resources/observability-stack.md +240 -0
- package/.claude/skills/sre/resources/on-call-runbooks.md +167 -0
- package/.claude/skills/sre/resources/performance-optimization.md +108 -0
- package/.claude/skills/sre/resources/reliability-patterns.md +183 -0
- package/.claude/skills/sre/resources/slo-sli-sla.md +464 -0
- package/.claude/skills/sre/resources/toil-reduction.md +145 -0
- package/.claude/skills/systems-engineering/SKILL.md +648 -0
- package/.claude/skills/systems-engineering/resources/automation-patterns.md +771 -0
- package/.claude/skills/systems-engineering/resources/configuration-management.md +998 -0
- package/.claude/skills/systems-engineering/resources/linux-administration.md +672 -0
- package/.claude/skills/systems-engineering/resources/networking-fundamentals.md +982 -0
- package/.claude/skills/systems-engineering/resources/performance-tuning.md +871 -0
- package/.claude/skills/systems-engineering/resources/powershell-scripting.md +482 -0
- package/.claude/skills/systems-engineering/resources/security-hardening.md +739 -0
- package/.claude/skills/systems-engineering/resources/shell-scripting.md +915 -0
- package/.claude/skills/systems-engineering/resources/storage-management.md +628 -0
- package/.claude/skills/systems-engineering/resources/system-monitoring.md +787 -0
- package/.claude/skills/systems-engineering/resources/troubleshooting-guide.md +753 -0
- package/.claude/skills/systems-engineering/resources/windows-administration.md +738 -0
- package/.claude/skills/technical-leadership/SKILL.md +728 -0
- package/CHANGELOG.md +90 -54
- package/README.md +94 -0
- package/backend/docs/SECRETS_DOCUMENTATION.md +327 -0
- package/backend/jest.config.js +59 -0
- package/backend/package-lock.json +6129 -0
- package/backend/package.json +16 -4
- package/backend/prisma/migrations/20251026104609_add_websocket_api/migration.sql +33 -0
- package/backend/prisma/schema.prisma +33 -0
- package/backend/src/__tests__/core/DependencyService.test.js +336 -0
- package/backend/src/__tests__/core/UserService.test.js +875 -0
- package/backend/src/__tests__/repositories/BaseRepository.test.js +146 -0
- package/backend/src/__tests__/repositories/BotRepository.test.js +118 -0
- package/backend/src/__tests__/repositories/CommandRepository.test.js +132 -0
- package/backend/src/__tests__/repositories/EventGraphRepository.test.js +93 -0
- package/backend/src/__tests__/repositories/GroupRepository.test.js +155 -0
- package/backend/src/__tests__/repositories/PermissionRepository.test.js +130 -0
- package/backend/src/__tests__/repositories/PluginRepository.test.js +107 -0
- package/backend/src/__tests__/repositories/ServerRepository.test.js +80 -0
- package/backend/src/__tests__/repositories/UserRepository.test.js +128 -0
- package/backend/src/__tests__/secretsFilter.test.js +425 -0
- package/backend/src/__tests__/services/BotLifecycleService.test.js +411 -0
- package/backend/src/__tests__/services/BotProcessManager.test.js +285 -0
- package/backend/src/__tests__/services/CacheManager.test.js +125 -0
- package/backend/src/__tests__/services/CommandExecutionService.test.js +460 -0
- package/backend/src/__tests__/services/ResourceMonitorService.test.js +207 -0
- package/backend/src/__tests__/services/TelemetryService.test.js +291 -0
- package/backend/src/__tests__/setup.js +25 -0
- package/backend/src/api/routes/apiKeys.js +181 -0
- package/backend/src/api/routes/bots.js +49 -7
- package/backend/src/api/routes/plugins.js +2 -1
- package/backend/src/api/routes/system.js +174 -0
- package/backend/src/container.js +82 -0
- package/backend/src/core/BotManager.js +142 -871
- package/backend/src/core/BotManager.old.js +1093 -0
- package/backend/src/core/BotProcess.js +1092 -858
- package/backend/src/core/EventGraphManager.js +280 -198
- package/backend/src/core/GraphExecutionEngine.js +321 -325
- package/backend/src/core/MessageQueue.js +27 -6
- package/backend/src/core/NodeRegistry.js +37 -1134
- package/backend/src/core/PluginManager.js +62 -12
- package/backend/src/core/PrismaService.js +32 -0
- package/backend/src/core/UserService.js +3 -3
- package/backend/src/core/__tests__/PrismaService.test.js +24 -0
- package/backend/src/core/commands/README.md +305 -0
- package/backend/src/core/commands/dev.js +13 -7
- package/backend/src/core/commands/ping.js +10 -4
- package/backend/src/core/commands/whois.js +63 -0
- package/backend/src/core/config/validation.js +27 -0
- package/backend/src/core/constants/graphTypes.js +21 -0
- package/backend/src/core/node-registries/actions.js +132 -0
- package/backend/src/core/node-registries/arrays.js +137 -0
- package/backend/src/core/node-registries/bot.js +23 -0
- package/backend/src/core/node-registries/data.js +290 -0
- package/backend/src/core/node-registries/debug.js +26 -0
- package/backend/src/core/node-registries/events.js +187 -0
- package/backend/src/core/node-registries/flow.js +139 -0
- package/backend/src/core/node-registries/logic.js +45 -0
- package/backend/src/core/node-registries/math.js +42 -0
- package/backend/src/core/node-registries/objects.js +98 -0
- package/backend/src/core/node-registries/strings.js +153 -0
- package/backend/src/core/node-registries/time.js +113 -0
- package/backend/src/core/node-registries/users.js +79 -0
- package/backend/src/core/nodes/{action_bot_look_at.js → actions/bot_look_at.js} +36 -36
- package/backend/src/core/nodes/{action_bot_set_variable.js → actions/bot_set_variable.js} +32 -32
- package/backend/src/core/nodes/{action_send_log.js → actions/send_log.js} +28 -23
- package/backend/src/core/nodes/{action_send_message.js → actions/send_message.js} +32 -32
- package/backend/src/core/nodes/actions/send_websocket_response.js +33 -0
- package/backend/src/core/nodes/arrays/get_next.js +35 -0
- package/backend/src/core/nodes/{data_cast.js → data/cast.js} +8 -0
- package/backend/src/core/nodes/data/datetime_literal.js +27 -0
- package/backend/src/core/nodes/data/entity_info.js +69 -0
- package/backend/src/core/nodes/data/get_nearby_entities.js +32 -0
- package/backend/src/core/nodes/data/get_nearby_players.js +64 -0
- package/backend/src/core/nodes/{data_get_user_field.js → data/get_user_field.js} +1 -1
- package/backend/src/core/nodes/data/type_check.js +53 -0
- package/backend/src/core/nodes/{debug_log.js → debug/log.js} +16 -16
- package/backend/src/core/nodes/{flow_branch.js → flow/branch.js} +15 -15
- package/backend/src/core/nodes/{flow_break.js → flow/break.js} +14 -14
- package/backend/src/core/nodes/flow/delay.js +43 -0
- package/backend/src/core/nodes/{flow_for_each.js → flow/for_each.js} +39 -39
- package/backend/src/core/nodes/{flow_sequence.js → flow/sequence.js} +16 -16
- package/backend/src/core/nodes/{flow_switch.js → flow/switch.js} +47 -47
- package/backend/src/core/nodes/{flow_while.js → flow/while.js} +1 -1
- package/backend/src/core/nodes/logic/__tests__/compare.test.js +83 -0
- package/backend/src/core/nodes/math/__tests__/operation.test.js +65 -0
- package/backend/src/core/nodes/strings/__tests__/concat.test.js +89 -0
- package/backend/src/core/nodes/time/__tests__/now.test.js +24 -0
- package/backend/src/core/nodes/time/add.js +33 -0
- package/backend/src/core/nodes/time/compare.js +35 -0
- package/backend/src/core/nodes/time/diff.js +29 -0
- package/backend/src/core/nodes/time/format.js +32 -0
- package/backend/src/core/nodes/time/now.js +18 -0
- package/backend/src/core/nodes/{user_check_blacklist.js → users/check_blacklist.js} +37 -37
- package/backend/src/core/nodes/{user_get_groups.js → users/get_groups.js} +36 -36
- package/backend/src/core/nodes/{user_get_permissions.js → users/get_permissions.js} +36 -36
- package/backend/src/core/nodes/{user_set_blacklist.js → users/set_blacklist.js} +37 -37
- package/backend/src/core/services/BotLifecycleService.js +596 -0
- package/backend/src/core/services/BotProcessManager.js +163 -0
- package/backend/src/core/services/CacheManager.js +111 -0
- package/backend/src/core/services/CommandExecutionService.js +351 -0
- package/backend/src/core/services/ResourceMonitorService.js +90 -0
- package/backend/src/core/services/TelemetryService.js +124 -0
- package/backend/src/core/services/ValidationService.js +132 -0
- package/backend/src/core/services/__tests__/ValidationService.test.js +148 -0
- package/backend/src/core/services.js +20 -5
- package/backend/src/core/system/CommandContext.js +84 -0
- package/backend/src/core/system/Transport.js +78 -0
- package/backend/src/core/utils/__tests__/jsonParser.test.js +44 -0
- package/backend/src/core/utils/jsonParser.js +18 -0
- package/backend/src/core/utils/secretsFilter.js +262 -0
- package/backend/src/core/utils/variableParser.js +89 -0
- package/backend/src/core/validation/__tests__/nodeSchemas.test.js +175 -0
- package/backend/src/core/validation/nodeSchemas.js +112 -0
- package/backend/src/lib/prisma.js +2 -4
- package/backend/src/real-time/botApi/handlers/commandHandlers.js +28 -0
- package/backend/src/real-time/botApi/handlers/graphHandlers.js +99 -0
- package/backend/src/real-time/botApi/handlers/graphWebSocketHandlers.js +147 -0
- package/backend/src/real-time/botApi/handlers/index.js +43 -0
- package/backend/src/real-time/botApi/handlers/messageHandlers.js +66 -0
- package/backend/src/real-time/botApi/handlers/statusHandlers.js +17 -0
- package/backend/src/real-time/botApi/handlers/userHandlers.js +141 -0
- package/backend/src/real-time/botApi/index.js +40 -0
- package/backend/src/real-time/botApi/middleware.js +79 -0
- package/backend/src/real-time/botApi/utils.js +54 -0
- package/backend/src/real-time/socketHandler.js +6 -2
- package/backend/src/repositories/BaseRepository.js +43 -0
- package/backend/src/repositories/BotRepository.js +42 -0
- package/backend/src/repositories/CommandRepository.js +53 -0
- package/backend/src/repositories/EventGraphRepository.js +40 -0
- package/backend/src/repositories/GroupRepository.js +69 -0
- package/backend/src/repositories/PermissionRepository.js +48 -0
- package/backend/src/repositories/PluginRepository.js +42 -0
- package/backend/src/repositories/ServerRepository.js +27 -0
- package/backend/src/repositories/UserRepository.js +48 -0
- package/backend/src/server.js +3 -0
- package/backend/src/test-refactor.js +85 -0
- package/frontend/dist/assets/index-CfTo92bP.css +1 -0
- package/frontend/dist/assets/index-CiFD5X9Z.js +8344 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +0 -5
- package/package.json +2 -1
- package/frontend/dist/assets/index-B9GedHEa.js +0 -8352
- package/frontend/dist/assets/index-zLiy9MDx.css +0 -1
- package/nul +0 -0
- /package/backend/src/core/nodes/{action_http_request.js → actions/http_request.js} +0 -0
- /package/backend/src/core/nodes/{array_add_element.js → arrays/add_element.js} +0 -0
- /package/backend/src/core/nodes/{array_contains.js → arrays/contains.js} +0 -0
- /package/backend/src/core/nodes/{array_find_index.js → arrays/find_index.js} +0 -0
- /package/backend/src/core/nodes/{array_get_by_index.js → arrays/get_by_index.js} +0 -0
- /package/backend/src/core/nodes/{array_get_random_element.js → arrays/get_random_element.js} +0 -0
- /package/backend/src/core/nodes/{array_remove_by_index.js → arrays/remove_by_index.js} +0 -0
- /package/backend/src/core/nodes/{bot_get_position.js → bot/get_position.js} +0 -0
- /package/backend/src/core/nodes/{data_array_literal.js → data/array_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_boolean_literal.js → data/boolean_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_get_argument.js → data/get_argument.js} +0 -0
- /package/backend/src/core/nodes/{data_get_bot_look.js → data/get_bot_look.js} +0 -0
- /package/backend/src/core/nodes/{data_get_entity_field.js → data/get_entity_field.js} +0 -0
- /package/backend/src/core/nodes/{data_get_server_players.js → data/get_server_players.js} +0 -0
- /package/backend/src/core/nodes/{data_get_variable.js → data/get_variable.js} +0 -0
- /package/backend/src/core/nodes/{data_length.js → data/length.js} +0 -0
- /package/backend/src/core/nodes/{data_make_object.js → data/make_object.js} +0 -0
- /package/backend/src/core/nodes/{data_number_literal.js → data/number_literal.js} +0 -0
- /package/backend/src/core/nodes/{data_string_literal.js → data/string_literal.js} +0 -0
- /package/backend/src/core/nodes/{logic_compare.js → logic/compare.js} +0 -0
- /package/backend/src/core/nodes/{logic_operation.js → logic/operation.js} +0 -0
- /package/backend/src/core/nodes/{math_operation.js → math/operation.js} +0 -0
- /package/backend/src/core/nodes/{math_random_number.js → math/random_number.js} +0 -0
- /package/backend/src/core/nodes/{object_create.js → objects/create.js} +0 -0
- /package/backend/src/core/nodes/{object_delete.js → objects/delete.js} +0 -0
- /package/backend/src/core/nodes/{object_get.js → objects/get.js} +0 -0
- /package/backend/src/core/nodes/{object_has_key.js → objects/has_key.js} +0 -0
- /package/backend/src/core/nodes/{object_set.js → objects/set.js} +0 -0
- /package/backend/src/core/nodes/{string_concat.js → strings/concat.js} +0 -0
- /package/backend/src/core/nodes/{string_contains.js → strings/contains.js} +0 -0
- /package/backend/src/core/nodes/{string_ends_with.js → strings/ends_with.js} +0 -0
- /package/backend/src/core/nodes/{string_equals.js → strings/equals.js} +0 -0
- /package/backend/src/core/nodes/{string_length.js → strings/length.js} +0 -0
- /package/backend/src/core/nodes/{string_matches.js → strings/matches.js} +0 -0
- /package/backend/src/core/nodes/{string_split.js → strings/split.js} +0 -0
- /package/backend/src/core/nodes/{string_starts_with.js → strings/starts_with.js} +0 -0
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
# Routing and Controllers - Best Practices
|
|
2
|
+
|
|
3
|
+
Complete guide to clean route definitions and controller patterns.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Routes: Routing Only](#routes-routing-only)
|
|
8
|
+
- [BaseController Pattern](#basecontroller-pattern)
|
|
9
|
+
- [Good Examples](#good-examples)
|
|
10
|
+
- [Anti-Patterns](#anti-patterns)
|
|
11
|
+
- [Refactoring Guide](#refactoring-guide)
|
|
12
|
+
- [Error Handling](#error-handling)
|
|
13
|
+
- [HTTP Status Codes](#http-status-codes)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Routes: Routing Only
|
|
18
|
+
|
|
19
|
+
### The Golden Rule
|
|
20
|
+
|
|
21
|
+
**Routes should ONLY:**
|
|
22
|
+
- ✅ Define route paths
|
|
23
|
+
- ✅ Register middleware
|
|
24
|
+
- ✅ Delegate to controllers
|
|
25
|
+
|
|
26
|
+
**Routes should NEVER:**
|
|
27
|
+
- ❌ Contain business logic
|
|
28
|
+
- ❌ Access database directly
|
|
29
|
+
- ❌ Implement validation logic (use Zod + controller)
|
|
30
|
+
- ❌ Format complex responses
|
|
31
|
+
- ❌ Handle complex error scenarios
|
|
32
|
+
|
|
33
|
+
### Clean Route Pattern
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// routes/userRoutes.ts
|
|
37
|
+
import { Router } from 'express';
|
|
38
|
+
import { UserController } from '../controllers/UserController';
|
|
39
|
+
import { SSOMiddlewareClient } from '../middleware/SSOMiddleware';
|
|
40
|
+
import { auditMiddleware } from '../middleware/auditMiddleware';
|
|
41
|
+
|
|
42
|
+
const router = Router();
|
|
43
|
+
const controller = new UserController();
|
|
44
|
+
|
|
45
|
+
// ✅ CLEAN: Route definition only
|
|
46
|
+
router.get('/:id',
|
|
47
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
48
|
+
auditMiddleware,
|
|
49
|
+
async (req, res) => controller.getUser(req, res)
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
router.post('/',
|
|
53
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
54
|
+
auditMiddleware,
|
|
55
|
+
async (req, res) => controller.createUser(req, res)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
router.put('/:id',
|
|
59
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
60
|
+
auditMiddleware,
|
|
61
|
+
async (req, res) => controller.updateUser(req, res)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export default router;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Key Points:**
|
|
68
|
+
- Each route: method, path, middleware chain, controller delegation
|
|
69
|
+
- No try-catch needed (controller handles errors)
|
|
70
|
+
- Clean, readable, maintainable
|
|
71
|
+
- Easy to see all endpoints at a glance
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## BaseController Pattern
|
|
76
|
+
|
|
77
|
+
### Why BaseController?
|
|
78
|
+
|
|
79
|
+
**Benefits:**
|
|
80
|
+
- Consistent error handling across all controllers
|
|
81
|
+
- Automatic Sentry integration
|
|
82
|
+
- Standardized response formats
|
|
83
|
+
- Reusable helper methods
|
|
84
|
+
- Performance tracking utilities
|
|
85
|
+
- Logging and breadcrumb helpers
|
|
86
|
+
|
|
87
|
+
### BaseController Pattern (Template)
|
|
88
|
+
|
|
89
|
+
**File:** `/email/src/controllers/BaseController.ts`
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import * as Sentry from '@sentry/node';
|
|
93
|
+
import { Response } from 'express';
|
|
94
|
+
|
|
95
|
+
export abstract class BaseController {
|
|
96
|
+
/**
|
|
97
|
+
* Handle errors with Sentry integration
|
|
98
|
+
*/
|
|
99
|
+
protected handleError(
|
|
100
|
+
error: unknown,
|
|
101
|
+
res: Response,
|
|
102
|
+
context: string,
|
|
103
|
+
statusCode = 500
|
|
104
|
+
): void {
|
|
105
|
+
Sentry.withScope((scope) => {
|
|
106
|
+
scope.setTag('controller', this.constructor.name);
|
|
107
|
+
scope.setTag('operation', context);
|
|
108
|
+
scope.setUser({ id: res.locals?.claims?.userId });
|
|
109
|
+
|
|
110
|
+
if (error instanceof Error) {
|
|
111
|
+
scope.setContext('error_details', {
|
|
112
|
+
message: error.message,
|
|
113
|
+
stack: error.stack,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
Sentry.captureException(error);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
res.status(statusCode).json({
|
|
121
|
+
success: false,
|
|
122
|
+
error: {
|
|
123
|
+
message: error instanceof Error ? error.message : 'An error occurred',
|
|
124
|
+
code: statusCode,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Handle success responses
|
|
131
|
+
*/
|
|
132
|
+
protected handleSuccess<T>(
|
|
133
|
+
res: Response,
|
|
134
|
+
data: T,
|
|
135
|
+
message?: string,
|
|
136
|
+
statusCode = 200
|
|
137
|
+
): void {
|
|
138
|
+
res.status(statusCode).json({
|
|
139
|
+
success: true,
|
|
140
|
+
message,
|
|
141
|
+
data,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Performance tracking wrapper
|
|
147
|
+
*/
|
|
148
|
+
protected async withTransaction<T>(
|
|
149
|
+
name: string,
|
|
150
|
+
operation: string,
|
|
151
|
+
callback: () => Promise<T>
|
|
152
|
+
): Promise<T> {
|
|
153
|
+
return await Sentry.startSpan(
|
|
154
|
+
{ name, op: operation },
|
|
155
|
+
callback
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Validate required fields
|
|
161
|
+
*/
|
|
162
|
+
protected validateRequest(
|
|
163
|
+
required: string[],
|
|
164
|
+
actual: Record<string, any>,
|
|
165
|
+
res: Response
|
|
166
|
+
): boolean {
|
|
167
|
+
const missing = required.filter((field) => !actual[field]);
|
|
168
|
+
|
|
169
|
+
if (missing.length > 0) {
|
|
170
|
+
Sentry.captureMessage(
|
|
171
|
+
`Missing required fields: ${missing.join(', ')}`,
|
|
172
|
+
'warning'
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
res.status(400).json({
|
|
176
|
+
success: false,
|
|
177
|
+
error: {
|
|
178
|
+
message: 'Missing required fields',
|
|
179
|
+
code: 'VALIDATION_ERROR',
|
|
180
|
+
details: { missing },
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Logging helpers
|
|
190
|
+
*/
|
|
191
|
+
protected logInfo(message: string, context?: Record<string, any>): void {
|
|
192
|
+
Sentry.addBreadcrumb({
|
|
193
|
+
category: this.constructor.name,
|
|
194
|
+
message,
|
|
195
|
+
level: 'info',
|
|
196
|
+
data: context,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
protected logWarning(message: string, context?: Record<string, any>): void {
|
|
201
|
+
Sentry.captureMessage(message, {
|
|
202
|
+
level: 'warning',
|
|
203
|
+
tags: { controller: this.constructor.name },
|
|
204
|
+
extra: context,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Add Sentry breadcrumb
|
|
210
|
+
*/
|
|
211
|
+
protected addBreadcrumb(
|
|
212
|
+
message: string,
|
|
213
|
+
category: string,
|
|
214
|
+
data?: Record<string, any>
|
|
215
|
+
): void {
|
|
216
|
+
Sentry.addBreadcrumb({ message, category, level: 'info', data });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Capture custom metric
|
|
221
|
+
*/
|
|
222
|
+
protected captureMetric(name: string, value: number, unit: string): void {
|
|
223
|
+
Sentry.metrics.gauge(name, value, { unit });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Using BaseController
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
// controllers/UserController.ts
|
|
232
|
+
import { Request, Response } from 'express';
|
|
233
|
+
import { BaseController } from './BaseController';
|
|
234
|
+
import { UserService } from '../services/userService';
|
|
235
|
+
import { createUserSchema } from '../validators/userSchemas';
|
|
236
|
+
|
|
237
|
+
export class UserController extends BaseController {
|
|
238
|
+
private userService: UserService;
|
|
239
|
+
|
|
240
|
+
constructor() {
|
|
241
|
+
super();
|
|
242
|
+
this.userService = new UserService();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async getUser(req: Request, res: Response): Promise<void> {
|
|
246
|
+
try {
|
|
247
|
+
this.addBreadcrumb('Fetching user', 'user_controller', { userId: req.params.id });
|
|
248
|
+
|
|
249
|
+
const user = await this.userService.findById(req.params.id);
|
|
250
|
+
|
|
251
|
+
if (!user) {
|
|
252
|
+
return this.handleError(
|
|
253
|
+
new Error('User not found'),
|
|
254
|
+
res,
|
|
255
|
+
'getUser',
|
|
256
|
+
404
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this.handleSuccess(res, user);
|
|
261
|
+
} catch (error) {
|
|
262
|
+
this.handleError(error, res, 'getUser');
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async createUser(req: Request, res: Response): Promise<void> {
|
|
267
|
+
try {
|
|
268
|
+
// Validate input
|
|
269
|
+
const validated = createUserSchema.parse(req.body);
|
|
270
|
+
|
|
271
|
+
// Track performance
|
|
272
|
+
const user = await this.withTransaction(
|
|
273
|
+
'user.create',
|
|
274
|
+
'db.query',
|
|
275
|
+
() => this.userService.create(validated)
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
this.handleSuccess(res, user, 'User created successfully', 201);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
this.handleError(error, res, 'createUser');
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
async updateUser(req: Request, res: Response): Promise<void> {
|
|
285
|
+
try {
|
|
286
|
+
const validated = updateUserSchema.parse(req.body);
|
|
287
|
+
const user = await this.userService.update(req.params.id, validated);
|
|
288
|
+
this.handleSuccess(res, user, 'User updated');
|
|
289
|
+
} catch (error) {
|
|
290
|
+
this.handleError(error, res, 'updateUser');
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**Benefits:**
|
|
297
|
+
- Consistent error handling
|
|
298
|
+
- Automatic Sentry integration
|
|
299
|
+
- Performance tracking
|
|
300
|
+
- Clean, readable code
|
|
301
|
+
- Easy to test
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Good Examples
|
|
306
|
+
|
|
307
|
+
### Example 1: Email Notification Routes (Excellent ✅)
|
|
308
|
+
|
|
309
|
+
**File:** `/email/src/routes/notificationRoutes.ts`
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { Router } from 'express';
|
|
313
|
+
import { NotificationController } from '../controllers/NotificationController';
|
|
314
|
+
import { SSOMiddlewareClient } from '../middleware/SSOMiddleware';
|
|
315
|
+
|
|
316
|
+
const router = Router();
|
|
317
|
+
const controller = new NotificationController();
|
|
318
|
+
|
|
319
|
+
// ✅ EXCELLENT: Clean delegation
|
|
320
|
+
router.get('/',
|
|
321
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
322
|
+
async (req, res) => controller.getNotifications(req, res)
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
router.post('/',
|
|
326
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
327
|
+
async (req, res) => controller.createNotification(req, res)
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
router.put('/:id/read',
|
|
331
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
332
|
+
async (req, res) => controller.markAsRead(req, res)
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
export default router;
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**What Makes This Excellent:**
|
|
339
|
+
- Zero business logic in routes
|
|
340
|
+
- Clear middleware chain
|
|
341
|
+
- Consistent pattern
|
|
342
|
+
- Easy to understand
|
|
343
|
+
|
|
344
|
+
### Example 2: Proxy Routes with Validation (Good ✅)
|
|
345
|
+
|
|
346
|
+
**File:** `/form/src/routes/proxyRoutes.ts`
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import { z } from 'zod';
|
|
350
|
+
|
|
351
|
+
const createProxySchema = z.object({
|
|
352
|
+
originalUserID: z.string().min(1),
|
|
353
|
+
proxyUserID: z.string().min(1),
|
|
354
|
+
startsAt: z.string().datetime(),
|
|
355
|
+
expiresAt: z.string().datetime(),
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
router.post('/',
|
|
359
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
360
|
+
async (req, res) => {
|
|
361
|
+
try {
|
|
362
|
+
const validated = createProxySchema.parse(req.body);
|
|
363
|
+
const proxy = await proxyService.createProxyRelationship(validated);
|
|
364
|
+
res.status(201).json({ success: true, data: proxy });
|
|
365
|
+
} catch (error) {
|
|
366
|
+
handler.handleException(res, error);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
);
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
**What Makes This Good:**
|
|
373
|
+
- Zod validation
|
|
374
|
+
- Delegates to service
|
|
375
|
+
- Proper HTTP status codes
|
|
376
|
+
- Error handling
|
|
377
|
+
|
|
378
|
+
**Could Be Better:**
|
|
379
|
+
- Move validation to controller
|
|
380
|
+
- Use BaseController
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
## Anti-Patterns
|
|
385
|
+
|
|
386
|
+
### Anti-Pattern 1: Business Logic in Routes (Bad ❌)
|
|
387
|
+
|
|
388
|
+
**File:** `/form/src/routes/responseRoutes.ts` (actual production code)
|
|
389
|
+
|
|
390
|
+
```typescript
|
|
391
|
+
// ❌ ANTI-PATTERN: 200+ lines of business logic in route
|
|
392
|
+
router.post('/:formID/submit', async (req: Request, res: Response) => {
|
|
393
|
+
try {
|
|
394
|
+
const username = res.locals.claims.preferred_username;
|
|
395
|
+
const responses = req.body.responses;
|
|
396
|
+
const stepInstanceId = req.body.stepInstanceId;
|
|
397
|
+
|
|
398
|
+
// ❌ Permission checking in route
|
|
399
|
+
const userId = await userProfileService.getProfileByEmail(username).then(p => p.id);
|
|
400
|
+
const canComplete = await permissionService.canCompleteStep(userId, stepInstanceId);
|
|
401
|
+
if (!canComplete) {
|
|
402
|
+
return res.status(403).json({ error: 'No permission' });
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// ❌ Workflow logic in route
|
|
406
|
+
const { createWorkflowEngine, CompleteStepCommand } = require('../workflow/core/WorkflowEngineV3');
|
|
407
|
+
const engine = await createWorkflowEngine();
|
|
408
|
+
const command = new CompleteStepCommand(
|
|
409
|
+
stepInstanceId,
|
|
410
|
+
userId,
|
|
411
|
+
responses,
|
|
412
|
+
additionalContext
|
|
413
|
+
);
|
|
414
|
+
const events = await engine.executeCommand(command);
|
|
415
|
+
|
|
416
|
+
// ❌ Impersonation handling in route
|
|
417
|
+
if (res.locals.isImpersonating) {
|
|
418
|
+
impersonationContextStore.storeContext(stepInstanceId, {
|
|
419
|
+
originalUserId: res.locals.originalUserId,
|
|
420
|
+
effectiveUserId: userId,
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// ❌ Response processing in route
|
|
425
|
+
const post = await PrismaService.main.post.findUnique({
|
|
426
|
+
where: { id: postData.id },
|
|
427
|
+
include: { comments: true },
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
// ❌ Permission check in route
|
|
431
|
+
await checkPostPermissions(post, userId);
|
|
432
|
+
|
|
433
|
+
// ... 100+ more lines of business logic
|
|
434
|
+
|
|
435
|
+
res.json({ success: true, data: result });
|
|
436
|
+
} catch (e) {
|
|
437
|
+
handler.handleException(res, e);
|
|
438
|
+
}
|
|
439
|
+
});
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Why This Is Terrible:**
|
|
443
|
+
- 200+ lines of business logic
|
|
444
|
+
- Hard to test (requires HTTP mocking)
|
|
445
|
+
- Hard to reuse (tied to route)
|
|
446
|
+
- Mixed responsibilities
|
|
447
|
+
- Difficult to debug
|
|
448
|
+
- Performance tracking difficult
|
|
449
|
+
|
|
450
|
+
### How to Refactor (Step-by-Step)
|
|
451
|
+
|
|
452
|
+
**Step 1: Create Controller**
|
|
453
|
+
|
|
454
|
+
```typescript
|
|
455
|
+
// controllers/PostController.ts
|
|
456
|
+
export class PostController extends BaseController {
|
|
457
|
+
private postService: PostService;
|
|
458
|
+
|
|
459
|
+
constructor() {
|
|
460
|
+
super();
|
|
461
|
+
this.postService = new PostService();
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
async createPost(req: Request, res: Response): Promise<void> {
|
|
465
|
+
try {
|
|
466
|
+
const validated = createPostSchema.parse({
|
|
467
|
+
...req.body,
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
const result = await this.postService.createPost(
|
|
471
|
+
validated,
|
|
472
|
+
res.locals.userId
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
this.handleSuccess(res, result, 'Post created successfully');
|
|
476
|
+
} catch (error) {
|
|
477
|
+
this.handleError(error, res, 'createPost');
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
**Step 2: Create Service**
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
// services/postService.ts
|
|
487
|
+
export class PostService {
|
|
488
|
+
async createPost(
|
|
489
|
+
data: CreatePostDTO,
|
|
490
|
+
userId: string
|
|
491
|
+
): Promise<PostResult> {
|
|
492
|
+
// Permission check
|
|
493
|
+
const canCreate = await permissionService.canCreatePost(userId);
|
|
494
|
+
if (!canCreate) {
|
|
495
|
+
throw new ForbiddenError('No permission to create post');
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Execute workflow
|
|
499
|
+
const engine = await createWorkflowEngine();
|
|
500
|
+
const command = new CompleteStepCommand(/* ... */);
|
|
501
|
+
const events = await engine.executeCommand(command);
|
|
502
|
+
|
|
503
|
+
// Handle impersonation if needed
|
|
504
|
+
if (context.isImpersonating) {
|
|
505
|
+
await this.handleImpersonation(data.stepInstanceId, context);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Synchronize roles
|
|
509
|
+
await this.synchronizeRoles(events, userId);
|
|
510
|
+
|
|
511
|
+
return { events, success: true };
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
private async handleImpersonation(stepInstanceId: number, context: any) {
|
|
515
|
+
impersonationContextStore.storeContext(stepInstanceId, {
|
|
516
|
+
originalUserId: context.originalUserId,
|
|
517
|
+
effectiveUserId: context.effectiveUserId,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
private async synchronizeRoles(events: WorkflowEvent[], userId: string) {
|
|
522
|
+
// Role synchronization logic
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Step 3: Update Route**
|
|
528
|
+
|
|
529
|
+
```typescript
|
|
530
|
+
// routes/postRoutes.ts
|
|
531
|
+
import { PostController } from '../controllers/PostController';
|
|
532
|
+
|
|
533
|
+
const router = Router();
|
|
534
|
+
const controller = new PostController();
|
|
535
|
+
|
|
536
|
+
// ✅ CLEAN: Just routing
|
|
537
|
+
router.post('/',
|
|
538
|
+
SSOMiddlewareClient.verifyLoginStatus,
|
|
539
|
+
auditMiddleware,
|
|
540
|
+
async (req, res) => controller.createPost(req, res)
|
|
541
|
+
);
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**Result:**
|
|
545
|
+
- Route: 8 lines (was 200+)
|
|
546
|
+
- Controller: 25 lines (request handling)
|
|
547
|
+
- Service: 50 lines (business logic)
|
|
548
|
+
- Testable, reusable, maintainable!
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## Error Handling
|
|
553
|
+
|
|
554
|
+
### Controller Error Handling
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
async createUser(req: Request, res: Response): Promise<void> {
|
|
558
|
+
try {
|
|
559
|
+
const result = await this.userService.create(req.body);
|
|
560
|
+
this.handleSuccess(res, result, 'User created', 201);
|
|
561
|
+
} catch (error) {
|
|
562
|
+
// BaseController.handleError automatically:
|
|
563
|
+
// - Captures to Sentry with context
|
|
564
|
+
// - Sets appropriate status code
|
|
565
|
+
// - Returns formatted error response
|
|
566
|
+
this.handleError(error, res, 'createUser');
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### Custom Error Status Codes
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
async getUser(req: Request, res: Response): Promise<void> {
|
|
575
|
+
try {
|
|
576
|
+
const user = await this.userService.findById(req.params.id);
|
|
577
|
+
|
|
578
|
+
if (!user) {
|
|
579
|
+
// Custom 404 status
|
|
580
|
+
return this.handleError(
|
|
581
|
+
new Error('User not found'),
|
|
582
|
+
res,
|
|
583
|
+
'getUser',
|
|
584
|
+
404 // Custom status code
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
this.handleSuccess(res, user);
|
|
589
|
+
} catch (error) {
|
|
590
|
+
this.handleError(error, res, 'getUser');
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
### Validation Errors
|
|
596
|
+
|
|
597
|
+
```typescript
|
|
598
|
+
async createUser(req: Request, res: Response): Promise<void> {
|
|
599
|
+
try {
|
|
600
|
+
const validated = createUserSchema.parse(req.body);
|
|
601
|
+
const user = await this.userService.create(validated);
|
|
602
|
+
this.handleSuccess(res, user, 'User created', 201);
|
|
603
|
+
} catch (error) {
|
|
604
|
+
// Zod errors get 400 status
|
|
605
|
+
if (error instanceof z.ZodError) {
|
|
606
|
+
return this.handleError(error, res, 'createUser', 400);
|
|
607
|
+
}
|
|
608
|
+
this.handleError(error, res, 'createUser');
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
---
|
|
614
|
+
|
|
615
|
+
## HTTP Status Codes
|
|
616
|
+
|
|
617
|
+
### Standard Codes
|
|
618
|
+
|
|
619
|
+
| Code | Use Case | Example |
|
|
620
|
+
|------|----------|---------|
|
|
621
|
+
| 200 | Success (GET, PUT) | User retrieved, Updated |
|
|
622
|
+
| 201 | Created (POST) | User created |
|
|
623
|
+
| 204 | No Content (DELETE) | User deleted |
|
|
624
|
+
| 400 | Bad Request | Invalid input data |
|
|
625
|
+
| 401 | Unauthorized | Not authenticated |
|
|
626
|
+
| 403 | Forbidden | No permission |
|
|
627
|
+
| 404 | Not Found | Resource doesn't exist |
|
|
628
|
+
| 409 | Conflict | Duplicate resource |
|
|
629
|
+
| 422 | Unprocessable Entity | Validation failed |
|
|
630
|
+
| 500 | Internal Server Error | Unexpected error |
|
|
631
|
+
|
|
632
|
+
### Usage Examples
|
|
633
|
+
|
|
634
|
+
```typescript
|
|
635
|
+
// 200 - Success (default)
|
|
636
|
+
this.handleSuccess(res, user);
|
|
637
|
+
|
|
638
|
+
// 201 - Created
|
|
639
|
+
this.handleSuccess(res, user, 'Created', 201);
|
|
640
|
+
|
|
641
|
+
// 400 - Bad Request
|
|
642
|
+
this.handleError(error, res, 'operation', 400);
|
|
643
|
+
|
|
644
|
+
// 404 - Not Found
|
|
645
|
+
this.handleError(new Error('Not found'), res, 'operation', 404);
|
|
646
|
+
|
|
647
|
+
// 403 - Forbidden
|
|
648
|
+
this.handleError(new ForbiddenError('No permission'), res, 'operation', 403);
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
## Refactoring Guide
|
|
654
|
+
|
|
655
|
+
### Identify Routes Needing Refactoring
|
|
656
|
+
|
|
657
|
+
**Red Flags:**
|
|
658
|
+
- Route file > 100 lines
|
|
659
|
+
- Multiple try-catch blocks in one route
|
|
660
|
+
- Direct database access (Prisma calls)
|
|
661
|
+
- Complex business logic (if statements, loops)
|
|
662
|
+
- Permission checks in routes
|
|
663
|
+
|
|
664
|
+
**Check your routes:**
|
|
665
|
+
```bash
|
|
666
|
+
# Find large route files
|
|
667
|
+
wc -l form/src/routes/*.ts | sort -n
|
|
668
|
+
|
|
669
|
+
# Find routes with Prisma usage
|
|
670
|
+
grep -r "PrismaService" form/src/routes/
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
### Refactoring Process
|
|
674
|
+
|
|
675
|
+
**1. Extract to Controller:**
|
|
676
|
+
```typescript
|
|
677
|
+
// Before: Route with logic
|
|
678
|
+
router.post('/action', async (req, res) => {
|
|
679
|
+
try {
|
|
680
|
+
// 50 lines of logic
|
|
681
|
+
} catch (e) {
|
|
682
|
+
handler.handleException(res, e);
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
// After: Clean route
|
|
687
|
+
router.post('/action', (req, res) => controller.performAction(req, res));
|
|
688
|
+
|
|
689
|
+
// New controller method
|
|
690
|
+
async performAction(req: Request, res: Response): Promise<void> {
|
|
691
|
+
try {
|
|
692
|
+
const result = await this.service.performAction(req.body);
|
|
693
|
+
this.handleSuccess(res, result);
|
|
694
|
+
} catch (error) {
|
|
695
|
+
this.handleError(error, res, 'performAction');
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
**2. Extract to Service:**
|
|
701
|
+
```typescript
|
|
702
|
+
// Controller stays thin
|
|
703
|
+
async performAction(req: Request, res: Response): Promise<void> {
|
|
704
|
+
try {
|
|
705
|
+
const validated = actionSchema.parse(req.body);
|
|
706
|
+
const result = await this.actionService.execute(validated);
|
|
707
|
+
this.handleSuccess(res, result);
|
|
708
|
+
} catch (error) {
|
|
709
|
+
this.handleError(error, res, 'performAction');
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Service contains business logic
|
|
714
|
+
export class ActionService {
|
|
715
|
+
async execute(data: ActionDTO): Promise<Result> {
|
|
716
|
+
// All business logic here
|
|
717
|
+
// Permission checks
|
|
718
|
+
// Database operations
|
|
719
|
+
// Complex transformations
|
|
720
|
+
return result;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
**3. Add Repository (if needed):**
|
|
726
|
+
```typescript
|
|
727
|
+
// Service calls repository
|
|
728
|
+
export class ActionService {
|
|
729
|
+
constructor(private actionRepository: ActionRepository) {}
|
|
730
|
+
|
|
731
|
+
async execute(data: ActionDTO): Promise<Result> {
|
|
732
|
+
// Business logic
|
|
733
|
+
const entity = await this.actionRepository.findById(data.id);
|
|
734
|
+
// More logic
|
|
735
|
+
return await this.actionRepository.update(data.id, changes);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// Repository handles data access
|
|
740
|
+
export class ActionRepository {
|
|
741
|
+
async findById(id: number): Promise<Entity | null> {
|
|
742
|
+
return PrismaService.main.entity.findUnique({ where: { id } });
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
async update(id: number, data: Partial<Entity>): Promise<Entity> {
|
|
746
|
+
return PrismaService.main.entity.update({ where: { id }, data });
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
---
|
|
752
|
+
|
|
753
|
+
**Related Files:**
|
|
754
|
+
- [SKILL.md](SKILL.md) - Main guide
|
|
755
|
+
- [services-and-repositories.md](services-and-repositories.md) - Service layer details
|
|
756
|
+
- [complete-examples.md](complete-examples.md) - Full refactoring examples
|