claudeinone-cli 1.0.1 → 1.0.3
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/dist/index.js +16 -1
- package/kit/.claude/.ck.json +9 -0
- package/kit/.claude/.ckignore +12 -0
- package/kit/.claude/agents/accessibility-auditor.md +46 -0
- package/kit/.claude/agents/api-designer.md +43 -0
- package/kit/.claude/agents/backend-developer.md +54 -0
- package/kit/.claude/agents/brainstormer.md +33 -0
- package/kit/.claude/agents/campaign-manager.md +36 -0
- package/kit/.claude/agents/code-reviewer.md +39 -0
- package/kit/.claude/agents/content-creator.md +38 -0
- package/kit/.claude/agents/copywriter.md +42 -0
- package/kit/.claude/agents/database-admin.md +37 -0
- package/kit/.claude/agents/debugger.md +46 -0
- package/kit/.claude/agents/devops-engineer.md +41 -0
- package/kit/.claude/agents/docs-manager.md +33 -0
- package/kit/.claude/agents/email-wizard.md +40 -0
- package/kit/.claude/agents/frontend-developer.md +52 -0
- package/kit/.claude/agents/fullstack-developer.md +55 -0
- package/kit/.claude/agents/git-manager.md +40 -0
- package/kit/.claude/agents/i18n-specialist.md +46 -0
- package/kit/.claude/agents/integration-specialist.md +48 -0
- package/kit/.claude/agents/journal-writer.md +39 -0
- package/kit/.claude/agents/mcp-manager.md +57 -0
- package/kit/.claude/agents/mobile-developer.md +38 -0
- package/kit/.claude/agents/performance-optimizer.md +38 -0
- package/kit/.claude/agents/planner.md +56 -0
- package/kit/.claude/agents/project-manager.md +34 -0
- package/kit/.claude/agents/refactorer.md +43 -0
- package/kit/.claude/agents/researcher.md +45 -0
- package/kit/.claude/agents/risk-analyst.md +33 -0
- package/kit/.claude/agents/scalability-consultant.md +39 -0
- package/kit/.claude/agents/scout.md +25 -0
- package/kit/.claude/agents/security-auditor.md +42 -0
- package/kit/.claude/agents/seo-specialist.md +44 -0
- package/kit/.claude/agents/skill-creator.md +64 -0
- package/kit/.claude/agents/social-media-manager.md +35 -0
- package/kit/.claude/agents/systems-designer.md +35 -0
- package/kit/.claude/agents/technology-strategist.md +43 -0
- package/kit/.claude/agents/tester.md +40 -0
- package/kit/.claude/agents/ui-ux-designer.md +40 -0
- package/kit/.claude/commands/co/ask.md +29 -0
- package/kit/.claude/commands/co/bootstrap-auto-fast.md +28 -0
- package/kit/.claude/commands/co/bootstrap-auto-parallel.md +29 -0
- package/kit/.claude/commands/co/bootstrap-auto.md +30 -0
- package/kit/.claude/commands/co/bootstrap.md +31 -0
- package/kit/.claude/commands/co/brainstorm.md +27 -0
- package/kit/.claude/commands/co/campaign.md +28 -0
- package/kit/.claude/commands/co/changelog.md +25 -0
- package/kit/.claude/commands/co/checkpoint.md +25 -0
- package/kit/.claude/commands/co/ci.md +26 -0
- package/kit/.claude/commands/co/ck-help.md +24 -0
- package/kit/.claude/commands/co/coding-level.md +24 -0
- package/kit/.claude/commands/co/content-cro.md +26 -0
- package/kit/.claude/commands/co/content-enhance.md +26 -0
- package/kit/.claude/commands/co/content-fast.md +24 -0
- package/kit/.claude/commands/co/content-good.md +26 -0
- package/kit/.claude/commands/co/cook.md +33 -0
- package/kit/.claude/commands/co/debug.md +26 -0
- package/kit/.claude/commands/co/deploy.md +25 -0
- package/kit/.claude/commands/co/design-3d.md +27 -0
- package/kit/.claude/commands/co/design-describe.md +25 -0
- package/kit/.claude/commands/co/design-fast.md +25 -0
- package/kit/.claude/commands/co/design-good.md +28 -0
- package/kit/.claude/commands/co/design-screenshot.md +26 -0
- package/kit/.claude/commands/co/design-video.md +26 -0
- package/kit/.claude/commands/co/docker.md +24 -0
- package/kit/.claude/commands/co/docs-api.md +25 -0
- package/kit/.claude/commands/co/docs-init.md +26 -0
- package/kit/.claude/commands/co/docs-readme.md +24 -0
- package/kit/.claude/commands/co/docs-summarize.md +25 -0
- package/kit/.claude/commands/co/docs-update.md +25 -0
- package/kit/.claude/commands/co/env-check.md +25 -0
- package/kit/.claude/commands/co/fix-ci.md +29 -0
- package/kit/.claude/commands/co/fix-fast.md +28 -0
- package/kit/.claude/commands/co/fix-hard.md +33 -0
- package/kit/.claude/commands/co/fix-logs.md +28 -0
- package/kit/.claude/commands/co/fix-types.md +28 -0
- package/kit/.claude/commands/co/fix-ui.md +28 -0
- package/kit/.claude/commands/co/fix.md +27 -0
- package/kit/.claude/commands/co/git-cm.md +26 -0
- package/kit/.claude/commands/co/git-cp.md +26 -0
- package/kit/.claude/commands/co/git-pr.md +26 -0
- package/kit/.claude/commands/co/index.md +24 -0
- package/kit/.claude/commands/co/integrate-polar.md +29 -0
- package/kit/.claude/commands/co/integrate-sepay.md +29 -0
- package/kit/.claude/commands/co/journal.md +27 -0
- package/kit/.claude/commands/co/k8s.md +24 -0
- package/kit/.claude/commands/co/kanban.md +25 -0
- package/kit/.claude/commands/co/lint-fix.md +24 -0
- package/kit/.claude/commands/co/load.md +25 -0
- package/kit/.claude/commands/co/migrate.md +28 -0
- package/kit/.claude/commands/co/mock.md +26 -0
- package/kit/.claude/commands/co/mode.md +24 -0
- package/kit/.claude/commands/co/monitor.md +25 -0
- package/kit/.claude/commands/co/new-feature.md +27 -0
- package/kit/.claude/commands/co/optimize.md +26 -0
- package/kit/.claude/commands/co/plan-archive.md +24 -0
- package/kit/.claude/commands/co/plan-ci.md +28 -0
- package/kit/.claude/commands/co/plan-cro.md +27 -0
- package/kit/.claude/commands/co/plan-fast.md +24 -0
- package/kit/.claude/commands/co/plan-hard.md +27 -0
- package/kit/.claude/commands/co/plan-parallel.md +25 -0
- package/kit/.claude/commands/co/plan-two.md +29 -0
- package/kit/.claude/commands/co/plan-validate.md +27 -0
- package/kit/.claude/commands/co/plan.md +27 -0
- package/kit/.claude/commands/co/pr.md +25 -0
- package/kit/.claude/commands/co/preview.md +26 -0
- package/kit/.claude/commands/co/refactor.md +25 -0
- package/kit/.claude/commands/co/release.md +25 -0
- package/kit/.claude/commands/co/review-a11y.md +24 -0
- package/kit/.claude/commands/co/review-codebase-parallel.md +27 -0
- package/kit/.claude/commands/co/review-codebase.md +27 -0
- package/kit/.claude/commands/co/review-perf.md +24 -0
- package/kit/.claude/commands/co/review-security.md +25 -0
- package/kit/.claude/commands/co/scaffold.md +25 -0
- package/kit/.claude/commands/co/scout.md +26 -0
- package/kit/.claude/commands/co/secure.md +26 -0
- package/kit/.claude/commands/co/seed.md +25 -0
- package/kit/.claude/commands/co/seo-audit.md +24 -0
- package/kit/.claude/commands/co/seo-keywords.md +25 -0
- package/kit/.claude/commands/co/skill-create.md +29 -0
- package/kit/.claude/commands/co/skill-fix-logs.md +28 -0
- package/kit/.claude/commands/co/slide-create.md +24 -0
- package/kit/.claude/commands/co/spawn.md +24 -0
- package/kit/.claude/commands/co/terraform.md +24 -0
- package/kit/.claude/commands/co/test-gen.md +24 -0
- package/kit/.claude/commands/co/test-ui.md +27 -0
- package/kit/.claude/commands/co/test.md +26 -0
- package/kit/.claude/commands/co/use-mcp.md +25 -0
- package/kit/.claude/commands/co/video-script.md +25 -0
- package/kit/.claude/commands/co/watzup.md +25 -0
- package/kit/.claude/commands/co/worktree.md +25 -0
- package/kit/.claude/commands/co/write-blog.md +25 -0
- package/kit/.claude/commands/co/write-copy.md +24 -0
- package/kit/.claude/commands/co/write-email.md +25 -0
- package/kit/.claude/commands/content/content-cro.md +26 -0
- package/kit/.claude/commands/content/content-enhance.md +26 -0
- package/kit/.claude/commands/content/content-fast.md +24 -0
- package/kit/.claude/commands/content/content-good.md +26 -0
- package/kit/.claude/commands/content/enhance.md +26 -0
- package/kit/.claude/commands/content/good.md +26 -0
- package/kit/.claude/commands/core/ask.md +29 -0
- package/kit/.claude/commands/core/bootstrap-auto-fast.md +28 -0
- package/kit/.claude/commands/core/bootstrap-auto-parallel.md +29 -0
- package/kit/.claude/commands/core/bootstrap-auto.md +30 -0
- package/kit/.claude/commands/core/bootstrap.md +31 -0
- package/kit/.claude/commands/core/ck-help.md +24 -0
- package/kit/.claude/commands/core/coding-level.md +24 -0
- package/kit/.claude/commands/core/cook.md +33 -0
- package/kit/.claude/commands/core/debug.md +26 -0
- package/kit/.claude/commands/core/journal.md +27 -0
- package/kit/.claude/commands/core/kanban.md +25 -0
- package/kit/.claude/commands/core/preview.md +26 -0
- package/kit/.claude/commands/core/scout.md +26 -0
- package/kit/.claude/commands/core/test-ui.md +27 -0
- package/kit/.claude/commands/core/test.md +26 -0
- package/kit/.claude/commands/core/use-mcp.md +25 -0
- package/kit/.claude/commands/core/watzup.md +25 -0
- package/kit/.claude/commands/core/worktree.md +25 -0
- package/kit/.claude/commands/design/3d.md +27 -0
- package/kit/.claude/commands/design/design-3d.md +27 -0
- package/kit/.claude/commands/design/design-describe.md +25 -0
- package/kit/.claude/commands/design/design-fast.md +25 -0
- package/kit/.claude/commands/design/design-good.md +28 -0
- package/kit/.claude/commands/design/design-screenshot.md +26 -0
- package/kit/.claude/commands/design/design-video.md +26 -0
- package/kit/.claude/commands/design/good.md +28 -0
- package/kit/.claude/commands/design/video.md +26 -0
- package/kit/.claude/commands/docs/docs-init.md +26 -0
- package/kit/.claude/commands/docs/docs-summarize.md +25 -0
- package/kit/.claude/commands/docs/docs-update.md +25 -0
- package/kit/.claude/commands/docs/init.md +26 -0
- package/kit/.claude/commands/docs/summarize.md +25 -0
- package/kit/.claude/commands/fix/ci.md +29 -0
- package/kit/.claude/commands/fix/fast.md +28 -0
- package/kit/.claude/commands/fix/fix-ci.md +29 -0
- package/kit/.claude/commands/fix/fix-fast.md +28 -0
- package/kit/.claude/commands/fix/fix-hard.md +33 -0
- package/kit/.claude/commands/fix/fix-logs.md +28 -0
- package/kit/.claude/commands/fix/fix-types.md +28 -0
- package/kit/.claude/commands/fix/fix-ui.md +28 -0
- package/kit/.claude/commands/fix/hard.md +33 -0
- package/kit/.claude/commands/fix/logs.md +28 -0
- package/kit/.claude/commands/fix/types.md +28 -0
- package/kit/.claude/commands/fix/ui.md +28 -0
- package/kit/.claude/commands/git/cp.md +26 -0
- package/kit/.claude/commands/git/git-cm.md +26 -0
- package/kit/.claude/commands/git/git-cp.md +26 -0
- package/kit/.claude/commands/git/git-pr.md +26 -0
- package/kit/.claude/commands/integrate/integrate-polar.md +29 -0
- package/kit/.claude/commands/integrate/integrate-sepay.md +29 -0
- package/kit/.claude/commands/integrate/sepay.md +29 -0
- package/kit/.claude/commands/plan/ci.md +28 -0
- package/kit/.claude/commands/plan/cro.md +27 -0
- package/kit/.claude/commands/plan/hard.md +27 -0
- package/kit/.claude/commands/plan/plan-archive.md +24 -0
- package/kit/.claude/commands/plan/plan-ci.md +28 -0
- package/kit/.claude/commands/plan/plan-cro.md +27 -0
- package/kit/.claude/commands/plan/plan-fast.md +24 -0
- package/kit/.claude/commands/plan/plan-hard.md +27 -0
- package/kit/.claude/commands/plan/plan-parallel.md +25 -0
- package/kit/.claude/commands/plan/plan-two.md +29 -0
- package/kit/.claude/commands/plan/plan-validate.md +27 -0
- package/kit/.claude/commands/plan/plan.md +27 -0
- package/kit/.claude/commands/plan/validate.md +27 -0
- package/kit/.claude/commands/skill/fix-logs.md +28 -0
- package/kit/.claude/commands/skill/skill-create.md +29 -0
- package/kit/.claude/commands/skill/skill-fix-logs.md +28 -0
- package/kit/.claude/settings.json +16 -0
- package/kit/.claude/skills/ai-anthropic.md +100 -0
- package/kit/.claude/skills/ai-context-engineering.md +113 -0
- package/kit/.claude/skills/ai-gemini.md +152 -0
- package/kit/.claude/skills/ai-langchain.md +93 -0
- package/kit/.claude/skills/ai-llamaindex.md +179 -0
- package/kit/.claude/skills/ai-mcp-builder.md +101 -0
- package/kit/.claude/skills/ai-openai.md +250 -0
- package/kit/.claude/skills/ai-prompt-engineering.md +173 -0
- package/kit/.claude/skills/ai-rag.md +91 -0
- package/kit/.claude/skills/ai-vectordb.md +215 -0
- package/kit/.claude/skills/analytics-segment.md +161 -0
- package/kit/.claude/skills/api-caching.md +103 -0
- package/kit/.claude/skills/api-documentation.md +50 -0
- package/kit/.claude/skills/api-graphql.md +234 -0
- package/kit/.claude/skills/api-openapi.md +116 -0
- package/kit/.claude/skills/api-pagination-filtering.md +239 -0
- package/kit/.claude/skills/api-rate-limiting.md +179 -0
- package/kit/.claude/skills/api-rest-advanced.md +50 -0
- package/kit/.claude/skills/api-rest.md +217 -0
- package/kit/.claude/skills/api-trpc.md +173 -0
- package/kit/.claude/skills/api-versioning.md +70 -0
- package/kit/.claude/skills/api-webhooks.md +226 -0
- package/kit/.claude/skills/arch-clean-code.md +226 -0
- package/kit/.claude/skills/arch-clean.md +91 -0
- package/kit/.claude/skills/arch-cqrs.md +229 -0
- package/kit/.claude/skills/arch-ddd.md +85 -0
- package/kit/.claude/skills/arch-event-driven.md +189 -0
- package/kit/.claude/skills/arch-microservices.md +80 -0
- package/kit/.claude/skills/arch-monorepo.md +87 -0
- package/kit/.claude/skills/arch-multi-tenant.md +81 -0
- package/kit/.claude/skills/arch-serverless.md +86 -0
- package/kit/.claude/skills/auth-clerk.md +97 -0
- package/kit/.claude/skills/auth-jwt.md +143 -0
- package/kit/.claude/skills/auth-lucia.md +93 -0
- package/kit/.claude/skills/auth-nextauth.md +446 -0
- package/kit/.claude/skills/auth-oauth.md +208 -0
- package/kit/.claude/skills/auth-oauth2.md +110 -0
- package/kit/.claude/skills/auth-passkeys.md +109 -0
- package/kit/.claude/skills/auth-session.md +88 -0
- package/kit/.claude/skills/backend-dotnet.md +414 -0
- package/kit/.claude/skills/backend-express.md +129 -0
- package/kit/.claude/skills/backend-fastify.md +104 -0
- package/kit/.claude/skills/backend-go.md +205 -0
- package/kit/.claude/skills/backend-graphql.md +149 -0
- package/kit/.claude/skills/backend-grpc.md +382 -0
- package/kit/.claude/skills/backend-hono.md +95 -0
- package/kit/.claude/skills/backend-java-spring.md +198 -0
- package/kit/.claude/skills/backend-nodejs-express.md +165 -0
- package/kit/.claude/skills/backend-nodejs.md +143 -0
- package/kit/.claude/skills/backend-php-laravel.md +156 -0
- package/kit/.claude/skills/backend-python-django.md +200 -0
- package/kit/.claude/skills/backend-python-fastapi.md +169 -0
- package/kit/.claude/skills/backend-ruby-rails.md +190 -0
- package/kit/.claude/skills/backend-rust.md +182 -0
- package/kit/.claude/skills/backend-websockets.md +392 -0
- package/kit/.claude/skills/cache-redis.md +195 -0
- package/kit/.claude/skills/caching-strategies.md +100 -0
- package/kit/.claude/skills/cloud-aws.md +165 -0
- package/kit/.claude/skills/cloud-azure.md +187 -0
- package/kit/.claude/skills/cloud-cloudflare.md +74 -0
- package/kit/.claude/skills/cloud-fly.md +94 -0
- package/kit/.claude/skills/cloud-gcp.md +160 -0
- package/kit/.claude/skills/cloud-railway.md +92 -0
- package/kit/.claude/skills/cloud-render.md +70 -0
- package/kit/.claude/skills/cloud-serverless.md +68 -0
- package/kit/.claude/skills/cloud-vercel.md +76 -0
- package/kit/.claude/skills/component-patterns.md +50 -0
- package/kit/.claude/skills/content-management.md +197 -0
- package/kit/.claude/skills/cors-security.md +50 -0
- package/kit/.claude/skills/data-csv-excel.md +210 -0
- package/kit/.claude/skills/database-optimization.md +196 -0
- package/kit/.claude/skills/databases-transactions.md +68 -0
- package/kit/.claude/skills/db-cassandra.md +89 -0
- package/kit/.claude/skills/db-drizzle.md +363 -0
- package/kit/.claude/skills/db-dynamodb.md +83 -0
- package/kit/.claude/skills/db-elasticsearch.md +105 -0
- package/kit/.claude/skills/db-firebase-firestore.md +191 -0
- package/kit/.claude/skills/db-mongodb.md +198 -0
- package/kit/.claude/skills/db-mysql.md +50 -0
- package/kit/.claude/skills/db-neon.md +72 -0
- package/kit/.claude/skills/db-planetscale.md +76 -0
- package/kit/.claude/skills/db-postgresql.md +50 -0
- package/kit/.claude/skills/db-prisma.md +414 -0
- package/kit/.claude/skills/db-redis.md +50 -0
- package/kit/.claude/skills/db-sqlite.md +149 -0
- package/kit/.claude/skills/db-supabase.md +445 -0
- package/kit/.claude/skills/devops-ci-cd.md +271 -0
- package/kit/.claude/skills/devops-database-backup.md +77 -0
- package/kit/.claude/skills/devops-docker.md +93 -0
- package/kit/.claude/skills/devops-github-actions.md +82 -0
- package/kit/.claude/skills/devops-health-checks.md +50 -0
- package/kit/.claude/skills/devops-kubernetes.md +109 -0
- package/kit/.claude/skills/devops-logging.md +163 -0
- package/kit/.claude/skills/devops-monitoring.md +203 -0
- package/kit/.claude/skills/devops-pulumi.md +94 -0
- package/kit/.claude/skills/devops-secrets.md +166 -0
- package/kit/.claude/skills/devops-terraform.md +226 -0
- package/kit/.claude/skills/error-boundaries.md +84 -0
- package/kit/.claude/skills/file-storage.md +50 -0
- package/kit/.claude/skills/frontend-angular.md +104 -0
- package/kit/.claude/skills/frontend-astro.md +94 -0
- package/kit/.claude/skills/frontend-bundle-analysis.md +147 -0
- package/kit/.claude/skills/frontend-forms.md +134 -0
- package/kit/.claude/skills/frontend-htmx.md +86 -0
- package/kit/.claude/skills/frontend-nextjs.md +188 -0
- package/kit/.claude/skills/frontend-pwa.md +105 -0
- package/kit/.claude/skills/frontend-react-hooks.md +238 -0
- package/kit/.claude/skills/frontend-react.md +129 -0
- package/kit/.claude/skills/frontend-remix-advanced.md +106 -0
- package/kit/.claude/skills/frontend-remix.md +101 -0
- package/kit/.claude/skills/frontend-solid.md +99 -0
- package/kit/.claude/skills/frontend-state-management.md +134 -0
- package/kit/.claude/skills/frontend-state.md +106 -0
- package/kit/.claude/skills/frontend-svelte.md +121 -0
- package/kit/.claude/skills/frontend-testing.md +100 -0
- package/kit/.claude/skills/frontend-vite.md +94 -0
- package/kit/.claude/skills/frontend-vue.md +133 -0
- package/kit/.claude/skills/frontend-webpack.md +93 -0
- package/kit/.claude/skills/functional-programming.md +50 -0
- package/kit/.claude/skills/hooks-custom.md +50 -0
- package/kit/.claude/skills/http-server.md +50 -0
- package/kit/.claude/skills/i18n-general.md +89 -0
- package/kit/.claude/skills/i18n-localization.md +191 -0
- package/kit/.claude/skills/i18n-nextjs.md +127 -0
- package/kit/.claude/skills/infrastructure-docker-compose.md +77 -0
- package/kit/.claude/skills/infrastructure-serverless.md +177 -0
- package/kit/.claude/skills/jwt-tokens.md +50 -0
- package/kit/.claude/skills/logging-winston.md +106 -0
- package/kit/.claude/skills/messaging-kafka.md +102 -0
- package/kit/.claude/skills/messaging-rabbitmq.md +50 -0
- package/kit/.claude/skills/mobile-capacitor.md +109 -0
- package/kit/.claude/skills/mobile-expo.md +101 -0
- package/kit/.claude/skills/mobile-flutter.md +259 -0
- package/kit/.claude/skills/mobile-react-native.md +238 -0
- package/kit/.claude/skills/monitoring-apm.md +50 -0
- package/kit/.claude/skills/monitoring-error-tracking.md +217 -0
- package/kit/.claude/skills/nodejs-streams.md +168 -0
- package/kit/.claude/skills/oauth-integration.md +50 -0
- package/kit/.claude/skills/patterns-dependency-injection.md +218 -0
- package/kit/.claude/skills/patterns-factory-singleton.md +209 -0
- package/kit/.claude/skills/patterns-observer-pubsub.md +210 -0
- package/kit/.claude/skills/payment-lemonsqueezy.md +101 -0
- package/kit/.claude/skills/payment-square.md +178 -0
- package/kit/.claude/skills/payment-stripe.md +206 -0
- package/kit/.claude/skills/perf-bundle.md +100 -0
- package/kit/.claude/skills/perf-web-vitals.md +102 -0
- package/kit/.claude/skills/performance-database-connection-pooling.md +67 -0
- package/kit/.claude/skills/performance-metrics.md +73 -0
- package/kit/.claude/skills/performance-optimization.md +208 -0
- package/kit/.claude/skills/performance-web-vitals.md +169 -0
- package/kit/.claude/skills/rate-limiting.md +77 -0
- package/kit/.claude/skills/reactive-programming.md +50 -0
- package/kit/.claude/skills/realtime-database.md +50 -0
- package/kit/.claude/skills/realtime-subscriptions.md +218 -0
- package/kit/.claude/skills/saas-ab-testing.md +90 -0
- package/kit/.claude/skills/saas-analytics.md +113 -0
- package/kit/.claude/skills/saas-billing.md +106 -0
- package/kit/.claude/skills/saas-email.md +88 -0
- package/kit/.claude/skills/saas-feature-flags.md +83 -0
- package/kit/.claude/skills/saas-onboarding.md +96 -0
- package/kit/.claude/skills/saas-user-onboarding.md +207 -0
- package/kit/.claude/skills/security-encryption.md +216 -0
- package/kit/.claude/skills/security-owasp.md +212 -0
- package/kit/.claude/skills/security-secrets-rotation.md +64 -0
- package/kit/.claude/skills/seo-content.md +94 -0
- package/kit/.claude/skills/seo-technical.md +101 -0
- package/kit/.claude/skills/serverless-framework.md +151 -0
- package/kit/.claude/skills/sharding-scaling.md +50 -0
- package/kit/.claude/skills/styling-css-modules.md +219 -0
- package/kit/.claude/skills/styling-styled-components.md +206 -0
- package/kit/.claude/skills/styling-tailwind.md +206 -0
- package/kit/.claude/skills/test-e2e.md +86 -0
- package/kit/.claude/skills/test-integration.md +216 -0
- package/kit/.claude/skills/test-performance.md +162 -0
- package/kit/.claude/skills/test-tdd.md +170 -0
- package/kit/.claude/skills/test-unit.md +301 -0
- package/kit/.claude/skills/testing-accessibility.md +117 -0
- package/kit/.claude/skills/testing-contract.md +75 -0
- package/kit/.claude/skills/testing-e2e-advanced.md +50 -0
- package/kit/.claude/skills/testing-load-stress.md +79 -0
- package/kit/.claude/skills/testing-mutation.md +92 -0
- package/kit/.claude/skills/testing-snapshot.md +50 -0
- package/kit/.claude/skills/testing-vitest.md +172 -0
- package/kit/.claude/skills/tooling-biome.md +91 -0
- package/kit/.claude/skills/tooling-build-tools.md +166 -0
- package/kit/.claude/skills/tooling-bun.md +94 -0
- package/kit/.claude/skills/tooling-eslint.md +103 -0
- package/kit/.claude/skills/tooling-git.md +79 -0
- package/kit/.claude/skills/tooling-monorepo.md +162 -0
- package/kit/.claude/skills/tooling-testing-frameworks.md +207 -0
- package/kit/.claude/skills/tooling-typescript.md +156 -0
- package/kit/.claude/skills/ui-a11y.md +106 -0
- package/kit/.claude/skills/ui-framer.md +106 -0
- package/kit/.claude/skills/ui-gsap.md +102 -0
- package/kit/.claude/skills/ui-radix.md +82 -0
- package/kit/.claude/skills/ui-shadcn.md +463 -0
- package/kit/.claude/skills/ui-tailwind.md +98 -0
- package/kit/.claude/skills/ui-threejs.md +110 -0
- package/kit/.claude/skills/ui-tokens.md +97 -0
- package/kit/.claude/skills/utilities-date-time.md +170 -0
- package/kit/.claude/skills/validation-schemas.md +110 -0
- package/kit/.claude/skills/version-control-git.md +144 -0
- package/kit/.claude/skills/web-accessibility-wcag.md +102 -0
- package/kit/.claude/skills/web-astro.md +197 -0
- package/kit/.claude/skills/web-html-css.md +224 -0
- package/kit/.claude/skills/web-htmx.md +99 -0
- package/kit/.claude/skills/web-nextjs-advanced.md +202 -0
- package/kit/.claude/skills/web-remix.md +194 -0
- package/kit/.claude/skills/web-seo.md +99 -0
- package/kit/.claude/skills/web-svelte.md +234 -0
- package/kit/.claude/skills/websocket-server.md +50 -0
- package/kit/.claude/skills/writing-marketing.md +89 -0
- package/kit/.claude/skills/writing-technical.md +119 -0
- package/kit/CLAUDE.md +206 -0
- package/kit/README.md +150 -0
- package/kit/SKILLS_INDEX.md +188 -0
- package/kit/docs/README.md +3 -0
- package/kit/journals/README.md +3 -0
- package/kit/plans/README.md +3 -0
- package/package.json +3 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Webhooks & Events
|
|
2
|
+
|
|
3
|
+
Push-based communication for real-time integrations.
|
|
4
|
+
|
|
5
|
+
## Webhook Implementation
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Endpoint to receive webhooks
|
|
9
|
+
app.post('/webhooks/stripe', express.raw({ type: 'application/json' }), async (req, res) => {
|
|
10
|
+
const sig = req.headers['stripe-signature'];
|
|
11
|
+
|
|
12
|
+
let event;
|
|
13
|
+
try {
|
|
14
|
+
event = stripe.webhooks.constructEvent(
|
|
15
|
+
req.body,
|
|
16
|
+
sig,
|
|
17
|
+
process.env.STRIPE_WEBHOOK_SECRET
|
|
18
|
+
);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
return res.status(400).send(`Webhook Error: ${err.message}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Handle event
|
|
24
|
+
switch (event.type) {
|
|
25
|
+
case 'payment_intent.succeeded':
|
|
26
|
+
await handlePaymentSuccess(event.data.object);
|
|
27
|
+
break;
|
|
28
|
+
case 'payment_intent.failed':
|
|
29
|
+
await handlePaymentFailure(event.data.object);
|
|
30
|
+
break;
|
|
31
|
+
default:
|
|
32
|
+
console.log(`Unhandled event type ${event.type}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
res.json({ received: true });
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
async function handlePaymentSuccess(paymentIntent: any) {
|
|
39
|
+
const order = await db.orders.findById(paymentIntent.metadata.orderId);
|
|
40
|
+
await db.orders.update(order.id, { status: 'paid' });
|
|
41
|
+
|
|
42
|
+
// Send confirmation email
|
|
43
|
+
await emailService.sendOrderConfirmation(order);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Retry Logic
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
interface WebhookDelivery {
|
|
51
|
+
id: string;
|
|
52
|
+
url: string;
|
|
53
|
+
payload: any;
|
|
54
|
+
status: 'pending' | 'delivered' | 'failed';
|
|
55
|
+
attempts: number;
|
|
56
|
+
nextRetry?: Date;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function deliverWebhook(delivery: WebhookDelivery) {
|
|
60
|
+
try {
|
|
61
|
+
const response = await fetch(delivery.url, {
|
|
62
|
+
method: 'POST',
|
|
63
|
+
headers: {
|
|
64
|
+
'Content-Type': 'application/json',
|
|
65
|
+
'X-Webhook-ID': delivery.id,
|
|
66
|
+
'X-Webhook-Signature': signPayload(delivery.payload)
|
|
67
|
+
},
|
|
68
|
+
body: JSON.stringify(delivery.payload),
|
|
69
|
+
timeout: 30000
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
if (response.ok) {
|
|
73
|
+
await db.webhookDeliveries.update(delivery.id, {
|
|
74
|
+
status: 'delivered'
|
|
75
|
+
});
|
|
76
|
+
} else {
|
|
77
|
+
throw new Error(`HTTP ${response.status}`);
|
|
78
|
+
}
|
|
79
|
+
} catch (error) {
|
|
80
|
+
delivery.attempts += 1;
|
|
81
|
+
|
|
82
|
+
if (delivery.attempts < 5) {
|
|
83
|
+
// Exponential backoff: 60s, 5m, 30m, 2h
|
|
84
|
+
const delays = [60, 300, 1800, 7200];
|
|
85
|
+
const delaySeconds = delays[delivery.attempts - 1];
|
|
86
|
+
|
|
87
|
+
await db.webhookDeliveries.update(delivery.id, {
|
|
88
|
+
attempts: delivery.attempts,
|
|
89
|
+
nextRetry: new Date(Date.now() + delaySeconds * 1000)
|
|
90
|
+
});
|
|
91
|
+
} else {
|
|
92
|
+
await db.webhookDeliveries.update(delivery.id, {
|
|
93
|
+
status: 'failed'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Retry worker
|
|
100
|
+
setInterval(async () => {
|
|
101
|
+
const pending = await db.webhookDeliveries.find({
|
|
102
|
+
status: 'pending',
|
|
103
|
+
nextRetry: { $lte: new Date() }
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
for (const delivery of pending) {
|
|
107
|
+
await deliverWebhook(delivery);
|
|
108
|
+
}
|
|
109
|
+
}, 60000); // Check every minute
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Webhook Security
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
import crypto from 'crypto';
|
|
116
|
+
|
|
117
|
+
function signPayload(payload: any): string {
|
|
118
|
+
const timestamp = Math.floor(Date.now() / 1000);
|
|
119
|
+
const message = `${timestamp}.${JSON.stringify(payload)}`;
|
|
120
|
+
|
|
121
|
+
const signature = crypto
|
|
122
|
+
.createHmac('sha256', process.env.WEBHOOK_SECRET!)
|
|
123
|
+
.update(message)
|
|
124
|
+
.digest('hex');
|
|
125
|
+
|
|
126
|
+
return `t=${timestamp},v1=${signature}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function verifySignature(payload: string, signature: string): boolean {
|
|
130
|
+
const [timestamp, ...parts] = signature.split(',');
|
|
131
|
+
const ts = parseInt(timestamp.split('=')[1]);
|
|
132
|
+
const sig = parts[0].split('=')[1];
|
|
133
|
+
|
|
134
|
+
// Prevent replay attacks
|
|
135
|
+
if (Math.abs(Date.now() / 1000 - ts) > 300) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const message = `${ts}.${payload}`;
|
|
140
|
+
const expectedSig = crypto
|
|
141
|
+
.createHmac('sha256', process.env.WEBHOOK_SECRET!)
|
|
142
|
+
.update(message)
|
|
143
|
+
.digest('hex');
|
|
144
|
+
|
|
145
|
+
return crypto.timingSafeEqual(sig, expectedSig);
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Publishing Events
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
async function publishWebhookEvent(event: {
|
|
153
|
+
type: string;
|
|
154
|
+
data: any;
|
|
155
|
+
}) {
|
|
156
|
+
// Find all webhook endpoints subscribed to this event type
|
|
157
|
+
const subscriptions = await db.webhookSubscriptions.find({
|
|
158
|
+
events: event.type
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
for (const subscription of subscriptions) {
|
|
162
|
+
// Create delivery record
|
|
163
|
+
await db.webhookDeliveries.insert({
|
|
164
|
+
id: crypto.randomUUID(),
|
|
165
|
+
url: subscription.url,
|
|
166
|
+
payload: event.data,
|
|
167
|
+
status: 'pending',
|
|
168
|
+
attempts: 0
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Attempt immediate delivery
|
|
172
|
+
const delivery = await db.webhookDeliveries.findById(id);
|
|
173
|
+
await deliverWebhook(delivery);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Usage
|
|
178
|
+
app.post('/api/orders', async (req, res) => {
|
|
179
|
+
const order = await db.orders.create(req.body);
|
|
180
|
+
|
|
181
|
+
// Publish event
|
|
182
|
+
await publishWebhookEvent({
|
|
183
|
+
type: 'order.created',
|
|
184
|
+
data: { orderId: order.id, amount: order.total }
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
res.status(201).json(order);
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Client-Side Webhook Handling
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
async function handleStripeWebhook(event: any) {
|
|
195
|
+
console.log('Received webhook:', event.type);
|
|
196
|
+
|
|
197
|
+
// Verify signature
|
|
198
|
+
const signature = request.headers['stripe-signature'];
|
|
199
|
+
if (!verifyStripeSignature(request.body, signature)) {
|
|
200
|
+
return res.status(401).send('Unauthorized');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Process asynchronously
|
|
204
|
+
await queue.enqueue({
|
|
205
|
+
type: 'webhook',
|
|
206
|
+
eventType: event.type,
|
|
207
|
+
data: event.data
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Return 200 immediately
|
|
211
|
+
res.json({ received: true });
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Best Practices
|
|
216
|
+
|
|
217
|
+
✅ **Verify signatures** - Ensure webhook authenticity
|
|
218
|
+
✅ **Retry logic** - Use exponential backoff
|
|
219
|
+
✅ **Idempotency** - Handle duplicate deliveries
|
|
220
|
+
✅ **Async processing** - Don't block on webhook delivery
|
|
221
|
+
✅ **Logging** - Track all webhook events
|
|
222
|
+
|
|
223
|
+
## Resources
|
|
224
|
+
|
|
225
|
+
- [Webhook Best Practices](https://docs.svix.com/webhooks/best-practices)
|
|
226
|
+
- [Stripe Webhooks](https://stripe.com/docs/webhooks)
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Clean Code Architecture
|
|
2
|
+
|
|
3
|
+
Principles for writing maintainable, testable code.
|
|
4
|
+
|
|
5
|
+
## SOLID Principles
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
// Single Responsibility Principle
|
|
9
|
+
// Bad: UserService does too much
|
|
10
|
+
class UserService {
|
|
11
|
+
async createUser(userData) { /*...*/ }
|
|
12
|
+
async sendEmail(to, subject, body) { /*...*/ }
|
|
13
|
+
async logActivity(userId, action) { /*...*/ }
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Good: Separate concerns
|
|
17
|
+
class UserService {
|
|
18
|
+
async createUser(userData) { /*...*/ }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
class EmailService {
|
|
22
|
+
async sendEmail(to, subject, body) { /*...*/ }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class LogService {
|
|
26
|
+
async logActivity(userId, action) { /*...*/ }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Open/Closed Principle
|
|
30
|
+
// Bad: Hard to extend without modification
|
|
31
|
+
class PaymentProcessor {
|
|
32
|
+
process(payment, method) {
|
|
33
|
+
if (method === 'stripe') {
|
|
34
|
+
// Stripe logic
|
|
35
|
+
} else if (method === 'paypal') {
|
|
36
|
+
// PayPal logic
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Good: Extensible via inheritance
|
|
42
|
+
abstract class PaymentProvider {
|
|
43
|
+
abstract process(payment: Payment): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class StripeProvider extends PaymentProvider {
|
|
47
|
+
async process(payment: Payment) { /*...*/ }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
class PayPalProvider extends PaymentProvider {
|
|
51
|
+
async process(payment: Payment) { /*...*/ }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
class PaymentProcessor {
|
|
55
|
+
constructor(private provider: PaymentProvider) {}
|
|
56
|
+
|
|
57
|
+
async process(payment: Payment) {
|
|
58
|
+
await this.provider.process(payment);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Dependency Injection
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Bad: Tightly coupled
|
|
67
|
+
class UserRepository {
|
|
68
|
+
private db = new Database();
|
|
69
|
+
|
|
70
|
+
async findById(id: string) {
|
|
71
|
+
return this.db.query('...');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Good: Injected dependencies
|
|
76
|
+
class UserRepository {
|
|
77
|
+
constructor(private db: Database) {}
|
|
78
|
+
|
|
79
|
+
async findById(id: string) {
|
|
80
|
+
return this.db.query('...');
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Container pattern
|
|
85
|
+
class Container {
|
|
86
|
+
private services = new Map();
|
|
87
|
+
|
|
88
|
+
register(name: string, factory: () => any) {
|
|
89
|
+
this.services.set(name, factory);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get(name: string) {
|
|
93
|
+
const factory = this.services.get(name);
|
|
94
|
+
return factory();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const container = new Container();
|
|
99
|
+
container.register('db', () => new Database());
|
|
100
|
+
container.register('userRepository', () =>
|
|
101
|
+
new UserRepository(container.get('db'))
|
|
102
|
+
);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Design Patterns
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Factory Pattern
|
|
109
|
+
interface UserFactory {
|
|
110
|
+
createAdmin(data: any): User;
|
|
111
|
+
createMember(data: any): User;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
class StandardUserFactory implements UserFactory {
|
|
115
|
+
createAdmin(data) {
|
|
116
|
+
return new User({ ...data, role: 'admin' });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
createMember(data) {
|
|
120
|
+
return new User({ ...data, role: 'member' });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Strategy Pattern
|
|
125
|
+
interface PaymentStrategy {
|
|
126
|
+
pay(amount: number): Promise<void>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
class CreditCardPayment implements PaymentStrategy {
|
|
130
|
+
async pay(amount: number) { /*...*/ }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
class PayPalPayment implements PaymentStrategy {
|
|
134
|
+
async pay(amount: number) { /*...*/ }
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
class OrderProcessor {
|
|
138
|
+
constructor(private paymentStrategy: PaymentStrategy) {}
|
|
139
|
+
|
|
140
|
+
async checkout(amount: number) {
|
|
141
|
+
await this.paymentStrategy.pay(amount);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Observer Pattern
|
|
146
|
+
class EventBus {
|
|
147
|
+
private listeners = new Map<string, Function[]>();
|
|
148
|
+
|
|
149
|
+
on(event: string, callback: Function) {
|
|
150
|
+
if (!this.listeners.has(event)) {
|
|
151
|
+
this.listeners.set(event, []);
|
|
152
|
+
}
|
|
153
|
+
this.listeners.get(event)!.push(callback);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
emit(event: string, data: any) {
|
|
157
|
+
this.listeners.get(event)?.forEach(cb => cb(data));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Error Handling
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
// Custom error classes
|
|
166
|
+
class ApplicationError extends Error {
|
|
167
|
+
constructor(
|
|
168
|
+
public statusCode: number,
|
|
169
|
+
message: string,
|
|
170
|
+
public code: string
|
|
171
|
+
) {
|
|
172
|
+
super(message);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
class ValidationError extends ApplicationError {
|
|
177
|
+
constructor(message: string) {
|
|
178
|
+
super(400, message, 'VALIDATION_ERROR');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
class NotFoundError extends ApplicationError {
|
|
183
|
+
constructor(resource: string) {
|
|
184
|
+
super(404, `${resource} not found`, 'NOT_FOUND');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Usage
|
|
189
|
+
async function getUser(id: string) {
|
|
190
|
+
if (!id) {
|
|
191
|
+
throw new ValidationError('User ID is required');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const user = await db.users.findById(id);
|
|
195
|
+
if (!user) {
|
|
196
|
+
throw new NotFoundError('User');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return user;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Error handler middleware
|
|
203
|
+
app.use((err: Error, req, res, next) => {
|
|
204
|
+
if (err instanceof ApplicationError) {
|
|
205
|
+
return res.status(err.statusCode).json({
|
|
206
|
+
code: err.code,
|
|
207
|
+
message: err.message
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
res.status(500).json({ code: 'INTERNAL_ERROR' });
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Best Practices
|
|
216
|
+
|
|
217
|
+
✅ **DRY** - Don't Repeat Yourself
|
|
218
|
+
✅ **KISS** - Keep It Simple, Stupid
|
|
219
|
+
✅ **YAGNI** - You Aren't Gonna Need It
|
|
220
|
+
✅ **Meaningful names** - Self-documenting code
|
|
221
|
+
✅ **Small functions** - Single responsibility
|
|
222
|
+
|
|
223
|
+
## Resources
|
|
224
|
+
|
|
225
|
+
- [Clean Code by Robert C. Martin](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882)
|
|
226
|
+
- [Design Patterns](https://refactoring.guru/design-patterns)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Clean Architecture
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Organize code in layers: Domain (core logic) → Application (use cases) → Infrastructure (DB/HTTP) → Interface (controllers).
|
|
5
|
+
|
|
6
|
+
## Project Structure
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
src/
|
|
10
|
+
├── domain/ # No external deps — pure business logic
|
|
11
|
+
│ └── user/
|
|
12
|
+
│ ├── User.ts # Entity
|
|
13
|
+
│ └── UserRepository.ts # Interface (Port)
|
|
14
|
+
├── application/ # Orchestrates domain
|
|
15
|
+
│ └── user/
|
|
16
|
+
│ └── CreateUserUseCase.ts
|
|
17
|
+
├── infrastructure/ # Implements ports
|
|
18
|
+
│ └── user/
|
|
19
|
+
│ └── PrismaUserRepository.ts
|
|
20
|
+
└── interfaces/ # HTTP, GraphQL — thin layer
|
|
21
|
+
└── UserController.ts
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Domain Entity
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
export class User {
|
|
28
|
+
private constructor(
|
|
29
|
+
public readonly id: string,
|
|
30
|
+
public readonly email: string,
|
|
31
|
+
public readonly name: string,
|
|
32
|
+
) {}
|
|
33
|
+
|
|
34
|
+
static create(props: { email: string; name: string }): User {
|
|
35
|
+
if (!props.email.includes('@')) throw new Error('Invalid email');
|
|
36
|
+
return new User(crypto.randomUUID(), props.email, props.name);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface UserRepository {
|
|
41
|
+
findById(id: string): Promise<User | null>;
|
|
42
|
+
findByEmail(email: string): Promise<User | null>;
|
|
43
|
+
save(user: User): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Application Use Case
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
export class CreateUserUseCase {
|
|
51
|
+
constructor(private readonly userRepo: UserRepository) {}
|
|
52
|
+
|
|
53
|
+
async execute(input: { email: string; name: string }) {
|
|
54
|
+
const existing = await this.userRepo.findByEmail(input.email);
|
|
55
|
+
if (existing) throw new Error('Email already in use');
|
|
56
|
+
const user = User.create(input);
|
|
57
|
+
await this.userRepo.save(user);
|
|
58
|
+
return { id: user.id, email: user.email, name: user.name };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Infrastructure Adapter
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
export class PrismaUserRepository implements UserRepository {
|
|
67
|
+
constructor(private readonly prisma: PrismaClient) {}
|
|
68
|
+
|
|
69
|
+
async findById(id: string): Promise<User | null> {
|
|
70
|
+
const row = await this.prisma.user.findUnique({ where: { id } });
|
|
71
|
+
return row ? User.create({ email: row.email, name: row.name }) : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async save(user: User): Promise<void> {
|
|
75
|
+
await this.prisma.user.upsert({
|
|
76
|
+
where: { id: user.id },
|
|
77
|
+
create: { id: user.id, email: user.email, name: user.name },
|
|
78
|
+
update: { name: user.name },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Best Practices
|
|
85
|
+
- Domain layer must have zero external dependencies
|
|
86
|
+
- Use interfaces (ports) at every layer boundary
|
|
87
|
+
- Inject all dependencies — never instantiate in use cases
|
|
88
|
+
- Entities validate their own invariants
|
|
89
|
+
|
|
90
|
+
## Resources
|
|
91
|
+
- [Clean Architecture (Robert C. Martin)](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
|