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,218 @@
|
|
|
1
|
+
# Real-Time Subscriptions
|
|
2
|
+
|
|
3
|
+
WebSockets and GraphQL subscriptions for live updates.
|
|
4
|
+
|
|
5
|
+
## WebSockets
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { WebSocketServer } from 'ws';
|
|
9
|
+
import http from 'http';
|
|
10
|
+
|
|
11
|
+
const server = http.createServer();
|
|
12
|
+
const wss = new WebSocketServer({ server });
|
|
13
|
+
|
|
14
|
+
const clients = new Map<string, WebSocket>();
|
|
15
|
+
|
|
16
|
+
wss.on('connection', (ws: WebSocket) => {
|
|
17
|
+
const clientId = crypto.randomUUID();
|
|
18
|
+
clients.set(clientId, ws);
|
|
19
|
+
|
|
20
|
+
ws.on('message', (message: string) => {
|
|
21
|
+
const data = JSON.parse(message);
|
|
22
|
+
|
|
23
|
+
switch (data.type) {
|
|
24
|
+
case 'subscribe':
|
|
25
|
+
// Subscribe to updates
|
|
26
|
+
handleSubscribe(clientId, data.channel);
|
|
27
|
+
break;
|
|
28
|
+
case 'message':
|
|
29
|
+
// Broadcast to all connected clients
|
|
30
|
+
broadcast(data);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
ws.on('close', () => {
|
|
36
|
+
clients.delete(clientId);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function broadcast(message: any) {
|
|
41
|
+
clients.forEach(client => {
|
|
42
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
43
|
+
client.send(JSON.stringify(message));
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function handleSubscribe(clientId: string, channel: string) {
|
|
49
|
+
const client = clients.get(clientId);
|
|
50
|
+
if (client) {
|
|
51
|
+
client.send(JSON.stringify({
|
|
52
|
+
type: 'subscribed',
|
|
53
|
+
channel
|
|
54
|
+
}));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
server.listen(3000);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Socket.io with Rooms
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { createServer } from 'http';
|
|
65
|
+
import { Server } from 'socket.io';
|
|
66
|
+
|
|
67
|
+
const server = createServer();
|
|
68
|
+
const io = new Server(server, {
|
|
69
|
+
cors: { origin: '*' }
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
io.on('connection', (socket) => {
|
|
73
|
+
console.log(`User connected: ${socket.id}`);
|
|
74
|
+
|
|
75
|
+
// Join room
|
|
76
|
+
socket.on('join-conversation', (conversationId) => {
|
|
77
|
+
socket.join(`conversation:${conversationId}`);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Send message to room
|
|
81
|
+
socket.on('message', (data) => {
|
|
82
|
+
io.to(`conversation:${data.conversationId}`).emit('new-message', {
|
|
83
|
+
userId: socket.id,
|
|
84
|
+
...data
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// Leave room
|
|
89
|
+
socket.on('leave-conversation', (conversationId) => {
|
|
90
|
+
socket.leave(`conversation:${conversationId}`);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
socket.on('disconnect', () => {
|
|
94
|
+
console.log(`User disconnected: ${socket.id}`);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
server.listen(3000);
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## GraphQL Subscriptions
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { gql } from 'apollo-server';
|
|
105
|
+
|
|
106
|
+
const typeDefs = gql`
|
|
107
|
+
type Subscription {
|
|
108
|
+
messageAdded(conversationId: ID!): Message!
|
|
109
|
+
userStatusChanged: User!
|
|
110
|
+
}
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
const resolvers = {
|
|
114
|
+
Subscription: {
|
|
115
|
+
messageAdded: {
|
|
116
|
+
subscribe: (_, { conversationId }) => {
|
|
117
|
+
return pubSub.asyncIterator([`MESSAGE_ADDED_${conversationId}`]);
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
userStatusChanged: {
|
|
121
|
+
subscribe: () => {
|
|
122
|
+
return pubSub.asyncIterator(['USER_STATUS_CHANGED']);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// Publish events
|
|
129
|
+
import { PubSub } from 'apollo-server';
|
|
130
|
+
|
|
131
|
+
const pubSub = new PubSub();
|
|
132
|
+
|
|
133
|
+
async function createMessage(conversationId: string, message: any) {
|
|
134
|
+
const newMessage = await db.messages.create(message);
|
|
135
|
+
|
|
136
|
+
pubSub.publish(`MESSAGE_ADDED_${conversationId}`, {
|
|
137
|
+
messageAdded: newMessage
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
return newMessage;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function updateUserStatus(userId: string, status: string) {
|
|
144
|
+
const user = await db.users.update(userId, { status });
|
|
145
|
+
|
|
146
|
+
pubSub.publish('USER_STATUS_CHANGED', {
|
|
147
|
+
userStatusChanged: user
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return user;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## React Hook for Subscriptions
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
import { useEffect, useState } from 'react';
|
|
158
|
+
import { useSubscription, gql } from '@apollo/client';
|
|
159
|
+
|
|
160
|
+
const MESSAGE_SUBSCRIPTION = gql`
|
|
161
|
+
subscription OnMessageAdded($conversationId: ID!) {
|
|
162
|
+
messageAdded(conversationId: $conversationId) {
|
|
163
|
+
id
|
|
164
|
+
content
|
|
165
|
+
sender {
|
|
166
|
+
id
|
|
167
|
+
name
|
|
168
|
+
}
|
|
169
|
+
createdAt
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
|
|
174
|
+
export function useConversationMessages(conversationId: string) {
|
|
175
|
+
const { data, error, loading } = useSubscription(MESSAGE_SUBSCRIPTION, {
|
|
176
|
+
variables: { conversationId }
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const [messages, setMessages] = useState<Message[]>([]);
|
|
180
|
+
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (data?.messageAdded) {
|
|
183
|
+
setMessages(prev => [...prev, data.messageAdded]);
|
|
184
|
+
}
|
|
185
|
+
}, [data]);
|
|
186
|
+
|
|
187
|
+
return { messages, loading, error };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Usage
|
|
191
|
+
export function ConversationView({ conversationId }: any) {
|
|
192
|
+
const { messages } = useConversationMessages(conversationId);
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<div>
|
|
196
|
+
{messages.map(msg => (
|
|
197
|
+
<div key={msg.id}>
|
|
198
|
+
<strong>{msg.sender.name}:</strong> {msg.content}
|
|
199
|
+
</div>
|
|
200
|
+
))}
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Best Practices
|
|
207
|
+
|
|
208
|
+
✅ **Heartbeat** - Send ping/pong to detect disconnects
|
|
209
|
+
✅ **Reconnection** - Auto-reconnect with exponential backoff
|
|
210
|
+
✅ **Room management** - Use rooms for efficient broadcasting
|
|
211
|
+
✅ **Message compression** - Reduce bandwidth usage
|
|
212
|
+
✅ **Error handling** - Graceful degradation
|
|
213
|
+
|
|
214
|
+
## Resources
|
|
215
|
+
|
|
216
|
+
- [Socket.io Documentation](https://socket.io/docs/)
|
|
217
|
+
- [GraphQL Subscriptions](https://www.apollographql.com/docs/apollo-server/data/subscriptions/)
|
|
218
|
+
- [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# A/B Testing
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Run controlled experiments to validate product decisions with statistical confidence.
|
|
5
|
+
|
|
6
|
+
## PostHog Feature Flags (Self-hosted / Cloud)
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install posthog-js posthog-node
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```typescript
|
|
13
|
+
// client-side
|
|
14
|
+
import posthog from 'posthog-js';
|
|
15
|
+
|
|
16
|
+
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
|
|
17
|
+
api_host: 'https://app.posthog.com',
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Get experiment variant
|
|
21
|
+
const variant = posthog.getFeatureFlag('checkout-button-color');
|
|
22
|
+
// Returns: 'control', 'variant-blue', 'variant-green'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// server-side (Next.js API route)
|
|
27
|
+
import { PostHog } from 'posthog-node';
|
|
28
|
+
const client = new PostHog(process.env.POSTHOG_API_KEY!);
|
|
29
|
+
|
|
30
|
+
export async function GET(req: Request) {
|
|
31
|
+
const userId = await getUserId(req);
|
|
32
|
+
const variant = await client.getFeatureFlag('new-onboarding', userId);
|
|
33
|
+
return Response.json({ variant });
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Simple In-House A/B Test
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// Deterministic assignment by user ID (consistent across sessions)
|
|
41
|
+
function getVariant(userId: string, experimentId: string, variants: string[]): string {
|
|
42
|
+
const hash = require('crypto')
|
|
43
|
+
.createHash('md5')
|
|
44
|
+
.update(`${userId}:${experimentId}`)
|
|
45
|
+
.digest('hex');
|
|
46
|
+
const index = parseInt(hash.slice(0, 8), 16) % variants.length;
|
|
47
|
+
return variants[index];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Usage
|
|
51
|
+
const variant = getVariant(user.id, 'checkout-cta', ['control', 'treatment']);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Track Conversion Events
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
// Track experiment exposure
|
|
58
|
+
posthog.capture('$experiment_started', {
|
|
59
|
+
'$experiment_name': 'checkout-cta',
|
|
60
|
+
'$variant': variant,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Track goal
|
|
64
|
+
posthog.capture('checkout_completed', { variant, revenue: 49 });
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Statistical Significance (Basic)
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
function zScore(control: { conversions: number; visitors: number },
|
|
71
|
+
treatment: { conversions: number; visitors: number }): number {
|
|
72
|
+
const p1 = control.conversions / control.visitors;
|
|
73
|
+
const p2 = treatment.conversions / treatment.visitors;
|
|
74
|
+
const pooled = (control.conversions + treatment.conversions) / (control.visitors + treatment.visitors);
|
|
75
|
+
return (p2 - p1) / Math.sqrt(pooled * (1 - pooled) * (1 / control.visitors + 1 / treatment.visitors));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const z = zScore({ conversions: 120, visitors: 1000 }, { conversions: 145, visitors: 1000 });
|
|
79
|
+
const significant = Math.abs(z) > 1.96; // 95% confidence
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Best Practices
|
|
83
|
+
- Run tests for at least 2 weeks to account for day-of-week effects
|
|
84
|
+
- Only test one change per experiment
|
|
85
|
+
- Pre-determine sample size before starting (avoid stopping early)
|
|
86
|
+
- Use server-side assignment to prevent flicker
|
|
87
|
+
|
|
88
|
+
## Resources
|
|
89
|
+
- [PostHog experiments](https://posthog.com/docs/experiments/manual)
|
|
90
|
+
- [Evan Miller A/B calculator](https://www.evanmiller.org/ab-testing/sample-size.html)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# SaaS Analytics
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Track user behavior, product usage, and business metrics to drive data-informed decisions.
|
|
5
|
+
|
|
6
|
+
## PostHog Integration
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install posthog-js posthog-node
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```tsx
|
|
13
|
+
// app/layout.tsx — client-side tracking
|
|
14
|
+
'use client';
|
|
15
|
+
import posthog from 'posthog-js';
|
|
16
|
+
import { PostHogProvider } from 'posthog-js/react';
|
|
17
|
+
import { useEffect } from 'react';
|
|
18
|
+
|
|
19
|
+
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { api_host: 'https://app.posthog.com' });
|
|
20
|
+
|
|
21
|
+
export function PHProvider({ children }: { children: React.ReactNode }) {
|
|
22
|
+
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Track Events
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { usePostHog } from 'posthog-js/react';
|
|
30
|
+
|
|
31
|
+
function CheckoutButton({ price }: { price: number }) {
|
|
32
|
+
const posthog = usePostHog();
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<button onClick={() => {
|
|
36
|
+
posthog.capture('checkout_initiated', {
|
|
37
|
+
plan: 'pro',
|
|
38
|
+
price,
|
|
39
|
+
source: 'pricing_page',
|
|
40
|
+
});
|
|
41
|
+
}}>
|
|
42
|
+
Upgrade to Pro
|
|
43
|
+
</button>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Identify Users
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// After login — tie events to user
|
|
52
|
+
posthog.identify(user.id, {
|
|
53
|
+
email: user.email,
|
|
54
|
+
name: user.name,
|
|
55
|
+
plan: user.plan,
|
|
56
|
+
createdAt: user.createdAt,
|
|
57
|
+
company: user.company,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Reset on logout
|
|
61
|
+
posthog.reset();
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Server-Side Event Tracking
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { PostHog } from 'posthog-node';
|
|
68
|
+
const analytics = new PostHog(process.env.POSTHOG_API_KEY!);
|
|
69
|
+
|
|
70
|
+
// Track subscription upgrade
|
|
71
|
+
await analytics.capture({
|
|
72
|
+
distinctId: userId,
|
|
73
|
+
event: 'subscription_upgraded',
|
|
74
|
+
properties: { from_plan: 'free', to_plan: 'pro', revenue: 49 }
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Flush before serverless function exits
|
|
78
|
+
await analytics.shutdown();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Key SaaS Metrics to Track
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
// Events to capture
|
|
85
|
+
const EVENTS = {
|
|
86
|
+
// Acquisition
|
|
87
|
+
SIGNUP: 'user_signed_up',
|
|
88
|
+
FIRST_LOGIN: 'user_first_login',
|
|
89
|
+
|
|
90
|
+
// Activation
|
|
91
|
+
ONBOARDING_COMPLETED: 'onboarding_completed',
|
|
92
|
+
FIRST_VALUE_ACTION: 'first_project_created',
|
|
93
|
+
|
|
94
|
+
// Retention
|
|
95
|
+
FEATURE_USED: 'feature_used',
|
|
96
|
+
SESSION_STARTED: '$pageview',
|
|
97
|
+
|
|
98
|
+
// Revenue
|
|
99
|
+
UPGRADE_CLICKED: 'upgrade_clicked',
|
|
100
|
+
CHECKOUT_COMPLETED: 'subscription_created',
|
|
101
|
+
CHURNED: 'subscription_cancelled',
|
|
102
|
+
};
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Best Practices
|
|
106
|
+
- Identify users right after authentication
|
|
107
|
+
- Track activation event (when user gets first value)
|
|
108
|
+
- Use `$set` properties for persistent user attributes
|
|
109
|
+
- Group users by organization for B2B analytics
|
|
110
|
+
|
|
111
|
+
## Resources
|
|
112
|
+
- [PostHog docs](https://posthog.com/docs)
|
|
113
|
+
- [Mixpanel](https://developer.mixpanel.com/docs)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# SaaS Billing with Stripe
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Implement subscription billing with Stripe: pricing plans, checkout, webhooks, and customer portal.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install stripe @stripe/stripe-js
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```env
|
|
13
|
+
STRIPE_SECRET_KEY=sk_live_...
|
|
14
|
+
STRIPE_WEBHOOK_SECRET=whsec_...
|
|
15
|
+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Create Checkout Session
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// app/api/checkout/route.ts
|
|
22
|
+
import Stripe from 'stripe';
|
|
23
|
+
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
|
|
24
|
+
|
|
25
|
+
export async function POST(req: Request) {
|
|
26
|
+
const { userId, priceId, email } = await req.json();
|
|
27
|
+
|
|
28
|
+
const session = await stripe.checkout.sessions.create({
|
|
29
|
+
customer_email: email,
|
|
30
|
+
mode: 'subscription',
|
|
31
|
+
line_items: [{ price: priceId, quantity: 1 }],
|
|
32
|
+
success_url: `${process.env.NEXT_PUBLIC_URL}/dashboard?success=true`,
|
|
33
|
+
cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing`,
|
|
34
|
+
metadata: { userId },
|
|
35
|
+
subscription_data: { metadata: { userId } },
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return Response.json({ url: session.url });
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Webhook Handler
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// app/api/webhooks/stripe/route.ts
|
|
46
|
+
import Stripe from 'stripe';
|
|
47
|
+
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
|
|
48
|
+
|
|
49
|
+
export async function POST(req: Request) {
|
|
50
|
+
const sig = req.headers.get('stripe-signature')!;
|
|
51
|
+
const body = await req.text();
|
|
52
|
+
|
|
53
|
+
let event: Stripe.Event;
|
|
54
|
+
try {
|
|
55
|
+
event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
|
|
56
|
+
} catch {
|
|
57
|
+
return Response.json({ error: 'Invalid signature' }, { status: 400 });
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const userId = (event.data.object as any).metadata?.userId;
|
|
61
|
+
|
|
62
|
+
switch (event.type) {
|
|
63
|
+
case 'customer.subscription.created':
|
|
64
|
+
case 'customer.subscription.updated': {
|
|
65
|
+
const sub = event.data.object as Stripe.Subscription;
|
|
66
|
+
await prisma.user.update({
|
|
67
|
+
where: { id: userId },
|
|
68
|
+
data: {
|
|
69
|
+
stripeCustomerId: sub.customer as string,
|
|
70
|
+
stripeSubscriptionId: sub.id,
|
|
71
|
+
plan: sub.status === 'active' ? 'pro' : 'free',
|
|
72
|
+
planExpiresAt: new Date(sub.current_period_end * 1000),
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
case 'customer.subscription.deleted':
|
|
78
|
+
await prisma.user.update({ where: { id: userId }, data: { plan: 'free' } });
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return Response.json({ received: true });
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Customer Portal
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
export async function POST(req: Request) {
|
|
90
|
+
const user = await getCurrentUser(req);
|
|
91
|
+
const session = await stripe.billingPortal.sessions.create({
|
|
92
|
+
customer: user.stripeCustomerId,
|
|
93
|
+
return_url: `${process.env.NEXT_PUBLIC_URL}/dashboard`,
|
|
94
|
+
});
|
|
95
|
+
return Response.json({ url: session.url });
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Best Practices
|
|
100
|
+
- Always verify webhook signatures
|
|
101
|
+
- Store `stripeCustomerId` in your DB — never recreate customers
|
|
102
|
+
- Use `idempotency_key` for retry-safe checkout session creation
|
|
103
|
+
- Handle `payment_intent.payment_failed` to notify users of failed renewals
|
|
104
|
+
|
|
105
|
+
## Resources
|
|
106
|
+
- [Stripe Billing docs](https://stripe.com/docs/billing)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Transactional Email
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Send reliable transactional emails (welcome, password reset, receipts) using Resend with React Email templates.
|
|
5
|
+
|
|
6
|
+
## Setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install resend @react-email/components
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```env
|
|
13
|
+
RESEND_API_KEY=re_...
|
|
14
|
+
FROM_EMAIL=noreply@yourdomain.com
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## React Email Template
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
// emails/WelcomeEmail.tsx
|
|
21
|
+
import { Html, Head, Body, Container, Heading, Text, Button, Hr } from '@react-email/components';
|
|
22
|
+
|
|
23
|
+
export function WelcomeEmail({ name, confirmUrl }: { name: string; confirmUrl: string }) {
|
|
24
|
+
return (
|
|
25
|
+
<Html>
|
|
26
|
+
<Head />
|
|
27
|
+
<Body style={{ fontFamily: 'sans-serif', backgroundColor: '#f4f4f5' }}>
|
|
28
|
+
<Container style={{ maxWidth: '580px', margin: '0 auto', padding: '20px' }}>
|
|
29
|
+
<Heading>Welcome to MyApp, {name}!</Heading>
|
|
30
|
+
<Text>Thanks for signing up. Confirm your email to get started.</Text>
|
|
31
|
+
<Button href={confirmUrl}
|
|
32
|
+
style={{ backgroundColor: '#0070f3', color: '#fff', padding: '12px 24px', borderRadius: '6px' }}>
|
|
33
|
+
Confirm Email
|
|
34
|
+
</Button>
|
|
35
|
+
<Hr />
|
|
36
|
+
<Text style={{ color: '#888', fontSize: '12px' }}>
|
|
37
|
+
If you didn't sign up, ignore this email.
|
|
38
|
+
</Text>
|
|
39
|
+
</Container>
|
|
40
|
+
</Body>
|
|
41
|
+
</Html>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Send Email
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
// lib/email.ts
|
|
50
|
+
import { Resend } from 'resend';
|
|
51
|
+
import { WelcomeEmail } from '@/emails/WelcomeEmail';
|
|
52
|
+
|
|
53
|
+
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
54
|
+
|
|
55
|
+
export async function sendWelcomeEmail(user: { email: string; name: string; confirmUrl: string }) {
|
|
56
|
+
return resend.emails.send({
|
|
57
|
+
from: process.env.FROM_EMAIL!,
|
|
58
|
+
to: user.email,
|
|
59
|
+
subject: `Welcome to MyApp, ${user.name}!`,
|
|
60
|
+
react: WelcomeEmail({ name: user.name, confirmUrl: user.confirmUrl }),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function sendPasswordReset(email: string, resetUrl: string) {
|
|
65
|
+
return resend.emails.send({
|
|
66
|
+
from: process.env.FROM_EMAIL!,
|
|
67
|
+
to: email,
|
|
68
|
+
subject: 'Reset your password',
|
|
69
|
+
html: `<p>Reset your password: <a href="${resetUrl}">Click here</a></p>`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Preview Emails in Development
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npx email dev --dir emails --port 3001
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Best Practices
|
|
81
|
+
- Preview emails at `localhost:3001` with `@react-email/components` dev server
|
|
82
|
+
- Set SPF, DKIM, DMARC DNS records for deliverability
|
|
83
|
+
- Use `Resend.batch.send()` for bulk sends
|
|
84
|
+
- Store email send records in DB for debugging delivery issues
|
|
85
|
+
|
|
86
|
+
## Resources
|
|
87
|
+
- [Resend docs](https://resend.com/docs)
|
|
88
|
+
- [React Email](https://react.email/docs/introduction)
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Feature Flags
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Control feature rollouts, kill switches, and A/B tests without code deployments.
|
|
5
|
+
|
|
6
|
+
## PostHog Feature Flags
|
|
7
|
+
|
|
8
|
+
```typescript
|
|
9
|
+
// Server-side flag check
|
|
10
|
+
import { PostHog } from 'posthog-node';
|
|
11
|
+
const posthog = new PostHog(process.env.POSTHOG_API_KEY!);
|
|
12
|
+
|
|
13
|
+
export async function isFeatureEnabled(flag: string, userId: string): Promise<boolean> {
|
|
14
|
+
return !!(await posthog.isFeatureEnabled(flag, userId));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// In API route
|
|
18
|
+
const canUseNewEditor = await isFeatureEnabled('new-editor', userId);
|
|
19
|
+
if (canUseNewEditor) return newEditorResponse();
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Simple Database-Driven Flags
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// Simple flag system without third-party
|
|
26
|
+
const FLAGS_CACHE = new Map<string, { value: boolean; expiry: number }>();
|
|
27
|
+
|
|
28
|
+
async function getFlag(name: string): Promise<boolean> {
|
|
29
|
+
const cached = FLAGS_CACHE.get(name);
|
|
30
|
+
if (cached && cached.expiry > Date.now()) return cached.value;
|
|
31
|
+
|
|
32
|
+
const flag = await prisma.featureFlag.findUnique({ where: { name } });
|
|
33
|
+
const value = flag?.enabled ?? false;
|
|
34
|
+
FLAGS_CACHE.set(name, { value, expiry: Date.now() + 60_000 }); // 60s cache
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Schema
|
|
39
|
+
// model FeatureFlag { name String @id; enabled Boolean @default(false); }
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Percentage Rollout
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
function isInRollout(userId: string, percentage: number): boolean {
|
|
46
|
+
const hash = parseInt(
|
|
47
|
+
require('crypto').createHash('sha256').update(userId).digest('hex').slice(0, 4),
|
|
48
|
+
16
|
|
49
|
+
);
|
|
50
|
+
return (hash % 100) < percentage;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Enable for 10% of users
|
|
54
|
+
const showBetaFeature = isInRollout(userId, 10);
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Next.js Middleware with Flags
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// middleware.ts
|
|
61
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
62
|
+
|
|
63
|
+
export async function middleware(req: NextRequest) {
|
|
64
|
+
const userId = req.cookies.get('userId')?.value;
|
|
65
|
+
if (!userId) return NextResponse.next();
|
|
66
|
+
|
|
67
|
+
// Redirect new-checkout test group
|
|
68
|
+
if (req.nextUrl.pathname === '/checkout' && await isFeatureEnabled('new-checkout', userId)) {
|
|
69
|
+
return NextResponse.rewrite(new URL('/checkout-v2', req.url));
|
|
70
|
+
}
|
|
71
|
+
return NextResponse.next();
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Best Practices
|
|
76
|
+
- Clean up flags after full rollout — avoid flag debt
|
|
77
|
+
- Name flags with intent: `new-checkout-flow` not `experiment-123`
|
|
78
|
+
- Add an emergency kill switch for every major feature
|
|
79
|
+
- Log flag evaluations for debugging unexpected behavior
|
|
80
|
+
|
|
81
|
+
## Resources
|
|
82
|
+
- [PostHog feature flags](https://posthog.com/docs/feature-flags)
|
|
83
|
+
- [Unleash](https://www.getunleash.io) — open-source alternative
|