cfsa-antigravity 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/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,778 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: java
|
|
3
|
+
description: Modern Java development patterns (17+). Covers records, sealed classes, pattern matching, Spring Boot, streams, Optional, JUnit 5, Maven/Gradle, JPA, design patterns, exception handling, logging, and concurrent utilities.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Java Development Patterns
|
|
8
|
+
|
|
9
|
+
Expert guidance for writing modern, production-grade Java code. Covers Java 17+ features (records, sealed classes, pattern matching), Spring Boot patterns, the streams API, testing with JUnit 5, build tools, and the design patterns that make Java codebases maintainable at enterprise scale.
|
|
10
|
+
|
|
11
|
+
## When to Use This Skill
|
|
12
|
+
|
|
13
|
+
- Building enterprise applications with Spring Boot
|
|
14
|
+
- Writing microservices with REST or gRPC APIs
|
|
15
|
+
- Implementing domain-driven design with rich domain models
|
|
16
|
+
- Creating libraries with strong API contracts
|
|
17
|
+
- Building concurrent systems with Java's concurrency utilities
|
|
18
|
+
- Migrating legacy Java code to modern patterns
|
|
19
|
+
|
|
20
|
+
## Core Concepts
|
|
21
|
+
|
|
22
|
+
### 1. Modern Java Features (17+)
|
|
23
|
+
|
|
24
|
+
#### Records (Java 16+)
|
|
25
|
+
|
|
26
|
+
Immutable data carriers that eliminate boilerplate.
|
|
27
|
+
|
|
28
|
+
```java
|
|
29
|
+
// Record -- generates constructor, getters, equals, hashCode, toString
|
|
30
|
+
public record User(String name, String email, int age) {
|
|
31
|
+
|
|
32
|
+
// Compact constructor for validation
|
|
33
|
+
public User {
|
|
34
|
+
if (name == null || name.isBlank()) {
|
|
35
|
+
throw new IllegalArgumentException("Name must not be blank");
|
|
36
|
+
}
|
|
37
|
+
if (age < 0 || age > 150) {
|
|
38
|
+
throw new IllegalArgumentException("Age must be between 0 and 150");
|
|
39
|
+
}
|
|
40
|
+
email = email.toLowerCase();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Custom factory method
|
|
44
|
+
public static User of(String name, String email) {
|
|
45
|
+
return new User(name, email, 0);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Usage
|
|
50
|
+
var user = new User("Alice", "Alice@Example.com", 30);
|
|
51
|
+
System.out.println(user.name()); // "Alice"
|
|
52
|
+
System.out.println(user.email()); // "alice@example.com" (normalized)
|
|
53
|
+
|
|
54
|
+
// Records work well with pattern matching
|
|
55
|
+
if (obj instanceof User(String name, String email, int age)) {
|
|
56
|
+
System.out.println(name + " is " + age + " years old");
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### Sealed Classes (Java 17+)
|
|
61
|
+
|
|
62
|
+
Restricted class hierarchies for exhaustive pattern matching.
|
|
63
|
+
|
|
64
|
+
```java
|
|
65
|
+
public sealed interface Shape
|
|
66
|
+
permits Circle, Rectangle, Triangle {
|
|
67
|
+
|
|
68
|
+
double area();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public record Circle(double radius) implements Shape {
|
|
72
|
+
public double area() { return Math.PI * radius * radius; }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public record Rectangle(double width, double height) implements Shape {
|
|
76
|
+
public double area() { return width * height; }
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public record Triangle(double base, double height) implements Shape {
|
|
80
|
+
public double area() { return 0.5 * base * height; }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Exhaustive switch -- compiler verifies all cases handled
|
|
84
|
+
public static String describe(Shape shape) {
|
|
85
|
+
return switch (shape) {
|
|
86
|
+
case Circle c -> String.format("Circle with radius %.2f", c.radius());
|
|
87
|
+
case Rectangle r -> String.format("Rectangle %sx%s", r.width(), r.height());
|
|
88
|
+
case Triangle t -> String.format("Triangle with base %.2f", t.base());
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Pattern Matching (Java 21+)
|
|
94
|
+
|
|
95
|
+
```java
|
|
96
|
+
// Pattern matching for instanceof (Java 16+)
|
|
97
|
+
public static double getArea(Object obj) {
|
|
98
|
+
if (obj instanceof Circle c) {
|
|
99
|
+
return c.area();
|
|
100
|
+
} else if (obj instanceof Rectangle r) {
|
|
101
|
+
return r.area();
|
|
102
|
+
}
|
|
103
|
+
throw new IllegalArgumentException("Unknown shape: " + obj.getClass());
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Switch pattern matching with guards (Java 21+)
|
|
107
|
+
public static String classify(Object obj) {
|
|
108
|
+
return switch (obj) {
|
|
109
|
+
case Integer i when i < 0 -> "negative integer";
|
|
110
|
+
case Integer i when i == 0 -> "zero";
|
|
111
|
+
case Integer i -> "positive integer: " + i;
|
|
112
|
+
case String s when s.isBlank() -> "blank string";
|
|
113
|
+
case String s -> "string: " + s;
|
|
114
|
+
case null -> "null";
|
|
115
|
+
default -> "unknown: " + obj.getClass().getSimpleName();
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Record patterns (Java 21+)
|
|
120
|
+
public static String formatPoint(Object obj) {
|
|
121
|
+
return switch (obj) {
|
|
122
|
+
case Point(int x, int y) when x == 0 && y == 0 -> "origin";
|
|
123
|
+
case Point(int x, int y) -> String.format("(%d, %d)", x, y);
|
|
124
|
+
default -> "not a point";
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Text Blocks (Java 15+)
|
|
130
|
+
|
|
131
|
+
```java
|
|
132
|
+
// Multi-line strings with proper indentation
|
|
133
|
+
String json = """
|
|
134
|
+
{
|
|
135
|
+
"name": "%s",
|
|
136
|
+
"email": "%s",
|
|
137
|
+
"age": %d
|
|
138
|
+
}
|
|
139
|
+
""".formatted(user.name(), user.email(), user.age());
|
|
140
|
+
|
|
141
|
+
String sql = """
|
|
142
|
+
SELECT u.id, u.name, u.email
|
|
143
|
+
FROM users u
|
|
144
|
+
JOIN orders o ON u.id = o.user_id
|
|
145
|
+
WHERE o.status = 'active'
|
|
146
|
+
ORDER BY u.name
|
|
147
|
+
""";
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 2. Spring Boot Patterns
|
|
151
|
+
|
|
152
|
+
```java
|
|
153
|
+
// Controller -- thin, delegates to service
|
|
154
|
+
@RestController
|
|
155
|
+
@RequestMapping("/api/users")
|
|
156
|
+
public class UserController {
|
|
157
|
+
|
|
158
|
+
private final UserService userService;
|
|
159
|
+
|
|
160
|
+
public UserController(UserService userService) {
|
|
161
|
+
this.userService = userService;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@GetMapping("/{id}")
|
|
165
|
+
public ResponseEntity<UserResponse> getUser(@PathVariable String id) {
|
|
166
|
+
return userService.findById(id)
|
|
167
|
+
.map(ResponseEntity::ok)
|
|
168
|
+
.orElse(ResponseEntity.notFound().build());
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@PostMapping
|
|
172
|
+
public ResponseEntity<UserResponse> createUser(
|
|
173
|
+
@Valid @RequestBody CreateUserRequest request) {
|
|
174
|
+
UserResponse created = userService.create(request);
|
|
175
|
+
URI location = URI.create("/api/users/" + created.id());
|
|
176
|
+
return ResponseEntity.created(location).body(created);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
@ExceptionHandler(IllegalArgumentException.class)
|
|
180
|
+
public ResponseEntity<ErrorResponse> handleBadRequest(IllegalArgumentException e) {
|
|
181
|
+
return ResponseEntity.badRequest()
|
|
182
|
+
.body(new ErrorResponse(e.getMessage()));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Service -- business logic
|
|
187
|
+
@Service
|
|
188
|
+
@Transactional(readOnly = true)
|
|
189
|
+
public class UserService {
|
|
190
|
+
|
|
191
|
+
private final UserRepository userRepository;
|
|
192
|
+
private final UserMapper userMapper;
|
|
193
|
+
|
|
194
|
+
public UserService(UserRepository userRepository, UserMapper userMapper) {
|
|
195
|
+
this.userRepository = userRepository;
|
|
196
|
+
this.userMapper = userMapper;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
public Optional<UserResponse> findById(String id) {
|
|
200
|
+
return userRepository.findById(id)
|
|
201
|
+
.map(userMapper::toResponse);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@Transactional
|
|
205
|
+
public UserResponse create(CreateUserRequest request) {
|
|
206
|
+
if (userRepository.existsByEmail(request.email())) {
|
|
207
|
+
throw new IllegalArgumentException("Email already registered");
|
|
208
|
+
}
|
|
209
|
+
User user = userMapper.toEntity(request);
|
|
210
|
+
User saved = userRepository.save(user);
|
|
211
|
+
return userMapper.toResponse(saved);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Request/Response DTOs as records
|
|
216
|
+
public record CreateUserRequest(
|
|
217
|
+
@NotBlank String name,
|
|
218
|
+
@Email String email,
|
|
219
|
+
@Min(13) @Max(150) int age
|
|
220
|
+
) {}
|
|
221
|
+
|
|
222
|
+
public record UserResponse(String id, String name, String email, int age) {}
|
|
223
|
+
|
|
224
|
+
public record ErrorResponse(String message) {}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 3. Streams API
|
|
228
|
+
|
|
229
|
+
```java
|
|
230
|
+
// Basic stream operations
|
|
231
|
+
List<String> activeUserNames = users.stream()
|
|
232
|
+
.filter(u -> u.isActive())
|
|
233
|
+
.map(User::name)
|
|
234
|
+
.sorted()
|
|
235
|
+
.toList(); // Java 16+, prefer over .collect(Collectors.toList())
|
|
236
|
+
|
|
237
|
+
// Grouping
|
|
238
|
+
Map<String, List<User>> usersByCity = users.stream()
|
|
239
|
+
.collect(Collectors.groupingBy(User::city));
|
|
240
|
+
|
|
241
|
+
// Reducing
|
|
242
|
+
int totalAge = users.stream()
|
|
243
|
+
.mapToInt(User::age)
|
|
244
|
+
.sum();
|
|
245
|
+
|
|
246
|
+
// FlatMap for nested structures
|
|
247
|
+
List<String> allTags = articles.stream()
|
|
248
|
+
.flatMap(article -> article.tags().stream())
|
|
249
|
+
.distinct()
|
|
250
|
+
.sorted()
|
|
251
|
+
.toList();
|
|
252
|
+
|
|
253
|
+
// Collectors
|
|
254
|
+
Map<Boolean, List<User>> partitioned = users.stream()
|
|
255
|
+
.collect(Collectors.partitioningBy(u -> u.age() >= 18));
|
|
256
|
+
|
|
257
|
+
String csv = users.stream()
|
|
258
|
+
.map(User::name)
|
|
259
|
+
.collect(Collectors.joining(", "));
|
|
260
|
+
|
|
261
|
+
// Stream.of, Stream.concat
|
|
262
|
+
Stream<String> combined = Stream.concat(
|
|
263
|
+
Stream.of("header"),
|
|
264
|
+
dataLines.stream()
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
// Parallel streams -- use only for CPU-bound work on large datasets
|
|
268
|
+
long count = hugeList.parallelStream()
|
|
269
|
+
.filter(this::expensiveCheck)
|
|
270
|
+
.count();
|
|
271
|
+
|
|
272
|
+
// Avoid streams for:
|
|
273
|
+
// - Simple iterations (use enhanced for loop)
|
|
274
|
+
// - Side effects (use forEach loop, not stream.forEach)
|
|
275
|
+
// - Small collections (overhead not worth it)
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### 4. Optional
|
|
279
|
+
|
|
280
|
+
```java
|
|
281
|
+
// Creating Optional
|
|
282
|
+
Optional<User> user = Optional.of(knownUser); // Throws if null
|
|
283
|
+
Optional<User> maybe = Optional.ofNullable(nullable); // Empty if null
|
|
284
|
+
Optional<User> empty = Optional.empty();
|
|
285
|
+
|
|
286
|
+
// Consuming Optional -- prefer functional style
|
|
287
|
+
String name = findUser(id)
|
|
288
|
+
.map(User::name)
|
|
289
|
+
.orElse("Unknown");
|
|
290
|
+
|
|
291
|
+
User user = findUser(id)
|
|
292
|
+
.orElseThrow(() -> new NotFoundException("User " + id + " not found"));
|
|
293
|
+
|
|
294
|
+
// Chaining
|
|
295
|
+
String city = findUser(id)
|
|
296
|
+
.flatMap(User::address)
|
|
297
|
+
.map(Address::city)
|
|
298
|
+
.orElse("Unknown");
|
|
299
|
+
|
|
300
|
+
// Conditional execution
|
|
301
|
+
findUser(id).ifPresentOrElse(
|
|
302
|
+
user -> sendWelcomeEmail(user),
|
|
303
|
+
() -> log.warn("User {} not found", id)
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
// Stream integration (Java 9+)
|
|
307
|
+
List<String> presentNames = userIds.stream()
|
|
308
|
+
.map(this::findUser)
|
|
309
|
+
.flatMap(Optional::stream) // Filters empty Optionals
|
|
310
|
+
.map(User::name)
|
|
311
|
+
.toList();
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**Optional rules:**
|
|
315
|
+
|
|
316
|
+
| Rule | Explanation |
|
|
317
|
+
|------|-------------|
|
|
318
|
+
| Never use Optional as a field | Use nullable fields with null checks |
|
|
319
|
+
| Never use Optional as a method parameter | Use overloading or nullable parameter |
|
|
320
|
+
| Use as return type for "might not exist" | The intended use case |
|
|
321
|
+
| Never call `.get()` without `.isPresent()` | Use `.orElse()`, `.orElseThrow()`, or `.map()` |
|
|
322
|
+
|
|
323
|
+
### 5. JUnit 5 Testing
|
|
324
|
+
|
|
325
|
+
```java
|
|
326
|
+
import org.junit.jupiter.api.*;
|
|
327
|
+
import org.junit.jupiter.params.ParameterizedTest;
|
|
328
|
+
import org.junit.jupiter.params.provider.*;
|
|
329
|
+
import static org.assertj.core.api.Assertions.*;
|
|
330
|
+
|
|
331
|
+
class UserServiceTest {
|
|
332
|
+
|
|
333
|
+
private UserService userService;
|
|
334
|
+
private UserRepository mockRepo;
|
|
335
|
+
|
|
336
|
+
@BeforeEach
|
|
337
|
+
void setUp() {
|
|
338
|
+
mockRepo = mock(UserRepository.class);
|
|
339
|
+
userService = new UserService(mockRepo, new UserMapper());
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@Test
|
|
343
|
+
@DisplayName("findById returns user when exists")
|
|
344
|
+
void findById_existingUser_returnsUser() {
|
|
345
|
+
// Arrange
|
|
346
|
+
var user = new User("1", "Alice", "alice@example.com", 30);
|
|
347
|
+
when(mockRepo.findById("1")).thenReturn(Optional.of(user));
|
|
348
|
+
|
|
349
|
+
// Act
|
|
350
|
+
var result = userService.findById("1");
|
|
351
|
+
|
|
352
|
+
// Assert
|
|
353
|
+
assertThat(result).isPresent();
|
|
354
|
+
assertThat(result.get().name()).isEqualTo("Alice");
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
@Test
|
|
358
|
+
@DisplayName("create throws when email already registered")
|
|
359
|
+
void create_duplicateEmail_throws() {
|
|
360
|
+
var request = new CreateUserRequest("Bob", "bob@example.com", 25);
|
|
361
|
+
when(mockRepo.existsByEmail("bob@example.com")).thenReturn(true);
|
|
362
|
+
|
|
363
|
+
assertThatThrownBy(() -> userService.create(request))
|
|
364
|
+
.isInstanceOf(IllegalArgumentException.class)
|
|
365
|
+
.hasMessage("Email already registered");
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Parameterized tests
|
|
369
|
+
@ParameterizedTest(name = "age {0} should be {1}")
|
|
370
|
+
@CsvSource({
|
|
371
|
+
"12, false",
|
|
372
|
+
"13, true",
|
|
373
|
+
"17, true",
|
|
374
|
+
"18, true",
|
|
375
|
+
"150, true",
|
|
376
|
+
"151, false"
|
|
377
|
+
})
|
|
378
|
+
void validateAge(int age, boolean expected) {
|
|
379
|
+
if (expected) {
|
|
380
|
+
assertThatNoException().isThrownBy(
|
|
381
|
+
() -> new User("Test", "t@t.com", age));
|
|
382
|
+
} else {
|
|
383
|
+
assertThatThrownBy(() -> new User("Test", "t@t.com", age))
|
|
384
|
+
.isInstanceOf(IllegalArgumentException.class);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
@ParameterizedTest
|
|
389
|
+
@MethodSource("invalidEmails")
|
|
390
|
+
void create_invalidEmail_throws(String email) {
|
|
391
|
+
assertThatThrownBy(() -> new User("Test", email, 25))
|
|
392
|
+
.isInstanceOf(IllegalArgumentException.class);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
static Stream<String> invalidEmails() {
|
|
396
|
+
return Stream.of("", " ", "no-at-sign", "@no-local", "no-domain@");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Nested tests for organization
|
|
400
|
+
@Nested
|
|
401
|
+
@DisplayName("when user exists")
|
|
402
|
+
class WhenUserExists {
|
|
403
|
+
|
|
404
|
+
private User existingUser;
|
|
405
|
+
|
|
406
|
+
@BeforeEach
|
|
407
|
+
void setUp() {
|
|
408
|
+
existingUser = new User("1", "Alice", "alice@example.com", 30);
|
|
409
|
+
when(mockRepo.findById("1")).thenReturn(Optional.of(existingUser));
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
@Test
|
|
413
|
+
void findById_returnsUser() {
|
|
414
|
+
assertThat(userService.findById("1")).isPresent();
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
@Test
|
|
418
|
+
void delete_removesUser() {
|
|
419
|
+
userService.delete("1");
|
|
420
|
+
verify(mockRepo).deleteById("1");
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### 6. Maven and Gradle
|
|
427
|
+
|
|
428
|
+
```xml
|
|
429
|
+
<!-- pom.xml (Maven) -->
|
|
430
|
+
<project>
|
|
431
|
+
<modelVersion>4.0.0</modelVersion>
|
|
432
|
+
<groupId>com.example</groupId>
|
|
433
|
+
<artifactId>my-service</artifactId>
|
|
434
|
+
<version>1.0.0</version>
|
|
435
|
+
|
|
436
|
+
<properties>
|
|
437
|
+
<java.version>21</java.version>
|
|
438
|
+
<maven.compiler.source>${java.version}</maven.compiler.source>
|
|
439
|
+
<maven.compiler.target>${java.version}</maven.compiler.target>
|
|
440
|
+
</properties>
|
|
441
|
+
|
|
442
|
+
<dependencies>
|
|
443
|
+
<dependency>
|
|
444
|
+
<groupId>org.springframework.boot</groupId>
|
|
445
|
+
<artifactId>spring-boot-starter-web</artifactId>
|
|
446
|
+
</dependency>
|
|
447
|
+
<dependency>
|
|
448
|
+
<groupId>org.junit.jupiter</groupId>
|
|
449
|
+
<artifactId>junit-jupiter</artifactId>
|
|
450
|
+
<scope>test</scope>
|
|
451
|
+
</dependency>
|
|
452
|
+
<dependency>
|
|
453
|
+
<groupId>org.assertj</groupId>
|
|
454
|
+
<artifactId>assertj-core</artifactId>
|
|
455
|
+
<scope>test</scope>
|
|
456
|
+
</dependency>
|
|
457
|
+
</dependencies>
|
|
458
|
+
</project>
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
```kotlin
|
|
462
|
+
// build.gradle.kts (Gradle Kotlin DSL)
|
|
463
|
+
plugins {
|
|
464
|
+
java
|
|
465
|
+
id("org.springframework.boot") version "3.2.0"
|
|
466
|
+
id("io.spring.dependency-management") version "1.1.4"
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
java {
|
|
470
|
+
sourceCompatibility = JavaVersion.VERSION_21
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
dependencies {
|
|
474
|
+
implementation("org.springframework.boot:spring-boot-starter-web")
|
|
475
|
+
testImplementation("org.springframework.boot:spring-boot-starter-test")
|
|
476
|
+
testImplementation("org.assertj:assertj-core")
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
tasks.test {
|
|
480
|
+
useJUnitPlatform()
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### 7. Design Patterns
|
|
485
|
+
|
|
486
|
+
```java
|
|
487
|
+
// Builder -- for objects with many optional parameters
|
|
488
|
+
public class HttpRequest {
|
|
489
|
+
private final String url;
|
|
490
|
+
private final String method;
|
|
491
|
+
private final Map<String, String> headers;
|
|
492
|
+
private final String body;
|
|
493
|
+
private final Duration timeout;
|
|
494
|
+
|
|
495
|
+
private HttpRequest(Builder builder) {
|
|
496
|
+
this.url = builder.url;
|
|
497
|
+
this.method = builder.method;
|
|
498
|
+
this.headers = Map.copyOf(builder.headers);
|
|
499
|
+
this.body = builder.body;
|
|
500
|
+
this.timeout = builder.timeout;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
public static Builder builder(String url) {
|
|
504
|
+
return new Builder(url);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
public static class Builder {
|
|
508
|
+
private final String url;
|
|
509
|
+
private String method = "GET";
|
|
510
|
+
private final Map<String, String> headers = new HashMap<>();
|
|
511
|
+
private String body;
|
|
512
|
+
private Duration timeout = Duration.ofSeconds(30);
|
|
513
|
+
|
|
514
|
+
private Builder(String url) {
|
|
515
|
+
this.url = Objects.requireNonNull(url);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
public Builder method(String method) { this.method = method; return this; }
|
|
519
|
+
public Builder header(String key, String value) { headers.put(key, value); return this; }
|
|
520
|
+
public Builder body(String body) { this.body = body; return this; }
|
|
521
|
+
public Builder timeout(Duration timeout) { this.timeout = timeout; return this; }
|
|
522
|
+
|
|
523
|
+
public HttpRequest build() { return new HttpRequest(this); }
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// Usage
|
|
528
|
+
var request = HttpRequest.builder("https://api.example.com/users")
|
|
529
|
+
.method("POST")
|
|
530
|
+
.header("Content-Type", "application/json")
|
|
531
|
+
.body("{\"name\": \"Alice\"}")
|
|
532
|
+
.timeout(Duration.ofSeconds(10))
|
|
533
|
+
.build();
|
|
534
|
+
|
|
535
|
+
// Strategy -- pluggable algorithms
|
|
536
|
+
public interface PricingStrategy {
|
|
537
|
+
BigDecimal calculatePrice(Order order);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
public class RegularPricing implements PricingStrategy {
|
|
541
|
+
public BigDecimal calculatePrice(Order order) {
|
|
542
|
+
return order.subtotal();
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
public class DiscountPricing implements PricingStrategy {
|
|
547
|
+
private final BigDecimal discountRate;
|
|
548
|
+
|
|
549
|
+
public DiscountPricing(BigDecimal discountRate) {
|
|
550
|
+
this.discountRate = discountRate;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
public BigDecimal calculatePrice(Order order) {
|
|
554
|
+
return order.subtotal().multiply(BigDecimal.ONE.subtract(discountRate));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Factory
|
|
559
|
+
public class PricingFactory {
|
|
560
|
+
public static PricingStrategy forCustomer(Customer customer) {
|
|
561
|
+
return switch (customer.tier()) {
|
|
562
|
+
case STANDARD -> new RegularPricing();
|
|
563
|
+
case PREMIUM -> new DiscountPricing(new BigDecimal("0.10"));
|
|
564
|
+
case VIP -> new DiscountPricing(new BigDecimal("0.20"));
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### 8. Exception Handling
|
|
571
|
+
|
|
572
|
+
```java
|
|
573
|
+
// Custom exception hierarchy
|
|
574
|
+
public class AppException extends RuntimeException {
|
|
575
|
+
private final String errorCode;
|
|
576
|
+
|
|
577
|
+
public AppException(String errorCode, String message) {
|
|
578
|
+
super(message);
|
|
579
|
+
this.errorCode = errorCode;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
public AppException(String errorCode, String message, Throwable cause) {
|
|
583
|
+
super(message, cause);
|
|
584
|
+
this.errorCode = errorCode;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
public String errorCode() { return errorCode; }
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
public class NotFoundException extends AppException {
|
|
591
|
+
public NotFoundException(String resource, String id) {
|
|
592
|
+
super("NOT_FOUND", resource + " with id " + id + " not found");
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
public class ConflictException extends AppException {
|
|
597
|
+
public ConflictException(String message) {
|
|
598
|
+
super("CONFLICT", message);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
// Global exception handler (Spring)
|
|
603
|
+
@RestControllerAdvice
|
|
604
|
+
public class GlobalExceptionHandler {
|
|
605
|
+
|
|
606
|
+
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
|
|
607
|
+
|
|
608
|
+
@ExceptionHandler(NotFoundException.class)
|
|
609
|
+
public ResponseEntity<ErrorResponse> handleNotFound(NotFoundException e) {
|
|
610
|
+
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
|
611
|
+
.body(new ErrorResponse(e.errorCode(), e.getMessage()));
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
@ExceptionHandler(MethodArgumentNotValidException.class)
|
|
615
|
+
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException e) {
|
|
616
|
+
String message = e.getBindingResult().getFieldErrors().stream()
|
|
617
|
+
.map(err -> err.getField() + ": " + err.getDefaultMessage())
|
|
618
|
+
.collect(Collectors.joining(", "));
|
|
619
|
+
return ResponseEntity.badRequest()
|
|
620
|
+
.body(new ErrorResponse("VALIDATION_ERROR", message));
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
@ExceptionHandler(Exception.class)
|
|
624
|
+
public ResponseEntity<ErrorResponse> handleUnexpected(Exception e) {
|
|
625
|
+
log.error("Unexpected error", e);
|
|
626
|
+
return ResponseEntity.internalServerError()
|
|
627
|
+
.body(new ErrorResponse("INTERNAL_ERROR", "An unexpected error occurred"));
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### 9. Logging with SLF4J
|
|
633
|
+
|
|
634
|
+
```java
|
|
635
|
+
import org.slf4j.Logger;
|
|
636
|
+
import org.slf4j.LoggerFactory;
|
|
637
|
+
|
|
638
|
+
public class OrderService {
|
|
639
|
+
|
|
640
|
+
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
|
|
641
|
+
|
|
642
|
+
public Order processOrder(OrderRequest request) {
|
|
643
|
+
log.info("Processing order for customer={}", request.customerId());
|
|
644
|
+
|
|
645
|
+
try {
|
|
646
|
+
Order order = createOrder(request);
|
|
647
|
+
log.debug("Order created: id={}, items={}", order.id(), order.items().size());
|
|
648
|
+
return order;
|
|
649
|
+
} catch (InsufficientStockException e) {
|
|
650
|
+
log.warn("Insufficient stock for order: customer={}, item={}",
|
|
651
|
+
request.customerId(), e.itemId());
|
|
652
|
+
throw e;
|
|
653
|
+
} catch (Exception e) {
|
|
654
|
+
log.error("Failed to process order for customer={}", request.customerId(), e);
|
|
655
|
+
throw new AppException("ORDER_FAILED", "Order processing failed", e);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// Logging rules:
|
|
661
|
+
// - Use parameterized messages: log.info("User {}", id) -- NOT log.info("User " + id)
|
|
662
|
+
// - ERROR: system is broken, needs immediate attention
|
|
663
|
+
// - WARN: something unexpected but recoverable
|
|
664
|
+
// - INFO: significant business events
|
|
665
|
+
// - DEBUG: diagnostic information for developers
|
|
666
|
+
// - Never log sensitive data (passwords, tokens, PII)
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
### 10. Concurrent Utilities
|
|
670
|
+
|
|
671
|
+
```java
|
|
672
|
+
import java.util.concurrent.*;
|
|
673
|
+
|
|
674
|
+
// ExecutorService for thread pool management
|
|
675
|
+
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); // Java 21+
|
|
676
|
+
|
|
677
|
+
// CompletableFuture for async composition
|
|
678
|
+
CompletableFuture<UserProfile> profileFuture = CompletableFuture
|
|
679
|
+
.supplyAsync(() -> fetchUser(userId), executor)
|
|
680
|
+
.thenCombine(
|
|
681
|
+
CompletableFuture.supplyAsync(() -> fetchPreferences(userId), executor),
|
|
682
|
+
(user, prefs) -> new UserProfile(user, prefs)
|
|
683
|
+
)
|
|
684
|
+
.exceptionally(ex -> {
|
|
685
|
+
log.error("Failed to build profile for user={}", userId, ex);
|
|
686
|
+
return UserProfile.DEFAULT;
|
|
687
|
+
});
|
|
688
|
+
|
|
689
|
+
// Virtual threads (Java 21+) -- lightweight, ideal for I/O-bound tasks
|
|
690
|
+
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
|
691
|
+
List<Future<String>> futures = urls.stream()
|
|
692
|
+
.map(url -> executor.submit(() -> fetch(url)))
|
|
693
|
+
.toList();
|
|
694
|
+
|
|
695
|
+
List<String> results = new ArrayList<>();
|
|
696
|
+
for (var future : futures) {
|
|
697
|
+
results.add(future.get());
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// Structured concurrency (Java 21+ preview)
|
|
702
|
+
// try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
|
|
703
|
+
// Subtask<User> userTask = scope.fork(() -> fetchUser(id));
|
|
704
|
+
// Subtask<Order> orderTask = scope.fork(() -> fetchOrder(id));
|
|
705
|
+
// scope.join().throwIfFailed();
|
|
706
|
+
// return new UserOrder(userTask.get(), orderTask.get());
|
|
707
|
+
// }
|
|
708
|
+
|
|
709
|
+
// Thread-safe collections
|
|
710
|
+
ConcurrentHashMap<String, AtomicInteger> counters = new ConcurrentHashMap<>();
|
|
711
|
+
counters.computeIfAbsent("key", k -> new AtomicInteger()).incrementAndGet();
|
|
712
|
+
|
|
713
|
+
// BlockingQueue for producer-consumer
|
|
714
|
+
BlockingQueue<Task> taskQueue = new LinkedBlockingQueue<>(100);
|
|
715
|
+
// Producer: taskQueue.put(task);
|
|
716
|
+
// Consumer: Task task = taskQueue.take();
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
## Anti-Patterns
|
|
720
|
+
|
|
721
|
+
| Anti-Pattern | Why It Is Bad | Do This Instead |
|
|
722
|
+
|-------------|--------------|----------------|
|
|
723
|
+
| `catch (Exception e) {}` | Silences errors | Log and re-throw, or handle specifically |
|
|
724
|
+
| Returning `null` from methods | NullPointerException risk | Return `Optional` or throw |
|
|
725
|
+
| `Optional.get()` without check | Throws NoSuchElementException | Use `orElse`, `orElseThrow`, `map` |
|
|
726
|
+
| Mutable DTOs with setters | Thread-unsafe, no validation | Use records or immutable objects |
|
|
727
|
+
| `static` mutable state | Hidden coupling, thread-unsafe | Inject dependencies via constructor |
|
|
728
|
+
| String concatenation in loops | O(n^2) performance | Use `StringBuilder` |
|
|
729
|
+
| Checked exceptions for control flow | Verbose, slow | Use unchecked exceptions or Optional |
|
|
730
|
+
| Field injection (`@Autowired` on fields) | Hides dependencies, hard to test | Constructor injection |
|
|
731
|
+
|
|
732
|
+
## Project Structure
|
|
733
|
+
|
|
734
|
+
```
|
|
735
|
+
src/
|
|
736
|
+
main/
|
|
737
|
+
java/com/example/myservice/
|
|
738
|
+
MyServiceApplication.java
|
|
739
|
+
controller/
|
|
740
|
+
service/
|
|
741
|
+
repository/
|
|
742
|
+
model/
|
|
743
|
+
config/
|
|
744
|
+
exception/
|
|
745
|
+
resources/
|
|
746
|
+
application.yml
|
|
747
|
+
test/
|
|
748
|
+
java/com/example/myservice/
|
|
749
|
+
controller/
|
|
750
|
+
service/
|
|
751
|
+
repository/
|
|
752
|
+
pom.xml / build.gradle.kts
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
## Common Commands
|
|
756
|
+
|
|
757
|
+
```bash
|
|
758
|
+
# Maven
|
|
759
|
+
mvn clean install # Build and test
|
|
760
|
+
mvn test # Run tests only
|
|
761
|
+
mvn spring-boot:run # Start Spring Boot app
|
|
762
|
+
mvn dependency:tree # Show dependency tree
|
|
763
|
+
|
|
764
|
+
# Gradle
|
|
765
|
+
./gradlew build # Build and test
|
|
766
|
+
./gradlew test # Run tests only
|
|
767
|
+
./gradlew bootRun # Start Spring Boot app
|
|
768
|
+
./gradlew dependencies # Show dependency tree
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
## Resources
|
|
772
|
+
|
|
773
|
+
- **Java Language Updates**: https://docs.oracle.com/en/java/javase/21/language/
|
|
774
|
+
- **Spring Boot Reference**: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/
|
|
775
|
+
- **Effective Java (Bloch)**: Definitive Java best practices book
|
|
776
|
+
- **JUnit 5 User Guide**: https://junit.org/junit5/docs/current/user-guide/
|
|
777
|
+
- **AssertJ**: https://assertj.github.io/doc/
|
|
778
|
+
- **Baeldung**: https://www.baeldung.com/
|