bmad-method-quarkus 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +53 -0
- package/AGENTS.md +12 -0
- package/LICENSE +30 -0
- package/README.md +94 -0
- package/README_CN.md +108 -0
- package/README_VN.md +109 -0
- package/bmad-modules.yaml +133 -0
- package/package.json +123 -0
- package/removals.txt +87 -0
- package/src/bmm-skills/agents/bmad-agent-analyst/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-analyst/customize.toml +105 -0
- package/src/bmm-skills/agents/bmad-agent-architect/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-architect/customize.toml +65 -0
- package/src/bmm-skills/agents/bmad-agent-dev/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-dev/customize.toml +83 -0
- package/src/bmm-skills/agents/bmad-agent-pm/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-pm/customize.toml +75 -0
- package/src/bmm-skills/agents/bmad-agent-ux-designer/SKILL.md +76 -0
- package/src/bmm-skills/agents/bmad-agent-ux-designer/customize.toml +60 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md +12 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/.memlog.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md +86 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml +37 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/customize.toml:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md +19 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/enrich-stories.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md +79 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/references/prompt-quality-canon.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md +80 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv +9 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module-help.csv:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml +16 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/assets/module.yaml:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py +287 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/cleanup-legacy.py:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py +441 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-config.py:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py +246 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/bqa-setup/scripts/merge-help-csv.py:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md +181 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-error-handling-i18n/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md +141 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-grpc-services/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md +392 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-hexagonal-core/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md +148 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-kafka-messaging/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md +180 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-observability-otel/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md +128 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-openapi-tmforum/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md +245 -0
- package/src/bmm-skills/agents/bmad-quarkus-architect/skills/quarkus-sql-jdbc-agroal/SKILL.md:Zone.Identifier +0 -0
- package/src/bmm-skills/module-help.csv +19 -0
- package/src/bmm-skills/module.yaml +92 -0
- package/src/bmm-skills/plan/bmad-architecture/SKILL.md +85 -0
- package/src/bmm-skills/plan/bmad-architecture/assets/spine-template.md +79 -0
- package/src/bmm-skills/plan/bmad-architecture/customize.toml +102 -0
- package/src/bmm-skills/plan/bmad-architecture/references/headless.md +26 -0
- package/src/bmm-skills/plan/bmad-architecture/references/reviewer-gate.md +13 -0
- package/src/bmm-skills/plan/bmad-architecture/scripts/lint_spine.py +257 -0
- package/src/bmm-skills/plan/bmad-architecture/scripts/tests/test_lint_spine.py +270 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/SKILL.md +93 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/customize.toml +41 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-01-validate-prerequisites.md +263 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-02-design-epics.md +242 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/steps/step-04-final-validation.md +143 -0
- package/src/bmm-skills/plan/bmad-create-epics-and-stories/templates/epics-template.md +61 -0
- package/src/bmm-skills/plan/bmad-generate-project-context/SKILL.md +10 -0
- package/src/bmm-skills/plan/bmad-prd/SKILL.md +94 -0
- package/src/bmm-skills/plan/bmad-prd/assets/headless-schemas.md +76 -0
- package/src/bmm-skills/plan/bmad-prd/assets/prd-template.md +165 -0
- package/src/bmm-skills/plan/bmad-prd/assets/prd-validation-checklist.md +135 -0
- package/src/bmm-skills/plan/bmad-prd/assets/validation-report-template.html +325 -0
- package/src/bmm-skills/plan/bmad-prd/customize.toml +149 -0
- package/src/bmm-skills/plan/bmad-prd/references/headless.md +39 -0
- package/src/bmm-skills/plan/bmad-prd/references/validate.md +97 -0
- package/src/bmm-skills/plan/bmad-prfaq/SKILL.md +135 -0
- package/src/bmm-skills/plan/bmad-prfaq/agents/artifact-analyzer.md +60 -0
- package/src/bmm-skills/plan/bmad-prfaq/agents/web-researcher.md +49 -0
- package/src/bmm-skills/plan/bmad-prfaq/assets/prfaq-template.md +62 -0
- package/src/bmm-skills/plan/bmad-prfaq/bmad-manifest.json +16 -0
- package/src/bmm-skills/plan/bmad-prfaq/customize.toml +41 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/customer-faq.md +55 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/internal-faq.md +51 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/press-release.md +60 -0
- package/src/bmm-skills/plan/bmad-prfaq/references/verdict.md +83 -0
- package/src/bmm-skills/plan/bmad-product-brief/SKILL.md +91 -0
- package/src/bmm-skills/plan/bmad-product-brief/assets/brief-template.md +41 -0
- package/src/bmm-skills/plan/bmad-product-brief/customize.toml +101 -0
- package/src/bmm-skills/plan/bmad-project-context/SKILL.md +110 -0
- package/src/bmm-skills/plan/bmad-project-context/customize.toml +24 -0
- package/src/bmm-skills/plan/bmad-project-context/references/best-practices.md +65 -0
- package/src/bmm-skills/plan/bmad-project-context/references/template.md +55 -0
- package/src/bmm-skills/plan/bmad-spec/SKILL.md +160 -0
- package/src/bmm-skills/plan/bmad-spec/assets/headless-schemas.md +33 -0
- package/src/bmm-skills/plan/bmad-spec/assets/spec-template.md +49 -0
- package/src/bmm-skills/plan/bmad-spec/assets/stories-schema.md +44 -0
- package/src/bmm-skills/plan/bmad-spec/customize.toml +52 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/SKILL.md +62 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/customize.toml +41 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/fix-sprint-status.md +30 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/generate-tracking.md +25 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/readiness-gate.md +20 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/status-view.md +14 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/references/validate.md +10 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/sprint_plan.py +697 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/test_sprint_plan.py +524 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/sprint-status-template.yaml +71 -0
- package/src/bmm-skills/plan/bmad-ux/SKILL.md +90 -0
- package/src/bmm-skills/plan/bmad-ux/assets/color-themes.md +9 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-directions.md +9 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-example-editorial.md +158 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-example-mobile.md +93 -0
- package/src/bmm-skills/plan/bmad-ux/assets/design-example-shadcn.md +109 -0
- package/src/bmm-skills/plan/bmad-ux/assets/excalidraw-wireframe.md +19 -0
- package/src/bmm-skills/plan/bmad-ux/assets/experience-example-mobile.md +112 -0
- package/src/bmm-skills/plan/bmad-ux/assets/experience-example-shadcn.md +133 -0
- package/src/bmm-skills/plan/bmad-ux/assets/headless-schemas.md +84 -0
- package/src/bmm-skills/plan/bmad-ux/assets/key-screens.md +29 -0
- package/src/bmm-skills/plan/bmad-ux/assets/validation-report-template.html +319 -0
- package/src/bmm-skills/plan/bmad-ux/customize.toml +102 -0
- package/src/bmm-skills/plan/bmad-ux/references/creative-tools.md +19 -0
- package/src/bmm-skills/plan/bmad-ux/references/design-md-spec.md +50 -0
- package/src/bmm-skills/plan/bmad-ux/references/headless.md +37 -0
- package/src/bmm-skills/plan/bmad-ux/references/validate.md +115 -0
- package/src/bmm-skills/ship/bmad-build/SKILL.md +13 -0
- package/src/bmm-skills/ship/bmad-build/compile-epic-context.md +62 -0
- package/src/bmm-skills/ship/bmad-build/customize.toml +164 -0
- package/src/bmm-skills/ship/bmad-build/references/deletion-check.md +14 -0
- package/src/bmm-skills/ship/bmad-build/review-prompts/edge-case-hunter.md +88 -0
- package/src/bmm-skills/ship/bmad-build/review-prompts/verification-gap.md +113 -0
- package/src/bmm-skills/ship/bmad-build/spec-template.md +89 -0
- package/src/bmm-skills/ship/bmad-build/step-01-clarify-and-route.md +105 -0
- package/src/bmm-skills/ship/bmad-build/step-02-plan.md +47 -0
- package/src/bmm-skills/ship/bmad-build/step-03-implement.md +49 -0
- package/src/bmm-skills/ship/bmad-build/step-04-review.md +55 -0
- package/src/bmm-skills/ship/bmad-build/step-05-present.md +75 -0
- package/src/bmm-skills/ship/bmad-build/step-oneshot.md +77 -0
- package/src/bmm-skills/ship/bmad-build/sync-sprint-status.md +19 -0
- package/src/bmm-skills/ship/bmad-build/workflow.md +84 -0
- package/src/bmm-skills/ship/bmad-build-auto/SKILL.md +13 -0
- package/src/bmm-skills/ship/bmad-build-auto/compile-epic-context.md +62 -0
- package/src/bmm-skills/ship/bmad-build-auto/customize.toml +121 -0
- package/src/bmm-skills/ship/bmad-build-auto/references/deletion-check.md +14 -0
- package/src/bmm-skills/ship/bmad-build-auto/review-prompts/edge-case-hunter.md +88 -0
- package/src/bmm-skills/ship/bmad-build-auto/review-prompts/verification-gap.md +113 -0
- package/src/bmm-skills/ship/bmad-build-auto/spec-template.md +99 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-01-clarify-and-route.md +83 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-02-plan.md +27 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-03-implement.md +44 -0
- package/src/bmm-skills/ship/bmad-build-auto/step-04-review.md +96 -0
- package/src/bmm-skills/ship/bmad-build-auto/workflow.md +104 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/SKILL.md +68 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/generate-trail.md +38 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-01-orientation.md +105 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-02-walkthrough.md +89 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-03-detail-pass.md +106 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-04-testing.md +74 -0
- package/src/bmm-skills/ship/bmad-checkpoint-preview/step-05-wrapup.md +30 -0
- package/src/bmm-skills/ship/bmad-code-review/SKILL.md +90 -0
- package/src/bmm-skills/ship/bmad-code-review/customize.toml +113 -0
- package/src/bmm-skills/ship/bmad-code-review/references/deletion-check.md +14 -0
- package/src/bmm-skills/ship/bmad-code-review/review-prompts/edge-case-hunter.md +88 -0
- package/src/bmm-skills/ship/bmad-code-review/review-prompts/verification-gap.md +113 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-01-gather-context.md +87 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-02-review.md +32 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-03-triage.md +50 -0
- package/src/bmm-skills/ship/bmad-code-review/steps/step-04-present.md +132 -0
- package/src/bmm-skills/ship/bmad-correct-course/SKILL.md +300 -0
- package/src/bmm-skills/ship/bmad-correct-course/checklist.md +288 -0
- package/src/bmm-skills/ship/bmad-correct-course/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/SKILL.md +176 -0
- package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/checklist.md +33 -0
- package/src/bmm-skills/ship/bmad-qa-generate-e2e-tests/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-retrospective/SKILL.md +94 -0
- package/src/bmm-skills/ship/bmad-retrospective/customize.toml +41 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/acceptance-verdict.md +55 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/aggregate-views.md +17 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/evidence-gathering.md +30 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/retro-document.md +84 -0
- package/src/bmm-skills/ship/bmad-retrospective/references/team-discussion.md +22 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/git_evidence.py +304 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/sprint_status.py +746 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/fixtures/sprint-status-template.yaml +71 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_git_evidence.py +750 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/test_sprint_status.py +1579 -0
- package/src/bmm-skills/v6-shims/README.md +28 -0
- package/src/bmm-skills/v6-shims/bmad-create-architecture/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-create-architecture/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-create-prd/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-create-prd/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/SKILL.md +434 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/checklist.md +357 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/discover-inputs.md +88 -0
- package/src/bmm-skills/v6-shims/bmad-create-story/template.md +49 -0
- package/src/bmm-skills/v6-shims/bmad-dev-auto/SKILL.md +19 -0
- package/src/bmm-skills/v6-shims/bmad-dev-story/SKILL.md +502 -0
- package/src/bmm-skills/v6-shims/bmad-dev-story/checklist.md +80 -0
- package/src/bmm-skills/v6-shims/bmad-dev-story/customize.toml +44 -0
- package/src/bmm-skills/v6-shims/bmad-document-project/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-domain-research/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-edit-prd/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-edit-prd/customize.toml +42 -0
- package/src/bmm-skills/v6-shims/bmad-market-research/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-quick-dev/SKILL.md +19 -0
- package/src/bmm-skills/v6-shims/bmad-sprint-status/SKILL.md +26 -0
- package/src/bmm-skills/v6-shims/bmad-sprint-status/customize.toml +41 -0
- package/src/bmm-skills/v6-shims/bmad-technical-research/SKILL.md +14 -0
- package/src/bmm-skills/v6-shims/bmad-validate-prd/SKILL.md +30 -0
- package/src/bmm-skills/v6-shims/bmad-validate-prd/customize.toml +42 -0
- package/src/core-skills/bmad-advanced-elicitation/SKILL.md +65 -0
- package/src/core-skills/bmad-advanced-elicitation/assets/methods.csv +72 -0
- package/src/core-skills/bmad-advanced-elicitation/customize.toml +54 -0
- package/src/core-skills/bmad-advanced-elicitation/scripts/pick_methods.py +233 -0
- package/src/core-skills/bmad-advanced-elicitation/scripts/tests/test_pick_methods.py +228 -0
- package/src/core-skills/bmad-brainstorming/SKILL.md +80 -0
- package/src/core-skills/bmad-brainstorming/assets/brain-icons.json +166 -0
- package/src/core-skills/bmad-brainstorming/assets/brain-methods.csv +109 -0
- package/src/core-skills/bmad-brainstorming/assets/brain-selector.html +328 -0
- package/src/core-skills/bmad-brainstorming/customize.toml +84 -0
- package/src/core-skills/bmad-brainstorming/references/converge.md +24 -0
- package/src/core-skills/bmad-brainstorming/references/finalize.md +26 -0
- package/src/core-skills/bmad-brainstorming/references/headless.md +54 -0
- package/src/core-skills/bmad-brainstorming/references/in-chat-techniques.md +18 -0
- package/src/core-skills/bmad-brainstorming/references/mode-autonomous.md +10 -0
- package/src/core-skills/bmad-brainstorming/references/mode-facilitator.md +11 -0
- package/src/core-skills/bmad-brainstorming/references/mode-partner.md +16 -0
- package/src/core-skills/bmad-brainstorming/references/resume.md +5 -0
- package/src/core-skills/bmad-brainstorming/scripts/brain.py +770 -0
- package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +239 -0
- package/src/core-skills/bmad-customize/SKILL.md +111 -0
- package/src/core-skills/bmad-customize/scripts/list_customizable_skills.py +231 -0
- package/src/core-skills/bmad-customize/scripts/tests/test_list_customizable_skills.py +249 -0
- package/src/core-skills/bmad-deep-recon/SKILL.md +82 -0
- package/src/core-skills/bmad-deep-recon/assets/research.template.md +18 -0
- package/src/core-skills/bmad-deep-recon/customize.toml +212 -0
- package/src/core-skills/bmad-deep-recon/references/draft.md +8 -0
- package/src/core-skills/bmad-deep-recon/references/finalize.md +11 -0
- package/src/core-skills/bmad-deep-recon/references/html-briefing.md +16 -0
- package/src/core-skills/bmad-deep-recon/references/lifecycle.md +11 -0
- package/src/core-skills/bmad-deep-recon/references/process.md +10 -0
- package/src/core-skills/bmad-deep-recon/references/run.md +73 -0
- package/src/core-skills/bmad-deep-recon/references/selection.md +13 -0
- package/src/core-skills/bmad-deep-recon/references/synthesis.md +16 -0
- package/src/core-skills/bmad-deep-recon/references/verification.md +29 -0
- package/src/core-skills/bmad-deep-recon/scripts/recon_kit.py +322 -0
- package/src/core-skills/bmad-deep-recon/scripts/tests/test_recon_kit.py +144 -0
- package/src/core-skills/bmad-deep-recon/types/academic-lit.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/competitive.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/domain.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/market.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/technical.md +19 -0
- package/src/core-skills/bmad-deep-recon/types/user-voice.md +19 -0
- package/src/core-skills/bmad-forge-idea/SKILL.md +107 -0
- package/src/core-skills/bmad-forge-idea/customize.toml +42 -0
- package/src/core-skills/bmad-forge-idea/scripts/resolve_personas.py +275 -0
- package/src/core-skills/bmad-forge-idea/scripts/tests/test_resolve_personas.py +138 -0
- package/src/core-skills/bmad-help/SKILL.md +75 -0
- package/src/core-skills/bmad-party-mode/SKILL.md +60 -0
- package/src/core-skills/bmad-party-mode/customize.toml +211 -0
- package/src/core-skills/bmad-party-mode/references/create-party.md +70 -0
- package/src/core-skills/bmad-party-mode/references/mode-agent-team.md +13 -0
- package/src/core-skills/bmad-party-mode/references/mode-auto.md +13 -0
- package/src/core-skills/bmad-party-mode/references/mode-subagent.md +31 -0
- package/src/core-skills/bmad-party-mode/references/party-memory.md +51 -0
- package/src/core-skills/bmad-party-mode/scripts/resolve_party.py +282 -0
- package/src/core-skills/bmad-party-mode/scripts/tests/test_resolve_party.py +146 -0
- package/src/core-skills/bmad-review/SKILL.md +49 -0
- package/src/core-skills/bmad-review/customize.toml +141 -0
- package/src/core-skills/bmad-review/references/editorial-common.md +56 -0
- package/src/core-skills/bmad-review/references/lens-adversarial.md +19 -0
- package/src/core-skills/bmad-review/references/lens-edge-case-hunter.md +54 -0
- package/src/core-skills/bmad-review/references/lens-prose.md +7 -0
- package/src/core-skills/bmad-review/references/lens-structure.md +9 -0
- package/src/core-skills/bmad-review/references/lens-verification-gap.md +92 -0
- package/src/core-skills/bmad-review/references/structure-models.md +44 -0
- package/src/core-skills/bmad-review/scripts/tests/test_word_metrics.py +62 -0
- package/src/core-skills/bmad-review/scripts/word_metrics.py +102 -0
- package/src/core-skills/module-help.csv +10 -0
- package/src/core-skills/module.yaml +38 -0
- package/src/core-skills/v6-shims/README.md +25 -0
- package/src/core-skills/v6-shims/bmad-editorial-review/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-editorial-review/customize.toml +31 -0
- package/src/core-skills/v6-shims/bmad-editorial-review-prose/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-editorial-review-structure/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-adversarial-general/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-edge-case-hunter/SKILL.md +6 -0
- package/src/core-skills/v6-shims/bmad-review-verification-gap/SKILL.md +6 -0
- package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
- package/src/scripts/config_utils.py +119 -0
- package/src/scripts/memlog.py +224 -0
- package/src/scripts/render_skill.py +401 -0
- package/src/scripts/resolve_config.py +74 -0
- package/src/scripts/resolve_customization.py +99 -0
- package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
- package/src/scripts/tests/test_config_utils.py +85 -0
- package/src/scripts/tests/test_memlog.py +306 -0
- package/src/scripts/tests/test_resolve_config.py +89 -0
- package/src/scripts/tests/test_resolve_customization.py +77 -0
- package/tools/bundle-web-bundles.js +117 -0
- package/tools/format-workflow-md.js +263 -0
- package/tools/installer/README.md +60 -0
- package/tools/installer/bmad-cli.js +105 -0
- package/tools/installer/cli-utils.js +57 -0
- package/tools/installer/commands/install.js +149 -0
- package/tools/installer/commands/status.js +65 -0
- package/tools/installer/commands/uninstall.js +167 -0
- package/tools/installer/core/config.js +73 -0
- package/tools/installer/core/existing-install.js +121 -0
- package/tools/installer/core/install-paths.js +132 -0
- package/tools/installer/core/installer.js +1767 -0
- package/tools/installer/core/legacy-warnings.js +151 -0
- package/tools/installer/core/manifest-generator.js +859 -0
- package/tools/installer/core/manifest.js +433 -0
- package/tools/installer/core/uv-check.js +195 -0
- package/tools/installer/core/wsl-node-check.js +109 -0
- package/tools/installer/file-ops.js +204 -0
- package/tools/installer/fs-native.js +116 -0
- package/tools/installer/ide/_config-driven.js +972 -0
- package/tools/installer/ide/manager.js +324 -0
- package/tools/installer/ide/platform-codes.js +80 -0
- package/tools/installer/ide/platform-codes.yaml +343 -0
- package/tools/installer/ide/shared/installed-skills.js +50 -0
- package/tools/installer/ide/shared/path-utils.js +219 -0
- package/tools/installer/ide/shared/skill-manifest.js +57 -0
- package/tools/installer/install-messages.yaml +37 -0
- package/tools/installer/list-options.js +210 -0
- package/tools/installer/message-loader.js +83 -0
- package/tools/installer/modules/channel-plan.js +203 -0
- package/tools/installer/modules/channel-resolver.js +241 -0
- package/tools/installer/modules/custom-module-manager.js +924 -0
- package/tools/installer/modules/external-manager.js +671 -0
- package/tools/installer/modules/git-env.js +47 -0
- package/tools/installer/modules/module-help-schema.js +13 -0
- package/tools/installer/modules/official-modules.js +2257 -0
- package/tools/installer/modules/plugin-resolver.js +398 -0
- package/tools/installer/modules/version-resolver.js +336 -0
- package/tools/installer/project-root.js +224 -0
- package/tools/installer/prompts.js +791 -0
- package/tools/installer/set-overrides.js +330 -0
- package/tools/installer/ui.js +2167 -0
- package/tools/installer/yaml-format.js +245 -0
- package/tools/javascript-conventions.md +5 -0
- package/tools/migrate-custom-module-paths.js +124 -0
- package/tools/skill-validator.md +378 -0
- package/tools/validate-published-implementation-model.mjs +68 -0
- package/tools/validate-sidebar-order.js +388 -0
- package/tools/validate-skills.js +735 -0
- package/tools/validate-svg-changes.sh +356 -0
- package/web-bundles/README.md +46 -0
- package/web-bundles/brainstorming-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/brainstorming-coach/SKILL.md +83 -0
- package/web-bundles/brainstorming-coach/brain-methods.csv +62 -0
- package/web-bundles/bundles.json +139 -0
- package/web-bundles/market-and-industry-research/INSTRUCTIONS.md +88 -0
- package/web-bundles/market-and-industry-research/SKILL.md +59 -0
- package/web-bundles/prd-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/prd-coach/SKILL.md +101 -0
- package/web-bundles/prd-coach/prd-template.md +165 -0
- package/web-bundles/prd-coach/prd-validation-checklist.md +135 -0
- package/web-bundles/prfaq-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/prfaq-coach/SKILL.md +139 -0
- package/web-bundles/product-brief-coach/INSTRUCTIONS.md +86 -0
- package/web-bundles/product-brief-coach/SKILL.md +113 -0
- package/web-bundles/ux-coach/INSTRUCTIONS.md +92 -0
- package/web-bundles/ux-coach/SKILL.md +187 -0
- package/web-bundles/ux-coach/ux-validation.md +100 -0
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: quarkus-hexagonal-core
|
|
3
|
+
description: Foundation for building Java + Quarkus backend services compiled to native binaries (GraalVM/Mandrel) with strict hexagonal architecture (ports & adapters). Applies to ANY Java/Quarkus backend project — DDD bounded contexts, standalone services, internal tools alike. Use this skill whenever creating, scaffolding, reviewing, or modifying ANY Quarkus backend service, module, REST/gRPC/Kafka adapter, repository, use case, or domain entity — even if the user only says "create a service", "add an endpoint", "new microservice", or "backend project". Also the canonical source for CLASS NAMING CONVENTIONS across all layers (entities, use cases, ports, adapters, DTOs, mappers, exceptions, tests), the domain-monorepo layout (apps/, libs/, contracts/, deploy/, db/, docs/), deployable app naming ({module}-{service}-ms, tenant-agnostic), and the mandatory per-app service.yaml + README.md documentation standard — consult it whenever naming/renaming any Java class, scaffolding an app folder, or writing service docs. Enforces Java 25, JDBC-only persistence via Agroal (NO Panache, NO Hibernate/ORM), ArchUnit boundary + naming tests, and native-image compatibility. Project-specific directives (CLAUDE.md, ADRs, explicit instructions) override this standard where they conflict.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Quarkus Hexagonal Core (Native-First)
|
|
7
|
+
|
|
8
|
+
Foundation skill for all backend services. Other skills in this set (error-handling-i18n, kafka-messaging, openapi-tmforum, grpc-services, observability-otel) build on the structure defined here — apply this one first when scaffolding.
|
|
9
|
+
|
|
10
|
+
**Scope & precedence:** these standards apply to any Java/Quarkus backend project, whether or not it is organized as DDD bounded contexts — where examples mention a BC code (`bc05`), read it as "short module/domain prefix". They are the default, not law: a project directive that says otherwise (CLAUDE.md, an ADR, an explicit user instruction) wins over this skill. When you deviate because of such a directive, follow the directive and mention which rule was overridden.
|
|
11
|
+
|
|
12
|
+
## Baseline constraints (unless a project directive overrides)
|
|
13
|
+
|
|
14
|
+
1. **Java 25 LTS** (`maven.compiler.release=25`). Records, sealed interfaces, pattern matching, virtual threads where blocking I/O is unavoidable.
|
|
15
|
+
2. **Native binary is the delivery artifact.** Every dependency and pattern must be GraalVM/Mandrel-compatible. Build with the Mandrel container image so builds don't depend on a local GraalVM.
|
|
16
|
+
3. **No ORM.** Persistence is plain JDBC through the Agroal datasource. No Panache, no Hibernate, no JPA annotations in any layer.
|
|
17
|
+
4. **Domain layer has zero framework imports.** No `jakarta.*`, no `io.quarkus.*`, no Jackson annotations in `domain`. Enforced by ArchUnit.
|
|
18
|
+
5. **Swagger UI only in dev/test** (see quarkus-openapi-tmforum skill).
|
|
19
|
+
|
|
20
|
+
## Monorepo layout (per domain/module)
|
|
21
|
+
|
|
22
|
+
One monorepo per domain (bounded context in DDD projects) holds its deployable apps plus internal libs. It never contains live environment/client configuration — the deployed state lives in the GitOps config repo.
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
/ (domain monorepo, e.g. wallet)
|
|
26
|
+
├── apps/ # deployable applications, one folder each
|
|
27
|
+
│ └── wallet-backend-core-ms/
|
|
28
|
+
│ ├── src/
|
|
29
|
+
│ ├── pom.xml
|
|
30
|
+
│ ├── Dockerfile # this app's image build (native)
|
|
31
|
+
│ ├── service.yaml # structured metadata — JSON-Schema validated in CI
|
|
32
|
+
│ └── README.md # per-app operational doc (see "Per-app documentation")
|
|
33
|
+
├── libs/ # modules shared within the domain
|
|
34
|
+
├── contracts/ # versioned API contracts (TMF/OpenAPI, JSON Schemas, protos)
|
|
35
|
+
├── deploy/ # k8s manifests, pipelines, observability-as-code
|
|
36
|
+
├── db/ # database migrations
|
|
37
|
+
├── docs/ # architecture, ADRs, runbooks
|
|
38
|
+
└── README.md # domain onboarding doc (see "Domain README")
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Deployable app naming (tenant-agnostic)
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
{module}-{service}-{type-suffix}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Suffixes: `-ms` (backend microservice — every Quarkus service here), `-mf` (microfrontend remote), `-module` (host/shell). Example: `wallet-backend-core-ms`. **Client and tenant never appear in app or code names** — they are runtime configuration (namespaces, labels, Helm values) applied at deploy time; the code is identical for every client and tenant.
|
|
48
|
+
|
|
49
|
+
## Package layout (per service/module)
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
com.<company>.<module> # <module> = BC code in DDD projects, service name otherwise
|
|
53
|
+
├── domain/ # PURE Java. Entities, value objects, domain events, domain services
|
|
54
|
+
│ ├── model/ # Records for VOs, sealed interfaces for events
|
|
55
|
+
│ ├── event/
|
|
56
|
+
│ └── exception/ # Domain exceptions with stable error codes
|
|
57
|
+
├── application/ # Use cases + ports. May use CDI annotations only (@ApplicationScoped)
|
|
58
|
+
│ ├── port/
|
|
59
|
+
│ │ ├── in/ # Inbound ports (use case interfaces)
|
|
60
|
+
│ │ └── out/ # Outbound ports (repository, publisher, external service interfaces)
|
|
61
|
+
│ └── usecase/ # One class per use case, implements inbound port
|
|
62
|
+
└── infrastructure/ # Adapters. All framework code lives here
|
|
63
|
+
├── rest/ # JAX-RS resources + DTOs + mappers (inbound adapter)
|
|
64
|
+
├── grpc/ # gRPC services (inbound) and clients (outbound)
|
|
65
|
+
├── persistence/ # JDBC repositories implementing out ports
|
|
66
|
+
├── messaging/ # Kafka producers/consumers, outbox
|
|
67
|
+
└── config/ # @ConfigMapping interfaces, CDI producers
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Rules of dependency: `infrastructure → application → domain`. Never the reverse. DTOs never leak into application/domain; map at the adapter boundary.
|
|
71
|
+
|
|
72
|
+
## Class naming conventions (canonical)
|
|
73
|
+
|
|
74
|
+
These names are the standard for ALL services and all sibling skills. A class name must reveal its layer and role without opening the file. Identifiers, packages, SQL objects and comments are **English only** — Spanish appears only in i18n message bundles and user-facing text (see quarkus-error-handling-i18n skill).
|
|
75
|
+
|
|
76
|
+
### Domain layer (`domain`)
|
|
77
|
+
|
|
78
|
+
| Artifact | Convention | Example |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| Entity / aggregate root | singular noun, no suffix | `User`, `Subscription` |
|
|
81
|
+
| Value object | singular noun record, no suffix | `Email`, `Money`, `Msisdn` |
|
|
82
|
+
| Typed identifier | `<Entity>Id` record | `UserId`, `SubscriptionId` |
|
|
83
|
+
| State enum | `<Entity>Status` | `UserStatus` |
|
|
84
|
+
| Domain event | past-tense verb phrase, **no** suffix | `UserRegistered`, `SubscriptionActivated` |
|
|
85
|
+
| Domain service / policy | `<Concept>Policy`, `<Concept>Calculator` | `PasswordPolicy`, `PricingCalculator` |
|
|
86
|
+
| Domain exception | `<Thing><Problem>Exception` | `UserNotFoundException`, `DuplicateEmailException` |
|
|
87
|
+
| Exception base | `DomainException` | |
|
|
88
|
+
|
|
89
|
+
`*Service` is **never** used in the domain layer — a domain service is a policy, a calculator or a factory, and saying so beats a generic suffix.
|
|
90
|
+
|
|
91
|
+
### Application layer (`application`)
|
|
92
|
+
|
|
93
|
+
| Artifact | Convention | Example |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| Inbound port (`port/in`) | `<Verb><Entity>UseCase` — always an interface | `RegisterUserUseCase`, `GetUserUseCase` |
|
|
96
|
+
| Use case implementation (`usecase`) | `<Verb><Entity>Service` | `RegisterUserService` |
|
|
97
|
+
| Command (write input) | `<Verb><Entity>Command` | `RegisterUserCommand` |
|
|
98
|
+
| Query (read input) | `<Verb><Entity>Query` | `FindUsersQuery` |
|
|
99
|
+
| Use case output | `<Verb><Entity>Result` | `RegisterUserResult` |
|
|
100
|
+
| Outbound port — persistence | `<Entity>Repository` | `UserRepository` |
|
|
101
|
+
| Outbound port — other capability | capability noun, **no technology** | `EventPublisher`, `CredentialsValidator`, `AuditRecorder` |
|
|
102
|
+
|
|
103
|
+
One use case per class, one public method named after the verb (`register`, `getById`). The `*Service` suffix is **reserved** for use-case implementations in `application/usecase` (plus proto-generated gRPC stubs); it never appears on repositories, mappers or helper classes.
|
|
104
|
+
|
|
105
|
+
### Infrastructure layer (`infrastructure`)
|
|
106
|
+
|
|
107
|
+
**Inbound (driving) adapters — suffixed by transport:**
|
|
108
|
+
|
|
109
|
+
| Adapter | Convention | Example |
|
|
110
|
+
|---|---|---|
|
|
111
|
+
| REST resource | `<Resource>Resource` | `UserResource`, `DigitalIdentityResource` |
|
|
112
|
+
| gRPC endpoint | `<ProtoService>GrpcService` | `UserGrpcService` |
|
|
113
|
+
| Kafka consumer | `<Event>Consumer` | `UserRegisteredConsumer` |
|
|
114
|
+
| Scheduled job | `<Task>Job` | `OutboxRelayJob` |
|
|
115
|
+
|
|
116
|
+
**Outbound (driven) adapters — prefixed by technology, keeping the port name:**
|
|
117
|
+
|
|
118
|
+
| Adapter | Convention | Example |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| JDBC repository | `Jdbc<Port>` | `JdbcUserRepository` |
|
|
121
|
+
| Outbox / Kafka publisher | `Outbox<Port>`, `Kafka<Port>` | `OutboxEventPublisher` |
|
|
122
|
+
| gRPC client adapter | `Grpc<Port>` | `GrpcCredentialsValidator` |
|
|
123
|
+
| REST client adapter | `Rest<Port>` | `RestPaymentGateway` |
|
|
124
|
+
|
|
125
|
+
The port says *what*, the prefix says *with what* — so a second implementation (`InMemoryUserRepository` in tests) reads naturally.
|
|
126
|
+
|
|
127
|
+
**Supporting classes:**
|
|
128
|
+
|
|
129
|
+
| Artifact | Convention | Example |
|
|
130
|
+
|---|---|---|
|
|
131
|
+
| REST DTO | `<Resource>Dto`, `<Resource>CreateDto`, `<Resource>UpdateDto` | `DigitalIdentityCreateDto` |
|
|
132
|
+
| Kafka payload DTO | `<Event>Payload` | `UserRegisteredPayload` |
|
|
133
|
+
| Mapper | `<Entity><Transport>Mapper` | `UserRestMapper`, `UserGrpcMapper`, `UserEventMapper` |
|
|
134
|
+
| Row mapper | `<Entity>RowMapper` | `UserRowMapper` |
|
|
135
|
+
| Config mapping | `<Area>Config` (`@ConfigMapping` interface) | `OutboxConfig` |
|
|
136
|
+
| Global handlers | `GlobalExceptionHandler`, `GrpcExceptionInterceptor` | |
|
|
137
|
+
| Technical exceptions | `PersistenceException`, `TransientPersistenceException`, `PersistenceTimeoutException`, `StaleVersionException` | |
|
|
138
|
+
|
|
139
|
+
The DTO ↔ domain distinction matters: `UserDto` lives in `infrastructure/rest/dto` and is what the wire sees; `User` is the domain entity. They are never the same class, even when the fields match today.
|
|
140
|
+
|
|
141
|
+
### Banned and reserved names
|
|
142
|
+
|
|
143
|
+
- Suffixes `*Impl`, `*Util`, `*Utils`, `*Helper`, `*Manager`, `*Handler` (the single `GlobalExceptionHandler` is the only sanctioned `*Handler`). If a class needs `Util`, it needs a real responsibility name.
|
|
144
|
+
- `*DTO` / `*VO` / `*Bean` / `*POJO` in all-caps or as decoration — the standard is `*Dto`.
|
|
145
|
+
- Names that shadow JDK or Jakarta types: never `ConcurrentModificationException` (use `StaleVersionException`), `Entity`, `Optional`, `Record`. An accidental `java.util` import silently changes behaviour.
|
|
146
|
+
- Abbreviations that are not org-wide vocabulary (`UsrRepo`, `SubsSvc`). Module/BC codes (`bc05`) are fine in packages and config, not in class names.
|
|
147
|
+
|
|
148
|
+
### Other identifiers (for reference)
|
|
149
|
+
|
|
150
|
+
| Kind | Convention | Example |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| Deployable app | `{module}-{service}-{type}` kebab-case, tenant-agnostic (`-ms` backend) | `wallet-backend-core-ms` |
|
|
153
|
+
| Package | lowercase, singular, no underscores | `com.alva.bc05.application.usecase` |
|
|
154
|
+
| Constant | `UPPER_SNAKE_CASE` | `FIND_BY_ID` |
|
|
155
|
+
| SQL table / column | `snake_case`, singular table | `app_user`, `created_at` |
|
|
156
|
+
| Test class | `<Class>Test` (unit/`@QuarkusTest`), `<Class>IT` (`@QuarkusIntegrationTest`), `ArchitectureTest` | `JdbcUserRepositoryTest` |
|
|
157
|
+
| Proto | `PascalCase` messages/services, `snake_case` fields | `GetUserRequest`, `user_id` |
|
|
158
|
+
| Kafka topic / channel | see quarkus-kafka-messaging skill | `alva.bc05.user.registered.v1` |
|
|
159
|
+
| Error code | `<MOD>-<HTTP>-<seq>` (`<MOD>` = short module/domain code) | `USR-404-001` |
|
|
160
|
+
|
|
161
|
+
## Scaffolding checklist
|
|
162
|
+
|
|
163
|
+
When creating a new service:
|
|
164
|
+
|
|
165
|
+
1. App folder `apps/<module>-<service>-ms/` per the monorepo layout above.
|
|
166
|
+
2. `pom.xml` with BOM `io.quarkus.platform:quarkus-bom` (latest 3.x LTS), extensions: `quarkus-rest`, `quarkus-rest-jackson`, `quarkus-agroal`, `quarkus-jdbc-postgresql`, `quarkus-arc`, `quarkus-smallrye-health`, `quarkus-flyway` (schema migrations), plus skills-specific extensions as needed.
|
|
167
|
+
3. `application.properties` baseline (below).
|
|
168
|
+
4. ArchUnit test (below) — add it in the same commit as the first class, not later.
|
|
169
|
+
5. Native profile using Mandrel container build.
|
|
170
|
+
6. `Dockerfile` at the app root, based on `quay.io/quarkus/quarkus-micro-image` (or distroless) running the native binary.
|
|
171
|
+
7. `service.yaml` + per-app `README.md` (below) — in the same PR as the first endpoint, not later; CI blocks merges without them.
|
|
172
|
+
|
|
173
|
+
### application.properties baseline
|
|
174
|
+
|
|
175
|
+
```properties
|
|
176
|
+
quarkus.datasource.db-kind=postgresql
|
|
177
|
+
quarkus.datasource.jdbc.max-size=16
|
|
178
|
+
quarkus.flyway.migrate-at-start=true
|
|
179
|
+
|
|
180
|
+
# Native build via Mandrel container (no local GraalVM needed)
|
|
181
|
+
quarkus.native.container-build=true
|
|
182
|
+
quarkus.native.builder-image=mandrel
|
|
183
|
+
|
|
184
|
+
quarkus.http.port=8080
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Maven native profile
|
|
188
|
+
|
|
189
|
+
```xml
|
|
190
|
+
<profile>
|
|
191
|
+
<id>native</id>
|
|
192
|
+
<activation><property><name>native</name></property></activation>
|
|
193
|
+
<properties>
|
|
194
|
+
<quarkus.native.enabled>true</quarkus.native.enabled>
|
|
195
|
+
<skipITs>false</skipITs>
|
|
196
|
+
</properties>
|
|
197
|
+
</profile>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Build: `./mvnw package -Dnative` → binary in `target/*-runner`.
|
|
201
|
+
|
|
202
|
+
## Per-app documentation (mandatory, blocking)
|
|
203
|
+
|
|
204
|
+
Every deployable under `apps/<app>/` carries two files, versioned with the code and updated in the **same PR** that changes the service's behavior:
|
|
205
|
+
|
|
206
|
+
- **`service.yaml`** — structured metadata validated against a JSON Schema in CI: identity (domain, system, component type, lifecycle), ownership (team, SRE, support group), criticality, tenancy (model, data isolation), runtime (type, version, ports), provided APIs with their contract files in `contracts/`, dependencies with `hard`/`soft` requirement, and the observability contract (log format, levels, required fields, data-protection rules). It feeds the service catalog and the dependency map.
|
|
207
|
+
- **`README.md`** (per app) — operational doc written so a system administrator who has never seen the code can configure, deploy and recover the service. No `TBD` / "see code" (a justified `N/A` is allowed). No manual changelog section — Git keeps the history.
|
|
208
|
+
|
|
209
|
+
Required `README.md` sections:
|
|
210
|
+
|
|
211
|
+
1. **Identity** — app name, module (`part-of`), type (`ms`), owning team, repository, criticality, part of core yes/no
|
|
212
|
+
2. **Purpose & responsibility** — description + out of scope
|
|
213
|
+
3. **Tenancy model** — `shared` | `per-tenant` | `pool`; tenant identification (validated JWT claim, never a free header); data isolation; per-tenant parameters
|
|
214
|
+
4. **APIs exposed** — table: api/version, protocol, route/topic, contract file, auth, visibility
|
|
215
|
+
5. **Dependencies** — table: name, type, criticality (`hard`|`soft`), timeout/retry, behavior if down
|
|
216
|
+
6. **Data & persistence** — engine, database/schema, tenant isolation, migrations (`db/`), cache, events
|
|
217
|
+
7. **Configuration** — table: variable, description, type, required, default, varies-by (`environment`|`client`|`tenant`)
|
|
218
|
+
8. **Secrets** — table: logical name, what it is, source (vault), who provides it, rotation period — **never the value**
|
|
219
|
+
9. **Runtime & resources** — runtime/version, ports, requests/limits, replicas/HPA
|
|
220
|
+
10. **Health checks** — liveness; readiness = **hard dependencies only**; startup probe
|
|
221
|
+
11. **Deployment dependencies** — classified: startup / readiness-critical / hard runtime / soft runtime
|
|
222
|
+
12. **Observability** — configurable log levels (`TRACE`–`FATAL`), the ConfigMap variable holding `logging_level`, its default, JSON log format
|
|
223
|
+
13. **GitOps deployment** — location in the config repo, delivery strategy, feature flags
|
|
224
|
+
14. **Rollback & recovery** — procedure, reversible migrations (N/N-1 compatible), RTO/RPO
|
|
225
|
+
15. **Post-deploy validation** — smoke tests, contract tests, tenant-isolation tests
|
|
226
|
+
16. **Troubleshooting** — symptom → cause → diagnosis
|
|
227
|
+
|
|
228
|
+
Rule of completeness: if a variable, secret or dependency is not documented here, it does not exist — CI validates the `service.yaml` schema and the mandatory `README.md` sections as a blocking gate.
|
|
229
|
+
|
|
230
|
+
### Domain README (repo root)
|
|
231
|
+
|
|
232
|
+
The monorepo root `README.md` is the onboarding doc for the domain, and the owning team keeps it current:
|
|
233
|
+
|
|
234
|
+
- **Identity table** — product, domain/bounded context, description, part of core, owning team, tech lead, SRE responsible, predominant criticality, predominant tenancy model, status, project, related GitOps repo.
|
|
235
|
+
- **Responsibility & limits** — what the domain owns, what is explicitly out of scope, and a table of dependencies on other domains/systems (type, use, `hard`/`soft`).
|
|
236
|
+
- **Deployable applications table** — one row per app: type, purpose, runtime, links to its `apps/<app>/README.md` and `service.yaml`.
|
|
237
|
+
|
|
238
|
+
It never documents live environment or client configuration — the deployed state per environment/client is managed in the GitOps config repo.
|
|
239
|
+
|
|
240
|
+
## Persistence pattern (JDBC + Agroal)
|
|
241
|
+
|
|
242
|
+
Full standard (pool config, transactions, batches, jsonb, pagination, SQLException translation) lives in the **quarkus-sql-jdbc-agroal** skill — consult it for any repository work. Summary of the shape:
|
|
243
|
+
|
|
244
|
+
Outbound port in `application/port/out`:
|
|
245
|
+
|
|
246
|
+
```java
|
|
247
|
+
public interface UserRepository {
|
|
248
|
+
Optional<User> findById(UserId id);
|
|
249
|
+
void save(User user);
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Adapter in `infrastructure/persistence`:
|
|
254
|
+
|
|
255
|
+
```java
|
|
256
|
+
@ApplicationScoped
|
|
257
|
+
public class JdbcUserRepository implements UserRepository {
|
|
258
|
+
|
|
259
|
+
private final AgroalDataSource ds;
|
|
260
|
+
|
|
261
|
+
public JdbcUserRepository(AgroalDataSource ds) { this.ds = ds; }
|
|
262
|
+
|
|
263
|
+
@Override
|
|
264
|
+
public Optional<User> findById(UserId id) {
|
|
265
|
+
var sql = "SELECT id, email, status, created_at FROM app_user WHERE id = ?";
|
|
266
|
+
try (var con = ds.getConnection(); var ps = con.prepareStatement(sql)) {
|
|
267
|
+
ps.setObject(1, id.value());
|
|
268
|
+
try (var rs = ps.executeQuery()) {
|
|
269
|
+
return rs.next() ? Optional.of(mapRow(rs)) : Optional.empty();
|
|
270
|
+
}
|
|
271
|
+
} catch (SQLException e) {
|
|
272
|
+
throw new PersistenceException("user.find_by_id", e);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// save(): use explicit transaction control or @Transactional on the use case
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Conventions:
|
|
280
|
+
- Constructor injection only (no field `@Inject`) — testable and native-friendly.
|
|
281
|
+
- SQL as constants or text blocks; never string concatenation with user input.
|
|
282
|
+
- Transactions: annotate the **use case** with `@Transactional` (from `quarkus-narayana-jta`) so the unit of work matches the business operation, not the repository call.
|
|
283
|
+
- Row mapping by hand or a small private `mapRow(ResultSet)` — no reflection-based mappers.
|
|
284
|
+
|
|
285
|
+
## Domain conventions
|
|
286
|
+
|
|
287
|
+
- Value objects = records with validation in a compact constructor.
|
|
288
|
+
- Entity identity = typed IDs (`record UserId(UUID value)`), never bare UUID/String in signatures.
|
|
289
|
+
- Domain events = sealed interface + records, named in past tense (`UserRegistered`).
|
|
290
|
+
- Domain exceptions carry a **stable error code** (used by the error-handling-i18n skill): `throw new UserNotFoundException(id)` where the exception exposes `code() -> "USR-404-001"`.
|
|
291
|
+
- Naming per the canonical table above — entities and events carry no suffix, ids are `<Entity>Id`, exceptions are `<Thing><Problem>Exception`.
|
|
292
|
+
|
|
293
|
+
## ArchUnit enforcement (mandatory)
|
|
294
|
+
|
|
295
|
+
`src/test/java/.../ArchitectureTest.java`:
|
|
296
|
+
|
|
297
|
+
```java
|
|
298
|
+
@AnalyzeClasses(packages = "com.company.bc")
|
|
299
|
+
class ArchitectureTest {
|
|
300
|
+
|
|
301
|
+
@ArchTest
|
|
302
|
+
static final ArchRule hexagonal = layeredArchitecture().consideringAllDependencies()
|
|
303
|
+
.layer("Domain").definedBy("..domain..")
|
|
304
|
+
.layer("Application").definedBy("..application..")
|
|
305
|
+
.layer("Infrastructure").definedBy("..infrastructure..")
|
|
306
|
+
.whereLayer("Domain").mayOnlyBeAccessedByLayers("Application", "Infrastructure")
|
|
307
|
+
.whereLayer("Application").mayOnlyBeAccessedByLayers("Infrastructure")
|
|
308
|
+
.whereLayer("Infrastructure").mayNotBeAccessedByAnyLayer();
|
|
309
|
+
|
|
310
|
+
@ArchTest
|
|
311
|
+
static final ArchRule domainIsPure = noClasses().that().resideInAPackage("..domain..")
|
|
312
|
+
.should().dependOnClassesThat().resideInAnyPackage(
|
|
313
|
+
"jakarta..", "io.quarkus..", "org.eclipse.microprofile..",
|
|
314
|
+
"com.fasterxml.jackson..", "io.smallrye..", "java.sql..");
|
|
315
|
+
|
|
316
|
+
@ArchTest
|
|
317
|
+
static final ArchRule noOrm = noClasses().should().dependOnClassesThat()
|
|
318
|
+
.resideInAnyPackage("jakarta.persistence..", "org.hibernate..", "io.quarkus.hibernate..");
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Naming rules (same test class)
|
|
323
|
+
|
|
324
|
+
Conventions that are not enforced decay within two sprints. Add these alongside the layer rules — `resideInAPackage` is statically imported from `JavaClass.Predicates`:
|
|
325
|
+
|
|
326
|
+
```java
|
|
327
|
+
@ArchTest
|
|
328
|
+
static final ArchRule inboundPorts = classes().that().resideInAPackage("..application.port.in..")
|
|
329
|
+
.should().beInterfaces()
|
|
330
|
+
.andShould().haveSimpleNameEndingWith("UseCase");
|
|
331
|
+
|
|
332
|
+
@ArchTest
|
|
333
|
+
static final ArchRule outboundPorts = classes().that().resideInAPackage("..application.port.out..")
|
|
334
|
+
.should().beInterfaces();
|
|
335
|
+
|
|
336
|
+
@ArchTest
|
|
337
|
+
static final ArchRule useCaseImpls = classes().that().resideInAPackage("..application.usecase..")
|
|
338
|
+
.should().haveSimpleNameEndingWith("Service")
|
|
339
|
+
.andShould().implement(resideInAPackage("..application.port.in.."));
|
|
340
|
+
|
|
341
|
+
@ArchTest
|
|
342
|
+
static final ArchRule serviceSuffixIsReserved = classes().that().haveSimpleNameEndingWith("Service")
|
|
343
|
+
.should().resideInAnyPackage("..application.usecase..", "..infrastructure.grpc..");
|
|
344
|
+
|
|
345
|
+
@ArchTest
|
|
346
|
+
static final ArchRule restResources = classes().that().areAnnotatedWith(Path.class)
|
|
347
|
+
.should().haveSimpleNameEndingWith("Resource")
|
|
348
|
+
.andShould().resideInAPackage("..infrastructure.rest..");
|
|
349
|
+
|
|
350
|
+
@ArchTest
|
|
351
|
+
static final ArchRule jdbcAdapters = classes().that().resideInAPackage("..infrastructure.persistence..")
|
|
352
|
+
.and().implement(resideInAPackage("..application.port.out.."))
|
|
353
|
+
.should().haveSimpleNameStartingWith("Jdbc");
|
|
354
|
+
|
|
355
|
+
@ArchTest
|
|
356
|
+
static final ArchRule dtosStayInAdapters = classes().that().haveSimpleNameEndingWith("Dto")
|
|
357
|
+
.should().resideInAPackage("..infrastructure..");
|
|
358
|
+
|
|
359
|
+
@ArchTest
|
|
360
|
+
static final ArchRule domainExceptions = classes().that().areAssignableTo(DomainException.class)
|
|
361
|
+
.should().haveSimpleNameEndingWith("Exception")
|
|
362
|
+
.andShould().resideInAPackage("..domain.exception..");
|
|
363
|
+
|
|
364
|
+
@ArchTest
|
|
365
|
+
static final ArchRule bannedSuffixes = noClasses().should().haveSimpleNameEndingWith("Impl")
|
|
366
|
+
.orShould().haveSimpleNameEndingWith("Util")
|
|
367
|
+
.orShould().haveSimpleNameEndingWith("Utils")
|
|
368
|
+
.orShould().haveSimpleNameEndingWith("Helper")
|
|
369
|
+
.orShould().haveSimpleNameEndingWith("Manager")
|
|
370
|
+
.orShould().haveSimpleNameEndingWith("DTO");
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Scope the analysis to your own packages (`@AnalyzeClasses(packages = "com.alva.bc05")`) so proto- and Quarkus-generated classes don't trip the suffix rules.
|
|
374
|
+
|
|
375
|
+
## Native-image survival rules
|
|
376
|
+
|
|
377
|
+
- Any class serialized by Jackson (DTOs, Kafka payloads) that is NOT touched by Quarkus build-time processing: annotate `@RegisterForReflection`.
|
|
378
|
+
- Resources (SQL files, i18n bundles, certs): declare in `quarkus.native.resources.includes` if read at runtime via classpath.
|
|
379
|
+
- Avoid libraries relying on dynamic proxies/bytecode generation at runtime. Prefer Quarkus extensions over raw libraries — extensions do build-time registration for you.
|
|
380
|
+
- Verify with a native integration test: `@QuarkusIntegrationTest` runs the same tests against the built binary. CI must run `./mvnw verify -Dnative` at least on release branches.
|
|
381
|
+
|
|
382
|
+
## Testing strategy
|
|
383
|
+
|
|
384
|
+
| Layer | Test type | Tools |
|
|
385
|
+
|---|---|---|
|
|
386
|
+
| domain | plain JUnit 5 unit tests, no Quarkus | JUnit, AssertJ |
|
|
387
|
+
| application | unit tests with mocked ports | Mockito |
|
|
388
|
+
| infrastructure/persistence | `@QuarkusTest` + Dev Services (Testcontainers Postgres) | REST Assured n/a |
|
|
389
|
+
| REST/gRPC adapters | `@QuarkusTest` + REST Assured / gRPC client | |
|
|
390
|
+
| native binary | `@QuarkusIntegrationTest` | |
|
|
391
|
+
|
|
392
|
+
Keep coverage meaningful: mutation testing (PIT) on domain + application layers is the quality gate, not raw line coverage.
|
|
Binary file
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: quarkus-kafka-messaging
|
|
3
|
+
description: Standard for asynchronous event-driven messaging with Apache Kafka in Quarkus native services — CloudEvents envelope, topic naming, transactional outbox, idempotent consumers, DLQ, and W3C trace context propagation. Use this skill whenever the user mentions Kafka, events, messaging, publish/subscribe, producers, consumers, outbox, domain events between services, SmallRye Reactive Messaging, or asynchronous integration between bounded contexts — even if they just say "emit an event" or "listen to a topic". Includes event, payload, consumer, publisher and channel naming conventions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Kafka Messaging Standard (Quarkus + SmallRye Reactive Messaging)
|
|
7
|
+
|
|
8
|
+
Events are the public contract between services (bounded contexts in DDD projects, but the standard applies to any Quarkus backend). Everything below is the default standard; a project directive (CLAUDE.md, ADR, explicit instruction) may override it — otherwise deviations require a change request.
|
|
9
|
+
|
|
10
|
+
Extension: `quarkus-messaging-kafka` (SmallRye Reactive Messaging). Native-compatible out of the box; payload classes need `@RegisterForReflection`.
|
|
11
|
+
|
|
12
|
+
## Topic naming
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
<org>.<module>.<entity>.<event-type>.v<major> # <module> = BC code or service name
|
|
16
|
+
alva.bc05.user.registered.v1
|
|
17
|
+
alva.bc01.subscription.status-changed.v2
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- Kebab-case segments, past-tense event types.
|
|
21
|
+
- Version bumps ONLY on breaking schema changes; additive fields do not bump.
|
|
22
|
+
- One entity type per topic. Partitioning key = entity id (guarantees per-entity ordering).
|
|
23
|
+
|
|
24
|
+
## Event envelope: CloudEvents 1.0 (binary mode)
|
|
25
|
+
|
|
26
|
+
Producers emit CloudEvents in **binary mode** (attributes as Kafka headers `ce_*`, payload = plain JSON body). SmallRye supports this natively:
|
|
27
|
+
|
|
28
|
+
```properties
|
|
29
|
+
mp.messaging.outgoing.user-registered.connector=smallrye-kafka
|
|
30
|
+
mp.messaging.outgoing.user-registered.topic=alva.bc05.user.registered.v1
|
|
31
|
+
mp.messaging.outgoing.user-registered.cloud-events=true
|
|
32
|
+
mp.messaging.outgoing.user-registered.cloud-events-source=//alva/bc05
|
|
33
|
+
mp.messaging.outgoing.user-registered.cloud-events-type=com.alva.bc05.user.registered.v1
|
|
34
|
+
mp.messaging.outgoing.user-registered.value.serializer=io.quarkus.kafka.client.serialization.ObjectMapperSerializer
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Required attributes: `id` (UUID, = outbox event id), `source`, `type`, `time`, `subject` (entity id). Mandatory custom header: `traceparent` (W3C — propagated automatically when OTel is enabled, see observability skill).
|
|
38
|
+
|
|
39
|
+
Payload schema:
|
|
40
|
+
- JSON, documented as JSON Schema stored in a `contracts/` repo folder per topic version.
|
|
41
|
+
- Payload = event facts, not full entity dumps. Include `entityId`, `occurredAt`, changed fields.
|
|
42
|
+
|
|
43
|
+
## Producing: transactional outbox (mandatory for domain events)
|
|
44
|
+
|
|
45
|
+
Never publish directly from a use case in the same breath as a DB write — dual-write problem. Standard:
|
|
46
|
+
|
|
47
|
+
1. Use case (in the SAME JDBC transaction as the state change) inserts into the outbox table.
|
|
48
|
+
2. A relay publishes to Kafka (Debezium outbox connector preferred; scheduled poller as fallback for environments without Kafka Connect).
|
|
49
|
+
|
|
50
|
+
Standard outbox table (one per service):
|
|
51
|
+
|
|
52
|
+
```sql
|
|
53
|
+
CREATE TABLE outbox_event (
|
|
54
|
+
id UUID PRIMARY KEY,
|
|
55
|
+
aggregate_type VARCHAR(64) NOT NULL, -- "user"
|
|
56
|
+
aggregate_id VARCHAR(64) NOT NULL, -- partition key
|
|
57
|
+
event_type VARCHAR(128) NOT NULL, -- "com.alva.bc05.user.registered.v1"
|
|
58
|
+
payload JSONB NOT NULL,
|
|
59
|
+
traceparent VARCHAR(64) NOT NULL, -- captured at insert time (W3C Trace Context)
|
|
60
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
61
|
+
published_at TIMESTAMPTZ NULL -- poller mode only
|
|
62
|
+
);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Payload traceability (mandatory):** besides the `traceparent` column (used by the relay to set the Kafka header), the `payload` jsonb itself must embed a `traceContext` block for audit and immutability:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"eventId": "evt-883920-a1",
|
|
70
|
+
"eventType": "ProductOrderStateChangeEvent",
|
|
71
|
+
"traceContext": {
|
|
72
|
+
"trace_id": "4bf92f3577b34da6a3ce929d0e0e4736",
|
|
73
|
+
"span_id": "00f067aa0ba902b7"
|
|
74
|
+
},
|
|
75
|
+
"event": { "productOrder": { "id": "6a43...", "state": "Acknowledged" } }
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Both `traceparent` and `traceContext` are captured at insert time from `Span.current().getSpanContext()` — manual construction of trace strings is prohibited (see quarkus-observability-otel skill).
|
|
80
|
+
|
|
81
|
+
The domain/application layer only knows an outbound port `EventPublisher.publish(DomainEvent e)`; the outbox insert is its JDBC adapter, `OutboxEventPublisher` in `infrastructure/messaging`.
|
|
82
|
+
|
|
83
|
+
Fire-and-forget technical messages (metrics, notifications with no consistency requirement) MAY use a direct `Emitter`:
|
|
84
|
+
|
|
85
|
+
```java
|
|
86
|
+
@Inject @Channel("audit-out") Emitter<AuditEventPayload> audit;
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Naming
|
|
90
|
+
|
|
91
|
+
Canonical rules in the quarkus-hexagonal-core skill; messaging specifics:
|
|
92
|
+
|
|
93
|
+
| Artifact | Convention | Example |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| Domain event | past tense, no suffix, in `domain/event` | `UserRegistered` |
|
|
96
|
+
| Wire payload DTO | `<Event>Payload`, in `infrastructure/messaging/dto` | `UserRegisteredPayload` |
|
|
97
|
+
| Outbound port | `EventPublisher` (capability, no technology) | |
|
|
98
|
+
| Publisher adapter | `Outbox<Port>` / `Kafka<Port>` | `OutboxEventPublisher` |
|
|
99
|
+
| Consumer | `<Event>Consumer` | `UserRegisteredConsumer` |
|
|
100
|
+
| Outbox relay job | `<Task>Job` | `OutboxRelayJob` |
|
|
101
|
+
| Event ↔ payload mapper | `<Entity>EventMapper` | `UserEventMapper` |
|
|
102
|
+
| SmallRye channel | `<entity>-<event>-in` / `-out`, kebab-case | `user-registered-in` |
|
|
103
|
+
| CloudEvents `type` | `<javaPackageStyle>.<entity>.<event>.v<major>` | `com.alva.bc05.user.registered.v1` |
|
|
104
|
+
|
|
105
|
+
Keep the domain event (`UserRegistered`) and the wire payload (`UserRegisteredPayload`) as separate classes even when their fields match: the domain event is free to change with the model, while the payload is a published contract versioned by topic. Never annotate the domain event with Jackson or `@RegisterForReflection` — that annotation belongs on the payload.
|
|
106
|
+
|
|
107
|
+
## Consuming
|
|
108
|
+
|
|
109
|
+
```java
|
|
110
|
+
@ApplicationScoped
|
|
111
|
+
public class UserRegisteredConsumer {
|
|
112
|
+
|
|
113
|
+
@Incoming("user-registered-in")
|
|
114
|
+
@Blocking // JDBC inside → run on worker thread (or virtual thread)
|
|
115
|
+
public void on(UserRegisteredPayload payload) { // wire DTO, not the domain event
|
|
116
|
+
// 1. idempotency check 2. delegate to use case 3. done
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```properties
|
|
122
|
+
mp.messaging.incoming.user-registered-in.connector=smallrye-kafka
|
|
123
|
+
mp.messaging.incoming.user-registered-in.topic=alva.bc05.user.registered.v1
|
|
124
|
+
mp.messaging.incoming.user-registered-in.group.id=${quarkus.application.name}
|
|
125
|
+
mp.messaging.incoming.user-registered-in.auto.offset.reset=earliest
|
|
126
|
+
mp.messaging.incoming.user-registered-in.failure-strategy=delayed-retry-then-dead-letter-queue
|
|
127
|
+
mp.messaging.incoming.user-registered-in.dead-letter-queue.topic=alva.bc05.user.registered.v1.dlq
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Rules:
|
|
131
|
+
- **Idempotency is mandatory**: `processed_event(consumer_group, event_id)` table checked/inserted in the same transaction as the side effects. Kafka is at-least-once; duplicates WILL happen.
|
|
132
|
+
- Consumer group = service name; stable across deployments.
|
|
133
|
+
- Failure strategy: bounded retries with delay, then DLQ topic `<topic>.dlq`. DLQ messages keep original headers plus `dead-letter-reason`. A DLQ must have an owner and an alert — never a silent graveyard.
|
|
134
|
+
- Poison-pill safety: deserialization failures also route to DLQ (`...deserialization-failure-handler` or failure strategy), never block the partition.
|
|
135
|
+
- Consumers validate against the payload's JSON Schema version; unknown additive fields are ignored (tolerant reader).
|
|
136
|
+
|
|
137
|
+
## Ordering & delivery semantics
|
|
138
|
+
|
|
139
|
+
- Per-entity ordering via partition key = aggregate id. No global ordering assumptions.
|
|
140
|
+
- Exactly-once is NOT assumed; design consumers idempotent instead of enabling Kafka transactions by default.
|
|
141
|
+
|
|
142
|
+
## Checklist for a new event
|
|
143
|
+
|
|
144
|
+
1. Define `<Event>Payload` record + JSON Schema in `contracts/`, name the topic and channel per convention.
|
|
145
|
+
2. Producer: outbox insert in use-case transaction; relay config.
|
|
146
|
+
3. `@RegisterForReflection` on the payload record (never on the domain event).
|
|
147
|
+
4. Consumer(s): idempotency table entry, DLQ topic + alert, `@Blocking` if JDBC.
|
|
148
|
+
5. Contract test: serialize/deserialize round-trip against the JSON Schema.
|