javi-forge 0.1.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/.gitignore.template +105 -0
- package/.releaserc +44 -0
- package/README.md +45 -0
- package/ai-config/.skillignore +15 -0
- package/ai-config/AUTO_INVOKE.md +300 -0
- package/ai-config/agents/_TEMPLATE.md +93 -0
- package/ai-config/agents/business/api-designer.md +1657 -0
- package/ai-config/agents/business/business-analyst.md +1331 -0
- package/ai-config/agents/business/product-strategist.md +206 -0
- package/ai-config/agents/business/project-manager.md +178 -0
- package/ai-config/agents/business/requirements-analyst.md +1277 -0
- package/ai-config/agents/business/technical-writer.md +1679 -0
- package/ai-config/agents/creative/ux-designer.md +205 -0
- package/ai-config/agents/data-ai/ai-engineer.md +487 -0
- package/ai-config/agents/data-ai/analytics-engineer.md +953 -0
- package/ai-config/agents/data-ai/data-engineer.md +173 -0
- package/ai-config/agents/data-ai/data-scientist.md +672 -0
- package/ai-config/agents/data-ai/mlops-engineer.md +814 -0
- package/ai-config/agents/data-ai/prompt-engineer.md +772 -0
- package/ai-config/agents/development/angular-expert.md +620 -0
- package/ai-config/agents/development/backend-architect.md +795 -0
- package/ai-config/agents/development/database-specialist.md +212 -0
- package/ai-config/agents/development/frontend-specialist.md +686 -0
- package/ai-config/agents/development/fullstack-engineer.md +668 -0
- package/ai-config/agents/development/golang-pro.md +338 -0
- package/ai-config/agents/development/java-enterprise.md +400 -0
- package/ai-config/agents/development/javascript-pro.md +422 -0
- package/ai-config/agents/development/nextjs-pro.md +474 -0
- package/ai-config/agents/development/python-pro.md +570 -0
- package/ai-config/agents/development/react-pro.md +487 -0
- package/ai-config/agents/development/rust-pro.md +246 -0
- package/ai-config/agents/development/spring-boot-4-expert.md +326 -0
- package/ai-config/agents/development/typescript-pro.md +336 -0
- package/ai-config/agents/development/vue-specialist.md +605 -0
- package/ai-config/agents/infrastructure/cloud-architect.md +472 -0
- package/ai-config/agents/infrastructure/deployment-manager.md +358 -0
- package/ai-config/agents/infrastructure/devops-engineer.md +455 -0
- package/ai-config/agents/infrastructure/incident-responder.md +519 -0
- package/ai-config/agents/infrastructure/kubernetes-expert.md +705 -0
- package/ai-config/agents/infrastructure/monitoring-specialist.md +674 -0
- package/ai-config/agents/infrastructure/performance-engineer.md +658 -0
- package/ai-config/agents/orchestrator.md +241 -0
- package/ai-config/agents/quality/accessibility-auditor.md +1204 -0
- package/ai-config/agents/quality/code-reviewer-compact.md +123 -0
- package/ai-config/agents/quality/code-reviewer.md +363 -0
- package/ai-config/agents/quality/dependency-manager.md +743 -0
- package/ai-config/agents/quality/e2e-test-specialist.md +1005 -0
- package/ai-config/agents/quality/performance-tester.md +1086 -0
- package/ai-config/agents/quality/security-auditor.md +133 -0
- package/ai-config/agents/quality/test-engineer.md +453 -0
- package/ai-config/agents/specialists/api-designer.md +87 -0
- package/ai-config/agents/specialists/backend-architect.md +73 -0
- package/ai-config/agents/specialists/code-reviewer.md +77 -0
- package/ai-config/agents/specialists/db-optimizer.md +75 -0
- package/ai-config/agents/specialists/devops-engineer.md +83 -0
- package/ai-config/agents/specialists/documentation-writer.md +78 -0
- package/ai-config/agents/specialists/frontend-developer.md +75 -0
- package/ai-config/agents/specialists/performance-analyst.md +82 -0
- package/ai-config/agents/specialists/refactor-specialist.md +74 -0
- package/ai-config/agents/specialists/security-auditor.md +74 -0
- package/ai-config/agents/specialists/test-engineer.md +81 -0
- package/ai-config/agents/specialists/ux-consultant.md +76 -0
- package/ai-config/agents/specialized/agent-generator.md +1190 -0
- package/ai-config/agents/specialized/blockchain-developer.md +149 -0
- package/ai-config/agents/specialized/code-migrator.md +892 -0
- package/ai-config/agents/specialized/context-manager.md +978 -0
- package/ai-config/agents/specialized/documentation-writer.md +1078 -0
- package/ai-config/agents/specialized/ecommerce-expert.md +1756 -0
- package/ai-config/agents/specialized/embedded-engineer.md +1714 -0
- package/ai-config/agents/specialized/error-detective.md +1034 -0
- package/ai-config/agents/specialized/fintech-specialist.md +1659 -0
- package/ai-config/agents/specialized/freelance-project-planner-v2.md +1988 -0
- package/ai-config/agents/specialized/freelance-project-planner-v3.md +2136 -0
- package/ai-config/agents/specialized/freelance-project-planner-v4.md +4503 -0
- package/ai-config/agents/specialized/freelance-project-planner.md +722 -0
- package/ai-config/agents/specialized/game-developer.md +1963 -0
- package/ai-config/agents/specialized/healthcare-dev.md +1620 -0
- package/ai-config/agents/specialized/mobile-developer.md +188 -0
- package/ai-config/agents/specialized/parallel-plan-executor.md +506 -0
- package/ai-config/agents/specialized/plan-executor.md +485 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +485 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +3493 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +778 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +918 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +1537 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +2633 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +5610 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +335 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +215 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +260 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +379 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +355 -0
- package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +279 -0
- package/ai-config/agents/specialized/template-writer.md +347 -0
- package/ai-config/agents/specialized/test-runner.md +99 -0
- package/ai-config/agents/specialized/vibekanban-smart-worker.md +244 -0
- package/ai-config/agents/specialized/wave-executor.md +138 -0
- package/ai-config/agents/specialized/workflow-optimizer.md +1114 -0
- package/ai-config/commands/git/changelog.md +32 -0
- package/ai-config/commands/git/ci-local.md +70 -0
- package/ai-config/commands/git/commit.md +35 -0
- package/ai-config/commands/git/fix-issue.md +23 -0
- package/ai-config/commands/git/pr-create.md +42 -0
- package/ai-config/commands/git/pr-review.md +50 -0
- package/ai-config/commands/git/worktree.md +39 -0
- package/ai-config/commands/refactoring/cleanup.md +24 -0
- package/ai-config/commands/refactoring/dead-code.md +40 -0
- package/ai-config/commands/refactoring/extract.md +31 -0
- package/ai-config/commands/testing/e2e.md +30 -0
- package/ai-config/commands/testing/tdd.md +36 -0
- package/ai-config/commands/testing/test-coverage.md +30 -0
- package/ai-config/commands/testing/test-fix.md +24 -0
- package/ai-config/commands/workflow/generate-agents-md.md +85 -0
- package/ai-config/commands/workflow/planning.md +47 -0
- package/ai-config/commands/workflows/compound.md +89 -0
- package/ai-config/commands/workflows/plan.md +77 -0
- package/ai-config/commands/workflows/review.md +78 -0
- package/ai-config/commands/workflows/work.md +75 -0
- package/ai-config/config.yaml +18 -0
- package/ai-config/hooks/_TEMPLATE.md +96 -0
- package/ai-config/hooks/block-dangerous-commands.md +75 -0
- package/ai-config/hooks/commit-guard.md +90 -0
- package/ai-config/hooks/context-loader.md +73 -0
- package/ai-config/hooks/improve-prompt.md +91 -0
- package/ai-config/hooks/learning-log.md +72 -0
- package/ai-config/hooks/model-router.md +86 -0
- package/ai-config/hooks/secret-scanner.md +64 -0
- package/ai-config/hooks/skill-validator.md +102 -0
- package/ai-config/hooks/task-artifact.md +114 -0
- package/ai-config/hooks/validate-workflow.md +100 -0
- package/ai-config/prompts/base.md +71 -0
- package/ai-config/prompts/modes/debug.md +34 -0
- package/ai-config/prompts/modes/deploy.md +40 -0
- package/ai-config/prompts/modes/research.md +32 -0
- package/ai-config/prompts/modes/review.md +33 -0
- package/ai-config/prompts/review-policy.md +79 -0
- package/ai-config/skills/_TEMPLATE.md +157 -0
- package/ai-config/skills/backend/api-gateway/SKILL.md +254 -0
- package/ai-config/skills/backend/bff-concepts/SKILL.md +239 -0
- package/ai-config/skills/backend/bff-spring/SKILL.md +364 -0
- package/ai-config/skills/backend/chi-router/SKILL.md +396 -0
- package/ai-config/skills/backend/error-handling/SKILL.md +255 -0
- package/ai-config/skills/backend/exceptions-spring/SKILL.md +323 -0
- package/ai-config/skills/backend/fastapi/SKILL.md +302 -0
- package/ai-config/skills/backend/gateway-spring/SKILL.md +390 -0
- package/ai-config/skills/backend/go-backend/SKILL.md +457 -0
- package/ai-config/skills/backend/gradle-multimodule/SKILL.md +274 -0
- package/ai-config/skills/backend/graphql-concepts/SKILL.md +352 -0
- package/ai-config/skills/backend/graphql-spring/SKILL.md +398 -0
- package/ai-config/skills/backend/grpc-concepts/SKILL.md +283 -0
- package/ai-config/skills/backend/grpc-spring/SKILL.md +445 -0
- package/ai-config/skills/backend/jwt-auth/SKILL.md +412 -0
- package/ai-config/skills/backend/notifications-concepts/SKILL.md +259 -0
- package/ai-config/skills/backend/recommendations-concepts/SKILL.md +261 -0
- package/ai-config/skills/backend/search-concepts/SKILL.md +263 -0
- package/ai-config/skills/backend/search-spring/SKILL.md +375 -0
- package/ai-config/skills/backend/spring-boot-4/SKILL.md +172 -0
- package/ai-config/skills/backend/websockets/SKILL.md +532 -0
- package/ai-config/skills/data-ai/ai-ml/SKILL.md +423 -0
- package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +195 -0
- package/ai-config/skills/data-ai/analytics-spring/SKILL.md +340 -0
- package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +440 -0
- package/ai-config/skills/data-ai/langchain/SKILL.md +238 -0
- package/ai-config/skills/data-ai/mlflow/SKILL.md +302 -0
- package/ai-config/skills/data-ai/onnx-inference/SKILL.md +290 -0
- package/ai-config/skills/data-ai/powerbi/SKILL.md +352 -0
- package/ai-config/skills/data-ai/pytorch/SKILL.md +274 -0
- package/ai-config/skills/data-ai/scikit-learn/SKILL.md +321 -0
- package/ai-config/skills/data-ai/vector-db/SKILL.md +301 -0
- package/ai-config/skills/database/graph-databases/SKILL.md +218 -0
- package/ai-config/skills/database/graph-spring/SKILL.md +361 -0
- package/ai-config/skills/database/pgx-postgres/SKILL.md +512 -0
- package/ai-config/skills/database/redis-cache/SKILL.md +343 -0
- package/ai-config/skills/database/sqlite-embedded/SKILL.md +388 -0
- package/ai-config/skills/database/timescaledb/SKILL.md +320 -0
- package/ai-config/skills/docs/api-documentation/SKILL.md +293 -0
- package/ai-config/skills/docs/docs-spring/SKILL.md +377 -0
- package/ai-config/skills/docs/mustache-templates/SKILL.md +190 -0
- package/ai-config/skills/docs/technical-docs/SKILL.md +447 -0
- package/ai-config/skills/frontend/astro-ssr/SKILL.md +441 -0
- package/ai-config/skills/frontend/frontend-design/SKILL.md +54 -0
- package/ai-config/skills/frontend/frontend-web/SKILL.md +368 -0
- package/ai-config/skills/frontend/mantine-ui/SKILL.md +396 -0
- package/ai-config/skills/frontend/tanstack-query/SKILL.md +439 -0
- package/ai-config/skills/frontend/zod-validation/SKILL.md +417 -0
- package/ai-config/skills/frontend/zustand-state/SKILL.md +350 -0
- package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +244 -0
- package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +378 -0
- package/ai-config/skills/infrastructure/devops-infra/SKILL.md +435 -0
- package/ai-config/skills/infrastructure/docker-containers/SKILL.md +420 -0
- package/ai-config/skills/infrastructure/kubernetes/SKILL.md +456 -0
- package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +546 -0
- package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +474 -0
- package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +315 -0
- package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +504 -0
- package/ai-config/skills/mobile/mobile-ionic/SKILL.md +448 -0
- package/ai-config/skills/prompt-improver/SKILL.md +125 -0
- package/ai-config/skills/quality/ghagga-review/SKILL.md +216 -0
- package/ai-config/skills/references/hooks-patterns/SKILL.md +238 -0
- package/ai-config/skills/references/mcp-servers/SKILL.md +275 -0
- package/ai-config/skills/references/plugins-reference/SKILL.md +110 -0
- package/ai-config/skills/references/skills-reference/SKILL.md +420 -0
- package/ai-config/skills/references/subagent-templates/SKILL.md +193 -0
- package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +410 -0
- package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +408 -0
- package/ai-config/skills/systems-iot/rust-systems/SKILL.md +386 -0
- package/ai-config/skills/systems-iot/tokio-async/SKILL.md +324 -0
- package/ai-config/skills/testing/playwright-e2e/SKILL.md +289 -0
- package/ai-config/skills/testing/testcontainers/SKILL.md +299 -0
- package/ai-config/skills/testing/vitest-testing/SKILL.md +381 -0
- package/ai-config/skills/workflow/ci-local-guide/SKILL.md +118 -0
- package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +299 -0
- package/ai-config/skills/workflow/claude-md-improver/SKILL.md +158 -0
- package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +117 -0
- package/ai-config/skills/workflow/git-github/SKILL.md +334 -0
- package/ai-config/skills/workflow/git-github/references/examples.md +160 -0
- package/ai-config/skills/workflow/git-workflow/SKILL.md +214 -0
- package/ai-config/skills/workflow/ide-plugins/SKILL.md +277 -0
- package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +401 -0
- package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +199 -0
- package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +100 -0
- package/ai-config/skills/workflow/verification-before-completion/SKILL.md +73 -0
- package/ai-config/skills/workflow/wave-workflow/SKILL.md +178 -0
- package/ci-local/README.md +170 -0
- package/ci-local/ci-local.sh +297 -0
- package/ci-local/hooks/commit-msg +74 -0
- package/ci-local/hooks/pre-commit +162 -0
- package/ci-local/hooks/pre-push +41 -0
- package/ci-local/install.sh +49 -0
- package/ci-local/semgrep.yml +214 -0
- package/dist/commands/analyze.d.ts +9 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +55 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/analyze.test.d.ts +2 -0
- package/dist/commands/analyze.test.d.ts.map +1 -0
- package/dist/commands/analyze.test.js +145 -0
- package/dist/commands/analyze.test.js.map +1 -0
- package/dist/commands/doctor.d.ts +7 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +158 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/doctor.test.d.ts +2 -0
- package/dist/commands/doctor.test.d.ts.map +1 -0
- package/dist/commands/doctor.test.js +200 -0
- package/dist/commands/doctor.test.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +283 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/init.test.d.ts +2 -0
- package/dist/commands/init.test.d.ts.map +1 -0
- package/dist/commands/init.test.js +271 -0
- package/dist/commands/init.test.js.map +1 -0
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +201 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/constants.d.ts +21 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +57 -0
- package/dist/constants.js.map +1 -0
- package/dist/e2e/aggressive.e2e.test.d.ts +2 -0
- package/dist/e2e/aggressive.e2e.test.d.ts.map +1 -0
- package/dist/e2e/aggressive.e2e.test.js +350 -0
- package/dist/e2e/aggressive.e2e.test.js.map +1 -0
- package/dist/e2e/commands.e2e.test.d.ts +2 -0
- package/dist/e2e/commands.e2e.test.d.ts.map +1 -0
- package/dist/e2e/commands.e2e.test.js +213 -0
- package/dist/e2e/commands.e2e.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/common.d.ts +17 -0
- package/dist/lib/common.d.ts.map +1 -0
- package/dist/lib/common.js +111 -0
- package/dist/lib/common.js.map +1 -0
- package/dist/lib/common.test.d.ts +2 -0
- package/dist/lib/common.test.d.ts.map +1 -0
- package/dist/lib/common.test.js +316 -0
- package/dist/lib/common.test.js.map +1 -0
- package/dist/lib/frontmatter.d.ts +18 -0
- package/dist/lib/frontmatter.d.ts.map +1 -0
- package/dist/lib/frontmatter.js +61 -0
- package/dist/lib/frontmatter.js.map +1 -0
- package/dist/lib/frontmatter.test.d.ts +2 -0
- package/dist/lib/frontmatter.test.d.ts.map +1 -0
- package/dist/lib/frontmatter.test.js +257 -0
- package/dist/lib/frontmatter.test.js.map +1 -0
- package/dist/lib/template.d.ts +24 -0
- package/dist/lib/template.d.ts.map +1 -0
- package/dist/lib/template.js +78 -0
- package/dist/lib/template.js.map +1 -0
- package/dist/lib/template.test.d.ts +2 -0
- package/dist/lib/template.test.d.ts.map +1 -0
- package/dist/lib/template.test.js +201 -0
- package/dist/lib/template.test.js.map +1 -0
- package/dist/types/index.d.ts +48 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/AnalyzeUI.d.ts +7 -0
- package/dist/ui/AnalyzeUI.d.ts.map +1 -0
- package/dist/ui/AnalyzeUI.js +100 -0
- package/dist/ui/AnalyzeUI.js.map +1 -0
- package/dist/ui/App.d.ts +13 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +100 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/CIContext.d.ts +9 -0
- package/dist/ui/CIContext.d.ts.map +1 -0
- package/dist/ui/CIContext.js +9 -0
- package/dist/ui/CIContext.js.map +1 -0
- package/dist/ui/CISelector.d.ts +8 -0
- package/dist/ui/CISelector.d.ts.map +1 -0
- package/dist/ui/CISelector.js +45 -0
- package/dist/ui/CISelector.js.map +1 -0
- package/dist/ui/Doctor.d.ts +3 -0
- package/dist/ui/Doctor.d.ts.map +1 -0
- package/dist/ui/Doctor.js +89 -0
- package/dist/ui/Doctor.js.map +1 -0
- package/dist/ui/Header.d.ts +8 -0
- package/dist/ui/Header.d.ts.map +1 -0
- package/dist/ui/Header.js +30 -0
- package/dist/ui/Header.js.map +1 -0
- package/dist/ui/MemorySelector.d.ts +8 -0
- package/dist/ui/MemorySelector.d.ts.map +1 -0
- package/dist/ui/MemorySelector.js +46 -0
- package/dist/ui/MemorySelector.js.map +1 -0
- package/dist/ui/NameInput.d.ts +8 -0
- package/dist/ui/NameInput.d.ts.map +1 -0
- package/dist/ui/NameInput.js +69 -0
- package/dist/ui/NameInput.js.map +1 -0
- package/dist/ui/OptionSelector.d.ts +12 -0
- package/dist/ui/OptionSelector.d.ts.map +1 -0
- package/dist/ui/OptionSelector.js +69 -0
- package/dist/ui/OptionSelector.js.map +1 -0
- package/dist/ui/Progress.d.ts +11 -0
- package/dist/ui/Progress.d.ts.map +1 -0
- package/dist/ui/Progress.js +58 -0
- package/dist/ui/Progress.js.map +1 -0
- package/dist/ui/StackSelector.d.ts +9 -0
- package/dist/ui/StackSelector.d.ts.map +1 -0
- package/dist/ui/StackSelector.js +65 -0
- package/dist/ui/StackSelector.js.map +1 -0
- package/dist/ui/Summary.d.ts +12 -0
- package/dist/ui/Summary.d.ts.map +1 -0
- package/dist/ui/Summary.js +114 -0
- package/dist/ui/Summary.js.map +1 -0
- package/dist/ui/SyncUI.d.ts +10 -0
- package/dist/ui/SyncUI.d.ts.map +1 -0
- package/dist/ui/SyncUI.js +64 -0
- package/dist/ui/SyncUI.js.map +1 -0
- package/dist/ui/Welcome.d.ts +7 -0
- package/dist/ui/Welcome.d.ts.map +1 -0
- package/dist/ui/Welcome.js +45 -0
- package/dist/ui/Welcome.js.map +1 -0
- package/dist/ui/theme.d.ts +10 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +9 -0
- package/dist/ui/theme.js.map +1 -0
- package/modules/engram/.gitignore-snippet.txt +6 -0
- package/modules/engram/.mcp-config-snippet.json +11 -0
- package/modules/engram/README.md +146 -0
- package/modules/engram/install-engram.sh +216 -0
- package/modules/ghagga/.env.example +43 -0
- package/modules/ghagga/README.md +153 -0
- package/modules/ghagga/docker-compose.yml +80 -0
- package/modules/ghagga/setup-ghagga.sh +139 -0
- package/modules/memory-simple/.project/NOTES.md +22 -0
- package/modules/memory-simple/README.md +23 -0
- package/modules/obsidian-brain/.obsidian/app.json +23 -0
- package/modules/obsidian-brain/.obsidian/appearance.json +5 -0
- package/modules/obsidian-brain/.obsidian/bookmarks.json +34 -0
- package/modules/obsidian-brain/.obsidian/community-plugins.json +1 -0
- package/modules/obsidian-brain/.obsidian/core-plugins-migration.json +21 -0
- package/modules/obsidian-brain/.obsidian/core-plugins.json +18 -0
- package/modules/obsidian-brain/.obsidian/daily-notes.json +5 -0
- package/modules/obsidian-brain/.obsidian/graph.json +37 -0
- package/modules/obsidian-brain/.obsidian/hotkeys.json +14 -0
- package/modules/obsidian-brain/.obsidian/plugins/dataview/data.json +25 -0
- package/modules/obsidian-brain/.obsidian/plugins/obsidian-kanban/data.json +29 -0
- package/modules/obsidian-brain/.obsidian/plugins/templater-obsidian/data.json +18 -0
- package/modules/obsidian-brain/.obsidian/snippets/project-memory.css +71 -0
- package/modules/obsidian-brain/.obsidian-gitignore-snippet.txt +8 -0
- package/modules/obsidian-brain/.project/Attachments/.gitkeep +0 -0
- package/modules/obsidian-brain/.project/Memory/BLOCKERS.md +78 -0
- package/modules/obsidian-brain/.project/Memory/CONTEXT.md +102 -0
- package/modules/obsidian-brain/.project/Memory/DASHBOARD.md +73 -0
- package/modules/obsidian-brain/.project/Memory/DECISIONS.md +87 -0
- package/modules/obsidian-brain/.project/Memory/KANBAN.md +15 -0
- package/modules/obsidian-brain/.project/Memory/README.md +61 -0
- package/modules/obsidian-brain/.project/Memory/WAVES.md +78 -0
- package/modules/obsidian-brain/.project/Sessions/TEMPLATE.md +99 -0
- package/modules/obsidian-brain/.project/Templates/ADR.md +33 -0
- package/modules/obsidian-brain/.project/Templates/Blocker.md +21 -0
- package/modules/obsidian-brain/.project/Templates/Session.md +88 -0
- package/modules/obsidian-brain/README.md +268 -0
- package/modules/obsidian-brain/new-wave.sh +182 -0
- package/package.json +51 -0
- package/schemas/agent.schema.json +34 -0
- package/schemas/ai-config.schema.json +28 -0
- package/schemas/skill.schema.json +44 -0
- package/src/commands/analyze.test.ts +145 -0
- package/src/commands/analyze.ts +69 -0
- package/src/commands/doctor.test.ts +208 -0
- package/src/commands/doctor.ts +163 -0
- package/src/commands/init.test.ts +298 -0
- package/src/commands/init.ts +285 -0
- package/src/constants.ts +69 -0
- package/src/e2e/aggressive.e2e.test.ts +557 -0
- package/src/e2e/commands.e2e.test.ts +298 -0
- package/src/index.tsx +106 -0
- package/src/lib/common.test.ts +318 -0
- package/src/lib/common.ts +127 -0
- package/src/lib/frontmatter.test.ts +291 -0
- package/src/lib/frontmatter.ts +77 -0
- package/src/lib/template.test.ts +226 -0
- package/src/lib/template.ts +99 -0
- package/src/types/index.ts +53 -0
- package/src/ui/AnalyzeUI.tsx +133 -0
- package/src/ui/App.tsx +175 -0
- package/src/ui/CIContext.tsx +25 -0
- package/src/ui/CISelector.tsx +72 -0
- package/src/ui/Doctor.tsx +122 -0
- package/src/ui/Header.tsx +48 -0
- package/src/ui/MemorySelector.tsx +73 -0
- package/src/ui/NameInput.tsx +82 -0
- package/src/ui/OptionSelector.tsx +100 -0
- package/src/ui/Progress.tsx +88 -0
- package/src/ui/StackSelector.tsx +101 -0
- package/src/ui/Summary.tsx +134 -0
- package/src/ui/Welcome.tsx +54 -0
- package/src/ui/theme.ts +10 -0
- package/stryker.config.json +19 -0
- package/tasks/_TEMPLATE/files-edited.md +3 -0
- package/tasks/_TEMPLATE/plan.md +3 -0
- package/tasks/_TEMPLATE/research.md +3 -0
- package/tasks/_TEMPLATE/verification.md +5 -0
- package/templates/common/dependabot/cargo.yml +11 -0
- package/templates/common/dependabot/github-actions.yml +16 -0
- package/templates/common/dependabot/gomod.yml +15 -0
- package/templates/common/dependabot/gradle.yml +15 -0
- package/templates/common/dependabot/header.yml +3 -0
- package/templates/common/dependabot/maven.yml +15 -0
- package/templates/common/dependabot/npm.yml +20 -0
- package/templates/common/dependabot/pip.yml +11 -0
- package/templates/dependabot.yml +162 -0
- package/templates/github/ci-go.yml +41 -0
- package/templates/github/ci-java.yml +45 -0
- package/templates/github/ci-monorepo.yml +150 -0
- package/templates/github/ci-node.yml +42 -0
- package/templates/github/ci-python.yml +42 -0
- package/templates/github/ci-rust.yml +42 -0
- package/templates/github/dependabot-automerge.yml +40 -0
- package/templates/gitlab/gitlab-ci-go.yml +88 -0
- package/templates/gitlab/gitlab-ci-java.yml +79 -0
- package/templates/gitlab/gitlab-ci-monorepo.yml +126 -0
- package/templates/gitlab/gitlab-ci-node.yml +63 -0
- package/templates/gitlab/gitlab-ci-python.yml +147 -0
- package/templates/gitlab/gitlab-ci-rust.yml +67 -0
- package/templates/global/claude-settings.json +98 -0
- package/templates/global/codex-config.toml +8 -0
- package/templates/global/copilot-instructions/base-rules.instructions.md +13 -0
- package/templates/global/copilot-instructions/sdd-orchestrator.instructions.md +37 -0
- package/templates/global/gemini-commands/cleanup.toml +20 -0
- package/templates/global/gemini-commands/commit.toml +15 -0
- package/templates/global/gemini-commands/dead-code.toml +22 -0
- package/templates/global/gemini-commands/plan.toml +30 -0
- package/templates/global/gemini-commands/review.toml +17 -0
- package/templates/global/gemini-commands/sdd-apply.toml +22 -0
- package/templates/global/gemini-commands/sdd-ff.toml +14 -0
- package/templates/global/gemini-commands/sdd-new.toml +21 -0
- package/templates/global/gemini-commands/sdd-verify.toml +21 -0
- package/templates/global/gemini-commands/tdd.toml +26 -0
- package/templates/global/gemini-settings.json +8 -0
- package/templates/global/opencode-config.json +44 -0
- package/templates/global/sdd-instructions.md +47 -0
- package/templates/global/sdd-orchestrator-claude.md +46 -0
- package/templates/global/sdd-orchestrator-copilot.md +34 -0
- package/templates/renovate.json +69 -0
- package/templates/woodpecker/monorepo/backend.yml +34 -0
- package/templates/woodpecker/monorepo/frontend.yml +34 -0
- package/templates/woodpecker/monorepo/summary.yml +25 -0
- package/templates/woodpecker/woodpecker-go.yml +51 -0
- package/templates/woodpecker/woodpecker-java.yml +67 -0
- package/templates/woodpecker/woodpecker-node.yml +47 -0
- package/templates/woodpecker/woodpecker-python.yml +108 -0
- package/templates/woodpecker/woodpecker-rust.yml +57 -0
- package/tsconfig.json +19 -0
- package/vitest.config.ts +16 -0
- package/workflows/reusable-build-go.yml +111 -0
- package/workflows/reusable-build-java.yml +120 -0
- package/workflows/reusable-build-node.yml +145 -0
- package/workflows/reusable-build-python.yml +159 -0
- package/workflows/reusable-build-rust.yml +135 -0
- package/workflows/reusable-docker.yml +120 -0
- package/workflows/reusable-ghagga-review.yml +165 -0
- package/workflows/reusable-release.yml +91 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: graphql-spring
|
|
3
|
+
description: >
|
|
4
|
+
Spring Boot GraphQL. Spring for GraphQL, resolvers, DataLoader, subscriptions.
|
|
5
|
+
Trigger: apigen-graphql, @QueryMapping, @MutationMapping, DataLoader, GraphQL Java
|
|
6
|
+
tools:
|
|
7
|
+
- Read
|
|
8
|
+
- Write
|
|
9
|
+
- Edit
|
|
10
|
+
- Bash
|
|
11
|
+
- Grep
|
|
12
|
+
metadata:
|
|
13
|
+
author: apigen-team
|
|
14
|
+
version: "1.0"
|
|
15
|
+
tags: [graphql, spring-boot, resolvers, java]
|
|
16
|
+
scope: ["apigen-graphql/**"]
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# GraphQL Spring Boot (apigen-graphql)
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
```yaml
|
|
24
|
+
spring:
|
|
25
|
+
graphql:
|
|
26
|
+
graphiql:
|
|
27
|
+
enabled: true
|
|
28
|
+
path: /graphiql
|
|
29
|
+
schema:
|
|
30
|
+
locations: classpath:graphql/
|
|
31
|
+
printer:
|
|
32
|
+
enabled: true
|
|
33
|
+
websocket:
|
|
34
|
+
path: /graphql
|
|
35
|
+
|
|
36
|
+
apigen:
|
|
37
|
+
graphql:
|
|
38
|
+
enabled: true
|
|
39
|
+
max-depth: 10
|
|
40
|
+
max-complexity: 200
|
|
41
|
+
introspection-enabled: ${DEBUG:false}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Schema Definition
|
|
45
|
+
|
|
46
|
+
```graphql
|
|
47
|
+
# src/main/resources/graphql/schema.graphqls
|
|
48
|
+
|
|
49
|
+
type Query {
|
|
50
|
+
user(id: ID!): User
|
|
51
|
+
users(page: Int = 0, size: Int = 20): UserConnection!
|
|
52
|
+
searchUsers(query: String!): [User!]!
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type Mutation {
|
|
56
|
+
createUser(input: CreateUserInput!): User!
|
|
57
|
+
updateUser(id: ID!, input: UpdateUserInput!): User!
|
|
58
|
+
deleteUser(id: ID!): Boolean!
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type Subscription {
|
|
62
|
+
userCreated: User!
|
|
63
|
+
userUpdated(id: ID!): User!
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type User {
|
|
67
|
+
id: ID!
|
|
68
|
+
email: String!
|
|
69
|
+
name: String
|
|
70
|
+
posts(first: Int, after: String): PostConnection!
|
|
71
|
+
createdAt: DateTime!
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type Post {
|
|
75
|
+
id: ID!
|
|
76
|
+
title: String!
|
|
77
|
+
author: User!
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type UserConnection {
|
|
81
|
+
edges: [UserEdge!]!
|
|
82
|
+
pageInfo: PageInfo!
|
|
83
|
+
totalCount: Int!
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
type UserEdge {
|
|
87
|
+
cursor: String!
|
|
88
|
+
node: User!
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
type PageInfo {
|
|
92
|
+
hasNextPage: Boolean!
|
|
93
|
+
hasPreviousPage: Boolean!
|
|
94
|
+
startCursor: String
|
|
95
|
+
endCursor: String
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
input CreateUserInput {
|
|
99
|
+
email: String!
|
|
100
|
+
name: String
|
|
101
|
+
password: String!
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
input UpdateUserInput {
|
|
105
|
+
name: String
|
|
106
|
+
email: String
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
scalar DateTime
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Query Controller
|
|
113
|
+
|
|
114
|
+
```java
|
|
115
|
+
@Controller
|
|
116
|
+
public class UserGraphQLController {
|
|
117
|
+
|
|
118
|
+
private final UserService userService;
|
|
119
|
+
|
|
120
|
+
@QueryMapping
|
|
121
|
+
public User user(@Argument UUID id) {
|
|
122
|
+
return userService.findById(id)
|
|
123
|
+
.orElse(null);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
@QueryMapping
|
|
127
|
+
public Connection<User> users(
|
|
128
|
+
@Argument int page,
|
|
129
|
+
@Argument int size) {
|
|
130
|
+
Page<User> userPage = userService.findAll(PageRequest.of(page, size));
|
|
131
|
+
return toConnection(userPage);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
@QueryMapping
|
|
135
|
+
public List<User> searchUsers(@Argument String query) {
|
|
136
|
+
return userService.search(query);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Nested field resolver
|
|
140
|
+
@SchemaMapping(typeName = "User", field = "posts")
|
|
141
|
+
public Connection<Post> posts(
|
|
142
|
+
User user,
|
|
143
|
+
@Argument Integer first,
|
|
144
|
+
@Argument String after) {
|
|
145
|
+
return postService.findByAuthorId(user.getId(), first, after);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Mutation Controller
|
|
151
|
+
|
|
152
|
+
```java
|
|
153
|
+
@Controller
|
|
154
|
+
public class UserMutationController {
|
|
155
|
+
|
|
156
|
+
private final UserService userService;
|
|
157
|
+
private final ApplicationEventPublisher eventPublisher;
|
|
158
|
+
|
|
159
|
+
@MutationMapping
|
|
160
|
+
public User createUser(@Argument("input") @Valid CreateUserInput input) {
|
|
161
|
+
User user = userService.create(input);
|
|
162
|
+
eventPublisher.publishEvent(new UserCreatedEvent(user));
|
|
163
|
+
return user;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@MutationMapping
|
|
167
|
+
public User updateUser(
|
|
168
|
+
@Argument UUID id,
|
|
169
|
+
@Argument("input") @Valid UpdateUserInput input) {
|
|
170
|
+
return userService.update(id, input);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
@MutationMapping
|
|
174
|
+
public boolean deleteUser(@Argument UUID id) {
|
|
175
|
+
userService.delete(id);
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Subscription Controller
|
|
182
|
+
|
|
183
|
+
```java
|
|
184
|
+
@Controller
|
|
185
|
+
public class UserSubscriptionController {
|
|
186
|
+
|
|
187
|
+
private final Sinks.Many<User> userCreatedSink =
|
|
188
|
+
Sinks.many().multicast().onBackpressureBuffer();
|
|
189
|
+
|
|
190
|
+
@SubscriptionMapping
|
|
191
|
+
public Flux<User> userCreated() {
|
|
192
|
+
return userCreatedSink.asFlux();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
@SubscriptionMapping
|
|
196
|
+
public Flux<User> userUpdated(@Argument UUID id) {
|
|
197
|
+
return userUpdatedSink.asFlux()
|
|
198
|
+
.filter(user -> user.getId().equals(id));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
@EventListener
|
|
202
|
+
public void onUserCreated(UserCreatedEvent event) {
|
|
203
|
+
userCreatedSink.tryEmitNext(event.getUser());
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## DataLoader Configuration
|
|
209
|
+
|
|
210
|
+
```java
|
|
211
|
+
@Configuration
|
|
212
|
+
public class DataLoaderConfiguration {
|
|
213
|
+
|
|
214
|
+
@Bean
|
|
215
|
+
public BatchLoaderRegistry batchLoaderRegistry(
|
|
216
|
+
UserRepository userRepository,
|
|
217
|
+
PostRepository postRepository) {
|
|
218
|
+
|
|
219
|
+
return BatchLoaderRegistry.create()
|
|
220
|
+
.registerMappedBatchLoader(
|
|
221
|
+
"usersById",
|
|
222
|
+
(Set<UUID> ids, BatchLoaderEnvironment env) ->
|
|
223
|
+
Mono.fromCallable(() ->
|
|
224
|
+
userRepository.findAllById(ids).stream()
|
|
225
|
+
.collect(Collectors.toMap(User::getId, Function.identity()))
|
|
226
|
+
)
|
|
227
|
+
)
|
|
228
|
+
.registerMappedBatchLoader(
|
|
229
|
+
"postsByAuthorId",
|
|
230
|
+
(Set<UUID> authorIds, BatchLoaderEnvironment env) ->
|
|
231
|
+
Mono.fromCallable(() ->
|
|
232
|
+
postRepository.findByAuthorIdIn(authorIds).stream()
|
|
233
|
+
.collect(Collectors.groupingBy(Post::getAuthorId))
|
|
234
|
+
)
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Using DataLoader in resolver
|
|
240
|
+
@Controller
|
|
241
|
+
public class PostGraphQLController {
|
|
242
|
+
|
|
243
|
+
@SchemaMapping(typeName = "Post", field = "author")
|
|
244
|
+
public CompletableFuture<User> author(
|
|
245
|
+
Post post,
|
|
246
|
+
DataLoader<UUID, User> usersById) {
|
|
247
|
+
return usersById.load(post.getAuthorId());
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Custom Scalar
|
|
253
|
+
|
|
254
|
+
```java
|
|
255
|
+
@Configuration
|
|
256
|
+
public class ScalarConfiguration {
|
|
257
|
+
|
|
258
|
+
@Bean
|
|
259
|
+
public RuntimeWiringConfigurer runtimeWiringConfigurer() {
|
|
260
|
+
return wiringBuilder -> wiringBuilder
|
|
261
|
+
.scalar(ExtendedScalars.DateTime)
|
|
262
|
+
.scalar(ExtendedScalars.UUID)
|
|
263
|
+
.scalar(ExtendedScalars.JSON);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Exception Handling
|
|
269
|
+
|
|
270
|
+
```java
|
|
271
|
+
@ControllerAdvice
|
|
272
|
+
public class GraphQLExceptionHandler {
|
|
273
|
+
|
|
274
|
+
@GraphQlExceptionHandler
|
|
275
|
+
public GraphQLError handleNotFoundException(ResourceNotFoundException ex) {
|
|
276
|
+
return GraphQLError.newError()
|
|
277
|
+
.errorType(ErrorType.NOT_FOUND)
|
|
278
|
+
.message(ex.getMessage())
|
|
279
|
+
.build();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
@GraphQlExceptionHandler
|
|
283
|
+
public GraphQLError handleValidation(ConstraintViolationException ex) {
|
|
284
|
+
return GraphQLError.newError()
|
|
285
|
+
.errorType(ErrorType.BAD_REQUEST)
|
|
286
|
+
.message("Validation failed")
|
|
287
|
+
.extensions(Map.of(
|
|
288
|
+
"errors", ex.getConstraintViolations().stream()
|
|
289
|
+
.map(cv -> Map.of(
|
|
290
|
+
"field", cv.getPropertyPath().toString(),
|
|
291
|
+
"message", cv.getMessage()
|
|
292
|
+
))
|
|
293
|
+
.toList()
|
|
294
|
+
))
|
|
295
|
+
.build();
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Query Complexity
|
|
301
|
+
|
|
302
|
+
```java
|
|
303
|
+
@Configuration
|
|
304
|
+
public class GraphQLSecurityConfiguration {
|
|
305
|
+
|
|
306
|
+
@Bean
|
|
307
|
+
public Instrumentation maxQueryDepthInstrumentation() {
|
|
308
|
+
return new MaxQueryDepthInstrumentation(10);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
@Bean
|
|
312
|
+
public Instrumentation maxQueryComplexityInstrumentation() {
|
|
313
|
+
return new MaxQueryComplexityInstrumentation(200);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Authorization
|
|
319
|
+
|
|
320
|
+
```java
|
|
321
|
+
@Controller
|
|
322
|
+
public class SecuredGraphQLController {
|
|
323
|
+
|
|
324
|
+
@QueryMapping
|
|
325
|
+
@PreAuthorize("hasRole('USER')")
|
|
326
|
+
public User me(@AuthenticationPrincipal UserDetails user) {
|
|
327
|
+
return userService.findByEmail(user.getUsername())
|
|
328
|
+
.orElseThrow();
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
@MutationMapping
|
|
332
|
+
@PreAuthorize("hasRole('ADMIN')")
|
|
333
|
+
public boolean deleteUser(@Argument UUID id) {
|
|
334
|
+
userService.delete(id);
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Field-level authorization
|
|
339
|
+
@SchemaMapping(typeName = "User", field = "email")
|
|
340
|
+
@PreAuthorize("hasRole('ADMIN') or #user.id == authentication.principal.id")
|
|
341
|
+
public String email(User user) {
|
|
342
|
+
return user.getEmail();
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
## Testing
|
|
348
|
+
|
|
349
|
+
```java
|
|
350
|
+
@GraphQlTest(UserGraphQLController.class)
|
|
351
|
+
class UserGraphQLControllerTest {
|
|
352
|
+
|
|
353
|
+
@Autowired
|
|
354
|
+
private GraphQlTester graphQlTester;
|
|
355
|
+
|
|
356
|
+
@MockBean
|
|
357
|
+
private UserService userService;
|
|
358
|
+
|
|
359
|
+
@Test
|
|
360
|
+
void shouldGetUser() {
|
|
361
|
+
User user = new User(UUID.randomUUID(), "test@example.com", "Test");
|
|
362
|
+
when(userService.findById(user.getId())).thenReturn(Optional.of(user));
|
|
363
|
+
|
|
364
|
+
graphQlTester.documentName("getUser")
|
|
365
|
+
.variable("id", user.getId())
|
|
366
|
+
.execute()
|
|
367
|
+
.path("user.email").entity(String.class).isEqualTo("test@example.com")
|
|
368
|
+
.path("user.name").entity(String.class).isEqualTo("Test");
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
@Test
|
|
372
|
+
void shouldCreateUser() {
|
|
373
|
+
graphQlTester.document("""
|
|
374
|
+
mutation CreateUser($input: CreateUserInput!) {
|
|
375
|
+
createUser(input: $input) {
|
|
376
|
+
id
|
|
377
|
+
email
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
""")
|
|
381
|
+
.variable("input", Map.of(
|
|
382
|
+
"email", "new@example.com",
|
|
383
|
+
"name", "New User",
|
|
384
|
+
"password", "SecurePass123"
|
|
385
|
+
))
|
|
386
|
+
.execute()
|
|
387
|
+
.path("createUser.email").entity(String.class).isEqualTo("new@example.com");
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Related Skills
|
|
393
|
+
|
|
394
|
+
- `graphql-concepts`: GraphQL concepts
|
|
395
|
+
- `spring-boot-4`: Spring Boot 4.0 patterns
|
|
396
|
+
- `apigen-architecture`: Overall system architecture
|
|
397
|
+
|
|
398
|
+
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: grpc-concepts
|
|
3
|
+
description: >
|
|
4
|
+
gRPC concepts. Protocol Buffers, service definitions, streaming, error handling.
|
|
5
|
+
Trigger: gRPC, protobuf, Protocol Buffers, RPC, streaming, service definition
|
|
6
|
+
tools:
|
|
7
|
+
- Read
|
|
8
|
+
- Write
|
|
9
|
+
- Edit
|
|
10
|
+
- Grep
|
|
11
|
+
metadata:
|
|
12
|
+
author: apigen-team
|
|
13
|
+
version: "1.0"
|
|
14
|
+
tags: [grpc, protobuf, rpc, microservices]
|
|
15
|
+
scope: ["**/grpc/**"]
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# gRPC Concepts
|
|
19
|
+
|
|
20
|
+
## What is gRPC?
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
gRPC = Google Remote Procedure Call
|
|
24
|
+
|
|
25
|
+
Features:
|
|
26
|
+
- Binary protocol (Protocol Buffers)
|
|
27
|
+
- HTTP/2 transport
|
|
28
|
+
- Bi-directional streaming
|
|
29
|
+
- Language agnostic
|
|
30
|
+
- Strong typing
|
|
31
|
+
|
|
32
|
+
Use cases:
|
|
33
|
+
- Microservices communication
|
|
34
|
+
- Real-time data streaming
|
|
35
|
+
- Mobile-backend communication
|
|
36
|
+
- IoT device communication
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Protocol Buffers (Protobuf)
|
|
40
|
+
|
|
41
|
+
### Message Definition
|
|
42
|
+
```protobuf
|
|
43
|
+
syntax = "proto3";
|
|
44
|
+
|
|
45
|
+
package com.example.user;
|
|
46
|
+
|
|
47
|
+
option java_package = "com.example.user.proto";
|
|
48
|
+
option java_multiple_files = true;
|
|
49
|
+
|
|
50
|
+
message User {
|
|
51
|
+
string id = 1;
|
|
52
|
+
string email = 2;
|
|
53
|
+
string name = 3;
|
|
54
|
+
UserStatus status = 4;
|
|
55
|
+
google.protobuf.Timestamp created_at = 5;
|
|
56
|
+
repeated Role roles = 6;
|
|
57
|
+
optional string phone = 7; // proto3 optional
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
enum UserStatus {
|
|
61
|
+
USER_STATUS_UNSPECIFIED = 0;
|
|
62
|
+
USER_STATUS_ACTIVE = 1;
|
|
63
|
+
USER_STATUS_INACTIVE = 2;
|
|
64
|
+
USER_STATUS_SUSPENDED = 3;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
message Role {
|
|
68
|
+
string id = 1;
|
|
69
|
+
string name = 2;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Field Numbers
|
|
74
|
+
```
|
|
75
|
+
Rules:
|
|
76
|
+
- 1-15: Single byte encoding (use for frequent fields)
|
|
77
|
+
- 16-2047: Two byte encoding
|
|
78
|
+
- 19000-19999: Reserved by protobuf
|
|
79
|
+
- Once assigned, never change
|
|
80
|
+
|
|
81
|
+
Best practices:
|
|
82
|
+
- Reserve removed field numbers
|
|
83
|
+
- Document field number allocations
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Service Definition
|
|
87
|
+
|
|
88
|
+
```protobuf
|
|
89
|
+
service UserService {
|
|
90
|
+
// Unary RPC
|
|
91
|
+
rpc GetUser(GetUserRequest) returns (User);
|
|
92
|
+
|
|
93
|
+
// Server streaming
|
|
94
|
+
rpc ListUsers(ListUsersRequest) returns (stream User);
|
|
95
|
+
|
|
96
|
+
// Client streaming
|
|
97
|
+
rpc CreateUsers(stream CreateUserRequest) returns (BatchCreateResponse);
|
|
98
|
+
|
|
99
|
+
// Bi-directional streaming
|
|
100
|
+
rpc Chat(stream ChatMessage) returns (stream ChatMessage);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
message GetUserRequest {
|
|
104
|
+
string user_id = 1;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
message ListUsersRequest {
|
|
108
|
+
int32 page_size = 1;
|
|
109
|
+
string page_token = 2;
|
|
110
|
+
UserFilter filter = 3;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
message UserFilter {
|
|
114
|
+
optional UserStatus status = 1;
|
|
115
|
+
optional string email_contains = 2;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## RPC Types
|
|
120
|
+
|
|
121
|
+
### Unary RPC
|
|
122
|
+
```
|
|
123
|
+
Client sends single request, server returns single response
|
|
124
|
+
|
|
125
|
+
Client ──request──> Server
|
|
126
|
+
Client <──response── Server
|
|
127
|
+
|
|
128
|
+
Use for: CRUD operations, simple queries
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Server Streaming
|
|
132
|
+
```
|
|
133
|
+
Client sends single request, server returns stream of responses
|
|
134
|
+
|
|
135
|
+
Client ──request──> Server
|
|
136
|
+
Client <──response1── Server
|
|
137
|
+
Client <──response2── Server
|
|
138
|
+
Client <──response3── Server
|
|
139
|
+
|
|
140
|
+
Use for: Large result sets, real-time updates
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Client Streaming
|
|
144
|
+
```
|
|
145
|
+
Client sends stream of requests, server returns single response
|
|
146
|
+
|
|
147
|
+
Client ──request1──> Server
|
|
148
|
+
Client ──request2──>
|
|
149
|
+
Client ──request3──>
|
|
150
|
+
Client <──response── Server
|
|
151
|
+
|
|
152
|
+
Use for: File uploads, batch operations
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Bi-directional Streaming
|
|
156
|
+
```
|
|
157
|
+
Both client and server send streams
|
|
158
|
+
|
|
159
|
+
Client ──request1──> Server
|
|
160
|
+
Client <──response1──
|
|
161
|
+
Client ──request2──>
|
|
162
|
+
Client <──response2──
|
|
163
|
+
|
|
164
|
+
Use for: Chat, real-time collaboration
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Error Handling
|
|
168
|
+
|
|
169
|
+
### Status Codes
|
|
170
|
+
```
|
|
171
|
+
OK (0): Success
|
|
172
|
+
CANCELLED (1): Operation cancelled
|
|
173
|
+
UNKNOWN (2): Unknown error
|
|
174
|
+
INVALID_ARGUMENT (3): Client error
|
|
175
|
+
DEADLINE_EXCEEDED (4): Timeout
|
|
176
|
+
NOT_FOUND (5): Resource not found
|
|
177
|
+
ALREADY_EXISTS (6): Duplicate
|
|
178
|
+
PERMISSION_DENIED (7): Authorization failed
|
|
179
|
+
UNAUTHENTICATED (16): Authentication required
|
|
180
|
+
RESOURCE_EXHAUSTED (8): Rate limited
|
|
181
|
+
FAILED_PRECONDITION (9): State conflict
|
|
182
|
+
ABORTED (10): Concurrency conflict
|
|
183
|
+
OUT_OF_RANGE (11): Invalid range
|
|
184
|
+
UNIMPLEMENTED (12): Not implemented
|
|
185
|
+
INTERNAL (13): Server error
|
|
186
|
+
UNAVAILABLE (14): Service unavailable
|
|
187
|
+
DATA_LOSS (15): Unrecoverable data loss
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Rich Error Details
|
|
191
|
+
```protobuf
|
|
192
|
+
import "google/rpc/error_details.proto";
|
|
193
|
+
|
|
194
|
+
// Error with field violations
|
|
195
|
+
google.rpc.BadRequest bad_request = {
|
|
196
|
+
field_violations: [
|
|
197
|
+
{field: "email", description: "Invalid email format"},
|
|
198
|
+
{field: "password", description: "Too short"}
|
|
199
|
+
]
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// Error with retry info
|
|
203
|
+
google.rpc.RetryInfo retry_info = {
|
|
204
|
+
retry_delay: {seconds: 30}
|
|
205
|
+
};
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Metadata
|
|
209
|
+
|
|
210
|
+
```
|
|
211
|
+
Headers sent with requests:
|
|
212
|
+
|
|
213
|
+
Standard metadata:
|
|
214
|
+
- :authority (host)
|
|
215
|
+
- :path (method)
|
|
216
|
+
- content-type
|
|
217
|
+
- user-agent
|
|
218
|
+
- grpc-timeout
|
|
219
|
+
|
|
220
|
+
Custom metadata:
|
|
221
|
+
- authorization: Bearer token
|
|
222
|
+
- x-request-id: correlation ID
|
|
223
|
+
- x-tenant-id: multi-tenancy
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Interceptors
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
Client-side:
|
|
230
|
+
1. Add authentication token
|
|
231
|
+
2. Log request/response
|
|
232
|
+
3. Handle errors
|
|
233
|
+
4. Add tracing context
|
|
234
|
+
|
|
235
|
+
Server-side:
|
|
236
|
+
1. Validate authentication
|
|
237
|
+
2. Rate limiting
|
|
238
|
+
3. Log request/response
|
|
239
|
+
4. Extract tracing context
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Best Practices
|
|
243
|
+
|
|
244
|
+
```
|
|
245
|
+
Proto design:
|
|
246
|
+
✅ Use descriptive field names
|
|
247
|
+
✅ Reserve deprecated field numbers
|
|
248
|
+
✅ Use well-known types (Timestamp, Duration)
|
|
249
|
+
✅ Define enums with UNSPECIFIED = 0
|
|
250
|
+
✅ Use optional for nullable fields
|
|
251
|
+
|
|
252
|
+
Performance:
|
|
253
|
+
✅ Reuse channels/stubs
|
|
254
|
+
✅ Use streaming for large data
|
|
255
|
+
✅ Set appropriate deadlines
|
|
256
|
+
✅ Enable compression
|
|
257
|
+
|
|
258
|
+
Versioning:
|
|
259
|
+
✅ Add fields (backward compatible)
|
|
260
|
+
❌ Remove/rename fields
|
|
261
|
+
❌ Change field types
|
|
262
|
+
❌ Change field numbers
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## gRPC vs REST
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
| Aspect | gRPC | REST |
|
|
269
|
+
|--------|------|------|
|
|
270
|
+
| Protocol | HTTP/2 | HTTP/1.1 or 2 |
|
|
271
|
+
| Format | Binary (Protobuf) | Text (JSON) |
|
|
272
|
+
| Contract | Strong (.proto) | Weak (OpenAPI) |
|
|
273
|
+
| Streaming | Native | Limited |
|
|
274
|
+
| Browser | Needs grpc-web | Native |
|
|
275
|
+
| Tools | Limited | Extensive |
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Related Skills
|
|
279
|
+
|
|
280
|
+
- `grpc-spring`: Spring Boot gRPC implementation
|
|
281
|
+
- `apigen-architecture`: Overall system architecture
|
|
282
|
+
|
|
283
|
+
|