Feat/submissions workflow#55
Conversation
|
@alex-strapi is attempting to deploy a commit to the Strapi-Website Team on Vercel. A member of the Team first needs to authorize it. |
…aude skills Extends apps/automation with an engine-agnostic Docker/Podman compose setup that runs a local n8n plus an opt-in n8n-mcp service (--profile mcp). A shell wrapper auto-detects the installed compose engine so pnpm scripts work for both Docker and Podman users. Adds Node 20+ scripts for exporting workflows from the local n8n into apps/automation/workflows/<slug>/workflow.json and importing them back, with instance-specific fields stripped for clean diffs and optional README files preserved across re-exports. Introduces seven project-scoped Claude Code skills covering lifecycle (start/stop/restart/status), workflow sync (export/import), and domain expertise for building workflows via n8n-mcp tools. Adds a root CLAUDE.md that indexes them and gitignores personal .claude/settings*.json plus the tmp/ scratch directory. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a README section covering both project-scoped (.mcp.json with
${MCP_AUTH_TOKEN} substitution) and user-scoped (claude mcp add without
--scope project) registration paths, plus a curl verification step. The
n8n-start skill now reminds the user about the registration step when the
mcp profile is brought up, and CLAUDE.md points at the new README section
from the skill index.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…own lint Expands the "Connecting Claude Code to the local n8n-mcp" section to cover all three scopes (local / user / project) with a decision table, not just two. The prior write-up conflated local (default) with user scope. Also notes that an already-running Claude Code session must be relaunched after `claude mcp add` for the new server's tools to appear. Incidentally fixes pre-existing markdown-lint warnings in the README (bare URLs in the Ports table, missing blank lines around fenced code blocks inside numbered-list steps, missing language hint on the workflow tree diagram). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ensures the workflows directory survives in version control when no workflows are checked in yet, so the n8n-export / n8n-import skills have a target path immediately after cloning. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Scaffolds six draft workflows covering the automation work tracked in issues strapi#12-strapi#17, strapi#21, strapi#53, and strapi#54. Everything is inactive by default — they reference a Strapi email-template content-type (strapi#53) and lifecycle webhook endpoints that don't exist yet, so activation waits on Boaz's CMS work landing. - render-email (shared sub-workflow): fetches the template from Strapi by key, interpolates {{ variables }}, wraps in a branded HTML shell, and sends via SendGrid (community@strapi.io, separate key from strapi#54). Other workflows call this rather than each handling SendGrid themselves. - package-submission-received: strapi#12 developer email + strapi#16 Slack post - package-approved: strapi#14 developer email + strapi#17 Slack post - package-declined: strapi#15 developer email with decline reason - package-changes-requested: strapi#13 developer email with reviewer feedback - cleanup-new-label-after-60d: strapi#21 daily cron that strips the 'is_new' label from packages older than 60 days Webhook paths are namespaced under /strapi/* and expect header auth. Env vars referenced: STRAPI_BASE_URL, STRAPI_API_TOKEN. Credentials for SendGrid, Slack, and the webhook header need to be attached in the n8n UI once the real deployment targets are picked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses strapi#53 and strapi#54 — closing the Strapi-side dependencies for the n8n package review automation workflows on feat/n8n-mcp-automation-setup. - email-template content-type (collectionType, draftAndPublish: false) with key (uid), subject, body (richtext), description, from_name, reply_to. n8n workflows look up templates by key. - Seeds four default templates on bootstrap if missing: plugin-submission-received, plugin-approved, plugin-declined, plugin-changes-requested. Uses `strapi.documents(...)` v5 API, skips existing rows so edits in the admin UI aren't clobbered. - @strapi/provider-email-sendgrid added at the same experimental version as the rest of the Strapi catalog, wired through config/plugins.ts with SENDGRID_API_KEY / EMAIL_DEFAULT_FROM / EMAIL_DEFAULT_REPLY_TO env vars. Defaults the sender to community@strapi.io per the decided automation architecture. - Automation emails continue to use a separate SendGrid key configured in n8n — native Strapi emails (password resets, admin invites) use the key wired here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Next.js dev server defaults to :3000, which collides with the n8n-mcp host mapping. Remap n8n-mcp to 3100 on the host; container-internal port stays at 3000 so the image defaults are untouched. Updates README, n8n-start skill, and n8n-status skill accordingly. Any existing Claude Code MCP registration needs its URL updated from http://localhost:3000/mcp → http://localhost:3100/mcp (remove the old server, then re-register with the new URL). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename plugin-submission.npm_package_name -> package_location (URL; supports npm/packagist/pypi/rubygems/nuget), propagated through admin UI, service, promoteToPackage, automated checks, and generated types - Add security_scan_* fields (status/started_at/run_at/dependencies/ai_analysis /summary) on both plugin-submission and template-submission; drop orphaned npm_advisories field (consolidated into OSV) - New helper get-package-security-info.js reuses package-info registry extract functions to fetch deps/scripts/install-hooks/readme/declared-repo before firing the scan webhook (n8n does not duplicate registry lookups) - New helper n8n-webhook.js centralises webhook URL construction from CLOUD_APP_URL (Strapi Cloud default) + N8N_WEBHOOK_MODE (production | test) - Wire Alex's 7 lifecycle TODO markers: plugin-submission-received/approved/ declined/changes-requested + template-submission-received/approved/declined - New content-api routes per submission type: security-scan-result (write-back from n8n) + stale-scans (polled by the sweeper workflow) - Delete security-checks.js; registry-based vuln scanning and AI analysis now run in n8n workflows - Extend email-templates seed with 3 template-* entries; drop dashboard_link from developer-facing email bodies (admin URL is internal-only) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Rename 4 package-* workflows to plugin-* (folders + workflow name + webhook path + Extract Payload reading flat CMS payload instead of Strapi content-type lifecycle body.entry.*) - Add 3 template-* workflows mirroring the plugin-* ones, adapted for the template-submission content type - New security-scan workflow: fires on manual admin trigger, consumes the CMS-prefetched package_info, runs OSV vuln scan + repo package.json cross- check + install-script flagging + Claude Haiku AI analysis on up to 20 source files (npm via jsDelivr / GitHub for repo fallback). Writes back per-stage results to Strapi via content-api - New error-handler workflow (settings.errorWorkflow on all 11 community-hub workflows) — Error Trigger -> Scope Check allowlist -> Slack alert to #integration-marketplace. Opt-in via wiring + defensive name allowlist - New scan-timeout-sweeper workflow — runs every 15 min, queries the CMS for plugin/template submissions stuck in security_scan_status=running past a 30- minute threshold, PATCHes them to failed, Slack-notifies the count - Code nodes in security-scan wrapped in try/catch with defined fallback shapes so a parse error mid-flow produces a typed error item instead of aborting the whole workflow - Drop dashboard_link from plugin-changes-requested email variables (admin URL is internal Slack-only — dropped from developer email body + payload defence-in-depth) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Replace npm_package_name field with package_location (URL) on the plugin submission form + Next.js proxy route — matches the renamed CMS field - Label "NPM Package Name" -> "Registry URL", hint generalised to cover npm, Packagist, PyPI, RubyGems, NuGet Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New ./scripts/setup.sh (run via `pnpm bootstrap` — pnpm setup is shadowed by pnpm's own built-in). Installs deps, seeds .env from .env.example, warns on 'tobemodified' placeholders, reports compose engine, flags low fs.inotify.max_user_instances (Linux) that would crash Turbopack's watcher - Add idempotency to apps/automation/scripts/compose.sh — 'up' detects already- running services and exits 0 instead of reconciling, so turbo dev doesn't conflict when the stack is already up - Give apps/search its own copy of the engine-agnostic compose wrapper (was hardcoded to docker-compose which fails on podman-only boxes); add stop/logs/ps scripts for parity with automation - Switch automation + search dev scripts to `up -d` so turbo doesn't hang attaching to container logs while trying to run cms + web in parallel - Root package.json shortcuts: n8n:start/stop + search:start/stop Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
My additions on top of Alex's moderation pluginInfra ( n8n workflows (11 total): CMS (
Web ( Dev experience:
Still open (none block merge)
|
| checks?: Record<string, AutomatedCheckResult>; | ||
| } | ||
|
|
||
| interface PluginSubmissionDetail { |
There was a problem hiding this comment.
Can we infer this type from Data.ContentType<'plugin::moderation.plugin-submission'>?
| @@ -0,0 +1,138 @@ | |||
| { | |||
| "kind": "collectionType", | |||
| "collectionName": "plugin_submissions", | |||
There was a problem hiding this comment.
I'm wondering if we should change the naming of this content type. It seems that package_review is more suitable.
| "type": "string", | ||
| "required": true | ||
| }, | ||
| "package_location": { |
There was a problem hiding this comment.
Can you help me better understand why we need this intermediary content type? It seems to me that we're violating the 'single source of truth' ideology. What if a package updates their package location later on, do we then need to retroactively update the package location in the submission content type?
| config: { | ||
| // Public endpoint — auth is handled at the Next.js proxy layer. | ||
| // The proxy must include a valid API token via Authorization header. | ||
| auth: false, |
There was a problem hiding this comment.
If we're using an API token in Next.js then auth should be true here.
| } | ||
|
|
||
| // Create the package entry in draft state. Publish step is manual. | ||
| const pkg = await strapi.documents("api::package.package").create({ |
There was a problem hiding this comment.
This is where we'll also need to look up the better auth user by email, and if it's not there create it.
| "Sent by n8n when a package is submitted to the community marketplace. Variables: package_name, author_name, git_repository.", | ||
| body: `Hi {{ author_name }}, | ||
|
|
||
| Thanks for submitting **{{ package_name }}** to the Strapi community marketplace. |
There was a problem hiding this comment.
Can we style this email template? @derrickmehaffy?
| */ | ||
| export async function GET() { | ||
| try { | ||
| const res = await fetch( |
There was a problem hiding this comment.
For GET requests we don't need to proxy. We can just do that using the cmsClient from server side Next.js
| return { | ||
| find: <const TParams extends GetQueryParams<TContentTypeUID>>( | ||
| queryParams?: TParams, | ||
| ) => { |
There was a problem hiding this comment.
This indentation doesn't seem right?
| "n8n:start": "pnpm --filter automation start", | ||
| "n8n:stop": "pnpm --filter automation n8n:down", | ||
| "search:start": "pnpm --filter search start", | ||
| "search:stop": "pnpm --filter search stop", |
There was a problem hiding this comment.
Why do we need these scripts? The goal is that we just run a single pnpm run dev command from the root and that starts all the apps/packages
Added submission workflow for both plugins and templates, plus the n8n automation + security-scan pipeline that hangs off Alex's moderation plugin lifecycle hooks.
Closes #8 #9 #10 #12 #13 #14 #15 #16 #17 #31 #32 #33 #34 #35