@mytechtoday/augment-extensions 0.1.2 → 0.4.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/README.md +614 -39
- package/augment-extensions/coding-standards/bash/README.md +196 -0
- package/augment-extensions/coding-standards/bash/module.json +163 -0
- package/augment-extensions/coding-standards/bash/rules/naming-conventions.md +336 -0
- package/augment-extensions/coding-standards/bash/rules/universal-standards.md +289 -0
- package/augment-extensions/coding-standards/css/README.md +40 -0
- package/augment-extensions/coding-standards/css/examples/css-examples.css +550 -0
- package/augment-extensions/coding-standards/css/module.json +44 -0
- package/augment-extensions/coding-standards/css/rules/css-modern-features.md +448 -0
- package/augment-extensions/coding-standards/css/rules/css-standards.md +492 -0
- package/augment-extensions/coding-standards/html/README.md +40 -0
- package/augment-extensions/coding-standards/html/examples/html-examples.html +267 -0
- package/augment-extensions/coding-standards/html/examples/responsive-layout.html +505 -0
- package/augment-extensions/coding-standards/html/module.json +44 -0
- package/augment-extensions/coding-standards/html/rules/html-standards.md +349 -0
- package/augment-extensions/coding-standards/html-css-js/README.md +194 -0
- package/augment-extensions/coding-standards/html-css-js/examples/async-examples.js +487 -0
- package/augment-extensions/coding-standards/html-css-js/examples/css-examples.css +550 -0
- package/augment-extensions/coding-standards/html-css-js/examples/dom-examples.js +667 -0
- package/augment-extensions/coding-standards/html-css-js/examples/html-examples.html +267 -0
- package/augment-extensions/coding-standards/html-css-js/examples/javascript-examples.js +612 -0
- package/augment-extensions/coding-standards/html-css-js/examples/responsive-layout.html +505 -0
- package/augment-extensions/coding-standards/html-css-js/module.json +48 -0
- package/augment-extensions/coding-standards/html-css-js/rules/async-patterns.md +515 -0
- package/augment-extensions/coding-standards/html-css-js/rules/css-modern-features.md +448 -0
- package/augment-extensions/coding-standards/html-css-js/rules/css-standards.md +492 -0
- package/augment-extensions/coding-standards/html-css-js/rules/dom-manipulation.md +439 -0
- package/augment-extensions/coding-standards/html-css-js/rules/html-standards.md +349 -0
- package/augment-extensions/coding-standards/html-css-js/rules/javascript-standards.md +486 -0
- package/augment-extensions/coding-standards/html-css-js/rules/performance.md +463 -0
- package/augment-extensions/coding-standards/html-css-js/rules/tooling.md +543 -0
- package/augment-extensions/coding-standards/js/README.md +46 -0
- package/augment-extensions/coding-standards/js/examples/async-examples.js +487 -0
- package/augment-extensions/coding-standards/js/examples/dom-examples.js +667 -0
- package/augment-extensions/coding-standards/js/examples/javascript-examples.js +612 -0
- package/augment-extensions/coding-standards/js/module.json +49 -0
- package/augment-extensions/coding-standards/js/rules/async-patterns.md +515 -0
- package/augment-extensions/coding-standards/js/rules/dom-manipulation.md +439 -0
- package/augment-extensions/coding-standards/js/rules/javascript-standards.md +486 -0
- package/augment-extensions/coding-standards/js/rules/performance.md +463 -0
- package/augment-extensions/coding-standards/js/rules/tooling.md +543 -0
- package/augment-extensions/coding-standards/php/README.md +248 -0
- package/augment-extensions/coding-standards/php/examples/api-endpoint-example.php +204 -0
- package/augment-extensions/coding-standards/php/examples/cli-command-example.php +206 -0
- package/augment-extensions/coding-standards/php/examples/legacy-refactoring-example.php +234 -0
- package/augment-extensions/coding-standards/php/examples/web-application-example.php +211 -0
- package/augment-extensions/coding-standards/php/examples/woocommerce-extension-example.php +215 -0
- package/augment-extensions/coding-standards/php/examples/wordpress-plugin-example.php +189 -0
- package/augment-extensions/coding-standards/php/module.json +166 -0
- package/augment-extensions/coding-standards/php/rules/api-development.md +480 -0
- package/augment-extensions/coding-standards/php/rules/category-configuration.md +332 -0
- package/augment-extensions/coding-standards/php/rules/cli-tools.md +472 -0
- package/augment-extensions/coding-standards/php/rules/cms-integration.md +561 -0
- package/augment-extensions/coding-standards/php/rules/code-quality.md +402 -0
- package/augment-extensions/coding-standards/php/rules/documentation.md +425 -0
- package/augment-extensions/coding-standards/php/rules/ecommerce.md +627 -0
- package/augment-extensions/coding-standards/php/rules/error-handling.md +336 -0
- package/augment-extensions/coding-standards/php/rules/legacy-migration.md +677 -0
- package/augment-extensions/coding-standards/php/rules/naming-conventions.md +279 -0
- package/augment-extensions/coding-standards/php/rules/performance.md +392 -0
- package/augment-extensions/coding-standards/php/rules/psr-standards.md +186 -0
- package/augment-extensions/coding-standards/php/rules/security.md +358 -0
- package/augment-extensions/coding-standards/php/rules/testing.md +403 -0
- package/augment-extensions/coding-standards/php/rules/type-declarations.md +331 -0
- package/augment-extensions/coding-standards/php/rules/web-applications.md +426 -0
- package/augment-extensions/coding-standards/powershell/README.md +154 -0
- package/augment-extensions/coding-standards/powershell/examples/admin-example.ps1 +272 -0
- package/augment-extensions/coding-standards/powershell/examples/automation-example.ps1 +173 -0
- package/augment-extensions/coding-standards/powershell/examples/cloud-example.ps1 +243 -0
- package/augment-extensions/coding-standards/powershell/examples/cross-platform-example.ps1 +297 -0
- package/augment-extensions/coding-standards/powershell/examples/dsc-example.ps1 +224 -0
- package/augment-extensions/coding-standards/powershell/examples/legacy-migration-example.ps1 +340 -0
- package/augment-extensions/coding-standards/powershell/examples/module-example.psm1 +255 -0
- package/augment-extensions/coding-standards/powershell/module.json +165 -0
- package/augment-extensions/coding-standards/powershell/rules/administrative-tools.md +439 -0
- package/augment-extensions/coding-standards/powershell/rules/automation-scripts.md +240 -0
- package/augment-extensions/coding-standards/powershell/rules/cloud-orchestration.md +384 -0
- package/augment-extensions/coding-standards/powershell/rules/configuration-schema.md +383 -0
- package/augment-extensions/coding-standards/powershell/rules/cross-platform-scripts.md +482 -0
- package/augment-extensions/coding-standards/powershell/rules/dsc-configurations.md +296 -0
- package/augment-extensions/coding-standards/powershell/rules/error-handling.md +314 -0
- package/augment-extensions/coding-standards/powershell/rules/legacy-migrations.md +466 -0
- package/augment-extensions/coding-standards/powershell/rules/modules-functions.md +244 -0
- package/augment-extensions/coding-standards/powershell/rules/naming-conventions.md +266 -0
- package/augment-extensions/coding-standards/powershell/rules/performance-optimization.md +209 -0
- package/augment-extensions/coding-standards/powershell/rules/security-practices.md +314 -0
- package/augment-extensions/coding-standards/powershell/rules/testing-guidelines.md +268 -0
- package/augment-extensions/coding-standards/powershell/rules/universal-standards.md +197 -0
- package/augment-extensions/coding-standards/python/README.md +12 -8
- package/augment-extensions/coding-standards/python/examples/best-practices.py +373 -0
- package/augment-extensions/coding-standards/python/module.json +8 -4
- package/augment-extensions/coding-standards/python/rules/async-patterns.md +884 -0
- package/augment-extensions/coding-standards/python/rules/documentation.md +831 -0
- package/augment-extensions/coding-standards/python/rules/error-handling.md +855 -68
- package/augment-extensions/coding-standards/python/rules/testing.md +409 -0
- package/augment-extensions/coding-standards/python/rules/tooling.md +446 -0
- package/augment-extensions/coding-standards/python/rules/type-hints.md +115 -50
- package/augment-extensions/collections/html-css-js/README.md +82 -0
- package/augment-extensions/collections/html-css-js/collection.json +41 -0
- package/augment-extensions/domain-rules/database/README.md +161 -0
- package/augment-extensions/domain-rules/database/examples/flat-database-example.md +793 -0
- package/augment-extensions/domain-rules/database/examples/hybrid-database-example.md +1132 -0
- package/augment-extensions/domain-rules/database/examples/nosql-document-example.md +868 -0
- package/augment-extensions/domain-rules/database/examples/nosql-graph-example.md +805 -0
- package/augment-extensions/domain-rules/database/examples/relational-schema-example.md +621 -0
- package/augment-extensions/domain-rules/database/examples/vector-database-example.md +965 -0
- package/augment-extensions/domain-rules/database/module.json +28 -0
- package/augment-extensions/domain-rules/database/rules/flat-databases.md +624 -0
- package/augment-extensions/domain-rules/database/rules/nosql-databases.md +588 -0
- package/augment-extensions/domain-rules/database/rules/nosql-document-stores.md +856 -0
- package/augment-extensions/domain-rules/database/rules/nosql-graph-databases.md +778 -0
- package/augment-extensions/domain-rules/database/rules/nosql-key-value-stores.md +963 -0
- package/augment-extensions/domain-rules/database/rules/performance-optimization.md +1076 -0
- package/augment-extensions/domain-rules/database/rules/relational-databases.md +697 -0
- package/augment-extensions/domain-rules/database/rules/relational-indexing.md +671 -0
- package/augment-extensions/domain-rules/database/rules/relational-query-optimization.md +607 -0
- package/augment-extensions/domain-rules/database/rules/relational-schema-design.md +907 -0
- package/augment-extensions/domain-rules/database/rules/relational-transactions.md +783 -0
- package/augment-extensions/domain-rules/database/rules/security-standards.md +980 -0
- package/augment-extensions/domain-rules/database/rules/universal-best-practices.md +485 -0
- package/augment-extensions/domain-rules/database/rules/vector-databases.md +521 -0
- package/augment-extensions/domain-rules/database/rules/vector-embeddings.md +858 -0
- package/augment-extensions/domain-rules/database/rules/vector-indexing.md +934 -0
- package/augment-extensions/domain-rules/mcp/README.md +150 -0
- package/augment-extensions/domain-rules/mcp/examples/compressed-example.md +522 -0
- package/augment-extensions/domain-rules/mcp/examples/graph-augmented-example.md +520 -0
- package/augment-extensions/domain-rules/mcp/examples/hybrid-example.md +570 -0
- package/augment-extensions/domain-rules/mcp/examples/state-based-example.md +427 -0
- package/augment-extensions/domain-rules/mcp/examples/token-based-example.md +435 -0
- package/augment-extensions/domain-rules/mcp/examples/vector-based-example.md +502 -0
- package/augment-extensions/domain-rules/mcp/module.json +49 -0
- package/augment-extensions/domain-rules/mcp/rules/compressed-mcp.md +595 -0
- package/augment-extensions/domain-rules/mcp/rules/configuration.md +345 -0
- package/augment-extensions/domain-rules/mcp/rules/graph-augmented-mcp.md +687 -0
- package/augment-extensions/domain-rules/mcp/rules/hybrid-mcp.md +636 -0
- package/augment-extensions/domain-rules/mcp/rules/state-based-mcp.md +484 -0
- package/augment-extensions/domain-rules/mcp/rules/testing-validation.md +360 -0
- package/augment-extensions/domain-rules/mcp/rules/token-based-mcp.md +393 -0
- package/augment-extensions/domain-rules/mcp/rules/universal-rules.md +194 -0
- package/augment-extensions/domain-rules/mcp/rules/vector-based-mcp.md +625 -0
- package/augment-extensions/domain-rules/wordpress/README.md +163 -0
- package/augment-extensions/domain-rules/wordpress/module.json +32 -0
- package/augment-extensions/domain-rules/wordpress/rules/coding-standards.md +617 -0
- package/augment-extensions/domain-rules/wordpress/rules/directory-structure.md +270 -0
- package/augment-extensions/domain-rules/wordpress/rules/file-patterns.md +423 -0
- package/augment-extensions/domain-rules/wordpress/rules/gutenberg-blocks.md +493 -0
- package/augment-extensions/domain-rules/wordpress/rules/performance.md +568 -0
- package/augment-extensions/domain-rules/wordpress/rules/plugin-development.md +510 -0
- package/augment-extensions/domain-rules/wordpress/rules/project-detection.md +251 -0
- package/augment-extensions/domain-rules/wordpress/rules/rest-api.md +501 -0
- package/augment-extensions/domain-rules/wordpress/rules/security.md +564 -0
- package/augment-extensions/domain-rules/wordpress/rules/theme-development.md +388 -0
- package/augment-extensions/domain-rules/wordpress/rules/woocommerce.md +441 -0
- package/augment-extensions/domain-rules/wordpress-plugin/README.md +139 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/ajax-plugin.md +1599 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/custom-post-type-plugin.md +1727 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block-plugin.md +428 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/gutenberg-block.md +422 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/mvc-plugin.md +1623 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/object-oriented-plugin.md +1343 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/rest-endpoint.md +734 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/settings-page-plugin.md +1350 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/simple-procedural-plugin.md +503 -0
- package/augment-extensions/domain-rules/wordpress-plugin/examples/singleton-plugin.md +971 -0
- package/augment-extensions/domain-rules/wordpress-plugin/module.json +53 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/activation-hooks.md +770 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/admin-interface.md +874 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/ajax-handlers.md +629 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/asset-management.md +559 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/context-providers.md +709 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/cron-jobs.md +736 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/database-management.md +1057 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/documentation-standards.md +463 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/frontend-functionality.md +478 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/gutenberg-blocks.md +818 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/internationalization.md +416 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/migration.md +667 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/performance-optimization.md +878 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-architecture.md +693 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/plugin-structure.md +352 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/rest-api.md +818 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/scaffolding-workflow.md +624 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/security-best-practices.md +866 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/testing-patterns.md +1165 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/testing.md +414 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/vscode-integration.md +751 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/woocommerce-integration.md +949 -0
- package/augment-extensions/domain-rules/wordpress-plugin/rules/wordpress-org-submission.md +458 -0
- package/augment-extensions/examples/gutenberg-block-plugin/README.md +101 -0
- package/augment-extensions/examples/gutenberg-block-plugin/examples/testimonial-block.md +428 -0
- package/augment-extensions/examples/gutenberg-block-plugin/module.json +40 -0
- package/augment-extensions/examples/rest-api-plugin/README.md +98 -0
- package/augment-extensions/examples/rest-api-plugin/examples/task-manager-api.md +1299 -0
- package/augment-extensions/examples/rest-api-plugin/module.json +40 -0
- package/augment-extensions/examples/woocommerce-extension/README.md +98 -0
- package/augment-extensions/examples/woocommerce-extension/examples/product-customizer.md +763 -0
- package/augment-extensions/examples/woocommerce-extension/module.json +40 -0
- package/augment-extensions/workflows/beads/module.json +4 -3
- package/augment-extensions/workflows/database/README.md +195 -0
- package/augment-extensions/workflows/database/ai-prompt-testing.md +295 -0
- package/augment-extensions/workflows/database/examples/migration-example.md +498 -0
- package/augment-extensions/workflows/database/examples/optimization-example.md +496 -0
- package/augment-extensions/workflows/database/examples/schema-design-example.md +444 -0
- package/augment-extensions/workflows/database/module.json +42 -0
- package/augment-extensions/workflows/database/rules/data-migration.md +249 -0
- package/augment-extensions/workflows/database/rules/documentation-standards.md +339 -0
- package/augment-extensions/workflows/database/rules/migration-workflow.md +352 -0
- package/augment-extensions/workflows/database/rules/optimization-workflow.md +435 -0
- package/augment-extensions/workflows/database/rules/schema-design-workflow.md +535 -0
- package/augment-extensions/workflows/database/rules/testing-patterns.md +305 -0
- package/augment-extensions/workflows/database/rules/workflow.md +458 -0
- package/augment-extensions/workflows/openspec/module.json +4 -3
- package/augment-extensions/workflows/wordpress-plugin/README.md +232 -0
- package/augment-extensions/workflows/wordpress-plugin/ai-prompts.md +839 -0
- package/augment-extensions/workflows/wordpress-plugin/bead-decomposition-patterns.md +854 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/complete-plugin-example.md +540 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/custom-post-type-example.md +1083 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/feature-addition-workflow.md +669 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/plugin-creation-workflow.md +597 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/secure-form-handler-example.md +925 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/security-audit-workflow.md +752 -0
- package/augment-extensions/workflows/wordpress-plugin/examples/wordpress-org-submission-workflow.md +773 -0
- package/augment-extensions/workflows/wordpress-plugin/module.json +49 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/best-practices.md +942 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/development-workflow.md +702 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/submission-workflow.md +728 -0
- package/augment-extensions/workflows/wordpress-plugin/rules/testing-workflow.md +775 -0
- package/augment-extensions/writing-standards/screenplay/README.md +171 -0
- package/augment-extensions/writing-standards/screenplay/examples/aaa-hollywood-scene.fountain +164 -0
- package/augment-extensions/writing-standards/screenplay/module.json +124 -0
- package/augment-extensions/writing-standards/screenplay/rules/universal-formatting.md +339 -0
- package/cli/MODULES.md +302 -0
- package/cli/dist/cli.js +142 -9
- package/cli/dist/cli.js.map +1 -1
- package/cli/dist/commands/catalog.d.ts +13 -0
- package/cli/dist/commands/catalog.d.ts.map +1 -0
- package/cli/dist/commands/catalog.js +104 -0
- package/cli/dist/commands/catalog.js.map +1 -0
- package/cli/dist/commands/gui.d.ts +6 -0
- package/cli/dist/commands/gui.d.ts.map +1 -0
- package/cli/dist/commands/gui.js +211 -0
- package/cli/dist/commands/gui.js.map +1 -0
- package/cli/dist/commands/init.d.ts.map +1 -1
- package/cli/dist/commands/init.js +12 -0
- package/cli/dist/commands/init.js.map +1 -1
- package/cli/dist/commands/install-rules.d.ts +14 -0
- package/cli/dist/commands/install-rules.d.ts.map +1 -0
- package/cli/dist/commands/install-rules.js +127 -0
- package/cli/dist/commands/install-rules.js.map +1 -0
- package/cli/dist/commands/link.d.ts.map +1 -1
- package/cli/dist/commands/link.js +9 -11
- package/cli/dist/commands/link.js.map +1 -1
- package/cli/dist/commands/list.d.ts.map +1 -1
- package/cli/dist/commands/list.js +11 -28
- package/cli/dist/commands/list.js.map +1 -1
- package/cli/dist/commands/mcp.d.ts +48 -0
- package/cli/dist/commands/mcp.d.ts.map +1 -0
- package/cli/dist/commands/mcp.js +229 -0
- package/cli/dist/commands/mcp.js.map +1 -0
- package/cli/dist/commands/self-remove.d.ts +7 -0
- package/cli/dist/commands/self-remove.d.ts.map +1 -0
- package/cli/dist/commands/self-remove.js +179 -0
- package/cli/dist/commands/self-remove.js.map +1 -0
- package/cli/dist/commands/show.d.ts.map +1 -1
- package/cli/dist/commands/show.js +42 -71
- package/cli/dist/commands/show.js.map +1 -1
- package/cli/dist/commands/skill.d.ts +67 -0
- package/cli/dist/commands/skill.d.ts.map +1 -0
- package/cli/dist/commands/skill.js +513 -0
- package/cli/dist/commands/skill.js.map +1 -0
- package/cli/dist/commands/unlink.d.ts +6 -0
- package/cli/dist/commands/unlink.d.ts.map +1 -0
- package/cli/dist/commands/unlink.js +115 -0
- package/cli/dist/commands/unlink.js.map +1 -0
- package/cli/dist/commands/validate.d.ts +6 -0
- package/cli/dist/commands/validate.d.ts.map +1 -0
- package/cli/dist/commands/validate.js +159 -0
- package/cli/dist/commands/validate.js.map +1 -0
- package/cli/dist/utils/catalog-sync.d.ts +22 -0
- package/cli/dist/utils/catalog-sync.d.ts.map +1 -0
- package/cli/dist/utils/catalog-sync.js +157 -0
- package/cli/dist/utils/catalog-sync.js.map +1 -0
- package/cli/dist/utils/character-count.d.ts +56 -0
- package/cli/dist/utils/character-count.d.ts.map +1 -0
- package/cli/dist/utils/character-count.js +190 -0
- package/cli/dist/utils/character-count.js.map +1 -0
- package/cli/dist/utils/documentation-validator.d.ts +18 -0
- package/cli/dist/utils/documentation-validator.d.ts.map +1 -0
- package/cli/dist/utils/documentation-validator.js +233 -0
- package/cli/dist/utils/documentation-validator.js.map +1 -0
- package/cli/dist/utils/install-rules.d.ts +32 -0
- package/cli/dist/utils/install-rules.d.ts.map +1 -0
- package/cli/dist/utils/install-rules.js +375 -0
- package/cli/dist/utils/install-rules.js.map +1 -0
- package/cli/dist/utils/mcp-integration.d.ts +70 -0
- package/cli/dist/utils/mcp-integration.d.ts.map +1 -0
- package/cli/dist/utils/mcp-integration.js +292 -0
- package/cli/dist/utils/mcp-integration.js.map +1 -0
- package/cli/dist/utils/module-system.d.ts +153 -0
- package/cli/dist/utils/module-system.d.ts.map +1 -0
- package/cli/dist/utils/module-system.js +528 -0
- package/cli/dist/utils/module-system.js.map +1 -0
- package/cli/dist/utils/modules-catalog.d.ts +33 -0
- package/cli/dist/utils/modules-catalog.d.ts.map +1 -0
- package/cli/dist/utils/modules-catalog.js +163 -0
- package/cli/dist/utils/modules-catalog.js.map +1 -0
- package/cli/dist/utils/rule-install-hooks.d.ts +19 -0
- package/cli/dist/utils/rule-install-hooks.d.ts.map +1 -0
- package/cli/dist/utils/rule-install-hooks.js +224 -0
- package/cli/dist/utils/rule-install-hooks.js.map +1 -0
- package/cli/dist/utils/skill-system.d.ts +95 -0
- package/cli/dist/utils/skill-system.d.ts.map +1 -0
- package/cli/dist/utils/skill-system.js +313 -0
- package/cli/dist/utils/skill-system.js.map +1 -0
- package/modules.md +534 -70
- package/package.json +12 -3
|
@@ -0,0 +1,868 @@
|
|
|
1
|
+
# NoSQL Document Store Example: Blog Application
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This example demonstrates a complete blog application using MongoDB as a document store. It covers schema design decisions (embedding vs referencing), aggregation pipelines, indexing strategies, and common query patterns.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Application Requirements
|
|
10
|
+
|
|
11
|
+
**Features:**
|
|
12
|
+
- Users can create accounts
|
|
13
|
+
- Users can write blog posts
|
|
14
|
+
- Users can comment on posts
|
|
15
|
+
- Users can like posts and comments
|
|
16
|
+
- Posts can have tags
|
|
17
|
+
- Users can follow other users
|
|
18
|
+
|
|
19
|
+
**Query Patterns:**
|
|
20
|
+
- Find all posts by a user
|
|
21
|
+
- Find recent posts with author info
|
|
22
|
+
- Find posts by tag
|
|
23
|
+
- Find comments for a post
|
|
24
|
+
- Find user's feed (posts from followed users)
|
|
25
|
+
- Count likes on posts
|
|
26
|
+
- Find popular posts (most likes/comments)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Schema Design
|
|
31
|
+
|
|
32
|
+
### Collections
|
|
33
|
+
|
|
34
|
+
**users** - User accounts
|
|
35
|
+
**posts** - Blog posts
|
|
36
|
+
**comments** - Comments on posts
|
|
37
|
+
**tags** - Post tags
|
|
38
|
+
|
|
39
|
+
### Design Decisions
|
|
40
|
+
|
|
41
|
+
#### Decision 1: User Profile (Embedding)
|
|
42
|
+
|
|
43
|
+
**Embed profile data in user document:**
|
|
44
|
+
|
|
45
|
+
```javascript
|
|
46
|
+
// ✅ GOOD: Embed profile (one-to-one, always accessed together)
|
|
47
|
+
{
|
|
48
|
+
"_id": ObjectId("507f1f77bcf86cd799439011"),
|
|
49
|
+
"username": "alice_dev",
|
|
50
|
+
"email": "alice@example.com",
|
|
51
|
+
"password_hash": "$2b$10$...",
|
|
52
|
+
"profile": {
|
|
53
|
+
"full_name": "Alice Johnson",
|
|
54
|
+
"bio": "Full-stack developer passionate about web technologies",
|
|
55
|
+
"avatar_url": "https://cdn.example.com/avatars/alice.jpg",
|
|
56
|
+
"location": "San Francisco, CA",
|
|
57
|
+
"website": "https://alice.dev"
|
|
58
|
+
},
|
|
59
|
+
"stats": {
|
|
60
|
+
"post_count": 42,
|
|
61
|
+
"follower_count": 156,
|
|
62
|
+
"following_count": 89
|
|
63
|
+
},
|
|
64
|
+
"created_at": ISODate("2024-01-15T10:00:00Z"),
|
|
65
|
+
"updated_at": ISODate("2024-01-20T14:30:00Z")
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Why embed?**
|
|
70
|
+
- ✅ Profile is always accessed with user data
|
|
71
|
+
- ✅ One-to-one relationship
|
|
72
|
+
- ✅ Profile data doesn't change frequently
|
|
73
|
+
- ✅ Single query to get complete user info
|
|
74
|
+
|
|
75
|
+
#### Decision 2: Blog Posts (Separate Collection)
|
|
76
|
+
|
|
77
|
+
**Store posts in separate collection with user reference:**
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
// ✅ GOOD: Separate collection (one-to-many, accessed independently)
|
|
81
|
+
{
|
|
82
|
+
"_id": ObjectId("507f191e810c19729de860ea"),
|
|
83
|
+
"author_id": ObjectId("507f1f77bcf86cd799439011"),
|
|
84
|
+
"title": "Getting Started with MongoDB",
|
|
85
|
+
"slug": "getting-started-with-mongodb",
|
|
86
|
+
"content": "MongoDB is a document database that provides...",
|
|
87
|
+
"excerpt": "Learn the basics of MongoDB document modeling...",
|
|
88
|
+
"status": "published", // draft, published, archived
|
|
89
|
+
"tags": ["mongodb", "database", "nosql"], // Embedded array (one-to-few)
|
|
90
|
+
"metadata": {
|
|
91
|
+
"read_time_minutes": 5,
|
|
92
|
+
"word_count": 1200,
|
|
93
|
+
"featured_image": "https://cdn.example.com/images/mongodb-intro.jpg"
|
|
94
|
+
},
|
|
95
|
+
"stats": {
|
|
96
|
+
"view_count": 1523,
|
|
97
|
+
"like_count": 87,
|
|
98
|
+
"comment_count": 12
|
|
99
|
+
},
|
|
100
|
+
"published_at": ISODate("2024-01-18T09:00:00Z"),
|
|
101
|
+
"created_at": ISODate("2024-01-15T14:00:00Z"),
|
|
102
|
+
"updated_at": ISODate("2024-01-18T09:00:00Z")
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Why separate collection?**
|
|
107
|
+
- ✅ One-to-many relationship (user has many posts)
|
|
108
|
+
- ✅ Posts are accessed independently
|
|
109
|
+
- ✅ Posts can be queried without user data
|
|
110
|
+
- ✅ Avoids unbounded array growth in user document
|
|
111
|
+
|
|
112
|
+
**Why embed tags?**
|
|
113
|
+
- ✅ One-to-few relationship (< 20 tags per post)
|
|
114
|
+
- ✅ Tags are always displayed with post
|
|
115
|
+
- ✅ Simple array, no complex queries needed
|
|
116
|
+
|
|
117
|
+
#### Decision 3: Comments (Separate Collection with Hybrid Approach)
|
|
118
|
+
|
|
119
|
+
**Store comments separately but embed author display info:**
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
// ✅ GOOD: Hybrid approach (reference + embedded display data)
|
|
123
|
+
{
|
|
124
|
+
"_id": ObjectId("507f191e810c19729de860eb"),
|
|
125
|
+
"post_id": ObjectId("507f191e810c19729de860ea"),
|
|
126
|
+
"author_id": ObjectId("507f1f77bcf86cd799439011"),
|
|
127
|
+
"author_display": { // Embedded for fast display
|
|
128
|
+
"username": "alice_dev",
|
|
129
|
+
"avatar_url": "https://cdn.example.com/avatars/alice.jpg"
|
|
130
|
+
},
|
|
131
|
+
"content": "Great article! Very helpful for beginners.",
|
|
132
|
+
"parent_comment_id": null, // For nested replies
|
|
133
|
+
"stats": {
|
|
134
|
+
"like_count": 5
|
|
135
|
+
},
|
|
136
|
+
"created_at": ISODate("2024-01-18T10:30:00Z"),
|
|
137
|
+
"updated_at": ISODate("2024-01-18T10:30:00Z")
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Why separate collection?**
|
|
142
|
+
- ✅ One-to-many relationship (post has many comments)
|
|
143
|
+
- ✅ Unbounded growth (posts can have hundreds of comments)
|
|
144
|
+
- ✅ Comments can be paginated
|
|
145
|
+
- ✅ Avoids 16MB document size limit
|
|
146
|
+
|
|
147
|
+
**Why embed author display data?**
|
|
148
|
+
- ✅ Fast display without JOIN
|
|
149
|
+
- ✅ Display data rarely changes
|
|
150
|
+
- ✅ Small data footprint
|
|
151
|
+
- ✅ Can update if needed (eventual consistency acceptable)
|
|
152
|
+
|
|
153
|
+
#### Decision 4: Likes (Embedded Array with Limit)
|
|
154
|
+
|
|
155
|
+
**Embed recent likes, reference for full list:**
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
// In posts collection
|
|
159
|
+
{
|
|
160
|
+
"_id": ObjectId("507f191e810c19729de860ea"),
|
|
161
|
+
"title": "Getting Started with MongoDB",
|
|
162
|
+
// ... other fields ...
|
|
163
|
+
"stats": {
|
|
164
|
+
"like_count": 87 // Total count
|
|
165
|
+
},
|
|
166
|
+
"recent_likes": [ // Last 10 likes for quick display
|
|
167
|
+
{
|
|
168
|
+
"user_id": ObjectId("507f1f77bcf86cd799439012"),
|
|
169
|
+
"username": "bob_smith",
|
|
170
|
+
"liked_at": ISODate("2024-01-20T15:00:00Z")
|
|
171
|
+
},
|
|
172
|
+
// ... up to 10 recent likes
|
|
173
|
+
]
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Separate likes collection for full history
|
|
177
|
+
{
|
|
178
|
+
"_id": ObjectId("507f191e810c19729de860ec"),
|
|
179
|
+
"post_id": ObjectId("507f191e810c19729de860ea"),
|
|
180
|
+
"user_id": ObjectId("507f1f77bcf86cd799439012"),
|
|
181
|
+
"created_at": ISODate("2024-01-20T15:00:00Z")
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Why hybrid approach?**
|
|
186
|
+
- ✅ Fast display of recent likes (embedded)
|
|
187
|
+
- ✅ Full history available (separate collection)
|
|
188
|
+
- ✅ Bounded array size (max 10 items)
|
|
189
|
+
- ✅ Efficient counting (stats.like_count)
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Indexing Strategy
|
|
194
|
+
|
|
195
|
+
### users Collection
|
|
196
|
+
|
|
197
|
+
```javascript
|
|
198
|
+
// Unique index on email (for login)
|
|
199
|
+
db.users.createIndex({ "email": 1 }, { unique: true })
|
|
200
|
+
|
|
201
|
+
// Unique index on username (for profile URLs)
|
|
202
|
+
db.users.createIndex({ "username": 1 }, { unique: true })
|
|
203
|
+
|
|
204
|
+
// Index on created_at (for sorting new users)
|
|
205
|
+
db.users.createIndex({ "created_at": -1 })
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### posts Collection
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
// Compound index for user's posts (sorted by date)
|
|
212
|
+
db.posts.createIndex({ "author_id": 1, "published_at": -1 })
|
|
213
|
+
|
|
214
|
+
// Index on slug (for URL lookups)
|
|
215
|
+
db.posts.createIndex({ "slug": 1 }, { unique: true })
|
|
216
|
+
|
|
217
|
+
// Index on tags (for tag-based queries)
|
|
218
|
+
db.posts.createIndex({ "tags": 1 })
|
|
219
|
+
|
|
220
|
+
// Index on status and published_at (for published posts feed)
|
|
221
|
+
db.posts.createIndex({ "status": 1, "published_at": -1 })
|
|
222
|
+
|
|
223
|
+
// Text index for full-text search
|
|
224
|
+
db.posts.createIndex({
|
|
225
|
+
"title": "text",
|
|
226
|
+
"content": "text",
|
|
227
|
+
"excerpt": "text"
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### comments Collection
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
// Compound index for post's comments (sorted by date)
|
|
235
|
+
db.comments.createIndex({ "post_id": 1, "created_at": 1 })
|
|
236
|
+
|
|
237
|
+
// Index on author_id (for user's comments)
|
|
238
|
+
db.comments.createIndex({ "author_id": 1, "created_at": -1 })
|
|
239
|
+
|
|
240
|
+
// Index on parent_comment_id (for nested replies)
|
|
241
|
+
db.comments.createIndex({ "parent_comment_id": 1 })
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### likes Collection
|
|
245
|
+
|
|
246
|
+
```javascript
|
|
247
|
+
// Compound unique index (prevent duplicate likes)
|
|
248
|
+
db.likes.createIndex({ "post_id": 1, "user_id": 1 }, { unique: true })
|
|
249
|
+
|
|
250
|
+
// Index on user_id (for user's liked posts)
|
|
251
|
+
db.likes.createIndex({ "user_id": 1, "created_at": -1 })
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Common Queries
|
|
257
|
+
|
|
258
|
+
### Query 1: Find All Posts by User
|
|
259
|
+
|
|
260
|
+
```javascript
|
|
261
|
+
// Simple query using author_id index
|
|
262
|
+
db.posts.find({
|
|
263
|
+
author_id: ObjectId("507f1f77bcf86cd799439011"),
|
|
264
|
+
status: "published"
|
|
265
|
+
})
|
|
266
|
+
.sort({ published_at: -1 })
|
|
267
|
+
.limit(20)
|
|
268
|
+
|
|
269
|
+
// With author info (using aggregation)
|
|
270
|
+
db.posts.aggregate([
|
|
271
|
+
{
|
|
272
|
+
$match: {
|
|
273
|
+
author_id: ObjectId("507f1f77bcf86cd799439011"),
|
|
274
|
+
status: "published"
|
|
275
|
+
}
|
|
276
|
+
},
|
|
277
|
+
{ $sort: { published_at: -1 } },
|
|
278
|
+
{ $limit: 20 },
|
|
279
|
+
{
|
|
280
|
+
$lookup: {
|
|
281
|
+
from: "users",
|
|
282
|
+
localField: "author_id",
|
|
283
|
+
foreignField: "_id",
|
|
284
|
+
as: "author"
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
{ $unwind: "$author" },
|
|
288
|
+
{
|
|
289
|
+
$project: {
|
|
290
|
+
title: 1,
|
|
291
|
+
slug: 1,
|
|
292
|
+
excerpt: 1,
|
|
293
|
+
tags: 1,
|
|
294
|
+
stats: 1,
|
|
295
|
+
published_at: 1,
|
|
296
|
+
"author.username": 1,
|
|
297
|
+
"author.profile.full_name": 1,
|
|
298
|
+
"author.profile.avatar_url": 1
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
])
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Query 2: Find Recent Posts with Author Info
|
|
305
|
+
|
|
306
|
+
```javascript
|
|
307
|
+
db.posts.aggregate([
|
|
308
|
+
{ $match: { status: "published" } },
|
|
309
|
+
{ $sort: { published_at: -1 } },
|
|
310
|
+
{ $limit: 20 },
|
|
311
|
+
{
|
|
312
|
+
$lookup: {
|
|
313
|
+
from: "users",
|
|
314
|
+
localField: "author_id",
|
|
315
|
+
foreignField: "_id",
|
|
316
|
+
as: "author"
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
{ $unwind: "$author" },
|
|
320
|
+
{
|
|
321
|
+
$project: {
|
|
322
|
+
title: 1,
|
|
323
|
+
slug: 1,
|
|
324
|
+
excerpt: 1,
|
|
325
|
+
tags: 1,
|
|
326
|
+
stats: 1,
|
|
327
|
+
published_at: 1,
|
|
328
|
+
"author.username": 1,
|
|
329
|
+
"author.profile.full_name": 1,
|
|
330
|
+
"author.profile.avatar_url": 1
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
])
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Query 3: Find Posts by Tag
|
|
337
|
+
|
|
338
|
+
```javascript
|
|
339
|
+
// Using tags index
|
|
340
|
+
db.posts.find({
|
|
341
|
+
tags: "mongodb",
|
|
342
|
+
status: "published"
|
|
343
|
+
})
|
|
344
|
+
.sort({ published_at: -1 })
|
|
345
|
+
.limit(20)
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Query 4: Find Comments for Post
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
// Using post_id index
|
|
352
|
+
db.comments.find({
|
|
353
|
+
post_id: ObjectId("507f191e810c19729de860ea")
|
|
354
|
+
})
|
|
355
|
+
.sort({ created_at: 1 })
|
|
356
|
+
.limit(50)
|
|
357
|
+
|
|
358
|
+
// With nested replies
|
|
359
|
+
db.comments.aggregate([
|
|
360
|
+
{
|
|
361
|
+
$match: {
|
|
362
|
+
post_id: ObjectId("507f191e810c19729de860ea"),
|
|
363
|
+
parent_comment_id: null // Top-level comments only
|
|
364
|
+
}
|
|
365
|
+
},
|
|
366
|
+
{ $sort: { created_at: 1 } },
|
|
367
|
+
{
|
|
368
|
+
$lookup: {
|
|
369
|
+
from: "comments",
|
|
370
|
+
localField: "_id",
|
|
371
|
+
foreignField: "parent_comment_id",
|
|
372
|
+
as: "replies"
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
$project: {
|
|
377
|
+
content: 1,
|
|
378
|
+
author_display: 1,
|
|
379
|
+
stats: 1,
|
|
380
|
+
created_at: 1,
|
|
381
|
+
replies: {
|
|
382
|
+
$slice: ["$replies", 5] // Limit replies to 5
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
])
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Query 5: User's Feed (Posts from Followed Users)
|
|
390
|
+
|
|
391
|
+
```javascript
|
|
392
|
+
// Assuming follows collection: { follower_id, following_id }
|
|
393
|
+
|
|
394
|
+
// Step 1: Get followed user IDs
|
|
395
|
+
const followedUsers = db.follows.find({
|
|
396
|
+
follower_id: ObjectId("507f1f77bcf86cd799439011")
|
|
397
|
+
}).map(f => f.following_id)
|
|
398
|
+
|
|
399
|
+
// Step 2: Get posts from followed users
|
|
400
|
+
db.posts.find({
|
|
401
|
+
author_id: { $in: followedUsers },
|
|
402
|
+
status: "published"
|
|
403
|
+
})
|
|
404
|
+
.sort({ published_at: -1 })
|
|
405
|
+
.limit(50)
|
|
406
|
+
|
|
407
|
+
// Combined aggregation
|
|
408
|
+
db.follows.aggregate([
|
|
409
|
+
{
|
|
410
|
+
$match: {
|
|
411
|
+
follower_id: ObjectId("507f1f77bcf86cd799439011")
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
$lookup: {
|
|
416
|
+
from: "posts",
|
|
417
|
+
localField: "following_id",
|
|
418
|
+
foreignField: "author_id",
|
|
419
|
+
as: "posts"
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
{ $unwind: "$posts" },
|
|
423
|
+
{ $match: { "posts.status": "published" } },
|
|
424
|
+
{ $replaceRoot: { newRoot: "$posts" } },
|
|
425
|
+
{ $sort: { published_at: -1 } },
|
|
426
|
+
{ $limit: 50 }
|
|
427
|
+
])
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### Query 6: Popular Posts (Most Likes/Comments)
|
|
431
|
+
|
|
432
|
+
```javascript
|
|
433
|
+
// Most liked posts in last 7 days
|
|
434
|
+
db.posts.find({
|
|
435
|
+
status: "published",
|
|
436
|
+
published_at: {
|
|
437
|
+
$gte: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
|
|
438
|
+
}
|
|
439
|
+
})
|
|
440
|
+
.sort({ "stats.like_count": -1 })
|
|
441
|
+
.limit(10)
|
|
442
|
+
|
|
443
|
+
// Most commented posts
|
|
444
|
+
db.posts.find({
|
|
445
|
+
status: "published"
|
|
446
|
+
})
|
|
447
|
+
.sort({ "stats.comment_count": -1 })
|
|
448
|
+
.limit(10)
|
|
449
|
+
|
|
450
|
+
// Combined score (likes + comments)
|
|
451
|
+
db.posts.aggregate([
|
|
452
|
+
{ $match: { status: "published" } },
|
|
453
|
+
{
|
|
454
|
+
$addFields: {
|
|
455
|
+
popularity_score: {
|
|
456
|
+
$add: ["$stats.like_count", { $multiply: ["$stats.comment_count", 2] }]
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
{ $sort: { popularity_score: -1 } },
|
|
461
|
+
{ $limit: 10 }
|
|
462
|
+
])
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Query 7: Full-Text Search
|
|
466
|
+
|
|
467
|
+
```javascript
|
|
468
|
+
// Search posts by text
|
|
469
|
+
db.posts.find({
|
|
470
|
+
$text: { $search: "mongodb database tutorial" },
|
|
471
|
+
status: "published"
|
|
472
|
+
})
|
|
473
|
+
.sort({ score: { $meta: "textScore" } })
|
|
474
|
+
.limit(20)
|
|
475
|
+
|
|
476
|
+
// With text score
|
|
477
|
+
db.posts.find({
|
|
478
|
+
$text: { $search: "mongodb database tutorial" },
|
|
479
|
+
status: "published"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
score: { $meta: "textScore" }
|
|
483
|
+
})
|
|
484
|
+
.sort({ score: { $meta: "textScore" } })
|
|
485
|
+
.limit(20)
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
---
|
|
489
|
+
|
|
490
|
+
## Aggregation Pipeline Examples
|
|
491
|
+
|
|
492
|
+
### Example 1: User Statistics
|
|
493
|
+
|
|
494
|
+
```javascript
|
|
495
|
+
// Calculate user statistics
|
|
496
|
+
db.posts.aggregate([
|
|
497
|
+
{
|
|
498
|
+
$match: {
|
|
499
|
+
author_id: ObjectId("507f1f77bcf86cd799439011"),
|
|
500
|
+
status: "published"
|
|
501
|
+
}
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
$group: {
|
|
505
|
+
_id: "$author_id",
|
|
506
|
+
total_posts: { $sum: 1 },
|
|
507
|
+
total_views: { $sum: "$stats.view_count" },
|
|
508
|
+
total_likes: { $sum: "$stats.like_count" },
|
|
509
|
+
total_comments: { $sum: "$stats.comment_count" },
|
|
510
|
+
avg_likes_per_post: { $avg: "$stats.like_count" },
|
|
511
|
+
most_popular_post: { $max: "$stats.view_count" }
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
])
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Example 2: Tag Popularity
|
|
518
|
+
|
|
519
|
+
```javascript
|
|
520
|
+
// Find most popular tags
|
|
521
|
+
db.posts.aggregate([
|
|
522
|
+
{ $match: { status: "published" } },
|
|
523
|
+
{ $unwind: "$tags" },
|
|
524
|
+
{
|
|
525
|
+
$group: {
|
|
526
|
+
_id: "$tags",
|
|
527
|
+
post_count: { $sum: 1 },
|
|
528
|
+
total_likes: { $sum: "$stats.like_count" }
|
|
529
|
+
}
|
|
530
|
+
},
|
|
531
|
+
{ $sort: { post_count: -1 } },
|
|
532
|
+
{ $limit: 20 }
|
|
533
|
+
])
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Example 3: Monthly Post Count
|
|
537
|
+
|
|
538
|
+
```javascript
|
|
539
|
+
// Posts per month
|
|
540
|
+
db.posts.aggregate([
|
|
541
|
+
{ $match: { status: "published" } },
|
|
542
|
+
{
|
|
543
|
+
$group: {
|
|
544
|
+
_id: {
|
|
545
|
+
year: { $year: "$published_at" },
|
|
546
|
+
month: { $month: "$published_at" }
|
|
547
|
+
},
|
|
548
|
+
count: { $sum: 1 }
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
{ $sort: { "_id.year": -1, "_id.month": -1 } }
|
|
552
|
+
])
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Example 4: Top Authors by Engagement
|
|
556
|
+
|
|
557
|
+
```javascript
|
|
558
|
+
// Find authors with highest engagement
|
|
559
|
+
db.posts.aggregate([
|
|
560
|
+
{ $match: { status: "published" } },
|
|
561
|
+
{
|
|
562
|
+
$group: {
|
|
563
|
+
_id: "$author_id",
|
|
564
|
+
post_count: { $sum: 1 },
|
|
565
|
+
total_likes: { $sum: "$stats.like_count" },
|
|
566
|
+
total_comments: { $sum: "$stats.comment_count" },
|
|
567
|
+
total_views: { $sum: "$stats.view_count" }
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
$addFields: {
|
|
572
|
+
engagement_score: {
|
|
573
|
+
$add: [
|
|
574
|
+
"$total_likes",
|
|
575
|
+
{ $multiply: ["$total_comments", 2] },
|
|
576
|
+
{ $divide: ["$total_views", 10] }
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
},
|
|
581
|
+
{ $sort: { engagement_score: -1 } },
|
|
582
|
+
{ $limit: 10 },
|
|
583
|
+
{
|
|
584
|
+
$lookup: {
|
|
585
|
+
from: "users",
|
|
586
|
+
localField: "_id",
|
|
587
|
+
foreignField: "_id",
|
|
588
|
+
as: "author"
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
{ $unwind: "$author" },
|
|
592
|
+
{
|
|
593
|
+
$project: {
|
|
594
|
+
"author.username": 1,
|
|
595
|
+
"author.profile.full_name": 1,
|
|
596
|
+
post_count: 1,
|
|
597
|
+
total_likes: 1,
|
|
598
|
+
total_comments: 1,
|
|
599
|
+
total_views: 1,
|
|
600
|
+
engagement_score: 1
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
])
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## Update Operations
|
|
609
|
+
|
|
610
|
+
### Update Post Stats (Increment Like Count)
|
|
611
|
+
|
|
612
|
+
```javascript
|
|
613
|
+
// Increment like count
|
|
614
|
+
db.posts.updateOne(
|
|
615
|
+
{ _id: ObjectId("507f191e810c19729de860ea") },
|
|
616
|
+
{
|
|
617
|
+
$inc: { "stats.like_count": 1 },
|
|
618
|
+
$set: { updated_at: new Date() }
|
|
619
|
+
}
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
// Add to recent_likes array (keep last 10)
|
|
623
|
+
db.posts.updateOne(
|
|
624
|
+
{ _id: ObjectId("507f191e810c19729de860ea") },
|
|
625
|
+
{
|
|
626
|
+
$push: {
|
|
627
|
+
recent_likes: {
|
|
628
|
+
$each: [{
|
|
629
|
+
user_id: ObjectId("507f1f77bcf86cd799439012"),
|
|
630
|
+
username: "bob_smith",
|
|
631
|
+
liked_at: new Date()
|
|
632
|
+
}],
|
|
633
|
+
$position: 0,
|
|
634
|
+
$slice: 10
|
|
635
|
+
}
|
|
636
|
+
},
|
|
637
|
+
$inc: { "stats.like_count": 1 }
|
|
638
|
+
}
|
|
639
|
+
)
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### Update Comment Count
|
|
643
|
+
|
|
644
|
+
```javascript
|
|
645
|
+
// Increment comment count when comment is added
|
|
646
|
+
db.posts.updateOne(
|
|
647
|
+
{ _id: ObjectId("507f191e810c19729de860ea") },
|
|
648
|
+
{
|
|
649
|
+
$inc: { "stats.comment_count": 1 },
|
|
650
|
+
$set: { updated_at: new Date() }
|
|
651
|
+
}
|
|
652
|
+
)
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
### Update User Stats
|
|
656
|
+
|
|
657
|
+
```javascript
|
|
658
|
+
// Increment post count when post is published
|
|
659
|
+
db.users.updateOne(
|
|
660
|
+
{ _id: ObjectId("507f1f77bcf86cd799439011") },
|
|
661
|
+
{
|
|
662
|
+
$inc: { "stats.post_count": 1 },
|
|
663
|
+
$set: { updated_at: new Date() }
|
|
664
|
+
}
|
|
665
|
+
)
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
### Update Author Display Info (Eventual Consistency)
|
|
669
|
+
|
|
670
|
+
```javascript
|
|
671
|
+
// When user changes username/avatar, update all comments
|
|
672
|
+
db.comments.updateMany(
|
|
673
|
+
{ author_id: ObjectId("507f1f77bcf86cd799439011") },
|
|
674
|
+
{
|
|
675
|
+
$set: {
|
|
676
|
+
"author_display.username": "alice_developer",
|
|
677
|
+
"author_display.avatar_url": "https://cdn.example.com/avatars/alice-new.jpg"
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
)
|
|
681
|
+
```
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## Schema Validation
|
|
686
|
+
|
|
687
|
+
### users Collection Validation
|
|
688
|
+
|
|
689
|
+
```javascript
|
|
690
|
+
db.createCollection("users", {
|
|
691
|
+
validator: {
|
|
692
|
+
$jsonSchema: {
|
|
693
|
+
bsonType: "object",
|
|
694
|
+
required: ["username", "email", "password_hash", "created_at"],
|
|
695
|
+
properties: {
|
|
696
|
+
username: {
|
|
697
|
+
bsonType: "string",
|
|
698
|
+
minLength: 3,
|
|
699
|
+
maxLength: 30,
|
|
700
|
+
pattern: "^[a-zA-Z0-9_]+$",
|
|
701
|
+
description: "Username must be 3-30 alphanumeric characters"
|
|
702
|
+
},
|
|
703
|
+
email: {
|
|
704
|
+
bsonType: "string",
|
|
705
|
+
pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
|
706
|
+
description: "Must be a valid email address"
|
|
707
|
+
},
|
|
708
|
+
password_hash: {
|
|
709
|
+
bsonType: "string",
|
|
710
|
+
description: "Hashed password"
|
|
711
|
+
},
|
|
712
|
+
profile: {
|
|
713
|
+
bsonType: "object",
|
|
714
|
+
properties: {
|
|
715
|
+
full_name: { bsonType: "string" },
|
|
716
|
+
bio: { bsonType: "string", maxLength: 500 },
|
|
717
|
+
avatar_url: { bsonType: "string" },
|
|
718
|
+
location: { bsonType: "string" },
|
|
719
|
+
website: { bsonType: "string" }
|
|
720
|
+
}
|
|
721
|
+
},
|
|
722
|
+
stats: {
|
|
723
|
+
bsonType: "object",
|
|
724
|
+
properties: {
|
|
725
|
+
post_count: { bsonType: "int", minimum: 0 },
|
|
726
|
+
follower_count: { bsonType: "int", minimum: 0 },
|
|
727
|
+
following_count: { bsonType: "int", minimum: 0 }
|
|
728
|
+
}
|
|
729
|
+
},
|
|
730
|
+
created_at: { bsonType: "date" },
|
|
731
|
+
updated_at: { bsonType: "date" }
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
})
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### posts Collection Validation
|
|
739
|
+
|
|
740
|
+
```javascript
|
|
741
|
+
db.createCollection("posts", {
|
|
742
|
+
validator: {
|
|
743
|
+
$jsonSchema: {
|
|
744
|
+
bsonType: "object",
|
|
745
|
+
required: ["author_id", "title", "slug", "content", "status", "created_at"],
|
|
746
|
+
properties: {
|
|
747
|
+
author_id: { bsonType: "objectId" },
|
|
748
|
+
title: {
|
|
749
|
+
bsonType: "string",
|
|
750
|
+
minLength: 1,
|
|
751
|
+
maxLength: 200
|
|
752
|
+
},
|
|
753
|
+
slug: {
|
|
754
|
+
bsonType: "string",
|
|
755
|
+
pattern: "^[a-z0-9-]+$"
|
|
756
|
+
},
|
|
757
|
+
content: { bsonType: "string" },
|
|
758
|
+
excerpt: { bsonType: "string", maxLength: 500 },
|
|
759
|
+
status: {
|
|
760
|
+
enum: ["draft", "published", "archived"]
|
|
761
|
+
},
|
|
762
|
+
tags: {
|
|
763
|
+
bsonType: "array",
|
|
764
|
+
maxItems: 20,
|
|
765
|
+
items: { bsonType: "string" }
|
|
766
|
+
},
|
|
767
|
+
stats: {
|
|
768
|
+
bsonType: "object",
|
|
769
|
+
properties: {
|
|
770
|
+
view_count: { bsonType: "int", minimum: 0 },
|
|
771
|
+
like_count: { bsonType: "int", minimum: 0 },
|
|
772
|
+
comment_count: { bsonType: "int", minimum: 0 }
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
published_at: { bsonType: "date" },
|
|
776
|
+
created_at: { bsonType: "date" },
|
|
777
|
+
updated_at: { bsonType: "date" }
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
})
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
---
|
|
785
|
+
|
|
786
|
+
## Performance Considerations
|
|
787
|
+
|
|
788
|
+
### Query Optimization
|
|
789
|
+
|
|
790
|
+
**Use projection to limit returned fields:**
|
|
791
|
+
```javascript
|
|
792
|
+
// ❌ BAD: Returns entire document
|
|
793
|
+
db.posts.find({ status: "published" })
|
|
794
|
+
|
|
795
|
+
// ✅ GOOD: Returns only needed fields
|
|
796
|
+
db.posts.find(
|
|
797
|
+
{ status: "published" },
|
|
798
|
+
{ title: 1, slug: 1, excerpt: 1, published_at: 1 }
|
|
799
|
+
)
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
**Use covered queries (index-only):**
|
|
803
|
+
```javascript
|
|
804
|
+
// Create index
|
|
805
|
+
db.posts.createIndex({ status: 1, published_at: -1, title: 1 })
|
|
806
|
+
|
|
807
|
+
// Query uses only indexed fields
|
|
808
|
+
db.posts.find(
|
|
809
|
+
{ status: "published" },
|
|
810
|
+
{ _id: 0, title: 1, published_at: 1 }
|
|
811
|
+
).sort({ published_at: -1 })
|
|
812
|
+
```
|
|
813
|
+
|
|
814
|
+
**Use explain() to analyze queries:**
|
|
815
|
+
```javascript
|
|
816
|
+
db.posts.find({ status: "published" }).explain("executionStats")
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
### Denormalization Trade-offs
|
|
820
|
+
|
|
821
|
+
**Embedded author display data:**
|
|
822
|
+
- ✅ **Pro**: Fast reads (no JOIN)
|
|
823
|
+
- ❌ **Con**: Must update when author changes username/avatar
|
|
824
|
+
- ✅ **Acceptable**: Display data changes infrequently
|
|
825
|
+
|
|
826
|
+
**Embedded stats:**
|
|
827
|
+
- ✅ **Pro**: Fast display of counts
|
|
828
|
+
- ❌ **Con**: Must update on every like/comment
|
|
829
|
+
- ✅ **Acceptable**: Atomic updates with $inc
|
|
830
|
+
|
|
831
|
+
### Sharding Strategy
|
|
832
|
+
|
|
833
|
+
**Shard key for posts collection:**
|
|
834
|
+
```javascript
|
|
835
|
+
// Shard by author_id (good for user-specific queries)
|
|
836
|
+
sh.shardCollection("blog.posts", { author_id: 1, _id: 1 })
|
|
837
|
+
|
|
838
|
+
// OR shard by published_at (good for time-based queries)
|
|
839
|
+
sh.shardCollection("blog.posts", { published_at: -1, _id: 1 })
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
---
|
|
843
|
+
|
|
844
|
+
## Summary
|
|
845
|
+
|
|
846
|
+
**Key Design Decisions:**
|
|
847
|
+
- ✅ **Embed**: Profile data (one-to-one), tags (one-to-few), recent likes (bounded)
|
|
848
|
+
- ✅ **Reference**: Posts (one-to-many), comments (unbounded), full likes history
|
|
849
|
+
- ✅ **Hybrid**: Author display data (reference + embedded for performance)
|
|
850
|
+
|
|
851
|
+
**Indexing Strategy:**
|
|
852
|
+
- ✅ Unique indexes on email, username, slug
|
|
853
|
+
- ✅ Compound indexes for common query patterns
|
|
854
|
+
- ✅ Text indexes for full-text search
|
|
855
|
+
|
|
856
|
+
**Performance Tips:**
|
|
857
|
+
- ✅ Use projection to limit returned fields
|
|
858
|
+
- ✅ Use aggregation pipelines for complex queries
|
|
859
|
+
- ✅ Denormalize for read performance (accept eventual consistency)
|
|
860
|
+
- ✅ Use $inc for atomic counter updates
|
|
861
|
+
- ✅ Monitor query performance with explain()
|
|
862
|
+
|
|
863
|
+
**Trade-offs:**
|
|
864
|
+
- **Embedding**: Faster reads, harder updates, bounded size
|
|
865
|
+
- **Referencing**: Flexible queries, slower reads (JOINs), unbounded growth
|
|
866
|
+
- **Hybrid**: Best of both worlds, complexity in maintaining consistency
|
|
867
|
+
|
|
868
|
+
|