agileflow 4.0.0-alpha.2 → 4.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/content/plugins/accessibility/plugin.yaml +14 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/SKILL.md +392 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/references/aria-patterns.md +528 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/references/testing-checklist.md +457 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/references/wcag-guide.md +683 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/workflows/audit-page.md +310 -0
- package/content/plugins/accessibility/skills/agileflow-accessibility/workflows/implement-accessible-component.md +479 -0
- package/content/plugins/ads/agents/ads-audit-budget.md +185 -0
- package/content/plugins/ads/agents/ads-audit-compliance.md +171 -0
- package/content/plugins/ads/agents/ads-audit-creative.md +168 -0
- package/content/plugins/ads/agents/ads-audit-google.md +227 -0
- package/content/plugins/ads/agents/ads-audit-meta.md +184 -0
- package/content/plugins/ads/agents/ads-audit-tracking.md +205 -0
- package/content/plugins/ads/agents/ads-consensus.md +410 -0
- package/content/plugins/ads/agents/ads-generate.md +152 -0
- package/content/plugins/ads/agents/ads-performance-tracker.md +212 -0
- package/content/plugins/ads/plugin.yaml +23 -4
- package/content/plugins/ads/skills/agileflow-ads/SKILL.md +218 -0
- package/content/plugins/ads/skills/agileflow-ads/references/ad-copy-formula-guide.md +131 -0
- package/content/plugins/ads/skills/agileflow-ads/references/audience-targeting-guide.md +137 -0
- package/content/plugins/ads/skills/agileflow-ads/references/bid-strategy-guide.md +115 -0
- package/content/plugins/ads/skills/agileflow-ads/references/platform-benchmarks.md +100 -0
- package/content/plugins/ads/skills/agileflow-ads/workflows/audit.md +118 -0
- package/content/plugins/ads/skills/agileflow-ads/workflows/generate.md +84 -0
- package/content/plugins/audit/agents/a11y-analyzer-aria.md +173 -0
- package/content/plugins/audit/agents/a11y-analyzer-forms.md +173 -0
- package/content/plugins/audit/agents/a11y-analyzer-keyboard.md +183 -0
- package/content/plugins/audit/agents/a11y-analyzer-semantic.md +169 -0
- package/content/plugins/audit/agents/a11y-analyzer-visual.md +172 -0
- package/content/plugins/audit/agents/a11y-consensus.md +249 -0
- package/content/plugins/audit/agents/accessibility.md +558 -0
- package/content/plugins/audit/agents/api-quality-analyzer-conventions.md +156 -0
- package/content/plugins/audit/agents/api-quality-analyzer-docs.md +184 -0
- package/content/plugins/audit/agents/api-quality-analyzer-errors.md +191 -0
- package/content/plugins/audit/agents/api-quality-analyzer-pagination.md +179 -0
- package/content/plugins/audit/agents/api-quality-analyzer-versioning.md +150 -0
- package/content/plugins/audit/agents/api-quality-consensus.md +217 -0
- package/content/plugins/audit/agents/api-validator.md +191 -0
- package/content/plugins/audit/agents/arch-analyzer-circular.md +156 -0
- package/content/plugins/audit/agents/arch-analyzer-complexity.md +193 -0
- package/content/plugins/audit/agents/arch-analyzer-coupling.md +152 -0
- package/content/plugins/audit/agents/arch-analyzer-layering.md +160 -0
- package/content/plugins/audit/agents/arch-analyzer-patterns.md +210 -0
- package/content/plugins/audit/agents/arch-consensus.md +228 -0
- package/content/plugins/audit/agents/browser-qa.md +342 -0
- package/content/plugins/audit/agents/code-reviewer.md +298 -0
- package/content/plugins/audit/agents/completeness-analyzer-api.md +199 -0
- package/content/plugins/audit/agents/completeness-analyzer-conditional.md +211 -0
- package/content/plugins/audit/agents/completeness-analyzer-handlers.md +166 -0
- package/content/plugins/audit/agents/completeness-analyzer-imports.md +165 -0
- package/content/plugins/audit/agents/completeness-analyzer-routes.md +190 -0
- package/content/plugins/audit/agents/completeness-analyzer-state.md +196 -0
- package/content/plugins/audit/agents/completeness-analyzer-stubs.md +206 -0
- package/content/plugins/audit/agents/completeness-consensus.md +295 -0
- package/content/plugins/audit/agents/error-analyzer.md +213 -0
- package/content/plugins/audit/agents/flow-analyzer-authorization.md +182 -0
- package/content/plugins/audit/agents/flow-analyzer-discovery.md +174 -0
- package/content/plugins/audit/agents/flow-analyzer-errors.md +186 -0
- package/content/plugins/audit/agents/flow-analyzer-feedback.md +185 -0
- package/content/plugins/audit/agents/flow-analyzer-navigation.md +177 -0
- package/content/plugins/audit/agents/flow-analyzer-persistence.md +193 -0
- package/content/plugins/audit/agents/flow-analyzer-wiring.md +169 -0
- package/content/plugins/audit/agents/flow-consensus.md +237 -0
- package/content/plugins/audit/agents/legal-analyzer-a11y.md +114 -0
- package/content/plugins/audit/agents/legal-analyzer-ai.md +121 -0
- package/content/plugins/audit/agents/legal-analyzer-consumer.md +114 -0
- package/content/plugins/audit/agents/legal-analyzer-content.md +117 -0
- package/content/plugins/audit/agents/legal-analyzer-international.md +119 -0
- package/content/plugins/audit/agents/legal-analyzer-licensing.md +119 -0
- package/content/plugins/audit/agents/legal-analyzer-privacy.md +112 -0
- package/content/plugins/audit/agents/legal-analyzer-security.md +116 -0
- package/content/plugins/audit/agents/legal-analyzer-terms.md +115 -0
- package/content/plugins/audit/agents/legal-consensus.md +250 -0
- package/content/plugins/audit/agents/logic-analyzer-edge.md +179 -0
- package/content/plugins/audit/agents/logic-analyzer-flow.md +264 -0
- package/content/plugins/audit/agents/logic-analyzer-invariant.md +215 -0
- package/content/plugins/audit/agents/logic-analyzer-race.md +280 -0
- package/content/plugins/audit/agents/logic-analyzer-type.md +227 -0
- package/content/plugins/audit/agents/logic-consensus.md +259 -0
- package/content/plugins/audit/agents/perf-analyzer-assets.md +182 -0
- package/content/plugins/audit/agents/perf-analyzer-bundle.md +173 -0
- package/content/plugins/audit/agents/perf-analyzer-caching.md +170 -0
- package/content/plugins/audit/agents/perf-analyzer-compute.md +173 -0
- package/content/plugins/audit/agents/perf-analyzer-memory.md +193 -0
- package/content/plugins/audit/agents/perf-analyzer-network.md +165 -0
- package/content/plugins/audit/agents/perf-analyzer-queries.md +162 -0
- package/content/plugins/audit/agents/perf-analyzer-rendering.md +168 -0
- package/content/plugins/audit/agents/perf-consensus.md +287 -0
- package/content/plugins/audit/agents/qa.md +820 -0
- package/content/plugins/audit/agents/quality-analyzer-comments.md +159 -0
- package/content/plugins/audit/agents/quality-analyzer-duplication.md +184 -0
- package/content/plugins/audit/agents/quality-analyzer-naming.md +160 -0
- package/content/plugins/audit/agents/quality-consensus.md +241 -0
- package/content/plugins/audit/agents/schema-validator.md +473 -0
- package/content/plugins/audit/agents/security-analyzer-api.md +210 -0
- package/content/plugins/audit/agents/security-analyzer-auth.md +169 -0
- package/content/plugins/audit/agents/security-analyzer-authz.md +180 -0
- package/content/plugins/audit/agents/security-analyzer-deps.md +153 -0
- package/content/plugins/audit/agents/security-analyzer-infra.md +184 -0
- package/content/plugins/audit/agents/security-analyzer-injection.md +155 -0
- package/content/plugins/audit/agents/security-analyzer-input.md +201 -0
- package/content/plugins/audit/agents/security-analyzer-secrets.md +183 -0
- package/content/plugins/audit/agents/security-consensus.md +283 -0
- package/content/plugins/audit/agents/test-analyzer-assertions.md +188 -0
- package/content/plugins/audit/agents/test-analyzer-coverage.md +189 -0
- package/content/plugins/audit/agents/test-analyzer-fragility.md +193 -0
- package/content/plugins/audit/agents/test-analyzer-integration.md +161 -0
- package/content/plugins/audit/agents/test-analyzer-maintenance.md +180 -0
- package/content/plugins/audit/agents/test-analyzer-mocking.md +188 -0
- package/content/plugins/audit/agents/test-analyzer-patterns.md +196 -0
- package/content/plugins/audit/agents/test-analyzer-structure.md +184 -0
- package/content/plugins/audit/agents/test-consensus.md +301 -0
- package/content/plugins/audit/agents/testing.md +561 -0
- package/content/plugins/audit/agents/ui-validator.md +344 -0
- package/content/plugins/audit/plugin.yaml +186 -5
- package/content/plugins/audit/skills/agileflow-audit/SKILL.md +113 -0
- package/content/plugins/audit/skills/agileflow-audit/references/audit-depth-guide.md +151 -0
- package/content/plugins/audit/skills/agileflow-audit/references/dependency-risk-guide.md +139 -0
- package/content/plugins/audit/skills/agileflow-audit/references/owasp-top10.md +120 -0
- package/content/plugins/audit/skills/agileflow-audit/references/performance-budget-guide.md +143 -0
- package/content/plugins/audit/skills/agileflow-audit/references/wcag-criteria.md +117 -0
- package/content/plugins/audit/skills/agileflow-audit/workflows/run-audit.md +52 -0
- package/content/plugins/audit/skills/agileflow-audit/workflows/tdd.md +66 -0
- package/content/plugins/core/agents/adr-writer.md +521 -0
- package/content/plugins/core/agents/epic-planner.md +520 -0
- package/content/plugins/core/agents/mentor.md +709 -0
- package/content/plugins/core/agents/orchestrator.md +776 -0
- package/content/plugins/core/agents/team-coordinator.md +334 -0
- package/content/plugins/core/agents/team-lead.md +181 -0
- package/content/plugins/core/agents/workspace-orchestrator.md +146 -0
- package/content/plugins/core/hooks/context-loader.js +31 -4
- package/content/plugins/core/hooks/damage-control-bash.js +10 -2
- package/content/plugins/core/hooks/damage-control-edit.js +4 -1
- package/content/plugins/core/hooks/damage-control-patterns.yaml +1 -1
- package/content/plugins/core/hooks/damage-control-write.js +4 -1
- package/content/plugins/core/hooks/{pre-compact-state.js → post-compact-state.js} +25 -8
- package/content/plugins/core/hooks/preferences-injector.js +352 -0
- package/content/plugins/core/plugin.yaml +24 -28
- package/content/plugins/core/skills/agileflow-adr/SKILL.md +34 -8
- package/content/plugins/core/skills/agileflow-adr/references/madr-format-guide.md +86 -0
- package/content/plugins/core/skills/agileflow-adr/workflows/write-adr.md +57 -0
- package/content/plugins/core/skills/agileflow-babysit-mentor/SKILL.md +94 -27
- package/content/plugins/core/skills/agileflow-babysit-mentor/references/mentor-decision-guide.md +81 -0
- package/content/plugins/core/skills/agileflow-babysit-mentor/workflows/mentor-session.md +79 -0
- package/content/plugins/core/skills/agileflow-epic-planner/SKILL.md +37 -7
- package/content/plugins/core/skills/agileflow-epic-planner/references/epic-sizing-guide.md +81 -0
- package/content/plugins/core/skills/agileflow-epic-planner/workflows/plan-epic.md +55 -0
- package/content/plugins/core/skills/agileflow-status-updater/SKILL.md +36 -20
- package/content/plugins/core/skills/agileflow-status-updater/references/status-transitions.md +89 -0
- package/content/plugins/core/skills/agileflow-status-updater/workflows/update-status.md +56 -0
- package/content/plugins/core/skills/agileflow-story-writer/SKILL.md +39 -114
- package/content/plugins/core/skills/agileflow-story-writer/references/estimation-reference.md +36 -0
- package/content/plugins/core/skills/agileflow-story-writer/references/story-template.md +92 -0
- package/content/plugins/core/skills/agileflow-story-writer/workflows/write-story.md +138 -0
- package/content/plugins/council/agents/council-advocate.md +223 -0
- package/content/plugins/council/agents/council-analyst.md +278 -0
- package/content/plugins/council/agents/council-compounder.md +204 -0
- package/content/plugins/council/agents/council-contrarian.md +217 -0
- package/content/plugins/council/agents/council-moonshot.md +217 -0
- package/content/plugins/council/agents/council-optimist.md +185 -0
- package/content/plugins/council/agents/council-revenue.md +200 -0
- package/content/plugins/council/agents/council-technical.md +218 -0
- package/content/plugins/council/agents/multi-expert.md +334 -0
- package/content/plugins/council/plugin.yaml +23 -4
- package/content/plugins/council/skills/agileflow-council/SKILL.md +102 -0
- package/content/plugins/council/skills/agileflow-council/references/decision-log-template.md +109 -0
- package/content/plugins/council/skills/agileflow-council/references/perspective-guide.md +104 -0
- package/content/plugins/council/skills/agileflow-council/references/when-to-convene-guide.md +112 -0
- package/content/plugins/council/skills/agileflow-council/workflows/convene.md +73 -0
- package/content/plugins/council/skills/agileflow-council/workflows/multi-expert.md +75 -0
- package/content/plugins/database/plugin.yaml +14 -0
- package/content/plugins/database/skills/agileflow-database/SKILL.md +284 -0
- package/content/plugins/database/skills/agileflow-database/references/indexing-guide.md +313 -0
- package/content/plugins/database/skills/agileflow-database/references/migration-guide.md +328 -0
- package/content/plugins/database/skills/agileflow-database/references/schema-design-guide.md +467 -0
- package/content/plugins/database/skills/agileflow-database/workflows/design-schema.md +213 -0
- package/content/plugins/database/skills/agileflow-database/workflows/optimize-query.md +253 -0
- package/content/plugins/debugging/plugin.yaml +14 -0
- package/content/plugins/debugging/skills/agileflow-debug/SKILL.md +236 -0
- package/content/plugins/debugging/skills/agileflow-debug/references/common-patterns.md +350 -0
- package/content/plugins/debugging/skills/agileflow-debug/references/debugging-strategies.md +328 -0
- package/content/plugins/debugging/skills/agileflow-debug/workflows/debug-issue.md +187 -0
- package/content/plugins/debugging/skills/agileflow-debug/workflows/reproduce-bug.md +194 -0
- package/content/plugins/delivery/agents/ci.md +547 -0
- package/content/plugins/delivery/agents/devops.md +789 -0
- package/content/plugins/delivery/plugin.yaml +19 -0
- package/content/plugins/delivery/skills/agileflow-delivery/SKILL.md +111 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/changelog-format-guide.md +133 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/ci-pipeline-guide.md +158 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/pr-checklist-guide.md +133 -0
- package/content/plugins/delivery/skills/agileflow-delivery/references/release-checklist.md +142 -0
- package/content/plugins/delivery/skills/agileflow-delivery/workflows/changelog.md +72 -0
- package/content/plugins/delivery/skills/agileflow-delivery/workflows/deploy.md +74 -0
- package/content/plugins/delivery/skills/agileflow-delivery/workflows/pr.md +75 -0
- package/content/plugins/docs/agents/documentation.md +544 -0
- package/content/plugins/docs/agents/readme-updater.md +640 -0
- package/content/plugins/docs/plugin.yaml +19 -0
- package/content/plugins/docs/skills/agileflow-docs/SKILL.md +106 -0
- package/content/plugins/docs/skills/agileflow-docs/references/api-doc-template.md +167 -0
- package/content/plugins/docs/skills/agileflow-docs/references/doc-types-guide.md +141 -0
- package/content/plugins/docs/skills/agileflow-docs/references/readme-template.md +156 -0
- package/content/plugins/docs/skills/agileflow-docs/workflows/readme-sync.md +57 -0
- package/content/plugins/docs/skills/agileflow-docs/workflows/sync.md +64 -0
- package/content/plugins/engineering/agents/api.md +718 -0
- package/content/plugins/engineering/agents/codebase-query.md +285 -0
- package/content/plugins/engineering/agents/compliance.md +559 -0
- package/content/plugins/engineering/agents/database.md +644 -0
- package/content/plugins/engineering/agents/integrations.md +644 -0
- package/content/plugins/engineering/agents/mobile.md +552 -0
- package/content/plugins/engineering/agents/monitoring.md +585 -0
- package/content/plugins/engineering/agents/performance.md +529 -0
- package/content/plugins/engineering/agents/refactor.md +592 -0
- package/content/plugins/engineering/agents/security.md +524 -0
- package/content/plugins/engineering/agents/ui.md +1336 -0
- package/content/plugins/engineering/plugin.yaml +37 -0
- package/content/plugins/engineering/skills/agileflow-engineering/SKILL.md +127 -0
- package/content/plugins/engineering/skills/agileflow-engineering/references/code-review-guide.md +126 -0
- package/content/plugins/engineering/skills/agileflow-engineering/references/domain-routing-guide.md +89 -0
- package/content/plugins/engineering/skills/agileflow-engineering/references/refactoring-guide.md +136 -0
- package/content/plugins/engineering/skills/agileflow-engineering/workflows/diagnose.md +63 -0
- package/content/plugins/engineering/skills/agileflow-engineering/workflows/impact.md +60 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-features.md +179 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-growth.md +169 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-integration.md +181 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-market.md +150 -0
- package/content/plugins/ideation/agents/brainstorm-analyzer-ux.md +180 -0
- package/content/plugins/ideation/agents/brainstorm-consensus.md +245 -0
- package/content/plugins/ideation/agents/design.md +568 -0
- package/content/plugins/ideation/agents/product.md +582 -0
- package/content/plugins/ideation/plugin.yaml +31 -0
- package/content/plugins/ideation/skills/agileflow-ideation/SKILL.md +109 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/brainstorm-techniques.md +138 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/competitive-analysis-template.md +148 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/feature-prioritization-guide.md +147 -0
- package/content/plugins/ideation/skills/agileflow-ideation/references/user-story-patterns.md +152 -0
- package/content/plugins/ideation/skills/agileflow-ideation/workflows/features.md +65 -0
- package/content/plugins/ideation/skills/agileflow-ideation/workflows/ideate.md +54 -0
- package/content/plugins/migration/agents/datamigration.md +757 -0
- package/content/plugins/migration/plugin.yaml +17 -0
- package/content/plugins/migration/skills/agileflow-migration/SKILL.md +106 -0
- package/content/plugins/migration/skills/agileflow-migration/references/data-validation-checklist.md +154 -0
- package/content/plugins/migration/skills/agileflow-migration/references/migration-patterns.md +209 -0
- package/content/plugins/migration/skills/agileflow-migration/references/rollback-playbook.md +171 -0
- package/content/plugins/migration/skills/agileflow-migration/references/version-compatibility-matrix.md +155 -0
- package/content/plugins/migration/skills/agileflow-migration/workflows/plan.md +73 -0
- package/content/plugins/migration/skills/agileflow-migration/workflows/validate.md +71 -0
- package/content/plugins/performance/plugin.yaml +14 -0
- package/content/plugins/performance/skills/agileflow-performance/SKILL.md +224 -0
- package/content/plugins/performance/skills/agileflow-performance/references/optimization-patterns.md +554 -0
- package/content/plugins/performance/skills/agileflow-performance/references/profiling-guide.md +383 -0
- package/content/plugins/performance/skills/agileflow-performance/references/web-vitals-guide.md +360 -0
- package/content/plugins/performance/skills/agileflow-performance/workflows/improve-web-vitals.md +344 -0
- package/content/plugins/performance/skills/agileflow-performance/workflows/profile-and-fix.md +254 -0
- package/content/plugins/planning/agents/analytics.md +670 -0
- package/content/plugins/planning/agents/rlm-subcore.md +215 -0
- package/content/plugins/planning/plugin.yaml +19 -0
- package/content/plugins/planning/skills/agileflow-planning/SKILL.md +111 -0
- package/content/plugins/planning/skills/agileflow-planning/references/estimation-guide.md +114 -0
- package/content/plugins/planning/skills/agileflow-planning/references/rpi-workflow.md +119 -0
- package/content/plugins/planning/skills/agileflow-planning/references/sprint-planning-guide.md +145 -0
- package/content/plugins/planning/skills/agileflow-planning/workflows/impact.md +63 -0
- package/content/plugins/planning/skills/agileflow-planning/workflows/rpi.md +104 -0
- package/content/plugins/psychology/plugin.yaml +14 -0
- package/content/plugins/psychology/skills/agileflow-retention/SKILL.md +252 -0
- package/content/plugins/psychology/skills/agileflow-retention/references/competitor-analysis.md +240 -0
- package/content/plugins/psychology/skills/agileflow-retention/references/psychology-models.md +349 -0
- package/content/plugins/psychology/skills/agileflow-retention/references/retention-patterns.md +279 -0
- package/content/plugins/psychology/skills/agileflow-retention/workflows/design-retention-feature.md +287 -0
- package/content/plugins/psychology/skills/agileflow-retention/workflows/retention-audit.md +259 -0
- package/content/plugins/refactoring/plugin.yaml +14 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/SKILL.md +235 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/references/refactoring-patterns.md +405 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/references/safety-checks.md +177 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/workflows/extract-module.md +226 -0
- package/content/plugins/refactoring/skills/agileflow-refactor/workflows/safe-refactor.md +169 -0
- package/content/plugins/research/agents/research.md +503 -0
- package/content/plugins/research/plugin.yaml +17 -0
- package/content/plugins/research/skills/agileflow-research/SKILL.md +110 -0
- package/content/plugins/research/skills/agileflow-research/references/knowledge-decay-guide.md +121 -0
- package/content/plugins/research/skills/agileflow-research/references/research-prompt-guide.md +141 -0
- package/content/plugins/research/skills/agileflow-research/references/synthesis-template.md +154 -0
- package/content/plugins/research/skills/agileflow-research/workflows/analyze.md +60 -0
- package/content/plugins/research/skills/agileflow-research/workflows/ask.md +64 -0
- package/content/plugins/research/skills/agileflow-research/workflows/import.md +66 -0
- package/content/plugins/research/skills/agileflow-research/workflows/synthesize.md +66 -0
- package/content/plugins/reviews/plugin.yaml +14 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/SKILL.md +241 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/references/review-checklist.md +200 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/references/security-patterns.md +328 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/workflows/review-pr.md +153 -0
- package/content/plugins/reviews/skills/agileflow-pr-reviewer/workflows/security-review.md +177 -0
- package/content/plugins/seo/agents/seo-analyzer-content.md +169 -0
- package/content/plugins/seo/agents/seo-analyzer-images.md +198 -0
- package/content/plugins/seo/agents/seo-analyzer-performance.md +217 -0
- package/content/plugins/seo/agents/seo-analyzer-schema.md +184 -0
- package/content/plugins/seo/agents/seo-analyzer-sitemap.md +177 -0
- package/content/plugins/seo/agents/seo-analyzer-technical.md +151 -0
- package/content/plugins/seo/agents/seo-consensus.md +304 -0
- package/content/plugins/seo/plugin.yaml +19 -4
- package/content/plugins/seo/skills/agileflow-seo/SKILL.md +188 -0
- package/content/plugins/seo/skills/agileflow-seo/references/cwv-thresholds.md +110 -0
- package/content/plugins/seo/skills/agileflow-seo/references/eeat-framework.md +144 -0
- package/content/plugins/seo/skills/agileflow-seo/references/keyword-research-guide.md +125 -0
- package/content/plugins/seo/skills/agileflow-seo/references/schema-types.md +139 -0
- package/content/plugins/seo/skills/agileflow-seo/references/technical-seo-checklist.md +139 -0
- package/content/plugins/seo/skills/agileflow-seo/workflows/audit.md +98 -0
- package/content/plugins/seo/skills/agileflow-seo/workflows/page.md +118 -0
- package/content/plugins/testing/plugin.yaml +16 -0
- package/content/plugins/testing/skills/agileflow-test-writer/SKILL.md +260 -0
- package/content/plugins/testing/skills/agileflow-test-writer/references/coverage-targets.md +239 -0
- package/content/plugins/testing/skills/agileflow-test-writer/references/test-patterns.md +420 -0
- package/content/plugins/testing/skills/agileflow-test-writer/workflows/add-coverage.md +154 -0
- package/content/plugins/testing/skills/agileflow-test-writer/workflows/write-tests-from-ac.md +225 -0
- package/package.json +2 -2
- package/src/cli/commands/doctor.js +818 -30
- package/src/cli/commands/hook.js +17 -14
- package/src/cli/commands/launch.js +1454 -0
- package/src/cli/commands/learn.js +149 -0
- package/src/cli/commands/plugins.js +113 -0
- package/src/cli/commands/setup.js +455 -110
- package/src/cli/commands/skills.js +324 -0
- package/src/cli/commands/status.js +8 -10
- package/src/cli/commands/update.js +76 -15
- package/src/cli/index.js +90 -26
- package/src/cli/wizard/babysit-mode-picker.js +192 -0
- package/src/cli/wizard/behaviors-picker.js +208 -54
- package/src/cli/wizard/ide-picker.js +40 -28
- package/src/cli/wizard/install-scope-picker.js +57 -0
- package/src/cli/wizard/launch-alias-picker.js +50 -0
- package/src/cli/wizard/launch-cli-picker.js +129 -0
- package/src/cli/wizard/launch-tmux-picker.js +133 -0
- package/src/cli/wizard/learnings-picker.js +40 -0
- package/src/cli/wizard/plugin-picker.js +47 -16
- package/src/lib/brand.js +116 -0
- package/src/lib/errors.js +120 -0
- package/src/lib/path-check.js +39 -0
- package/src/runtime/config/defaults.js +22 -17
- package/src/runtime/config/loader.js +77 -8
- package/src/runtime/config/schema.json +43 -16
- package/src/runtime/config/writer.js +3 -1
- package/src/runtime/ide/babysit-skill.js +202 -0
- package/src/runtime/ide/capabilities.js +84 -29
- package/src/runtime/ide/claude-code-content.js +177 -0
- package/src/runtime/ide/claude-code-settings.js +67 -29
- package/src/runtime/ide/claude-code-skills.js +47 -32
- package/src/runtime/ide/codex-config.js +295 -0
- package/src/runtime/installer/install.js +252 -24
- package/src/runtime/launch/alias-installer.js +191 -0
- package/src/runtime/launch/cli-resume.js +244 -0
- package/src/runtime/launch/closed-windows.js +338 -0
- package/src/runtime/launch/defaults.js +66 -0
- package/src/runtime/launch/detect-clis.js +69 -0
- package/src/runtime/launch/doctor.js +464 -0
- package/src/runtime/launch/exec-wrapper.js +114 -0
- package/src/runtime/launch/parallel-session.js +247 -0
- package/src/runtime/launch/prefs.js +211 -0
- package/src/runtime/launch/project-prefs.js +234 -0
- package/src/runtime/launch/resolve-cli.js +56 -0
- package/src/runtime/launch/restore.js +152 -0
- package/src/runtime/launch/schema.json +75 -0
- package/src/runtime/launch/session-lifecycle.js +313 -0
- package/src/runtime/launch/session-registry.js +401 -0
- package/src/runtime/launch/spawn.js +103 -0
- package/src/runtime/launch/tabs.js +350 -0
- package/src/runtime/launch/tmux.js +764 -0
- package/src/runtime/launch/worktree.js +260 -0
- package/src/runtime/plugins/registry.js +16 -11
- package/src/runtime/plugins/validator.js +57 -43
- package/src/runtime/skills/learnings.js +308 -0
- package/content/plugins/core/hooks/babysit-mentor-injector.js +0 -55
- package/src/cli/wizard/personalization.js +0 -64
package/content/plugins/performance/skills/agileflow-performance/references/optimization-patterns.md
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
# Optimization Patterns
|
|
2
|
+
|
|
3
|
+
**Load this when:** you have profiling data that identifies a bottleneck and need concrete techniques to address it. Organized by domain. Apply one change at a time and measure after each.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Frontend rendering
|
|
8
|
+
|
|
9
|
+
### Code splitting
|
|
10
|
+
|
|
11
|
+
Delivering all JavaScript up front is the single most common cause of slow Time to Interactive. Split by route at minimum.
|
|
12
|
+
|
|
13
|
+
**Route-based splitting (React + React Router):**
|
|
14
|
+
|
|
15
|
+
```jsx
|
|
16
|
+
import { lazy, Suspense } from "react";
|
|
17
|
+
import { Routes, Route } from "react-router-dom";
|
|
18
|
+
|
|
19
|
+
const Dashboard = lazy(() => import("./pages/Dashboard"));
|
|
20
|
+
const Settings = lazy(() => import("./pages/Settings"));
|
|
21
|
+
|
|
22
|
+
function App() {
|
|
23
|
+
return (
|
|
24
|
+
<Suspense fallback={<PageSkeleton />}>
|
|
25
|
+
<Routes>
|
|
26
|
+
<Route path="/dashboard" element={<Dashboard />} />
|
|
27
|
+
<Route path="/settings" element={<Settings />} />
|
|
28
|
+
</Routes>
|
|
29
|
+
</Suspense>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Component-level splitting for heavy components:**
|
|
35
|
+
|
|
36
|
+
```jsx
|
|
37
|
+
// Heavy editor only loaded when user clicks "Edit"
|
|
38
|
+
const RichTextEditor = lazy(() => import("./components/RichTextEditor"));
|
|
39
|
+
|
|
40
|
+
function PostEditor({ editing }) {
|
|
41
|
+
return editing ? (
|
|
42
|
+
<Suspense fallback={<Spinner />}>
|
|
43
|
+
<RichTextEditor />
|
|
44
|
+
</Suspense>
|
|
45
|
+
) : (
|
|
46
|
+
<ReadonlyView />
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Dynamic import for rarely-used utilities:**
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
async function exportToPDF(data) {
|
|
55
|
+
const { jsPDF } = await import("jspdf"); // only loaded on demand
|
|
56
|
+
const doc = new jsPDF();
|
|
57
|
+
// ...
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### Tree shaking
|
|
64
|
+
|
|
65
|
+
Tree shaking eliminates dead code from the bundle. It only works with ES module `import`/`export` syntax.
|
|
66
|
+
|
|
67
|
+
**Use named imports — not default namespace imports:**
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
// Bad — imports the entire lodash library (~70 KB gzipped)
|
|
71
|
+
import _ from "lodash";
|
|
72
|
+
const result = _.debounce(fn, 300);
|
|
73
|
+
|
|
74
|
+
// Good — imports only debounce (~2 KB)
|
|
75
|
+
import debounce from "lodash/debounce";
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Avoid barrel re-exports of unused code:**
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
// Bad — index.js re-exports everything; bundler may include all of it
|
|
82
|
+
// components/index.js:
|
|
83
|
+
export { Button } from "./Button";
|
|
84
|
+
export { Modal } from "./Modal";
|
|
85
|
+
export { HeavyDataGrid } from "./HeavyDataGrid"; // included even if not used
|
|
86
|
+
|
|
87
|
+
// Good — import directly from the component file
|
|
88
|
+
import { Button } from "./components/Button";
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Mark packages as side-effect-free in `package.json` to enable full tree shaking:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{ "sideEffects": false }
|
|
95
|
+
// Or list specific files with side effects:
|
|
96
|
+
{ "sideEffects": ["./src/polyfills.js", "*.css"] }
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### Image optimization
|
|
102
|
+
|
|
103
|
+
Images are the most common reason for slow LCP. Unoptimized images routinely account for 60–80% of page weight.
|
|
104
|
+
|
|
105
|
+
**Format: prefer WebP, then AVIF for modern browsers:**
|
|
106
|
+
|
|
107
|
+
```html
|
|
108
|
+
<picture>
|
|
109
|
+
<source srcset="hero.avif" type="image/avif" />
|
|
110
|
+
<source srcset="hero.webp" type="image/webp" />
|
|
111
|
+
<img src="hero.jpg" alt="..." width="1200" height="630" />
|
|
112
|
+
</picture>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Responsive images with `srcset` + `sizes`:**
|
|
116
|
+
|
|
117
|
+
```html
|
|
118
|
+
<img
|
|
119
|
+
srcset="hero-400.webp 400w, hero-800.webp 800w, hero-1200.webp 1200w"
|
|
120
|
+
sizes="(max-width: 600px) 100vw, (max-width: 1024px) 800px, 1200px"
|
|
121
|
+
src="hero-1200.webp"
|
|
122
|
+
alt="..."
|
|
123
|
+
width="1200"
|
|
124
|
+
height="630"
|
|
125
|
+
loading="lazy"
|
|
126
|
+
/>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Always specify `width` and `height` attributes** — the browser can reserve space and prevent CLS before the image loads.
|
|
130
|
+
|
|
131
|
+
**Do NOT use `loading="lazy"` on the LCP image** — this delays the most important image. Only lazy-load images below the fold.
|
|
132
|
+
|
|
133
|
+
**Preload the LCP image:**
|
|
134
|
+
|
|
135
|
+
```html
|
|
136
|
+
<link rel="preload" as="image" href="hero.webp" fetchpriority="high" />
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
### Critical CSS and JavaScript deferral
|
|
142
|
+
|
|
143
|
+
**Render-blocking resources delay First Contentful Paint:**
|
|
144
|
+
|
|
145
|
+
```html
|
|
146
|
+
<!-- Bad: render-blocking -->
|
|
147
|
+
<link rel="stylesheet" href="all-styles.css" />
|
|
148
|
+
<script src="analytics.js"></script>
|
|
149
|
+
|
|
150
|
+
<!-- Good: inline critical CSS, defer the rest -->
|
|
151
|
+
<style>
|
|
152
|
+
/* above-the-fold styles only */
|
|
153
|
+
</style>
|
|
154
|
+
<link
|
|
155
|
+
rel="preload"
|
|
156
|
+
href="non-critical.css"
|
|
157
|
+
as="style"
|
|
158
|
+
onload="this.rel='stylesheet'"
|
|
159
|
+
/>
|
|
160
|
+
<script src="analytics.js" defer></script>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Script loading strategies:**
|
|
164
|
+
|
|
165
|
+
| Attribute | When to use |
|
|
166
|
+
| ------------- | ------------------------------------------------------------------- |
|
|
167
|
+
| (none) | Never — blocks parsing |
|
|
168
|
+
| `defer` | Scripts that need the DOM; executes after parse, in order |
|
|
169
|
+
| `async` | Scripts that don't need the DOM and don't need ordering (analytics) |
|
|
170
|
+
| `type=module` | ES modules — deferred by default |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### Memoization in React
|
|
175
|
+
|
|
176
|
+
Memoization prevents unnecessary re-renders but adds overhead. Use only when profiling shows a component is an actual bottleneck.
|
|
177
|
+
|
|
178
|
+
```jsx
|
|
179
|
+
// React.memo — skip re-render if props haven't changed
|
|
180
|
+
const UserCard = React.memo(function UserCard({ user, onSelect }) {
|
|
181
|
+
return <div onClick={() => onSelect(user.id)}>{user.name}</div>;
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// useMemo — memoize an expensive computation
|
|
185
|
+
const sortedItems = useMemo(
|
|
186
|
+
() => [...items].sort((a, b) => a.price - b.price),
|
|
187
|
+
[items], // only recompute when items changes
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
// useCallback — stable function reference for memoized children
|
|
191
|
+
const handleSelect = useCallback((id) => {
|
|
192
|
+
setSelectedId(id);
|
|
193
|
+
}, []); // empty deps = stable reference
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**When memoization hurts more than it helps:**
|
|
197
|
+
|
|
198
|
+
- The computation is trivial (< 1 ms) — the memoization overhead exceeds the savings
|
|
199
|
+
- The dependency array changes on every render anyway (common with inline objects)
|
|
200
|
+
- The component renders rarely regardless
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
### Virtualization for long lists
|
|
205
|
+
|
|
206
|
+
Rendering a DOM node for every item in a 10,000-row list destroys performance. Virtualization renders only the visible rows.
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
npm install @tanstack/react-virtual
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
```jsx
|
|
213
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
214
|
+
|
|
215
|
+
function VirtualList({ items }) {
|
|
216
|
+
const parentRef = useRef(null);
|
|
217
|
+
|
|
218
|
+
const virtualizer = useVirtualizer({
|
|
219
|
+
count: items.length,
|
|
220
|
+
getScrollElement: () => parentRef.current,
|
|
221
|
+
estimateSize: () => 48, // estimated row height in px
|
|
222
|
+
overscan: 5, // rows to render above/below viewport
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<div ref={parentRef} style={{ height: "600px", overflow: "auto" }}>
|
|
227
|
+
<div style={{ height: virtualizer.getTotalSize() }}>
|
|
228
|
+
{virtualizer.getVirtualItems().map((virtualRow) => (
|
|
229
|
+
<div
|
|
230
|
+
key={virtualRow.index}
|
|
231
|
+
style={{
|
|
232
|
+
position: "absolute",
|
|
233
|
+
top: 0,
|
|
234
|
+
transform: `translateY(${virtualRow.start}px)`,
|
|
235
|
+
height: `${virtualRow.size}px`,
|
|
236
|
+
}}
|
|
237
|
+
>
|
|
238
|
+
{items[virtualRow.index].name}
|
|
239
|
+
</div>
|
|
240
|
+
))}
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Rule of thumb:** virtualize any list with more than 100 items visible at once.
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Backend
|
|
252
|
+
|
|
253
|
+
### Response caching
|
|
254
|
+
|
|
255
|
+
**HTTP cache headers:**
|
|
256
|
+
|
|
257
|
+
```js
|
|
258
|
+
// Express — cache static assets aggressively, API responses briefly
|
|
259
|
+
app.use(
|
|
260
|
+
"/static",
|
|
261
|
+
express.static("public", {
|
|
262
|
+
maxAge: "1y", // static assets: cache forever (content-hashed filenames)
|
|
263
|
+
immutable: true,
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
app.get("/api/products", (req, res) => {
|
|
268
|
+
res.set("Cache-Control", "public, max-age=60, stale-while-revalidate=300");
|
|
269
|
+
// stale-while-revalidate: serve stale content while refreshing in background
|
|
270
|
+
res.json(products);
|
|
271
|
+
});
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**Redis caching in Node.js:**
|
|
275
|
+
|
|
276
|
+
```js
|
|
277
|
+
import { createClient } from "redis";
|
|
278
|
+
|
|
279
|
+
const redis = createClient({ url: process.env.REDIS_URL });
|
|
280
|
+
|
|
281
|
+
async function getCachedProducts(categoryId) {
|
|
282
|
+
const key = `products:category:${categoryId}`;
|
|
283
|
+
const cached = await redis.get(key);
|
|
284
|
+
if (cached) return JSON.parse(cached);
|
|
285
|
+
|
|
286
|
+
const products = await db.query(
|
|
287
|
+
"SELECT * FROM products WHERE category_id = $1",
|
|
288
|
+
[categoryId],
|
|
289
|
+
);
|
|
290
|
+
await redis.setEx(key, 300, JSON.stringify(products)); // TTL: 5 minutes
|
|
291
|
+
return products;
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**Cache invalidation strategy:** prefer TTL-based expiry for read-heavy data. Use event-based invalidation (delete the cache key on write) only when staleness is unacceptable.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### Async I/O and event loop health
|
|
300
|
+
|
|
301
|
+
**Never block the Node.js event loop:**
|
|
302
|
+
|
|
303
|
+
```js
|
|
304
|
+
// Bad — synchronous file read blocks all other requests
|
|
305
|
+
app.get("/report", (req, res) => {
|
|
306
|
+
const data = fs.readFileSync("/large-file.csv"); // blocks!
|
|
307
|
+
res.send(process(data));
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Good — async with streaming
|
|
311
|
+
app.get("/report", async (req, res) => {
|
|
312
|
+
const stream = fs.createReadStream("/large-file.csv");
|
|
313
|
+
res.setHeader("Content-Type", "text/csv");
|
|
314
|
+
stream.pipe(res);
|
|
315
|
+
});
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
**Move CPU-intensive work off the main thread:**
|
|
319
|
+
|
|
320
|
+
```js
|
|
321
|
+
// Worker threads for CPU-bound computation (image processing, PDF generation)
|
|
322
|
+
import { Worker, isMainThread, parentPort, workerData } from "worker_threads";
|
|
323
|
+
|
|
324
|
+
if (isMainThread) {
|
|
325
|
+
function processImage(buffer) {
|
|
326
|
+
return new Promise((resolve, reject) => {
|
|
327
|
+
const worker = new Worker("./image-worker.js", { workerData: buffer });
|
|
328
|
+
worker.on("message", resolve);
|
|
329
|
+
worker.on("error", reject);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
const result = heavyImageProcessing(workerData);
|
|
334
|
+
parentPort.postMessage(result);
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Paginate large responses — never return unbounded result sets:**
|
|
339
|
+
|
|
340
|
+
```js
|
|
341
|
+
// Bad
|
|
342
|
+
const allOrders = await db.query("SELECT * FROM orders WHERE user_id = $1", [
|
|
343
|
+
id,
|
|
344
|
+
]);
|
|
345
|
+
|
|
346
|
+
// Good — keyset pagination (see Database section)
|
|
347
|
+
const orders = await db.query(
|
|
348
|
+
"SELECT * FROM orders WHERE user_id = $1 AND id > $2 ORDER BY id LIMIT 50",
|
|
349
|
+
[id, cursor],
|
|
350
|
+
);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### Compression
|
|
356
|
+
|
|
357
|
+
```js
|
|
358
|
+
// Express with compression middleware
|
|
359
|
+
import compression from "compression";
|
|
360
|
+
|
|
361
|
+
app.use(
|
|
362
|
+
compression({
|
|
363
|
+
threshold: 1024, // don't compress responses < 1 KB (overhead exceeds benefit)
|
|
364
|
+
filter: (req, res) => {
|
|
365
|
+
if (req.headers["x-no-compression"]) return false;
|
|
366
|
+
return compression.filter(req, res);
|
|
367
|
+
},
|
|
368
|
+
}),
|
|
369
|
+
);
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Pre-compress static assets at build time (Vite/webpack) rather than compressing on the fly. Use brotli where supported (20–30% smaller than gzip).
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
### Connection pooling
|
|
377
|
+
|
|
378
|
+
Every database connection has overhead. Establishing a new connection per request is catastrophic at scale.
|
|
379
|
+
|
|
380
|
+
**PostgreSQL with node-postgres:**
|
|
381
|
+
|
|
382
|
+
```js
|
|
383
|
+
import { Pool } from "pg";
|
|
384
|
+
|
|
385
|
+
const pool = new Pool({
|
|
386
|
+
connectionString: process.env.DATABASE_URL,
|
|
387
|
+
max: 20, // max connections in pool
|
|
388
|
+
idleTimeoutMillis: 30000,
|
|
389
|
+
connectionTimeoutMillis: 2000,
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Optimal pool size formula (for OLTP workloads):
|
|
393
|
+
// max = (core_count * 2) + effective_spindle_count
|
|
394
|
+
// For a 4-core server with SSD: max ≈ 9–10
|
|
395
|
+
// More connections ≠ faster; too many causes context-switch overhead
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**pgBouncer** for connection pooling at the infrastructure level — essential when many application instances connect to a single PostgreSQL server.
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## Database
|
|
403
|
+
|
|
404
|
+
### Index design
|
|
405
|
+
|
|
406
|
+
Indexes are the single highest-leverage database optimization. A sequential scan on a 10M-row table can take seconds; an index lookup takes microseconds.
|
|
407
|
+
|
|
408
|
+
**Composite index column order:**
|
|
409
|
+
|
|
410
|
+
```sql
|
|
411
|
+
-- Query: WHERE status = 'active' AND created_at > '2024-01-01' ORDER BY created_at
|
|
412
|
+
-- Correct index: equality columns first, then range/sort column
|
|
413
|
+
CREATE INDEX idx_orders_status_created ON orders (status, created_at);
|
|
414
|
+
|
|
415
|
+
-- Wrong order (less efficient for this query):
|
|
416
|
+
CREATE INDEX idx_orders_created_status ON orders (created_at, status);
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
**Covering index** (includes all columns the query needs — avoids a table heap fetch):
|
|
420
|
+
|
|
421
|
+
```sql
|
|
422
|
+
-- Query only needs user_id, email, name — no heap fetch needed
|
|
423
|
+
CREATE INDEX idx_users_covering ON users (status, created_at)
|
|
424
|
+
INCLUDE (user_id, email, name);
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Partial index** (index only the rows that matter — smaller, faster):
|
|
428
|
+
|
|
429
|
+
```sql
|
|
430
|
+
-- If 95% of queries filter on status = 'pending'
|
|
431
|
+
CREATE INDEX idx_orders_pending ON orders (created_at)
|
|
432
|
+
WHERE status = 'pending';
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Check for missing indexes:**
|
|
436
|
+
|
|
437
|
+
```sql
|
|
438
|
+
-- PostgreSQL: tables with sequential scans
|
|
439
|
+
SELECT schemaname, tablename, seq_scan, idx_scan,
|
|
440
|
+
seq_scan - idx_scan AS too_much_seq
|
|
441
|
+
FROM pg_stat_user_tables
|
|
442
|
+
WHERE seq_scan > idx_scan
|
|
443
|
+
ORDER BY too_much_seq DESC;
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
### N+1 elimination
|
|
449
|
+
|
|
450
|
+
N+1 is the most common database performance bug in ORM-heavy codebases. It occurs when code fetches a list (1 query) then fetches related data per item (N queries).
|
|
451
|
+
|
|
452
|
+
**Identifying N+1 in logs:** look for many identical queries with different IDs in rapid succession.
|
|
453
|
+
|
|
454
|
+
**Fix 1: Eager loading with JOIN:**
|
|
455
|
+
|
|
456
|
+
```sql
|
|
457
|
+
-- Bad (N+1): fetch users, then for each user fetch their posts
|
|
458
|
+
SELECT * FROM users WHERE active = true;
|
|
459
|
+
-- ... then for each user: SELECT * FROM posts WHERE user_id = $1
|
|
460
|
+
|
|
461
|
+
-- Good: one query with JOIN
|
|
462
|
+
SELECT u.id, u.name, u.email, p.id AS post_id, p.title
|
|
463
|
+
FROM users u
|
|
464
|
+
LEFT JOIN posts p ON p.user_id = u.id
|
|
465
|
+
WHERE u.active = true;
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**Fix 2: Batch query (DataLoader pattern):**
|
|
469
|
+
|
|
470
|
+
```js
|
|
471
|
+
// Instead of one query per user ID, collect IDs and query once
|
|
472
|
+
import DataLoader from "dataloader";
|
|
473
|
+
|
|
474
|
+
const postLoader = new DataLoader(async (userIds) => {
|
|
475
|
+
const posts = await db.query("SELECT * FROM posts WHERE user_id = ANY($1)", [
|
|
476
|
+
userIds,
|
|
477
|
+
]);
|
|
478
|
+
// Group by user_id to match DataLoader's expected shape
|
|
479
|
+
return userIds.map((id) => posts.filter((p) => p.user_id === id));
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
// Now each call queues; DataLoader batches into a single DB query
|
|
483
|
+
const posts = await postLoader.load(user.id);
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
### Query optimization
|
|
489
|
+
|
|
490
|
+
**Avoid `SELECT *`** — fetch only the columns you need. On wide tables this can halve I/O.
|
|
491
|
+
|
|
492
|
+
**Push filters to the database:**
|
|
493
|
+
|
|
494
|
+
```js
|
|
495
|
+
// Bad — fetch all users, filter in JavaScript
|
|
496
|
+
const users = await db.query("SELECT * FROM users");
|
|
497
|
+
const activeAdmins = users.filter((u) => u.active && u.role === "admin");
|
|
498
|
+
|
|
499
|
+
// Good — filter in SQL
|
|
500
|
+
const activeAdmins = await db.query(
|
|
501
|
+
"SELECT id, name, email FROM users WHERE active = true AND role = 'admin'",
|
|
502
|
+
);
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Batch inserts:**
|
|
506
|
+
|
|
507
|
+
```sql
|
|
508
|
+
-- Bad: one INSERT per row (N round trips)
|
|
509
|
+
|
|
510
|
+
-- Good: multi-row INSERT
|
|
511
|
+
INSERT INTO events (user_id, type, created_at)
|
|
512
|
+
VALUES ($1, $2, $3), ($4, $5, $6), ($7, $8, $9);
|
|
513
|
+
|
|
514
|
+
-- Or with COPY for bulk loads (10–100x faster than INSERT)
|
|
515
|
+
COPY events (user_id, type, created_at) FROM STDIN;
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
---
|
|
519
|
+
|
|
520
|
+
### Keyset pagination
|
|
521
|
+
|
|
522
|
+
Offset pagination degrades linearly as the offset grows — a `LIMIT 50 OFFSET 10000` still scans 10,050 rows.
|
|
523
|
+
|
|
524
|
+
```sql
|
|
525
|
+
-- Bad: offset pagination
|
|
526
|
+
SELECT * FROM posts ORDER BY created_at DESC LIMIT 50 OFFSET 10000;
|
|
527
|
+
|
|
528
|
+
-- Good: keyset pagination (always fast regardless of page depth)
|
|
529
|
+
SELECT * FROM posts
|
|
530
|
+
WHERE created_at < $1 -- $1 = last seen created_at from previous page
|
|
531
|
+
ORDER BY created_at DESC
|
|
532
|
+
LIMIT 50;
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Keyset pagination requires a cursor (the last-seen value of the sort column). It does not support random page access ("jump to page 47"), but it scales indefinitely and the response time is constant.
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## Performance budgets — quick reference
|
|
540
|
+
|
|
541
|
+
| Resource | Target |
|
|
542
|
+
| -------------------------- | ----------------------------------------- |
|
|
543
|
+
| JS bundle: initial (gzip) | < 200 KB |
|
|
544
|
+
| JS bundle: per route chunk | < 50 KB |
|
|
545
|
+
| Image: LCP image | < 200 KB (WebP/AVIF) |
|
|
546
|
+
| Total page weight | < 1 MB on a 3G connection in < 5 s |
|
|
547
|
+
| API response: p50 | < 100 ms |
|
|
548
|
+
| API response: p95 | < 500 ms |
|
|
549
|
+
| API response: p99 | < 2 s |
|
|
550
|
+
| DB query: simple lookup | < 10 ms |
|
|
551
|
+
| DB query: complex join | < 100 ms |
|
|
552
|
+
| DB query: flag if over | > 500 ms — always investigate |
|
|
553
|
+
| Heap growth (steady) | < 10 MB/hr |
|
|
554
|
+
| Long task threshold | > 50 ms — investigate; > 200 ms — serious |
|