@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,631 @@
|
|
|
1
|
+
# Content Publishing State Machine
|
|
2
|
+
|
|
3
|
+
> Production-ready content lifecycle management: DRAFT → IN_REVIEW → SCHEDULED → PUBLISHED → ARCHIVED with full audit trail.
|
|
4
|
+
|
|
5
|
+
**When to use:** Any CMS, blog engine, LMS, or content platform where content has a lifecycle with approval gates, scheduled publishing, and rollback capability.
|
|
6
|
+
**Stack:** PostgreSQL or MySQL, Node.js/Express or Bun, TypeScript, React
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## State Machine Overview
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
┌─────────┐
|
|
14
|
+
│ DRAFT │◄────────────────────────────┐
|
|
15
|
+
└────┬────┘ │
|
|
16
|
+
│ submit_for_review │ request_changes
|
|
17
|
+
▼ │
|
|
18
|
+
┌───────────┐ ┌────────┴────────┐
|
|
19
|
+
│ IN_REVIEW │────────────────────►│ (back draft) │
|
|
20
|
+
└─────┬─────┘ └─────────────────┘
|
|
21
|
+
│ approve ▲
|
|
22
|
+
┌─────────┼──────────┐ │ unschedule
|
|
23
|
+
│ │ │ │
|
|
24
|
+
▼ ▼ ▼ │
|
|
25
|
+
publish schedule reject ┌────┴─────┐
|
|
26
|
+
│ (future) │ │ SCHEDULED │
|
|
27
|
+
│ │ │ └──────┬────┘
|
|
28
|
+
│ └──────────┼─────────────────► │ (cron fires)
|
|
29
|
+
│ │ │
|
|
30
|
+
▼ ▼ ▼
|
|
31
|
+
┌───────────┐ ┌──────────┐ ┌───────────┐
|
|
32
|
+
│ PUBLISHED │ │ REJECTED │ │ PUBLISHED │
|
|
33
|
+
└─────┬─────┘ └──────────┘ └─────┬─────┘
|
|
34
|
+
│ archive │ archive
|
|
35
|
+
▼ ▼
|
|
36
|
+
┌──────────┐ ┌──────────┐
|
|
37
|
+
│ ARCHIVED │ │ ARCHIVED │
|
|
38
|
+
└──────────┘ └──────────┘
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Valid transitions:**
|
|
42
|
+
|
|
43
|
+
| From | To | Action |
|
|
44
|
+
|------|----|--------|
|
|
45
|
+
| DRAFT | IN_REVIEW | submit_for_review |
|
|
46
|
+
| IN_REVIEW | DRAFT | request_changes |
|
|
47
|
+
| IN_REVIEW | SCHEDULED | approve + schedule date |
|
|
48
|
+
| IN_REVIEW | PUBLISHED | approve + publish now |
|
|
49
|
+
| IN_REVIEW | REJECTED | reject |
|
|
50
|
+
| SCHEDULED | PUBLISHED | cron fires (auto) |
|
|
51
|
+
| SCHEDULED | DRAFT | unschedule |
|
|
52
|
+
| PUBLISHED | ARCHIVED | archive |
|
|
53
|
+
| ARCHIVED | DRAFT | restore (creates new draft) |
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Database Schema
|
|
58
|
+
|
|
59
|
+
### PostgreSQL
|
|
60
|
+
|
|
61
|
+
```sql
|
|
62
|
+
-- Status enum
|
|
63
|
+
CREATE TYPE content_status AS ENUM (
|
|
64
|
+
'draft',
|
|
65
|
+
'in_review',
|
|
66
|
+
'scheduled',
|
|
67
|
+
'published',
|
|
68
|
+
'archived',
|
|
69
|
+
'rejected'
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
-- Content table
|
|
73
|
+
CREATE TABLE content (
|
|
74
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
75
|
+
title TEXT NOT NULL DEFAULT '',
|
|
76
|
+
slug TEXT UNIQUE,
|
|
77
|
+
body TEXT NOT NULL DEFAULT '',
|
|
78
|
+
excerpt TEXT,
|
|
79
|
+
featured_image TEXT,
|
|
80
|
+
tags TEXT[] DEFAULT '{}',
|
|
81
|
+
content_type TEXT NOT NULL DEFAULT 'post', -- post, page, lesson, etc.
|
|
82
|
+
|
|
83
|
+
-- State machine fields
|
|
84
|
+
status content_status NOT NULL DEFAULT 'draft',
|
|
85
|
+
published_at TIMESTAMPTZ, -- actual publish time
|
|
86
|
+
scheduled_at TIMESTAMPTZ, -- future publish time
|
|
87
|
+
archived_at TIMESTAMPTZ,
|
|
88
|
+
|
|
89
|
+
-- Authorship
|
|
90
|
+
author_id UUID NOT NULL REFERENCES users(id),
|
|
91
|
+
created_by UUID NOT NULL REFERENCES users(id),
|
|
92
|
+
updated_by UUID REFERENCES users(id),
|
|
93
|
+
reviewed_by UUID REFERENCES users(id),
|
|
94
|
+
|
|
95
|
+
-- Review fields
|
|
96
|
+
review_notes TEXT, -- reviewer feedback
|
|
97
|
+
rejection_reason TEXT,
|
|
98
|
+
|
|
99
|
+
-- Metadata
|
|
100
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
101
|
+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
102
|
+
|
|
103
|
+
-- Constraints
|
|
104
|
+
CONSTRAINT published_requires_slug
|
|
105
|
+
CHECK (status != 'published' OR slug IS NOT NULL),
|
|
106
|
+
CONSTRAINT scheduled_requires_date
|
|
107
|
+
CHECK (status != 'scheduled' OR scheduled_at IS NOT NULL),
|
|
108
|
+
CONSTRAINT scheduled_date_in_future
|
|
109
|
+
CHECK (status != 'scheduled' OR scheduled_at > NOW() - INTERVAL '1 minute')
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
-- Indexes
|
|
113
|
+
CREATE INDEX idx_content_status ON content(status);
|
|
114
|
+
CREATE INDEX idx_content_scheduled ON content(scheduled_at) WHERE status = 'scheduled';
|
|
115
|
+
CREATE INDEX idx_content_author ON content(author_id, status);
|
|
116
|
+
CREATE INDEX idx_content_published ON content(published_at DESC) WHERE status = 'published';
|
|
117
|
+
|
|
118
|
+
-- Audit log table
|
|
119
|
+
CREATE TABLE content_status_history (
|
|
120
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
121
|
+
content_id UUID NOT NULL REFERENCES content(id) ON DELETE CASCADE,
|
|
122
|
+
from_status content_status,
|
|
123
|
+
to_status content_status NOT NULL,
|
|
124
|
+
changed_by UUID NOT NULL REFERENCES users(id),
|
|
125
|
+
changed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
126
|
+
notes TEXT, -- why the change was made
|
|
127
|
+
metadata JSONB DEFAULT '{}' -- extra context (IP, etc.)
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
CREATE INDEX idx_status_history_content ON content_status_history(content_id, changed_at DESC);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### MySQL Equivalent
|
|
134
|
+
|
|
135
|
+
```sql
|
|
136
|
+
-- MySQL uses ENUM column type (no separate CREATE TYPE)
|
|
137
|
+
CREATE TABLE content (
|
|
138
|
+
id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
|
|
139
|
+
title TEXT NOT NULL,
|
|
140
|
+
slug VARCHAR(255) UNIQUE,
|
|
141
|
+
body LONGTEXT NOT NULL,
|
|
142
|
+
excerpt TEXT,
|
|
143
|
+
tags JSON DEFAULT ('[]'),
|
|
144
|
+
content_type VARCHAR(50) NOT NULL DEFAULT 'post',
|
|
145
|
+
|
|
146
|
+
-- State machine fields
|
|
147
|
+
status ENUM('draft','in_review','scheduled','published','archived','rejected')
|
|
148
|
+
NOT NULL DEFAULT 'draft',
|
|
149
|
+
published_at DATETIME,
|
|
150
|
+
scheduled_at DATETIME,
|
|
151
|
+
archived_at DATETIME,
|
|
152
|
+
|
|
153
|
+
-- Authorship
|
|
154
|
+
author_id CHAR(36) NOT NULL,
|
|
155
|
+
created_by CHAR(36) NOT NULL,
|
|
156
|
+
updated_by CHAR(36),
|
|
157
|
+
reviewed_by CHAR(36),
|
|
158
|
+
review_notes TEXT,
|
|
159
|
+
rejection_reason TEXT,
|
|
160
|
+
|
|
161
|
+
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
162
|
+
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
163
|
+
|
|
164
|
+
CONSTRAINT fk_content_author FOREIGN KEY (author_id) REFERENCES users(id)
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
CREATE INDEX idx_content_status ON content(status);
|
|
168
|
+
CREATE INDEX idx_content_scheduled ON content(scheduled_at, status);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## State Transition Validator (TypeScript)
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// lib/content-state-machine.ts
|
|
177
|
+
|
|
178
|
+
export type ContentStatus =
|
|
179
|
+
| 'draft'
|
|
180
|
+
| 'in_review'
|
|
181
|
+
| 'scheduled'
|
|
182
|
+
| 'published'
|
|
183
|
+
| 'archived'
|
|
184
|
+
| 'rejected';
|
|
185
|
+
|
|
186
|
+
export type TransitionAction =
|
|
187
|
+
| 'submit_for_review'
|
|
188
|
+
| 'request_changes'
|
|
189
|
+
| 'approve_and_publish'
|
|
190
|
+
| 'approve_and_schedule'
|
|
191
|
+
| 'reject'
|
|
192
|
+
| 'unschedule'
|
|
193
|
+
| 'archive'
|
|
194
|
+
| 'restore';
|
|
195
|
+
|
|
196
|
+
interface Transition {
|
|
197
|
+
from: ContentStatus[];
|
|
198
|
+
to: ContentStatus;
|
|
199
|
+
requiredRole?: string[]; // roles allowed to perform this transition
|
|
200
|
+
guard?: (content: ContentRecord) => string | null; // returns error or null
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
interface ContentRecord {
|
|
204
|
+
id: string;
|
|
205
|
+
title: string;
|
|
206
|
+
slug: string | null;
|
|
207
|
+
status: ContentStatus;
|
|
208
|
+
scheduled_at?: Date | null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const TRANSITIONS: Record<TransitionAction, Transition> = {
|
|
212
|
+
submit_for_review: {
|
|
213
|
+
from: ['draft', 'rejected'],
|
|
214
|
+
to: 'in_review',
|
|
215
|
+
guard: (c) => {
|
|
216
|
+
if (!c.title?.trim()) return 'Title is required before submitting for review';
|
|
217
|
+
return null;
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
request_changes: {
|
|
221
|
+
from: ['in_review'],
|
|
222
|
+
to: 'draft',
|
|
223
|
+
requiredRole: ['editor', 'admin'],
|
|
224
|
+
},
|
|
225
|
+
approve_and_publish: {
|
|
226
|
+
from: ['in_review'],
|
|
227
|
+
to: 'published',
|
|
228
|
+
requiredRole: ['editor', 'admin'],
|
|
229
|
+
guard: (c) => {
|
|
230
|
+
if (!c.title?.trim()) return 'Title is required to publish';
|
|
231
|
+
if (!c.slug?.trim()) return 'Slug is required to publish';
|
|
232
|
+
return null;
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
approve_and_schedule: {
|
|
236
|
+
from: ['in_review'],
|
|
237
|
+
to: 'scheduled',
|
|
238
|
+
requiredRole: ['editor', 'admin'],
|
|
239
|
+
guard: (c) => {
|
|
240
|
+
if (!c.title?.trim()) return 'Title is required to schedule';
|
|
241
|
+
if (!c.slug?.trim()) return 'Slug is required to schedule';
|
|
242
|
+
if (!c.scheduled_at) return 'Scheduled date is required';
|
|
243
|
+
if (new Date(c.scheduled_at) <= new Date()) return 'Scheduled date must be in the future';
|
|
244
|
+
return null;
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
reject: {
|
|
248
|
+
from: ['in_review'],
|
|
249
|
+
to: 'rejected',
|
|
250
|
+
requiredRole: ['editor', 'admin'],
|
|
251
|
+
},
|
|
252
|
+
unschedule: {
|
|
253
|
+
from: ['scheduled'],
|
|
254
|
+
to: 'draft',
|
|
255
|
+
},
|
|
256
|
+
archive: {
|
|
257
|
+
from: ['published'],
|
|
258
|
+
to: 'archived',
|
|
259
|
+
requiredRole: ['editor', 'admin'],
|
|
260
|
+
},
|
|
261
|
+
restore: {
|
|
262
|
+
from: ['archived'],
|
|
263
|
+
to: 'draft',
|
|
264
|
+
requiredRole: ['editor', 'admin'],
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
export function validateTransition(
|
|
269
|
+
action: TransitionAction,
|
|
270
|
+
content: ContentRecord,
|
|
271
|
+
userRole: string
|
|
272
|
+
): { valid: boolean; error?: string } {
|
|
273
|
+
const transition = TRANSITIONS[action];
|
|
274
|
+
|
|
275
|
+
if (!transition) {
|
|
276
|
+
return { valid: false, error: `Unknown action: ${action}` };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!transition.from.includes(content.status)) {
|
|
280
|
+
return {
|
|
281
|
+
valid: false,
|
|
282
|
+
error: `Cannot ${action} from status '${content.status}'. ` +
|
|
283
|
+
`Valid from: ${transition.from.join(', ')}`,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (transition.requiredRole && !transition.requiredRole.includes(userRole)) {
|
|
288
|
+
return {
|
|
289
|
+
valid: false,
|
|
290
|
+
error: `Role '${userRole}' cannot perform '${action}'. ` +
|
|
291
|
+
`Required: ${transition.requiredRole.join(' or ')}`,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (transition.guard) {
|
|
296
|
+
const guardError = transition.guard(content);
|
|
297
|
+
if (guardError) return { valid: false, error: guardError };
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return { valid: true };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function getTargetStatus(action: TransitionAction): ContentStatus {
|
|
304
|
+
return TRANSITIONS[action].to;
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Express Middleware
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// middleware/content-transition.ts
|
|
314
|
+
import { Request, Response, NextFunction } from 'express';
|
|
315
|
+
import { validateTransition, TransitionAction } from '../lib/content-state-machine';
|
|
316
|
+
|
|
317
|
+
export function requireValidTransition(action: TransitionAction) {
|
|
318
|
+
return async (req: Request, res: Response, next: NextFunction) => {
|
|
319
|
+
const { id } = req.params;
|
|
320
|
+
const userRole = req.user?.role ?? 'author';
|
|
321
|
+
|
|
322
|
+
const content = await db.query(
|
|
323
|
+
'SELECT id, title, slug, status, scheduled_at FROM content WHERE id = $1',
|
|
324
|
+
[id]
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
if (!content.rows[0]) {
|
|
328
|
+
return res.status(404).json({ error: 'Content not found' });
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const result = validateTransition(action, content.rows[0], userRole);
|
|
332
|
+
|
|
333
|
+
if (!result.valid) {
|
|
334
|
+
return res.status(422).json({ error: result.error });
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Attach to request for the route handler
|
|
338
|
+
req.contentRecord = content.rows[0];
|
|
339
|
+
next();
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## API Endpoints
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
// routes/content-transitions.ts
|
|
350
|
+
import { Router } from 'express';
|
|
351
|
+
import { requireValidTransition } from '../middleware/content-transition';
|
|
352
|
+
import { getTargetStatus } from '../lib/content-state-machine'; // getTargetStatus is exported from lib, not middleware
|
|
353
|
+
import { logStatusChange } from '../lib/audit-log';
|
|
354
|
+
|
|
355
|
+
const router = Router();
|
|
356
|
+
|
|
357
|
+
// Publish immediately
|
|
358
|
+
router.patch(
|
|
359
|
+
'/content/:id/publish',
|
|
360
|
+
requireValidTransition('approve_and_publish'),
|
|
361
|
+
async (req, res) => {
|
|
362
|
+
const { id } = req.params;
|
|
363
|
+
const { notes } = req.body;
|
|
364
|
+
const now = new Date();
|
|
365
|
+
|
|
366
|
+
await db.query(`
|
|
367
|
+
UPDATE content SET
|
|
368
|
+
status = 'published',
|
|
369
|
+
published_at = $1,
|
|
370
|
+
scheduled_at = NULL,
|
|
371
|
+
reviewed_by = $2,
|
|
372
|
+
updated_by = $2,
|
|
373
|
+
updated_at = $1
|
|
374
|
+
WHERE id = $3
|
|
375
|
+
`, [now, req.user.id, id]);
|
|
376
|
+
|
|
377
|
+
await logStatusChange(db, {
|
|
378
|
+
contentId: id,
|
|
379
|
+
fromStatus: req.contentRecord.status,
|
|
380
|
+
toStatus: 'published',
|
|
381
|
+
changedBy: req.user.id,
|
|
382
|
+
notes,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
res.json({ status: 'published', published_at: now });
|
|
386
|
+
}
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
// Schedule for future publication
|
|
390
|
+
router.patch(
|
|
391
|
+
'/content/:id/schedule',
|
|
392
|
+
requireValidTransition('approve_and_schedule'),
|
|
393
|
+
async (req, res) => {
|
|
394
|
+
const { id } = req.params;
|
|
395
|
+
const { scheduled_at, notes } = req.body;
|
|
396
|
+
|
|
397
|
+
if (!scheduled_at) {
|
|
398
|
+
return res.status(400).json({ error: 'scheduled_at is required' });
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const scheduleDate = new Date(scheduled_at);
|
|
402
|
+
if (scheduleDate <= new Date()) {
|
|
403
|
+
return res.status(400).json({ error: 'scheduled_at must be in the future' });
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
await db.query(`
|
|
407
|
+
UPDATE content SET
|
|
408
|
+
status = 'scheduled',
|
|
409
|
+
scheduled_at = $1,
|
|
410
|
+
reviewed_by = $2,
|
|
411
|
+
updated_by = $2,
|
|
412
|
+
updated_at = NOW()
|
|
413
|
+
WHERE id = $3
|
|
414
|
+
`, [scheduleDate, req.user.id, id]);
|
|
415
|
+
|
|
416
|
+
await logStatusChange(db, {
|
|
417
|
+
contentId: id,
|
|
418
|
+
fromStatus: req.contentRecord.status,
|
|
419
|
+
toStatus: 'scheduled',
|
|
420
|
+
changedBy: req.user.id,
|
|
421
|
+
notes,
|
|
422
|
+
metadata: { scheduled_at: scheduleDate },
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
res.json({ status: 'scheduled', scheduled_at: scheduleDate });
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
// Archive
|
|
430
|
+
router.patch(
|
|
431
|
+
'/content/:id/archive',
|
|
432
|
+
requireValidTransition('archive'),
|
|
433
|
+
async (req, res) => {
|
|
434
|
+
const { id } = req.params;
|
|
435
|
+
|
|
436
|
+
await db.query(`
|
|
437
|
+
UPDATE content SET
|
|
438
|
+
status = 'archived',
|
|
439
|
+
archived_at = NOW(),
|
|
440
|
+
updated_by = $1,
|
|
441
|
+
updated_at = NOW()
|
|
442
|
+
WHERE id = $2
|
|
443
|
+
`, [req.user.id, id]);
|
|
444
|
+
|
|
445
|
+
await logStatusChange(db, {
|
|
446
|
+
contentId: id,
|
|
447
|
+
fromStatus: req.contentRecord.status,
|
|
448
|
+
toStatus: 'archived',
|
|
449
|
+
changedBy: req.user.id,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
res.json({ status: 'archived' });
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
|
|
456
|
+
// Submit for review
|
|
457
|
+
router.patch(
|
|
458
|
+
'/content/:id/submit',
|
|
459
|
+
requireValidTransition('submit_for_review'),
|
|
460
|
+
async (req, res) => {
|
|
461
|
+
const { id } = req.params;
|
|
462
|
+
|
|
463
|
+
await db.query(`
|
|
464
|
+
UPDATE content SET
|
|
465
|
+
status = 'in_review',
|
|
466
|
+
updated_by = $1,
|
|
467
|
+
updated_at = NOW()
|
|
468
|
+
WHERE id = $2
|
|
469
|
+
`, [req.user.id, id]);
|
|
470
|
+
|
|
471
|
+
await logStatusChange(db, {
|
|
472
|
+
contentId: id,
|
|
473
|
+
fromStatus: req.contentRecord.status,
|
|
474
|
+
toStatus: 'in_review',
|
|
475
|
+
changedBy: req.user.id,
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
res.json({ status: 'in_review' });
|
|
479
|
+
}
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
export default router;
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
---
|
|
486
|
+
|
|
487
|
+
## Audit Log Helper
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
// lib/audit-log.ts
|
|
491
|
+
import { Pool } from 'pg';
|
|
492
|
+
import { ContentStatus } from './content-state-machine';
|
|
493
|
+
|
|
494
|
+
interface LogEntry {
|
|
495
|
+
contentId: string;
|
|
496
|
+
fromStatus: ContentStatus | null;
|
|
497
|
+
toStatus: ContentStatus;
|
|
498
|
+
changedBy: string;
|
|
499
|
+
notes?: string;
|
|
500
|
+
metadata?: Record<string, unknown>;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
export async function logStatusChange(db: Pool, entry: LogEntry): Promise<void> {
|
|
504
|
+
await db.query(`
|
|
505
|
+
INSERT INTO content_status_history
|
|
506
|
+
(content_id, from_status, to_status, changed_by, notes, metadata)
|
|
507
|
+
VALUES ($1, $2, $3, $4, $5, $6)
|
|
508
|
+
`, [
|
|
509
|
+
entry.contentId,
|
|
510
|
+
entry.fromStatus,
|
|
511
|
+
entry.toStatus,
|
|
512
|
+
entry.changedBy,
|
|
513
|
+
entry.notes ?? null,
|
|
514
|
+
JSON.stringify(entry.metadata ?? {}),
|
|
515
|
+
]);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export async function getContentHistory(db: Pool, contentId: string) {
|
|
519
|
+
const { rows } = await db.query(`
|
|
520
|
+
SELECT
|
|
521
|
+
h.from_status,
|
|
522
|
+
h.to_status,
|
|
523
|
+
h.changed_at,
|
|
524
|
+
h.notes,
|
|
525
|
+
u.name AS changed_by_name,
|
|
526
|
+
u.email AS changed_by_email
|
|
527
|
+
FROM content_status_history h
|
|
528
|
+
JOIN users u ON u.id = h.changed_by
|
|
529
|
+
WHERE h.content_id = $1
|
|
530
|
+
ORDER BY h.changed_at DESC
|
|
531
|
+
`, [contentId]);
|
|
532
|
+
|
|
533
|
+
return rows;
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
---
|
|
538
|
+
|
|
539
|
+
## React Status Badge Component
|
|
540
|
+
|
|
541
|
+
```tsx
|
|
542
|
+
// components/ContentStatusBadge.tsx
|
|
543
|
+
import React from 'react';
|
|
544
|
+
|
|
545
|
+
type ContentStatus = 'draft' | 'in_review' | 'scheduled' | 'published' | 'archived' | 'rejected';
|
|
546
|
+
|
|
547
|
+
const STATUS_CONFIG: Record<ContentStatus, { label: string; className: string }> = {
|
|
548
|
+
draft: { label: 'Draft', className: 'bg-gray-100 text-gray-700 border-gray-300' },
|
|
549
|
+
in_review: { label: 'In Review', className: 'bg-yellow-100 text-yellow-800 border-yellow-300' },
|
|
550
|
+
scheduled: { label: 'Scheduled', className: 'bg-blue-100 text-blue-800 border-blue-300' },
|
|
551
|
+
published: { label: 'Published', className: 'bg-green-100 text-green-800 border-green-300' },
|
|
552
|
+
archived: { label: 'Archived', className: 'bg-slate-100 text-slate-600 border-slate-300' },
|
|
553
|
+
rejected: { label: 'Rejected', className: 'bg-red-100 text-red-700 border-red-300' },
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
interface Props {
|
|
557
|
+
status: ContentStatus;
|
|
558
|
+
scheduledAt?: string | null;
|
|
559
|
+
size?: 'sm' | 'md';
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
export function ContentStatusBadge({ status, scheduledAt, size = 'md' }: Props) {
|
|
563
|
+
const config = STATUS_CONFIG[status] ?? STATUS_CONFIG.draft;
|
|
564
|
+
const sizeClass = size === 'sm' ? 'text-xs px-2 py-0.5' : 'text-sm px-3 py-1';
|
|
565
|
+
|
|
566
|
+
return (
|
|
567
|
+
<span className={`inline-flex items-center gap-1.5 rounded-full border font-medium ${sizeClass} ${config.className}`}>
|
|
568
|
+
<StatusDot status={status} />
|
|
569
|
+
{config.label}
|
|
570
|
+
{status === 'scheduled' && scheduledAt && (
|
|
571
|
+
<span className="text-xs font-normal ml-1">
|
|
572
|
+
({new Date(scheduledAt).toLocaleDateString()})
|
|
573
|
+
</span>
|
|
574
|
+
)}
|
|
575
|
+
</span>
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function StatusDot({ status }: { status: ContentStatus }) {
|
|
580
|
+
const dotColors: Record<ContentStatus, string> = {
|
|
581
|
+
draft: 'bg-gray-400',
|
|
582
|
+
in_review: 'bg-yellow-500 animate-pulse',
|
|
583
|
+
scheduled: 'bg-blue-500',
|
|
584
|
+
published: 'bg-green-500',
|
|
585
|
+
archived: 'bg-slate-400',
|
|
586
|
+
rejected: 'bg-red-500',
|
|
587
|
+
};
|
|
588
|
+
|
|
589
|
+
return (
|
|
590
|
+
<span className={`w-1.5 h-1.5 rounded-full ${dotColors[status]}`} />
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## Guard Clause Reference
|
|
598
|
+
|
|
599
|
+
These are the business rules enforced by the state machine:
|
|
600
|
+
|
|
601
|
+
```
|
|
602
|
+
DRAFT → IN_REVIEW:
|
|
603
|
+
✓ Title must not be empty
|
|
604
|
+
|
|
605
|
+
IN_REVIEW → PUBLISHED:
|
|
606
|
+
✓ Title must not be empty
|
|
607
|
+
✓ Slug must exist and be unique
|
|
608
|
+
✓ User must have role: editor or admin
|
|
609
|
+
|
|
610
|
+
IN_REVIEW → SCHEDULED:
|
|
611
|
+
✓ Title must not be empty
|
|
612
|
+
✓ Slug must exist
|
|
613
|
+
✓ scheduled_at must be provided
|
|
614
|
+
✓ scheduled_at must be in the future
|
|
615
|
+
✓ User must have role: editor or admin
|
|
616
|
+
|
|
617
|
+
PUBLISHED → ARCHIVED:
|
|
618
|
+
✓ User must have role: editor or admin
|
|
619
|
+
✗ Cannot archive a scheduled post (unschedule first)
|
|
620
|
+
✗ Cannot publish without first unpublishing (use restore → draft flow)
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
625
|
+
## Common Gotchas
|
|
626
|
+
|
|
627
|
+
1. **Don't use booleans** (`is_published`, `is_draft`) — they can't express multi-state workflows and create contradictory states (`is_published = true AND is_draft = true`).
|
|
628
|
+
2. **Store `published_at` separately from `scheduled_at`** — `published_at` is the actual publication timestamp (set when the cron fires or when manually published), `scheduled_at` is the intended time.
|
|
629
|
+
3. **Soft deletes vs ARCHIVED** — archived content is still in the DB and readable by admins. Don't conflate with deletion.
|
|
630
|
+
4. **MySQL ENUM ordering** — MySQL ENUMs have an implicit ordering based on their definition order. This doesn't affect queries but can cause surprising sort behavior. Always sort by explicit column values, not ENUM ordinal.
|
|
631
|
+
5. **Audit log is append-only** — never UPDATE or DELETE audit log rows. Add new rows. This is your forensic trail.
|