@thierrynakoa/fire-flow 12.2.1 → 13.0.1
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/CREDITS.md +25 -0
- package/DOMINION-FLOW-OVERVIEW.md +182 -38
- package/README.md +399 -455
- package/TROUBLESHOOTING.md +264 -264
- package/agents/fire-debugger.md +54 -0
- package/agents/fire-executor.md +1610 -1033
- package/agents/fire-fact-checker.md +1 -1
- package/agents/fire-planner.md +85 -17
- package/agents/fire-project-researcher.md +1 -1
- package/agents/fire-researcher.md +4 -22
- package/agents/{fire-phoenix-analyst.md → fire-resurrection-analyst.md} +394 -394
- package/agents/fire-reviewer.md +552 -499
- package/agents/fire-verifier.md +114 -19
- package/bin/cli.js +18 -101
- package/commands/fire-0-orient.md +2 -2
- package/commands/fire-1a-new.md +50 -15
- package/commands/fire-1c-setup.md +33 -5
- package/commands/fire-1d-discuss.md +87 -1
- package/commands/fire-2-plan.md +556 -527
- package/commands/fire-3-execute.md +2046 -1356
- package/commands/fire-4-verify.md +975 -906
- package/commands/fire-5-handoff.md +46 -5
- package/commands/fire-6-resume.md +2 -31
- package/commands/fire-add-new-skill.md +138 -19
- package/commands/fire-autonomous.md +14 -2
- package/commands/fire-complete-milestone.md +1 -1
- package/commands/fire-cost.md +179 -183
- package/commands/fire-debug.md +1 -6
- package/commands/fire-loop-resume.md +2 -2
- package/commands/fire-loop-stop.md +1 -1
- package/commands/fire-loop.md +2 -15
- package/commands/fire-map-codebase.md +1 -1
- package/commands/fire-migrate-database.md +548 -0
- package/commands/fire-new-milestone.md +1 -1
- package/commands/fire-reflect.md +1 -2
- package/commands/fire-research.md +142 -21
- package/commands/{fire-phoenix.md → fire-resurrect.md} +859 -603
- package/commands/fire-scaffold.md +297 -0
- package/commands/fire-search.md +1 -2
- package/commands/fire-security-scan.md +483 -484
- package/commands/fire-setup.md +359 -0
- package/commands/fire-skill.md +770 -0
- package/commands/fire-skills-diff.md +506 -506
- package/commands/fire-skills-history.md +388 -388
- package/commands/fire-skills-rollback.md +7 -7
- package/commands/fire-skills-sync.md +470 -470
- package/commands/fire-test.md +5 -5
- package/commands/fire-todos.md +1 -1
- package/commands/fire-update.md +5 -5
- package/commands/fire-validate-skills.md +282 -0
- package/commands/fire-vuln-scan.md +492 -493
- package/hooks/run-hook.sh +8 -8
- package/hooks/run-session-end.sh +7 -7
- package/hooks/session-end.sh +90 -90
- package/hooks/session-start.sh +1 -1
- package/package.json +4 -24
- package/plugin.json +7 -7
- package/references/autonomy-levels.md +235 -0
- package/references/behavioral-directives.md +95 -3
- package/references/blocker-tracking.md +1 -1
- package/references/circuit-breaker.md +93 -2
- package/references/context-engineering.md +227 -9
- package/references/honesty-protocols.md +70 -1
- package/references/issue-to-pr-pipeline.md +149 -150
- package/references/metrics-and-trends.md +1 -2
- package/references/research-improvements.md +4 -108
- package/references/sdlc-mapping.md +73 -0
- package/references/state-machine.md +151 -0
- package/skills-library/AVAILABLE_TOOLS_REFERENCE.md +333 -0
- package/skills-library/SKILLS-INDEX.md +57 -558
- package/skills-library/SKILLS_LIBRARY_INDEX.md +532 -0
- package/skills-library/_general/api-patterns/api-field-name-mismatch.md +107 -0
- package/skills-library/_general/api-patterns/streaming-command-timeout.md +122 -0
- package/skills-library/_general/api-patterns/streaming-proxy-cors-bypass.md +102 -0
- package/skills-library/_general/automation/settings-gui-generator.md +172 -0
- package/skills-library/_general/database-solutions/data-type-mapping-reference.md +181 -0
- package/skills-library/_general/database-solutions/mysql-limit-offset-string-coercion.md +102 -0
- package/skills-library/_general/database-solutions/mysql-to-pg-migration.md +195 -0
- package/skills-library/_general/database-solutions/orm-schema-portability.md +193 -0
- package/skills-library/_general/database-solutions/persistent-analysis-storage.md +207 -0
- package/skills-library/_general/database-solutions/pg-to-mysql-schema-migration-methodology.md +190 -0
- package/skills-library/_general/database-solutions/sql-dialect-compatibility-matrix.md +306 -0
- package/skills-library/_general/database-solutions/sqlite-to-pg-migration.md +219 -0
- package/skills-library/_general/frontend/canvas-bubble-animation-grouping.md +270 -0
- package/skills-library/_general/frontend/color-token-migration.md +112 -0
- package/skills-library/_general/frontend/framer-motion-layoutid-grouping.md +150 -0
- package/skills-library/_general/frontend/pyqt6-settings-dialog.md +191 -0
- package/skills-library/_general/frontend/react-flow-animated-layout-switching.md +101 -0
- package/skills-library/_general/frontend/react-hooks-order-debugging.md +141 -0
- package/skills-library/_general/frontend/redux-localstorage-auth-desync.md +126 -0
- package/skills-library/_general/frontend/safari-csp-theme-color-debugging.md +124 -0
- package/skills-library/_general/frontend/safari-sw-cache-poisoning.md +138 -0
- package/skills-library/_general/frontend/svg-sparkline-no-charting-library.md +131 -0
- package/skills-library/_general/growth-marketing/oss-daily-growth-intelligence.md +224 -0
- package/skills-library/_general/integrations/claude-code-local-mcp-integration.md +250 -0
- package/skills-library/_general/integrations/mcp-composite-tool-orchestration.md +200 -0
- package/skills-library/_general/methodology/AGENT_SDK_STANDALONE_TOOLING.md +181 -0
- package/skills-library/_general/methodology/AGENT_TEAMS_GUIDE.md +169 -0
- package/skills-library/_general/methodology/ALAS_STATEFUL_EXECUTION.md +207 -0
- package/skills-library/_general/methodology/AUTO_REVIEWER_SUBAGENT.md +211 -0
- package/skills-library/_general/methodology/CONSISTENCY_CHECK_AMBIGUITY_GATE.md +96 -0
- package/skills-library/_general/methodology/DEAD_ENDS_SHELF.md +4 -4
- package/skills-library/_general/methodology/DISTILL_NOT_DUMP.md +108 -0
- package/skills-library/_general/methodology/EXECUTION_PROGRESS_MONITOR.md +157 -0
- package/skills-library/_general/methodology/HIERARCHICAL_REVIEW_MARS.md +122 -0
- package/skills-library/_general/methodology/MCP_INTER_AGENT_BRIDGE.md +207 -0
- package/skills-library/_general/methodology/MERMAID_WIZARD_DIAGRAMS.md +77 -0
- package/skills-library/_general/methodology/MISSING_DIMENSION_DETECTOR.md +89 -0
- package/skills-library/_general/methodology/MULTI_AGENT_COORDINATION.md +397 -0
- package/skills-library/_general/methodology/OBSERVATION_MASKING.md +100 -0
- package/skills-library/_general/methodology/PHOENIX_REBUILD_METHODOLOGY.md +82 -11
- package/skills-library/_general/methodology/REVIEW_BACKTRACK_PANEL.md +140 -0
- package/skills-library/_general/methodology/REVIEW_FIX_LOOP.md +117 -0
- package/skills-library/_general/methodology/VOTING_VERDICT_ARBITRATION.md +155 -0
- package/skills-library/_general/methodology/ZERO_FRICTION_CLI_SETUP.md +2 -2
- package/skills-library/_general/methodology/dead-code-activation.md +123 -0
- package/skills-library/_general/methodology/debug-swarm-researcher-escape-hatch.md +240 -240
- package/skills-library/_general/methodology/shell-autonomous-loop-fixplan.md +1 -1
- package/skills-library/_general/patterns-standards/GOF_DESIGN_PATTERNS_FOR_AI_AGENTS.md +5 -5
- package/skills-library/_general/patterns-standards/cascading-failure-diagnosis.md +119 -0
- package/skills-library/_general/patterns-standards/domain-specific-layout-algorithms.md +209 -0
- package/skills-library/_general/patterns-standards/python-desktop-app-architecture.md +399 -0
- package/skills-library/_general/patterns-standards/realtime-monitoring-dashboard.md +457 -0
- package/skills-library/_general/patterns-standards/togglable-processing-pipeline.md +169 -0
- package/skills-library/_general/performance/liveclock-extraction.md +112 -0
- package/skills-library/_general/performance/ref-based-canvas-animation.md +117 -0
- package/skills-library/_general/performance/use-visible-interval.md +131 -0
- package/skills-library/_general/testing/playwright-firefox-withcredentials-auth-issue.md +104 -0
- package/skills-library/_quarantine/README.md +30 -0
- package/skills-library/api-patterns/BROADCAST_SCHEDULER_SHARED_EXECUTE_FUNCTION.md +150 -0
- package/skills-library/api-patterns/ERROR_RESPONSE_STANDARDS.md +145 -0
- package/skills-library/api-patterns/EXPRESS_ROUTE_ORDERING_MIDDLEWARE_INTERCEPTION.md +326 -0
- package/skills-library/api-patterns/PAGINATION_PATTERNS.md +137 -0
- package/skills-library/api-patterns/PODCAST_PROGRESS_TRACKING_THREE_ROOT_CAUSES.md +277 -0
- package/skills-library/api-patterns/RATE_LIMITING_TOGGLE.md +155 -0
- package/skills-library/api-patterns/graphql-content-queries.md +708 -0
- package/skills-library/appointment-scheduler-design.md +423 -0
- package/skills-library/automation/AUTO_POPULATE_COMPLETE_GUIDE.md +631 -0
- package/skills-library/automation/CC_WORKFLOW_STUDIO.md +83 -0
- package/skills-library/automation/CLAUDE_CODE_SWARM_MODE.md +95 -0
- package/skills-library/automation/DAEMON_TRIGGER_FILE_IPC.md +195 -0
- package/skills-library/automation/scheduled-content-publishing.md +608 -0
- package/skills-library/awesome-workflows/Blogging-Platform-Instructions/view_commands.md +25 -0
- package/skills-library/awesome-workflows/CREDENTIAL-SECURITY-WORKFLOW.md +109 -0
- package/skills-library/awesome-workflows/DEBUGGING-WORKFLOW.md +124 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/README.md +31 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-principles-example.md +129 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-agent.md +107 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-claude-md-snippet.md +24 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-slash-command.md +38 -0
- package/skills-library/awesome-workflows/PARALLEL-RESEARCH-WORKFLOW.md +89 -0
- package/skills-library/awesome-workflows/PHASE-EXECUTION-WORKFLOW.md +97 -0
- package/skills-library/awesome-workflows/SESSION-HANDOFF-WORKFLOW.md +116 -0
- package/skills-library/cms-patterns/content-branch-preview.md +515 -0
- package/skills-library/cms-patterns/inline-visual-editing.md +666 -0
- package/skills-library/cms-patterns/mdx-component-content.md +649 -0
- package/skills-library/cms-patterns/media-manager-abstraction.md +827 -0
- package/skills-library/cms-patterns/schema-driven-form-generator.md +838 -0
- package/skills-library/complexity-metrics/complexity-divider.md +707 -0
- package/skills-library/complexity-metrics/work-with-complexity.md +193 -0
- package/skills-library/creative-multimedia/animation-stack-guide.md +577 -0
- package/skills-library/creative-multimedia/audio-enhancement-pipeline.md +625 -0
- package/skills-library/creative-multimedia/content-repurposing-pipeline.md +1146 -0
- package/skills-library/creative-multimedia/data-visualization-generator.md +862 -0
- package/skills-library/creative-multimedia/doc-to-podcast-pipeline.md +2184 -0
- package/skills-library/creative-multimedia/ffmpeg-command-generator.md +405 -0
- package/skills-library/creative-multimedia/image-optimization-pipeline.md +605 -0
- package/skills-library/creative-multimedia/multi-format-content-generator.md +1759 -0
- package/skills-library/creative-multimedia/og-image-generator.md +635 -0
- package/skills-library/creative-multimedia/podcast-audio-composition.md +1355 -0
- package/skills-library/creative-multimedia/podcast-quality-evaluation.md +1452 -0
- package/skills-library/creative-multimedia/podcast-script-generation.md +1841 -0
- package/skills-library/creative-multimedia/svg-generation.md +750 -0
- package/skills-library/creative-multimedia/text-to-speech-provider-selector.md +1414 -0
- package/skills-library/creative-multimedia/transcription-pipeline-selector.md +677 -0
- package/skills-library/creative-multimedia/video-streaming-setup.md +559 -0
- package/skills-library/database-solutions/AI_RESPONSE_DATABASE_CACHING.md +520 -0
- package/skills-library/database-solutions/CONDITIONAL_SQL_MIGRATION_PATTERN.md +119 -0
- package/skills-library/database-solutions/DATABASE_COLUMN_NAME_MISMATCH.md +393 -0
- package/skills-library/database-solutions/DATABASE_SCHEMA.md +394 -0
- package/skills-library/database-solutions/DATABASE_SCHEMA_VERIFICATION_GUIDE.md +348 -0
- package/skills-library/database-solutions/DATABASE_STRATEGY.md +71 -0
- package/skills-library/database-solutions/ES_MODULE_SEED_SCRIPT_PATTERN.md +52 -0
- package/skills-library/database-solutions/MIGRATION_GUIDE.md +3 -0
- package/skills-library/database-solutions/PLPGSQL_VARIABLE_CONFLICT_FIX.md +208 -0
- package/skills-library/database-solutions/POSTGRESQL_JSONB_DOUBLE_STRINGIFY_FIX.md +245 -0
- package/skills-library/database-solutions/POSTGRESQL_LICENSE_TABLE_DESIGN.md +393 -0
- package/skills-library/database-solutions/POSTGRESQL_UUID_DOCUMENT_RAG_DUAL_SCOPE.md +732 -0
- package/skills-library/database-solutions/POSTGRES_SQL_TEMPLATE_BINDING_ERROR.md +240 -0
- package/skills-library/database-solutions/PRISMA_DB_PUSH_DATA_LOSS_PREVENTION.md +141 -0
- package/skills-library/database-solutions/PRODUCTION_QUERY_OPTIMIZATION_RESTART_FIX.md +389 -0
- package/skills-library/database-solutions/RLS_SECURITY_GUIDE.md +107 -0
- package/skills-library/database-solutions/SCHEMA_ENHANCEMENTS_GUIDE.md +373 -0
- package/skills-library/database-solutions/SCHEMA_MIGRATION_GUIDE.md +368 -0
- package/skills-library/database-solutions/SCHEMA_VERIFICATION_QUICK_REFERENCE.md +104 -0
- package/skills-library/database-solutions/ai-erd-generator.md +1213 -0
- package/skills-library/database-solutions/content-publishing-states.md +631 -0
- package/skills-library/database-solutions/database-schema-designer.md +522 -0
- package/skills-library/database-solutions/er-diagram-components.md +569 -0
- package/skills-library/database-solutions/er-to-ddl-mapping.md +1405 -0
- package/skills-library/database-solutions/erd-creator-textbook-research.md +433 -0
- package/skills-library/database-solutions/erd-react-flow-architecture.md +1965 -0
- package/skills-library/database-solutions/mariadb-aggregate-function-replacement.md +145 -0
- package/skills-library/database-solutions/normalization-validator.md +778 -0
- package/skills-library/database-solutions/postgres-full-text-search-content.md +494 -0
- package/skills-library/database-solutions/postgresql-to-mysql-runtime-translation.md +286 -0
- package/skills-library/database-solutions/regex-alternation-ordering-sql-types.md +92 -0
- package/skills-library/database-solutions/reserved-word-context-aware-quoting.md +142 -0
- package/skills-library/database-solutions/sql-ddl-generator.md +756 -0
- package/skills-library/database-solutions/supabase-connection-pooler-fix.md +102 -0
- package/skills-library/deployment-security/CPANEL_NODE_DEPLOYMENT.md +166 -0
- package/skills-library/deployment-security/DEPLOYMENT.md +275 -0
- package/skills-library/deployment-security/DEPLOYMENT_CHECKLIST.md +363 -0
- package/skills-library/deployment-security/DEPLOYMENT_PLAN.md +669 -0
- package/skills-library/deployment-security/KNEX_DATABASE_ABSTRACTION.md +444 -0
- package/skills-library/deployment-security/LICENSE_KEY_SYSTEM.md +206 -0
- package/skills-library/deployment-security/NODE18_DEPENDENCY_COMPATIBILITY.md +284 -0
- package/skills-library/deployment-security/PHP_INSTALLER_WIZARD_GUIDE.md +315 -0
- package/skills-library/deployment-security/PM2_ENVIRONMENT_VARIABLE_CACHING.md +256 -0
- package/skills-library/deployment-security/PM2_MEMORY_EXHAUSTION_FIX.md +370 -0
- package/skills-library/deployment-security/PRODUCTION_DEPLOYMENT_GUIDE.md +592 -0
- package/skills-library/deployment-security/PRODUCTION_HARDENING_DOCUMENTATION.md +307 -0
- package/skills-library/deployment-security/PRODUCTION_RECOVERY_CHERRY_PICK_PATTERN.md +202 -0
- package/skills-library/deployment-security/PYINSTALLER_CUDA_WHISPER_BUNDLING.md +236 -0
- package/skills-library/deployment-security/SECURITY.md +41 -0
- package/skills-library/deployment-security/SMTP_SSL_HOSTNAME_MISMATCH_SHARED_HOSTING.md +220 -0
- package/skills-library/deployment-security/SPA_SEO_OPTIMIZATION_CPANEL.md +200 -0
- package/skills-library/deployment-security/SUPABASE_EDGE_FUNCTIONS.md +338 -0
- package/skills-library/deployment-security/VERCEL_GITHUB_DEPLOYMENT_GUIDE.md +858 -0
- package/skills-library/deployment-security/VPS_DEPLOYMENT_READINESS.md +356 -0
- package/skills-library/deployment-security/deployment-changes-not-applying.md +241 -0
- package/skills-library/deployment-security/env-file-management-production-local.md +203 -0
- package/skills-library/deployment-security/express-secure-file-downloads.md +413 -0
- package/skills-library/deployment-security/react-production-deployment-desktop-guide.md +2011 -0
- package/skills-library/deployment-security/self-hosted-supabase-coolify-guide.md +1684 -0
- package/skills-library/deployment-security/unique-features-ai-strategy-plaid-security.md +1613 -0
- package/skills-library/deployment-security/vps-deployment.md +135 -0
- package/skills-library/document-processing/WORD_EXPORT_MARKDOWN_FORMATTING.md +482 -0
- package/skills-library/document-processing/document-ai-landingai-integration.md +677 -0
- package/skills-library/document-processing/express-secure-file-downloads-mern.md +413 -0
- package/skills-library/document-processing/express-secure-file-downloads.md +413 -0
- package/skills-library/document-processing/md-to-word-converter.md +318 -0
- package/skills-library/document-processing/pdf-forms-integration/README.md +101 -0
- package/skills-library/document-processing/pdf-forms-integration/SKILL.md +662 -0
- package/skills-library/ecommerce/ADMIN_PRODUCTS_GUIDE.md +428 -0
- package/skills-library/ecommerce/ECOMMERCE_API_REFERENCE.md +776 -0
- package/skills-library/ecommerce/ECOMMERCE_COMPLETION_SUMMARY.md +673 -0
- package/skills-library/ecommerce/ECOMMERCE_IMPLEMENTATION_GUIDE.md +729 -0
- package/skills-library/ecommerce/ECOMMERCE_QUICK_REFERENCE.md +521 -0
- package/skills-library/ecommerce/ECOMMERCE_TESTING_CHECKLIST.md +565 -0
- package/skills-library/ecommerce/ECOMMERCE_WORKFLOW_GUIDE.md +1059 -0
- package/skills-library/ecommerce/PRODUCT_CREATION_EXPANDED.md +522 -0
- package/skills-library/ecommerce/agentic-commerce-protocol.md +203 -0
- package/skills-library/ecommerce/cart-abandonment-recovery.md +236 -0
- package/skills-library/ecommerce/cart-architecture-patterns.md +300 -0
- package/skills-library/ecommerce/cart-item-count-indicator.md +264 -0
- package/skills-library/ecommerce/checkout-ux-conversion.md +227 -0
- package/skills-library/ecommerce/composable-commerce-selection.md +166 -0
- package/skills-library/ecommerce/ecommerce-analytics-patterns.md +167 -0
- package/skills-library/ecommerce/fraud-detection-patterns.md +179 -0
- package/skills-library/ecommerce/inventory-stock-management.md +270 -0
- package/skills-library/ecommerce/order-saga-state-machine.md +336 -0
- package/skills-library/ecommerce/payment-provider-abstraction.md +245 -0
- package/skills-library/ecommerce/pci-compliance-checklist.md +192 -0
- package/skills-library/ecommerce/refund-chargeback-handling.md +177 -0
- package/skills-library/ecommerce/shipping-carrier-integration.md +218 -0
- package/skills-library/ecommerce/webhook-idempotency-patterns.md +253 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/ci.yml +558 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/prompt-gallery.yml +448 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/release.yml +42 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/test-reusable-ci.yml +25 -0
- package/skills-library/excalidraw-diagrams/CLAUDE.md +57 -0
- package/skills-library/excalidraw-diagrams/LICENSE +21 -0
- package/skills-library/excalidraw-diagrams/README.md +178 -0
- package/skills-library/excalidraw-diagrams/SKILL.md +715 -0
- package/skills-library/form-solutions/BUTTON_TYPE_FORM_SUBMISSION.md +336 -0
- package/skills-library/form-solutions/FILLABLE_PDF_IMPLEMENTATION.md +226 -0
- package/skills-library/form-solutions/SURVEYJS_QUESTIONNAIRE_SYSTEM.md +367 -0
- package/skills-library/form-solutions/tiptap-minimal-setup.md +690 -0
- package/skills-library/frontend/scholarly-classification-bubble-map.md +149 -0
- package/skills-library/infrastructure/ci-cd-pipeline-builder.md +517 -0
- package/skills-library/infrastructure/observability-designer.md +264 -0
- package/skills-library/infrastructure/performance-profiler.md +621 -0
- package/skills-library/installer-wizard-patterns.md +249 -0
- package/skills-library/integrations/CLAUDE_CODE_TOKEN_ANALYTICS.md +160 -0
- package/skills-library/integrations/CONFIGURABLE_AI_PROVIDER_SELECTION.md +728 -0
- package/skills-library/integrations/SOCKET_IO_BROADCAST_ALL_VS_ROOM.md +141 -0
- package/skills-library/integrations/VIRTUAL_MEETINGS_IMPLEMENTATION.md +374 -0
- package/skills-library/integrations/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
- package/skills-library/integrations/YOUTUBE_API_SETUP.md +141 -0
- package/skills-library/integrations/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
- package/skills-library/integrations/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
- package/skills-library/integrations/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
- package/skills-library/integrations/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
- package/skills-library/integrations/ai-ml/GEMINI_AI_RAG_PIPELINE_COMPLETE_GUIDE.md +195 -0
- package/skills-library/integrations/ai-ml/GEMINI_IMAGE_GENERATION_SETUP.md +64 -0
- package/skills-library/integrations/cloudflare/cloudflare-turnstile-debugging.md +202 -0
- package/skills-library/integrations/cloudflare/cloudflare-turnstile-implementation.md +476 -0
- package/skills-library/integrations/cloudflare-turnstile-debugging.md +202 -0
- package/skills-library/integrations/cloudflare-turnstile-implementation.md +476 -0
- package/skills-library/integrations/ghost-creator-monetization-pattern.md +454 -0
- package/skills-library/integrations/headless-cms-architecture.md +484 -0
- package/skills-library/integrations/headless-cms-stack-selection.md +183 -0
- package/skills-library/integrations/payload-cms-patterns.md +674 -0
- package/skills-library/integrations/realtimestt-openwakeword-cuda-windows.md +229 -0
- package/skills-library/integrations/rss-podcast-integration.md +300 -0
- package/skills-library/integrations/wordpress/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
- package/skills-library/integrations/youtube/YOUTUBE_API_SETUP.md +141 -0
- package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
- package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
- package/skills-library/integrations/youtube/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
- package/skills-library/integrations/youtube/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
- package/skills-library/marketing/campaign-analytics.md +97 -0
- package/skills-library/marketing/content-creator.md +105 -0
- package/skills-library/marketing/marketing-strategy-pmm.md +94 -0
- package/skills-library/marketing/social-media-analyzer.md +81 -0
- package/skills-library/methodology/ADVANCED_ORCHESTRATION_PATTERNS.md +401 -0
- package/skills-library/methodology/AGENT_SELF_IMPROVEMENT_LOOP.md +179 -0
- package/skills-library/methodology/BREATH_BASED_PARALLEL_EXECUTION.md +1 -1
- package/skills-library/methodology/CLEANSING_CYCLE.md +358 -0
- package/skills-library/methodology/CONFIDENCE_ANNOTATION_PATTERN.md +143 -0
- package/skills-library/methodology/CRITICAL_PATTERNS_DOCUMENTATION_COMPLETE.md +204 -0
- package/skills-library/methodology/DELIVERABLES_SUMMARY.md +341 -0
- package/skills-library/methodology/DIFFICULTY_AWARE_AGENT_ROUTING.md +252 -0
- package/skills-library/methodology/EVOLUTIONARY_SKILL_SYNTHESIS.md +219 -0
- package/skills-library/methodology/GLOMERULUS_DECISION_GATE.md +223 -0
- package/skills-library/methodology/HIBERNATION_SYSTEM.md +231 -0
- package/skills-library/methodology/INSTRUMENTATION_OVER_RESTRICTION.md +192 -0
- package/skills-library/methodology/MASTER_COMPLETION_SUMMARY.md +444 -0
- package/skills-library/methodology/MASTER_SESSION_COMPLETION.md +743 -0
- package/skills-library/methodology/MERN_QUICK_REFERENCE.md +358 -0
- package/skills-library/methodology/ORGAN_AGENT_MAPPING.md +177 -0
- package/skills-library/methodology/PARALLEL_WAVE_BASED_REFACTORING.md +440 -0
- package/skills-library/methodology/QUICK_REFERENCE.md +358 -0
- package/skills-library/methodology/SDFT_ONPOLICY_SELF_DISTILLATION.md +186 -0
- package/skills-library/methodology/SELF_QUESTIONING_TASK_GENERATION.md +270 -0
- package/skills-library/methodology/SESSION_COMPLETION_SUMMARY.md +304 -0
- package/skills-library/methodology/SESSION_SUMMARY.md +432 -0
- package/skills-library/methodology/WARRIOR_WORKFLOW_DEBUGGING_PROTOCOL.md +252 -0
- package/skills-library/methodology/tech-debt-tracker.md +570 -0
- package/skills-library/parallel-debug/SKILL.md +60 -0
- package/skills-library/patterns-standards/API_PATTERN_FIX_SUMMARY.md +236 -0
- package/skills-library/patterns-standards/BATCH_OPERATIONS_WITH_PROGRESS_MODAL.md +362 -0
- package/skills-library/patterns-standards/CRITICAL_CODING_PATTERNS.md +639 -0
- package/skills-library/patterns-standards/DARK_MODE_MODAL_VISIBILITY.md +258 -0
- package/skills-library/patterns-standards/ERROR_RESILIENCE_IMPLEMENTATION.md +375 -0
- package/skills-library/patterns-standards/ES_MODULE_IMPORT_HOISTING_DOTENV.md +298 -0
- package/skills-library/patterns-standards/NESTED_BACKDROP_FILTER_CSS_ARTIFACT_FIX.md +76 -0
- package/skills-library/patterns-standards/ORDERED_DETECTOR_PIPELINE_GRACEFUL_FALLBACK.md +333 -0
- package/skills-library/patterns-standards/PHASE_IMPORT_ERROR_DEBUGGING.md +271 -0
- package/skills-library/patterns-standards/PYNPUT_GLOBAL_HOTKEY_VK_MATCHING.md +252 -0
- package/skills-library/patterns-standards/REACT_USEEFFECT_CASCADE_RESET_FIX.md +132 -0
- package/skills-library/patterns-standards/SUBMENU_HOVER_DROPDOWN_PATTERN.md +225 -0
- package/skills-library/patterns-standards/TAILWIND_TEXT_VISIBILITY_OVERRIDE.md +322 -0
- package/skills-library/patterns-standards/THEME_AWARE_CSS_VARIABLES_PATTERN.md +209 -0
- package/skills-library/patterns-standards/THEME_USER_OBJECT_PROPERTY_NAMING.md +194 -0
- package/skills-library/patterns-standards/TOOLTIP_BLOCKING_CLICKS_FIX.md +267 -0
- package/skills-library/patterns-standards/claude-code-plugin-structure.md +235 -0
- package/skills-library/patterns-standards/react-i18next-setup.md +429 -0
- package/skills-library/patterns-standards/thesys-c1-generative-ui-integration.md +967 -0
- package/skills-library/plugin-development/CLAUDE_CODE_COMMAND_REGISTRATION_SILENT_FAILURE.md +315 -0
- package/skills-library/plugin-development/plugin-command-namespace-vs-global.md +390 -0
- package/skills-library/plugin-development/plugin-doc-auto-generation.md +172 -0
- package/skills-library/security/GITHUB_REPO_SECURITY_AUDIT.md +115 -0
- package/skills-library/security/admin-deletion-safety.md +396 -0
- package/skills-library/security/application-vuln-patterns.md +477 -0
- package/skills-library/security/env-secrets-manager.md +686 -0
- package/skills-library/security/secure-ai-application-templates.md +347 -0
- package/skills-library/security/sql-injection-prevention-postgresjs.md +151 -0
- package/skills-library/supabase-connection-pooler-fix.md +102 -0
- package/skills-library/system-context/POWERSHELL_BASH_INTEROP.md +82 -0
- package/skills-library/system-context/SERVICE_LIFECYCLE_MANAGEMENT.md +119 -0
- package/skills-library/system-context/SKILL.md +40 -0
- package/skills-library/system-context/WINDOWS_DEV_ENVIRONMENT.md +73 -0
- package/skills-library/testing/E2E_PLAYWRIGHT_PATTERNS.md +99 -0
- package/skills-library/testing/INTEGRATION_TEST_STRATEGY.md +82 -0
- package/skills-library/testing/RED_GREEN_BUGFIX_GATE.md +203 -0
- package/skills-library/testing/TEST_DATA_MANAGEMENT.md +69 -0
- package/skills-library/testing/VITEST_UNIT_TEST_PATTERNS.md +75 -0
- package/skills-library/testing/playwright-api-security-tests.md +202 -0
- package/skills-library/toolbox/SKILL.md +84 -0
- package/skills-library/toolbox/code-graph-and-web-scraping-mcps.md +237 -0
- package/skills-library/ui-ux-pro-max/ACCESSIBILITY_ESSENTIALS.md +115 -0
- package/skills-library/ui-ux-pro-max/DESIGN_SYSTEM_SCAFFOLDING.md +133 -0
- package/skills-library/ui-ux-pro-max/RESPONSIVE_LAYOUT_PATTERNS.md +119 -0
- package/skills-library/ui-ux-pro-max/SKILL.md +386 -0
- package/skills-library/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills-library/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills-library/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills-library/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills-library/ui-ux-pro-max/data/products.csv +97 -0
- package/skills-library/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills-library/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills-library/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills-library/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills-library/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills-library/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills-library/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills-library/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills-library/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills-library/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills-library/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills-library/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills-library/wordpress-style-theme-components.md +1526 -0
- package/templates/ASSUMPTIONS.md +1 -1
- package/templates/DECISION_LOG.md +0 -1
- package/templates/phase-prompt.md +1 -1
- package/templates/phoenix-comparison.md +6 -6
- package/templates/skill-api-integration.md +106 -0
- package/templates/skill-architecture-pattern.md +92 -0
- package/templates/skill-debug-pattern.md +98 -0
- package/templates/skill-devops-recipe.md +107 -0
- package/templates/skill-general.md +65 -0
- package/templates/skill-ui-component.md +113 -0
- package/tools/uat-runner.py +179 -0
- package/version.json +7 -3
- package/workflows/handoff-session.md +2 -2
- package/workflows/new-project.md +2 -2
- package/workflows/plan-phase.md +1 -1
- package/.claude-plugin/plugin.json +0 -64
- package/skills-library/_general/methodology/LIVE_BREADCRUMB_PROTOCOL.md +0 -242
- package/skills-library/_general/methodology/llm-judge-memory-crud.md +0 -241
- package/skills-library/methodology/REFLEXION_MEMORY_PATTERN.md +0 -183
- package/skills-library/methodology/RESEARCH_BACKED_WORKFLOW_UPGRADE.md +0 -263
- package/skills-library/methodology/SABBATH_REST_PATTERN.md +0 -267
- package/skills-library/methodology/STONE_AND_SCAFFOLD.md +0 -220
- package/skills-library/specialists/api-architecture/api-designer.md +0 -49
- package/skills-library/specialists/api-architecture/graphql-architect.md +0 -49
- package/skills-library/specialists/api-architecture/mcp-developer.md +0 -51
- package/skills-library/specialists/api-architecture/microservices-architect.md +0 -50
- package/skills-library/specialists/api-architecture/websocket-engineer.md +0 -48
- package/skills-library/specialists/backend/django-expert.md +0 -52
- package/skills-library/specialists/backend/fastapi-expert.md +0 -52
- package/skills-library/specialists/backend/laravel-specialist.md +0 -52
- package/skills-library/specialists/backend/nestjs-expert.md +0 -51
- package/skills-library/specialists/backend/rails-expert.md +0 -53
- package/skills-library/specialists/backend/spring-boot-engineer.md +0 -56
- package/skills-library/specialists/data-ml/fine-tuning-expert.md +0 -48
- package/skills-library/specialists/data-ml/ml-pipeline.md +0 -47
- package/skills-library/specialists/data-ml/pandas-pro.md +0 -47
- package/skills-library/specialists/data-ml/rag-architect.md +0 -51
- package/skills-library/specialists/data-ml/spark-engineer.md +0 -47
- package/skills-library/specialists/frontend/angular-architect.md +0 -52
- package/skills-library/specialists/frontend/flutter-expert.md +0 -51
- package/skills-library/specialists/frontend/nextjs-developer.md +0 -54
- package/skills-library/specialists/frontend/react-native-expert.md +0 -50
- package/skills-library/specialists/frontend/vue-expert.md +0 -51
- package/skills-library/specialists/infrastructure/chaos-engineer.md +0 -74
- package/skills-library/specialists/infrastructure/cloud-architect.md +0 -70
- package/skills-library/specialists/infrastructure/database-optimizer.md +0 -64
- package/skills-library/specialists/infrastructure/devops-engineer.md +0 -70
- package/skills-library/specialists/infrastructure/kubernetes-specialist.md +0 -52
- package/skills-library/specialists/infrastructure/monitoring-expert.md +0 -70
- package/skills-library/specialists/infrastructure/sre-engineer.md +0 -70
- package/skills-library/specialists/infrastructure/terraform-engineer.md +0 -51
- package/skills-library/specialists/languages/cpp-pro.md +0 -74
- package/skills-library/specialists/languages/csharp-developer.md +0 -69
- package/skills-library/specialists/languages/dotnet-core-expert.md +0 -54
- package/skills-library/specialists/languages/golang-pro.md +0 -51
- package/skills-library/specialists/languages/java-architect.md +0 -49
- package/skills-library/specialists/languages/javascript-pro.md +0 -68
- package/skills-library/specialists/languages/kotlin-specialist.md +0 -68
- package/skills-library/specialists/languages/php-pro.md +0 -49
- package/skills-library/specialists/languages/python-pro.md +0 -52
- package/skills-library/specialists/languages/react-expert.md +0 -51
- package/skills-library/specialists/languages/rust-engineer.md +0 -50
- package/skills-library/specialists/languages/sql-pro.md +0 -56
- package/skills-library/specialists/languages/swift-expert.md +0 -69
- package/skills-library/specialists/languages/typescript-pro.md +0 -51
- package/skills-library/specialists/platform/atlassian-mcp.md +0 -52
- package/skills-library/specialists/platform/embedded-systems.md +0 -53
- package/skills-library/specialists/platform/game-developer.md +0 -53
- package/skills-library/specialists/platform/salesforce-developer.md +0 -53
- package/skills-library/specialists/platform/shopify-expert.md +0 -49
- package/skills-library/specialists/platform/wordpress-pro.md +0 -49
- package/skills-library/specialists/quality/code-documenter.md +0 -51
- package/skills-library/specialists/quality/code-reviewer.md +0 -67
- package/skills-library/specialists/quality/debugging-wizard.md +0 -51
- package/skills-library/specialists/quality/fullstack-guardian.md +0 -51
- package/skills-library/specialists/quality/legacy-modernizer.md +0 -50
- package/skills-library/specialists/quality/playwright-expert.md +0 -65
- package/skills-library/specialists/quality/spec-miner.md +0 -56
- package/skills-library/specialists/quality/test-master.md +0 -65
- package/skills-library/specialists/security/secure-code-guardian.md +0 -55
- package/skills-library/specialists/security/security-reviewer.md +0 -53
- package/skills-library/specialists/workflow/architecture-designer.md +0 -53
- package/skills-library/specialists/workflow/cli-developer.md +0 -70
- package/skills-library/specialists/workflow/feature-forge.md +0 -65
- package/skills-library/specialists/workflow/prompt-engineer.md +0 -54
- package/skills-library/specialists/workflow/the-fool.md +0 -62
- /package/skills-library/{performance → _general/performance}/cache-augmented-generation.md +0 -0
- /package/skills-library/{debugging → parallel-debug}/FAILURE_TAXONOMY_CLASSIFICATION.md +0 -0
- /package/skills-library/{debugging → parallel-debug}/THREE_AGENT_HYPOTHESIS_DEBUGGING.md +0 -0
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
# Cloudflare Turnstile CAPTCHA - Complete Implementation Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Cloudflare Turnstile is a CAPTCHA alternative that provides bot protection without user friction. This guide covers complete implementation for a MERN stack application with registration spam protection.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
1. **Cloudflare Account** with Turnstile access
|
|
10
|
+
2. **Site Key** (public, used in frontend)
|
|
11
|
+
3. **Secret Key** (private, used in backend verification)
|
|
12
|
+
|
|
13
|
+
## Setup in Cloudflare Dashboard
|
|
14
|
+
|
|
15
|
+
1. Go to Cloudflare Dashboard → Turnstile
|
|
16
|
+
2. Click "Add Site"
|
|
17
|
+
3. Enter your domain (e.g., `schooloftheprophets.club`)
|
|
18
|
+
4. Choose widget mode: "Managed" (recommended)
|
|
19
|
+
5. Copy the **Site Key** and **Secret Key**
|
|
20
|
+
|
|
21
|
+
## Environment Variables
|
|
22
|
+
|
|
23
|
+
### Client (.env or .env.local)
|
|
24
|
+
```bash
|
|
25
|
+
VITE_TURNSTILE_SITE_KEY=0x4AAAAAAxxxxxxxxxxxxxx
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Server (.env)
|
|
29
|
+
```bash
|
|
30
|
+
TURNSTILE_SECRET_KEY=0x4AAAAAAxxxxxxxxxxxxxx_server_key
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Frontend Implementation (React)
|
|
34
|
+
|
|
35
|
+
### Install Dependencies
|
|
36
|
+
```bash
|
|
37
|
+
npm install @marsidev/react-turnstile
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Register.jsx - Complete Implementation
|
|
41
|
+
|
|
42
|
+
```jsx
|
|
43
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
44
|
+
import { Link, useNavigate } from 'react-router-dom';
|
|
45
|
+
import { Helmet } from 'react-helmet-async';
|
|
46
|
+
import { toast } from 'react-hot-toast';
|
|
47
|
+
import { Turnstile } from '@marsidev/react-turnstile';
|
|
48
|
+
import { useRegister } from '../../hooks/useQueries';
|
|
49
|
+
import { parseApiError } from '../../utils/errorUtils';
|
|
50
|
+
|
|
51
|
+
const TURNSTILE_SITE_KEY = import.meta.env.VITE_TURNSTILE_SITE_KEY;
|
|
52
|
+
|
|
53
|
+
const Register = () => {
|
|
54
|
+
const [formData, setFormData] = useState({
|
|
55
|
+
firstName: '',
|
|
56
|
+
lastName: '',
|
|
57
|
+
email: '',
|
|
58
|
+
password: '',
|
|
59
|
+
confirmPassword: '',
|
|
60
|
+
agreeToTerms: false,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Turnstile state
|
|
64
|
+
const [turnstileToken, setTurnstileToken] = useState('');
|
|
65
|
+
const [turnstileStatus, setTurnstileStatus] = useState('loading'); // 'loading' | 'ready' | 'expired' | 'error'
|
|
66
|
+
const turnstileRef = useRef(null);
|
|
67
|
+
|
|
68
|
+
const navigate = useNavigate();
|
|
69
|
+
const registerMutation = useRegister();
|
|
70
|
+
|
|
71
|
+
// Handle form submission
|
|
72
|
+
const handleSubmit = (e) => {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
|
|
75
|
+
// Validation
|
|
76
|
+
if (formData.password !== formData.confirmPassword) {
|
|
77
|
+
toast.error('Passwords do not match');
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!formData.agreeToTerms) {
|
|
82
|
+
toast.error('Please agree to the terms and conditions');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// CRITICAL: Require Turnstile if site key is configured
|
|
87
|
+
if (TURNSTILE_SITE_KEY) {
|
|
88
|
+
console.log('[Register] Turnstile check - token:', turnstileToken ? 'present' : 'missing', 'status:', turnstileStatus);
|
|
89
|
+
|
|
90
|
+
if (!turnstileToken) {
|
|
91
|
+
if (turnstileStatus === 'expired') {
|
|
92
|
+
toast.error('CAPTCHA verification expired. Please complete it again.');
|
|
93
|
+
} else if (turnstileStatus === 'error') {
|
|
94
|
+
toast.error('CAPTCHA error. Please refresh the page and try again.');
|
|
95
|
+
} else {
|
|
96
|
+
toast.error('Please complete the CAPTCHA verification');
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// IMPORTANT: Capture token immediately to prevent race conditions
|
|
103
|
+
const capturedToken = turnstileToken;
|
|
104
|
+
console.log('[Register] Submitting with token:', capturedToken ? capturedToken.substring(0, 20) + '...' : 'none');
|
|
105
|
+
|
|
106
|
+
const userData = {
|
|
107
|
+
name: `${formData.firstName} ${formData.lastName}`.trim(),
|
|
108
|
+
email: formData.email,
|
|
109
|
+
password: formData.password,
|
|
110
|
+
turnstileToken: capturedToken || undefined,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
registerMutation.mutate(userData, {
|
|
114
|
+
onSuccess: () => {
|
|
115
|
+
toast.success('Registration successful! Check your email to verify your account.');
|
|
116
|
+
|
|
117
|
+
// Reset Turnstile for potential future use
|
|
118
|
+
if (turnstileRef.current) {
|
|
119
|
+
turnstileRef.current.reset();
|
|
120
|
+
}
|
|
121
|
+
setTurnstileToken('');
|
|
122
|
+
setTurnstileStatus('loading');
|
|
123
|
+
|
|
124
|
+
// Redirect to login
|
|
125
|
+
setTimeout(() => navigate('/login'), 2000);
|
|
126
|
+
},
|
|
127
|
+
onError: () => {
|
|
128
|
+
// CRITICAL: Reset Turnstile on ANY error
|
|
129
|
+
// Tokens can only be verified ONCE by Cloudflare
|
|
130
|
+
// If we don't reset, retry will fail with "timeout-or-duplicate"
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
if (turnstileRef.current) {
|
|
133
|
+
turnstileRef.current.reset();
|
|
134
|
+
}
|
|
135
|
+
setTurnstileToken('');
|
|
136
|
+
setTurnstileStatus('loading');
|
|
137
|
+
}, 100);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<form onSubmit={handleSubmit}>
|
|
144
|
+
{/* Form fields... */}
|
|
145
|
+
|
|
146
|
+
{/* Cloudflare Turnstile CAPTCHA */}
|
|
147
|
+
{TURNSTILE_SITE_KEY && (
|
|
148
|
+
<div className="space-y-2">
|
|
149
|
+
<div className="flex justify-center">
|
|
150
|
+
<Turnstile
|
|
151
|
+
ref={turnstileRef}
|
|
152
|
+
siteKey={TURNSTILE_SITE_KEY}
|
|
153
|
+
onSuccess={(token) => {
|
|
154
|
+
console.log('[Turnstile] Success - token received');
|
|
155
|
+
setTurnstileToken(token);
|
|
156
|
+
setTurnstileStatus('ready');
|
|
157
|
+
}}
|
|
158
|
+
onError={() => {
|
|
159
|
+
console.log('[Turnstile] Error');
|
|
160
|
+
setTurnstileToken('');
|
|
161
|
+
setTurnstileStatus('error');
|
|
162
|
+
toast.error('CAPTCHA failed to load. Please refresh the page.');
|
|
163
|
+
}}
|
|
164
|
+
onExpire={() => {
|
|
165
|
+
console.log('[Turnstile] Token expired');
|
|
166
|
+
setTurnstileToken('');
|
|
167
|
+
setTurnstileStatus('expired');
|
|
168
|
+
}}
|
|
169
|
+
options={{
|
|
170
|
+
theme: 'light',
|
|
171
|
+
size: 'normal',
|
|
172
|
+
retry: 'auto', // Auto-retry on failure
|
|
173
|
+
retryInterval: 3000, // Retry every 3 seconds
|
|
174
|
+
refreshExpired: 'auto', // Auto-refresh expired tokens
|
|
175
|
+
}}
|
|
176
|
+
/>
|
|
177
|
+
</div>
|
|
178
|
+
|
|
179
|
+
{/* Visual feedback for token status */}
|
|
180
|
+
{turnstileStatus === 'expired' && (
|
|
181
|
+
<div className="flex items-center justify-center text-sm text-amber-600 bg-amber-50 border border-amber-200 rounded px-3 py-2">
|
|
182
|
+
<span>Verification expired. Please complete the CAPTCHA again.</span>
|
|
183
|
+
</div>
|
|
184
|
+
)}
|
|
185
|
+
{turnstileStatus === 'error' && (
|
|
186
|
+
<div className="flex items-center justify-center text-sm text-red-600 bg-red-50 border border-red-200 rounded px-3 py-2">
|
|
187
|
+
<span>CAPTCHA error. Please refresh the page.</span>
|
|
188
|
+
</div>
|
|
189
|
+
)}
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
|
|
193
|
+
<button type="submit" disabled={registerMutation.isPending}>
|
|
194
|
+
{registerMutation.isPending ? 'Creating account...' : 'Create Account'}
|
|
195
|
+
</button>
|
|
196
|
+
</form>
|
|
197
|
+
);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
export default Register;
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Backend Implementation (Node.js/Express)
|
|
204
|
+
|
|
205
|
+
### authController.js - Turnstile Verification
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
import crypto from 'crypto';
|
|
209
|
+
import bcrypt from 'bcryptjs';
|
|
210
|
+
import sql from '../config/sql.js';
|
|
211
|
+
import { ApiError } from '../middleware/errorHandler.js';
|
|
212
|
+
import asyncHandler from '../middleware/asyncHandler.js';
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Verify Cloudflare Turnstile token
|
|
216
|
+
* @param {String} token - Turnstile response token from frontend
|
|
217
|
+
* @param {String} ip - Client IP address (optional, improves security)
|
|
218
|
+
* @returns {Promise<Object>} - Verification result { success: boolean, error-codes: [] }
|
|
219
|
+
*/
|
|
220
|
+
const verifyTurnstile = async (token, ip = null) => {
|
|
221
|
+
const secretKey = process.env.TURNSTILE_SECRET_KEY;
|
|
222
|
+
|
|
223
|
+
// Skip verification if no secret key configured (development mode)
|
|
224
|
+
if (!secretKey) {
|
|
225
|
+
console.warn('[Auth] TURNSTILE_SECRET_KEY not configured - skipping CAPTCHA verification');
|
|
226
|
+
return { success: true, skipped: true };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
try {
|
|
230
|
+
const formData = new URLSearchParams();
|
|
231
|
+
formData.append('secret', secretKey);
|
|
232
|
+
formData.append('response', token);
|
|
233
|
+
if (ip) formData.append('remoteip', ip);
|
|
234
|
+
|
|
235
|
+
const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
|
|
236
|
+
method: 'POST',
|
|
237
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
238
|
+
body: formData.toString(),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const result = await response.json();
|
|
242
|
+
console.log('[Auth] Turnstile verification response:', JSON.stringify(result));
|
|
243
|
+
return result;
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.error('[Auth] Turnstile verification error:', error.message);
|
|
246
|
+
return { success: false, error: 'Verification service unavailable' };
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Register user with Turnstile CAPTCHA protection
|
|
252
|
+
*/
|
|
253
|
+
export const register = asyncHandler(async (req, res, next) => {
|
|
254
|
+
try {
|
|
255
|
+
const { name, email, password, turnstileToken } = req.body;
|
|
256
|
+
console.log('[Auth] Register attempt for:', name, email);
|
|
257
|
+
|
|
258
|
+
// Basic validation
|
|
259
|
+
if (!name || !email || !password) {
|
|
260
|
+
return next(new ApiError('Please provide name, email, and password', 400));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Verify Turnstile CAPTCHA (if configured)
|
|
264
|
+
if (process.env.TURNSTILE_SECRET_KEY) {
|
|
265
|
+
console.log('[Auth] Turnstile token received:', turnstileToken ? turnstileToken.substring(0, 30) + '...' : 'MISSING');
|
|
266
|
+
|
|
267
|
+
if (!turnstileToken) {
|
|
268
|
+
console.log('[Auth] No turnstile token provided');
|
|
269
|
+
return next(new ApiError('Please complete the CAPTCHA verification', 400));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const clientIp = req.ip || req.connection?.remoteAddress;
|
|
273
|
+
console.log('[Auth] Verifying turnstile with Cloudflare, client IP:', clientIp);
|
|
274
|
+
|
|
275
|
+
const turnstileResult = await verifyTurnstile(turnstileToken, clientIp);
|
|
276
|
+
console.log('[Auth] Turnstile result:', JSON.stringify(turnstileResult));
|
|
277
|
+
|
|
278
|
+
if (!turnstileResult.success) {
|
|
279
|
+
console.log('[Auth] Turnstile verification FAILED:', turnstileResult['error-codes']);
|
|
280
|
+
return next(new ApiError('CAPTCHA verification failed. Please try again.', 400));
|
|
281
|
+
}
|
|
282
|
+
console.log('[Auth] Turnstile verification PASSED');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Check if user exists
|
|
286
|
+
console.log('[Auth] Step 1: Checking if user exists...');
|
|
287
|
+
const userResult = await sql`SELECT * FROM profiles WHERE email = ${email}`;
|
|
288
|
+
if (userResult.length > 0) {
|
|
289
|
+
return next(new ApiError('User already exists', 400));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Hash password
|
|
293
|
+
console.log('[Auth] Step 2: Hashing password...');
|
|
294
|
+
const salt = await bcrypt.genSalt(12);
|
|
295
|
+
const hashedPassword = await bcrypt.hash(password, salt);
|
|
296
|
+
|
|
297
|
+
// Generate email verification token
|
|
298
|
+
console.log('[Auth] Step 3: Generating verification token...');
|
|
299
|
+
const verificationToken = crypto.randomBytes(32).toString('hex');
|
|
300
|
+
const hashedVerificationToken = crypto.createHash('sha256').update(verificationToken).digest('hex');
|
|
301
|
+
const verificationExpire = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
|
|
302
|
+
|
|
303
|
+
// Insert user
|
|
304
|
+
console.log('[Auth] Step 4: Inserting user into database...');
|
|
305
|
+
const insertResult = await sql.unsafe(
|
|
306
|
+
`INSERT INTO profiles (name, email, password, role, email_verified, email_verification_token, email_verification_expire)
|
|
307
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
308
|
+
RETURNING id, name, email, role`,
|
|
309
|
+
[name, email, hashedPassword, 'user', false, hashedVerificationToken, verificationExpire]
|
|
310
|
+
);
|
|
311
|
+
console.log('[Auth] User inserted successfully, id:', insertResult[0]?.id);
|
|
312
|
+
const newUser = insertResult[0];
|
|
313
|
+
|
|
314
|
+
// Auto-assign free membership (optional)
|
|
315
|
+
console.log('[Auth] Step 5: Auto-assigning free membership...');
|
|
316
|
+
try {
|
|
317
|
+
const freeLevel = await sql`SELECT id FROM membership_levels WHERE slug = 'free' AND is_active = true LIMIT 1`;
|
|
318
|
+
if (freeLevel.length > 0) {
|
|
319
|
+
await sql`
|
|
320
|
+
INSERT INTO user_memberships (user_id, membership_level_id, status, started_at)
|
|
321
|
+
VALUES (${newUser.id}, ${freeLevel[0].id}, 'active', CURRENT_TIMESTAMP)
|
|
322
|
+
`;
|
|
323
|
+
console.log('[Auth] Free membership assigned');
|
|
324
|
+
}
|
|
325
|
+
} catch (membershipError) {
|
|
326
|
+
console.error('[Auth] Failed to assign free membership:', membershipError.message);
|
|
327
|
+
// Don't fail registration if membership assignment fails
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Send verification email (non-blocking)
|
|
331
|
+
console.log('[Auth] Step 6: Sending verification email...');
|
|
332
|
+
// ... email sending code ...
|
|
333
|
+
|
|
334
|
+
console.log('[Auth] Step 8: Registration complete, sending response...');
|
|
335
|
+
res.status(201).json({
|
|
336
|
+
status: 'success',
|
|
337
|
+
message: 'Registration successful! Please check your email to verify your account.',
|
|
338
|
+
data: newUser,
|
|
339
|
+
});
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.error('[Auth] REGISTRATION ERROR:', error.message);
|
|
342
|
+
console.error('[Auth] Error stack:', error.stack);
|
|
343
|
+
return next(new ApiError('Registration failed', 500));
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Database Schema Requirements
|
|
349
|
+
|
|
350
|
+
The profiles table needs these columns for email verification:
|
|
351
|
+
|
|
352
|
+
```sql
|
|
353
|
+
-- Migration: Add email verification columns
|
|
354
|
+
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verification_token VARCHAR(255);
|
|
355
|
+
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verification_expire TIMESTAMPTZ;
|
|
356
|
+
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verified BOOLEAN DEFAULT FALSE;
|
|
357
|
+
|
|
358
|
+
-- Index for efficient token lookups
|
|
359
|
+
CREATE INDEX IF NOT EXISTS idx_profiles_email_verification_token
|
|
360
|
+
ON profiles(email_verification_token)
|
|
361
|
+
WHERE email_verification_token IS NOT NULL;
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
## Critical Implementation Notes
|
|
365
|
+
|
|
366
|
+
### 1. Token Single-Use Behavior
|
|
367
|
+
|
|
368
|
+
**Cloudflare Turnstile tokens can only be verified ONCE.**
|
|
369
|
+
|
|
370
|
+
If your backend verification succeeds but the request fails later (e.g., database error), the frontend cannot retry with the same token. Cloudflare will return `timeout-or-duplicate`.
|
|
371
|
+
|
|
372
|
+
**Solution:** Always reset the Turnstile widget on ANY error:
|
|
373
|
+
|
|
374
|
+
```javascript
|
|
375
|
+
onError: () => {
|
|
376
|
+
setTimeout(() => {
|
|
377
|
+
if (turnstileRef.current) {
|
|
378
|
+
turnstileRef.current.reset();
|
|
379
|
+
}
|
|
380
|
+
setTurnstileToken('');
|
|
381
|
+
setTurnstileStatus('loading');
|
|
382
|
+
}, 100);
|
|
383
|
+
}
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
### 2. Token Capture Before Async Operations
|
|
387
|
+
|
|
388
|
+
Capture the token value BEFORE starting async operations to prevent race conditions where the token state might change:
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
const capturedToken = turnstileToken; // Capture immediately
|
|
392
|
+
registerMutation.mutate({ ...userData, turnstileToken: capturedToken });
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 3. Status Tracking for UX
|
|
396
|
+
|
|
397
|
+
Track the widget status to provide appropriate error messages:
|
|
398
|
+
- `loading` - Widget is initializing
|
|
399
|
+
- `ready` - Token received, ready to submit
|
|
400
|
+
- `expired` - Token expired, needs refresh
|
|
401
|
+
- `error` - Widget failed to load
|
|
402
|
+
|
|
403
|
+
### 4. Graceful Degradation
|
|
404
|
+
|
|
405
|
+
If Turnstile is not configured (no site key), the form should still work:
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
{TURNSTILE_SITE_KEY && (
|
|
409
|
+
<Turnstile ... />
|
|
410
|
+
)}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Backend should also skip verification if secret key is not set:
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
if (!process.env.TURNSTILE_SECRET_KEY) {
|
|
417
|
+
return { success: true, skipped: true };
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Debugging Tips
|
|
422
|
+
|
|
423
|
+
### PM2 Log Analysis
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Watch logs in real-time
|
|
427
|
+
pm2 logs lms-server --lines 100
|
|
428
|
+
|
|
429
|
+
# Look for auth-specific logs
|
|
430
|
+
pm2 logs lms-server --lines 500 | grep "\[Auth\]"
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
### Expected Log Sequence (Success)
|
|
434
|
+
|
|
435
|
+
```
|
|
436
|
+
[Auth] Register attempt for: John Doe john@example.com
|
|
437
|
+
[Auth] Turnstile token received: 0.N-XAnnM26LxCGvNp...
|
|
438
|
+
[Auth] Verifying turnstile with Cloudflare, client IP: ::ffff:127.0.0.1
|
|
439
|
+
[Auth] Turnstile verification response: {"success":true,...}
|
|
440
|
+
[Auth] Turnstile verification PASSED
|
|
441
|
+
[Auth] Step 1: Checking if user exists...
|
|
442
|
+
[Auth] Step 2: Hashing password...
|
|
443
|
+
[Auth] Step 3: Generating verification token...
|
|
444
|
+
[Auth] Step 4: Inserting user into database...
|
|
445
|
+
[Auth] User inserted successfully, id: xxxx-xxxx-xxxx
|
|
446
|
+
[Auth] Step 5: Auto-assigning free membership...
|
|
447
|
+
[Auth] Free membership assigned
|
|
448
|
+
[Auth] Step 6: Sending verification email...
|
|
449
|
+
[Auth] Step 8: Registration complete, sending response...
|
|
450
|
+
POST /api/auth/register 201 2037.828 ms
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Common Error Codes
|
|
454
|
+
|
|
455
|
+
| Error Code | Meaning | Solution |
|
|
456
|
+
|------------|---------|----------|
|
|
457
|
+
| `timeout-or-duplicate` | Token already used or expired | Reset widget and get new token |
|
|
458
|
+
| `invalid-input-secret` | Wrong secret key | Check TURNSTILE_SECRET_KEY env var |
|
|
459
|
+
| `invalid-input-response` | Malformed token | Ensure token is passed correctly |
|
|
460
|
+
| `bad-request` | Request format error | Check Content-Type and body format |
|
|
461
|
+
|
|
462
|
+
## Files Reference
|
|
463
|
+
|
|
464
|
+
- `client/src/pages/auth/Register.jsx` - Frontend implementation
|
|
465
|
+
- `server/controllers/authController.js` - Backend verification
|
|
466
|
+
- `server/migrations/078_add_email_verification_columns.sql` - Database schema
|
|
467
|
+
- `.claude/skills/cloudflare-turnstile-debugging.md` - Debugging guide
|
|
468
|
+
|
|
469
|
+
## Session Context
|
|
470
|
+
|
|
471
|
+
This implementation was completed on January 9, 2026 to add registration spam protection. The initial debugging session revealed that a "Turnstile failure" was actually caused by missing database columns - the Turnstile verification passed but the INSERT failed, causing a retry with a stale token.
|
|
472
|
+
|
|
473
|
+
Key learnings:
|
|
474
|
+
1. Add step-by-step logging to identify exact failure points
|
|
475
|
+
2. Turnstile tokens are single-use - reset on ANY error
|
|
476
|
+
3. Check database schema when registration fails after Turnstile passes
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Cloudflare Turnstile CAPTCHA Debugging Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide documents how to debug Cloudflare Turnstile integration issues, particularly the common "timeout-or-duplicate" error that occurs when registration appears to fail but the root cause is elsewhere.
|
|
6
|
+
|
|
7
|
+
## The Common Misdiagnosis
|
|
8
|
+
|
|
9
|
+
**Symptom:** Registration fails with "CAPTCHA verification failed" message.
|
|
10
|
+
|
|
11
|
+
**Initial assumption:** Turnstile is broken or timing out.
|
|
12
|
+
|
|
13
|
+
**Reality:** Turnstile often passes successfully, but a downstream error (e.g., database issue) causes the request to fail. The frontend then retries with the same token, which Cloudflare rejects as "timeout-or-duplicate" because tokens can only be used ONCE.
|
|
14
|
+
|
|
15
|
+
## Debugging Approach
|
|
16
|
+
|
|
17
|
+
### Step 1: Add Detailed Backend Logging
|
|
18
|
+
|
|
19
|
+
Add step-by-step logging to identify exactly where the failure occurs:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
export const register = asyncHandler(async (req, res, next) => {
|
|
23
|
+
try {
|
|
24
|
+
const { name, email, password, turnstileToken } = req.body;
|
|
25
|
+
console.log('[Auth] Register attempt for:', name, email);
|
|
26
|
+
|
|
27
|
+
// Turnstile verification
|
|
28
|
+
if (process.env.TURNSTILE_SECRET_KEY) {
|
|
29
|
+
console.log('[Auth] Turnstile token received:', turnstileToken ? turnstileToken.substring(0, 30) + '...' : 'MISSING');
|
|
30
|
+
const turnstileResult = await verifyTurnstile(turnstileToken, clientIp);
|
|
31
|
+
console.log('[Auth] Turnstile result:', JSON.stringify(turnstileResult));
|
|
32
|
+
if (!turnstileResult.success) {
|
|
33
|
+
console.log('[Auth] Turnstile verification FAILED:', turnstileResult['error-codes']);
|
|
34
|
+
return next(new ApiError('CAPTCHA verification failed', 400));
|
|
35
|
+
}
|
|
36
|
+
console.log('[Auth] Turnstile verification PASSED');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Step-by-step logging for each operation
|
|
40
|
+
console.log('[Auth] Step 1: Checking if user exists...');
|
|
41
|
+
// ... user check code
|
|
42
|
+
|
|
43
|
+
console.log('[Auth] Step 2: Hashing password...');
|
|
44
|
+
// ... password hashing
|
|
45
|
+
|
|
46
|
+
console.log('[Auth] Step 3: Generating verification token...');
|
|
47
|
+
// ... token generation
|
|
48
|
+
|
|
49
|
+
console.log('[Auth] Step 4: Inserting user into database...');
|
|
50
|
+
try {
|
|
51
|
+
// ... database insert
|
|
52
|
+
console.log('[Auth] User inserted successfully, id:', insertResult[0]?.id);
|
|
53
|
+
} catch (insertError) {
|
|
54
|
+
console.error('[Auth] DATABASE INSERT ERROR:', insertError.message);
|
|
55
|
+
console.error('[Auth] Insert error details:', insertError.code, insertError.detail);
|
|
56
|
+
throw insertError;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
console.log('[Auth] Step 5: Auto-assigning free membership...');
|
|
60
|
+
// ... membership assignment
|
|
61
|
+
|
|
62
|
+
console.log('[Auth] Step 6: Sending verification email...');
|
|
63
|
+
// ... email sending
|
|
64
|
+
|
|
65
|
+
console.log('[Auth] Step 7: Firing plugin hooks...');
|
|
66
|
+
// ... hooks
|
|
67
|
+
|
|
68
|
+
console.log('[Auth] Step 8: Registration complete, sending response...');
|
|
69
|
+
// ... success response
|
|
70
|
+
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error('[Auth] REGISTRATION ERROR at final catch:', error.message);
|
|
73
|
+
console.error('[Auth] Error stack:', error.stack);
|
|
74
|
+
console.error('[Auth] Error code:', error.code);
|
|
75
|
+
return next(new ApiError('Registration failed', 500));
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Step 2: Frontend Token Reset on Error
|
|
81
|
+
|
|
82
|
+
Ensure the frontend resets the Turnstile token on ANY error (since tokens are single-use):
|
|
83
|
+
|
|
84
|
+
```javascript
|
|
85
|
+
registerMutation.mutate(userData, {
|
|
86
|
+
onSuccess: () => {
|
|
87
|
+
// Reset Turnstile for potential future use
|
|
88
|
+
if (turnstileRef.current) {
|
|
89
|
+
turnstileRef.current.reset();
|
|
90
|
+
}
|
|
91
|
+
setTurnstileToken('');
|
|
92
|
+
setTurnstileStatus('loading');
|
|
93
|
+
},
|
|
94
|
+
onError: () => {
|
|
95
|
+
// CRITICAL: Reset Turnstile on error - token can only be used once
|
|
96
|
+
setTimeout(() => {
|
|
97
|
+
if (turnstileRef.current) {
|
|
98
|
+
turnstileRef.current.reset();
|
|
99
|
+
}
|
|
100
|
+
setTurnstileToken('');
|
|
101
|
+
setTurnstileStatus('loading');
|
|
102
|
+
}, 100);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Step 3: Add Status Tracking
|
|
108
|
+
|
|
109
|
+
Track Turnstile widget status for better UX:
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const [turnstileStatus, setTurnstileStatus] = useState('loading'); // 'loading' | 'ready' | 'expired' | 'error'
|
|
113
|
+
|
|
114
|
+
<Turnstile
|
|
115
|
+
ref={turnstileRef}
|
|
116
|
+
siteKey={TURNSTILE_SITE_KEY}
|
|
117
|
+
onSuccess={(token) => {
|
|
118
|
+
setTurnstileToken(token);
|
|
119
|
+
setTurnstileStatus('ready');
|
|
120
|
+
}}
|
|
121
|
+
onError={() => {
|
|
122
|
+
setTurnstileToken('');
|
|
123
|
+
setTurnstileStatus('error');
|
|
124
|
+
}}
|
|
125
|
+
onExpire={() => {
|
|
126
|
+
setTurnstileToken('');
|
|
127
|
+
setTurnstileStatus('expired');
|
|
128
|
+
}}
|
|
129
|
+
options={{
|
|
130
|
+
theme: 'light',
|
|
131
|
+
size: 'normal',
|
|
132
|
+
retry: 'auto',
|
|
133
|
+
retryInterval: 3000,
|
|
134
|
+
refreshExpired: 'auto',
|
|
135
|
+
}}
|
|
136
|
+
/>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Common Root Causes
|
|
140
|
+
|
|
141
|
+
### 1. Missing Database Columns
|
|
142
|
+
|
|
143
|
+
**Error in logs:**
|
|
144
|
+
```
|
|
145
|
+
column "email_verification_token" of relation "profiles" does not exist
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Fix:** Run migration to add missing columns:
|
|
149
|
+
```sql
|
|
150
|
+
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verification_token VARCHAR(255);
|
|
151
|
+
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verification_expire TIMESTAMPTZ;
|
|
152
|
+
ALTER TABLE profiles ADD COLUMN IF NOT EXISTS email_verified BOOLEAN DEFAULT FALSE;
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### 2. Duplicate Token Usage
|
|
156
|
+
|
|
157
|
+
**Error codes:** `['timeout-or-duplicate']`
|
|
158
|
+
|
|
159
|
+
**Cause:** Token was already verified (possibly during a failed attempt that reached Cloudflare but then failed elsewhere).
|
|
160
|
+
|
|
161
|
+
**Fix:** Ensure frontend resets token on ANY error, not just success.
|
|
162
|
+
|
|
163
|
+
### 3. Token Expiration
|
|
164
|
+
|
|
165
|
+
**Error codes:** `['timeout-or-duplicate']` with old timestamp
|
|
166
|
+
|
|
167
|
+
**Cause:** User took too long to fill out the form after completing CAPTCHA.
|
|
168
|
+
|
|
169
|
+
**Fix:** Add `refreshExpired: 'auto'` option to automatically refresh expired tokens.
|
|
170
|
+
|
|
171
|
+
## Log Analysis Pattern
|
|
172
|
+
|
|
173
|
+
When debugging, look for this sequence in PM2 logs:
|
|
174
|
+
|
|
175
|
+
1. `[Auth] Turnstile verification PASSED` - Token was valid
|
|
176
|
+
2. `POST /api/auth/register 500` - Request failed AFTER Turnstile
|
|
177
|
+
3. Second request with `timeout-or-duplicate` - Retry with stale token
|
|
178
|
+
|
|
179
|
+
If you see pattern 1+2, the issue is NOT Turnstile - look at the error between Step 1 and Step 8.
|
|
180
|
+
|
|
181
|
+
## VPS Log Commands
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# Watch logs in real-time
|
|
185
|
+
pm2 logs lms-server --lines 100
|
|
186
|
+
|
|
187
|
+
# Search for auth-related logs
|
|
188
|
+
pm2 logs lms-server --lines 500 | grep "\[Auth\]"
|
|
189
|
+
|
|
190
|
+
# Check error log specifically
|
|
191
|
+
tail -100 ~/.pm2/logs/lms-server-error.log
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
## Related Files
|
|
195
|
+
|
|
196
|
+
- `server/controllers/authController.js` - Registration logic
|
|
197
|
+
- `client/src/pages/auth/Register.jsx` - Frontend form
|
|
198
|
+
- `server/migrations/078_add_email_verification_columns.sql` - Missing columns fix
|
|
199
|
+
|
|
200
|
+
## Session Reference
|
|
201
|
+
|
|
202
|
+
This debugging pattern was developed during the Jan 9, 2026 session to fix a production registration issue where Turnstile appeared to fail but the real cause was missing `email_verification_token` column in the profiles table.
|