Domainchase4heat.euWP 6.6.2RAICOF plugin 0.4.1MCP adapter 0.3.0Themeraicof-base (1.2.0)Manifest2026.06.01

Deployment Plan

From this prototype to a deployed cloud environment, step by step. Every WordPress function the adapter touches is enumerated in §6.

Product
RAICOF / AI ContentOps
Doc version
v1.0
Owner
Platform Architect
Status
For review

1 · Executive summary

Two delivery tracks share one control plane. Native track: control plane → native renderer → managed hosting. Adapter track: control plane → WordPress plugin → draft-only post in wp-admin; publishing remains a human action inside WordPress. Both tracks share the same plan/guardrail/audit pipeline. AI output is JSON only and is never executed.

2 · Target architecture


 Dashboard (TanStack Start)
       │  signed session
       ▼
 Control plane (Fastify, Node 22)
   ├── Postgres 16  (state of record)
   ├── Redis 7      (queues, locks, rate limits)
   ├── Object store (S3 / R2)
   ├── AI orchestrator   ── packages/ai-orchestrator
   ├── Guardrail engine  ── packages/guardrails
   └── Deployment worker ── packages/deployment (15 stages)
       │
       ├──► Native renderer ──► Staging ──► Production
       │
       └──► WordPress adapter plugin (PHP)
                  │ HMAC-signed REST
                  ▼
            wp-admin: draft post + preview URL

3 · Environments

EnvURL shapeDataPromotion
locallocalhostcompose: pg / redis / minion/a
staginghttps://staging.<host>managed pg / redis / objectauto on merge to main
prodhttps://app.<host>managed pg / redis / objecthuman gate in dashboard

4 · Phased rollout — step by step

  1. Initialise the monorepo: bun workspaces, shared tsconfig.base.json, root scripts dev / build / typecheck / test.
  2. Lift platform/packages/* into packages/* unchanged; update path aliases.
  3. Lift the dashboard into apps/dashboard; add apps/wordpress-plugin and apps/renderer stubs.
  4. Scaffold apps/control-plane (Fastify, TS strict) with /healthz and /readyz; structured JSON logs with request IDs.
  5. Add docker-compose.yml with Postgres 16, Redis 7, MinIO; add .env.example.
  6. Write Postgres migrations: tenants, users, memberships, projects, sites, site_credentials, content_requests, content_plans, page_documents, page_versions, approvals, deployments, wordpress_operations, audit_events, idempotency_keys.
  7. Auth: email+password, OIDC-ready; signed httpOnly cookies; CSRF on state-changing routes.
  8. Tenancy middleware: every authed request resolves tenantId and scopes every query.
  9. RBAC roles owner, editor, operator, viewer; requireRole() helper.
  10. BullMQ worker process with shared Redis connection; jobs typed as a discriminated union.
  11. Object-storage wrapper: media/{tenant}/{site}/..., builds/{deployment}/..., tmp/{request}/...; signed-URL helper.
  12. Audit writer: every state transition writes one row with actor, tenant, target, before/after hash.
  13. Seed script: tenant_demo, project_chase4heat, one site, an owner user; load CHASE4HEAT manifest into site_credentials.manifest_cache.
  14. CI: GitHub Actions runs typecheck / lint / test / build on PR; branch protection on main.
  15. Cloud bootstrap: provision managed pg + redis + object storage on the chosen host; wire secrets via the host's secret manager.
Exit checks
  • Control plane boots locally and in staging.
  • Seeded owner can log in, see their tenant, switch tenants.
  • Audit log records login + tenant switch.
  • CI green on a clean PR; staging URL serves the dashboard.

  1. Pick plugin distribution channel (manual zip vs self-hosted update server) — tracked in §10.
  2. CI job produces a versioned agent-assisted-content-{version}.zip from apps/wordpress-plugin; pin the bundled SPA build id.
  3. Plugin metadata: Plugin Name, Version, Requires at least, Requires PHP, Update URI; PSR-4 autoload.
  4. On register_activation_hook: create the aac_audit custom table, schedule aac_refresh_manifest daily.
  5. Admin page registered with manage_options; SPA bundle enqueued only on the plugin screen.
  6. Settings stored server-side via update_option; API key never echoed to the browser; Test connection hits aac/v1/diagnostics.
  7. Register REST namespace aac/v1 via register_rest_route; every route has a permission_callback checking manage_options + valid X-WP-Nonce.
  8. Server-to-server signer (PHP): HMAC-SHA256 over METHOD + PATH + BODY_SHA256 + TIMESTAMP + NONCE with ADAPTER_SIGNING_SECRET; 5-min replay window; nonces in a transient.
  9. Pairing flow: dashboard mints a Site Key → admin pastes it → plugin calls /api/v1/sites/pair → long-lived signed site identity cached server-side.
  10. Manifest collector: scheduled job calls every WP read function in §6 and POSTs a normalised SiteCapabilityManifest; also triggered on activation, theme change, and on demand.
  11. Draft writer: receives a ContentPlan from the control plane, executes the allowed write functions in §6 in one PHP request, returns post_id + preview URL. All writes are post_status=draft; no publish path exists in code.
  12. Media sideloader: pulls media from a signed URL, uses media_sideload_image / wp_handle_sideload, attaches to the target post.
  13. Audit logger: every plugin op writes one row to aac_audit (operation, actor, post_id, payload hash, result, timestamp); mirrored to the control plane via /api/v1/audit.
  14. Fixed error taxonomy: NOT_PAIRED, SIGNATURE_INVALID, CAPABILITY_DENIED, WP_INSERT_FAILED, MEDIA_SIDELOAD_FAILED, MANIFEST_DRIFT, RATE_LIMITED.
  15. Rate limiting + circuit breaker per site in the control plane (token bucket, opens after N consecutive 5xx).
  16. Dashboard Connection screen shows plugin version, manifest version, last sync, last error, Refresh manifest button.
  17. E2E smoke against a throwaway WP: pair → manifest → create draft page → preview URL renders in wp-admin.
Exit checks
  • A real WP site pairs in under 5 minutes.
  • A draft post created from the dashboard appears in wp-admin with correct preview URL.
  • Tampered or replayed requests are rejected and logged.
  • Manifest refresh runs on schedule and on demand; drift surfaces in the dashboard.

  1. Provider adapter behind AI_PROVIDER / AI_API_KEY; default Lovable AI Gateway.
  2. Implement the orchestrator contract: JSON-only output — either ClarificationQuestion[] or a ContentPlan. Non-JSON or schema-failing output is rejected.
  3. Structured prompt assembly from ContentRequest, cached SiteCapabilityManifest, target schema, allowed operations, allowed block contracts. Never raw HTML.
  4. Hard guard: only allowedBlockContracts / editableSections may be referenced; first violation regenerates with tightened prompt; second becomes needs_clarification.
  5. Wire packages/guardrails: schema validation, block-registry validation, media resolution, SEO fields, slug/route collision, destructive-action detector.
  6. Request state machine: received → plan_pending → (plan_ready | needs_clarification | rejected); transitions persisted, audit row per transition.
  7. Clarification loop UI: questions render, user answers, orchestrator re-invoked with answers appended.
  8. Plan rendering in dashboard: field-level diff against current page_document; only safe fields are user-editable.
  9. Plan approval = first human gate; transitions to awaiting_build.
  10. Per-tenant quotas: prompt tokens, output tokens, requests/hour, retries.
  11. Observability: per-request trace row with prompt_hash, tool_calls, validation_outcomes, latency_ms, cost_estimate.
  12. Prompt-injection defense: manifest text fields JSON-escaped and delimited; orchestrator instructed to treat as data.
  13. Hard rule at the call site: orchestrator output is never executed. No eval, no template hydration with raw output, no shell.
Exit checks
  • A CHASE4HEAT request produces a valid ContentPlan reviewable in the dashboard.
  • Invalid plans never persist; user sees a clear error.
  • Clarification loop works end to end.
  • No code path allows AI output to be executed.

#StageGateNative trackAdapter track
1validate_page_schema—guardrailsguardrails
2validate_blocks—block registryblock registry
3validate_media—resolve referencesresolve references
4validate_seo—title / desc / OG / heading ordertitle / desc / OG / heading order
5validate_routes—slug + collisionsslug + collisions
6build_preview—renderer → object storewp_insert_post (draft)
7seo_checks—HTML lint, OG, Twitter, headingsskipped (WP renders)
8generate_sitemap—sitemap.xmlskipped (WP)
9generate_robots—robots.txtskipped (WP)
10generate_jsonld—per schemaTypeskipped (WP)
11deploy_staging—atomic upload + URLWP preview URL
12await_promotionhumanside-by-side diffdisabled in MVP
13deploy_production—atomic swapdisabled in MVP
14log_deployment—deployments + audit_eventsaudit row
15preserve_rollback—previous prod = rollback_targetlast-known-good draft id
  1. BullMQ deployment worker consumes { deployment_id } jobs; idempotent and resumable.
  2. Each stage implements Stage from packages/deployment/src/pipeline.ts and returns StageResult.
  3. Per-stage timeout + retry policy: exponential backoff with jitter, max 3 retries on transient errors; fatal errors halt immediately.
  4. Stage 12 timeout policy: 7 days → cancelled.
  5. One-click rollback in the dashboard restores the previous artifact via rollback_target.
  6. Observability: per-stage duration, success rate, gate wait, queue depth; alerts on consecutive failures of the same stage.
Exit checks
  • An approved plan reaches production through all 15 stages, exercising both human gates.
  • An adapter plan produces a draft in wp-admin with preview URL, audit row, rollback ref.
  • A failed stage halts the pipeline with a clear remediation message.
  • Rollback restores the previous production deployment in one click.

5 · WordPress contact surface — every function we call

All WordPress reads and writes happen inside the adapter plugin. The control plane never speaks to WordPress directly; it only speaks to the plugin's signed REST channel.

FunctionPurposeConstraint we enforce
register_activation_hookCreate plugin tables, schedule cronIdempotent
register_deactivation_hookUnschedule cron, keep dataNo data loss on deactivate
add_menu_pageRegister Agent Content admin pageCapability manage_options
current_user_can('manage_options')Permission gateRequired in every REST handler
wp_verify_nonce / wp_create_nonceCSRF for admin → plugin RESTAll state-changing routes
register_rest_routeExpose aac/v1/* endpointspermission_callback required
wp_enqueue_script / wp_enqueue_styleLoad SPA bundle on plugin screen onlyScreen check guard
get_option / update_option / delete_optionPersist plugin settingsAPI key never sent to browser
wp_remote_post / wp_remote_getS2S calls to control planeHMAC-signed, 10s timeout
wp_schedule_event / wp_unschedule_eventDaily manifest refreshSingle recurring slot
wp_insert_post(post_status=draft)Create draft Page / Post / CPTDraft only — never publish
wp_update_postUpdate existing draftStatus pinned to draft
update_post_meta / get_post_meta / delete_post_metaStructured field values per sectionKeys whitelisted by manifest
wp_set_object_terms / wp_get_object_termsTaxonomy assignment on CPTsOnly registered taxonomies
get_post / get_posts / WP_QueryRead content for manifest + planningRead-only
get_pagesEnumerate PagesRead-only
get_post_types(['public' => true])Enumerate CPTsRead-only
get_taxonomiesEnumerate taxonomiesRead-only
get_termsEnumerate termsRead-only
register_block_typeList allowed blocks for manifestRead-only
wp_get_nav_menus / wp_get_nav_menu_itemsRead menus for manifestRead-only
wp_update_nav_menu_itemEdit menu itemsAllowed locations only, gated by approval
wp_delete_post(force_delete=false)Move post / menu item to trashNever force_delete=true
wp_get_sidebars_widgets / the_widget introspectionRead widgets for manifestRead-only
update_option('widget_*', …)Update widget fieldsGated by approval
wp_get_theme / wp_get_themesActive theme + version for manifestRead-only
media_sideload_imagePull media from signed URLMIME + size allowlist
wp_handle_sideloadLower-level media intakeMIME + size allowlist
wp_insert_attachment / wp_generate_attachment_metadata / wp_update_attachment_metadataPersist attachmentLinked to target post
set_post_thumbnailFeatured imageAttachment must belong to this site
get_preview_post_linkReturn preview URLReturned only to authenticated admin
add_query_arg / home_url / rest_urlBuild URLs returned to dashboardNo raw concatenation
wp_kses / wp_kses_post / wp_kses_allowed_htmlSanitize text rendered server-sideAllowlist from block registry
sanitize_text_field / sanitize_textarea_field / esc_url_raw / absintREST boundary input sanitisationApplied per field type
$wpdb->prepareWrites to aac_audit onlyNever used on core tables
wp_get_current_userActor identity for auditRequired on every write
__() / esc_html__()i18n + escapeAll UI strings

6 · Infrastructure checklist

ComponentChoice (default)Why
Hosting (control plane)Cloud Run / Fly / RenderTS Node service, autoscale
Hosting (native frontend)CDN-backed static + edge SSRTanStack Start output
DatabaseManaged Postgres 16State of record
Queue / cacheManaged Redis 7BullMQ + rate limits
Object storageS3-compatible (R2 / S3)Media + build artifacts
SecretsHost secret managerNo secrets in env files
Logs / tracesOpenTelemetry → managed backendPer-request trace id
EmailProvider behind one adapterApproval + alert notifications

7 · Secrets & configuration matrix

KeyScopeUsed by
DATABASE_URLservercontrol plane, worker
REDIS_URLservercontrol plane, worker
OBJECT_STORE_*servercontrol plane, worker
SESSION_SECRETserverauth cookies
ADAPTER_SIGNING_SECRETserver + pluginHMAC for plugin ⇄ control plane
AI_PROVIDERserverorchestrator
AI_API_KEYserverorchestrator
DEPLOY_TARGET_*worker onlystage 11 / 13
SENTRY_DSNservererror reporting

8 · Security & compliance gates

  • Two human gates: plan approval, production promotion.
  • AI output is JSON-only and never executed; no eval, no shell, no template hydration of raw output.
  • Plugin enforces capability + nonce on every REST route; control plane verifies HMAC on every plugin call.
  • Audit row per state transition, per WP operation, per deployment stage.
  • Tenant scoping applied in a single middleware; queries cannot skip it.
  • Rate limits + circuit breaker per site; quotas per tenant.
  • No publish path in adapter code; no force-delete; no privileged role mutation.

9 · Go-live checklist

  • Staging green for 7 days under synthetic load (1 op/sec/site).
  • Disaster-recovery drill: restore pg from backup, replay last 24h of audit.
  • Rotate ADAPTER_SIGNING_SECRET once before launch; verify rotation procedure.
  • Pen-test the plugin REST surface and the control-plane public endpoints.
  • Status page + on-call rota in place.
  • Runbooks for: failed deployment, manifest drift, signature reject storm, AI quota exhausted.

10 · Open decisions

  • Plugin distribution: manual zip vs self-hosted update server.
  • Primary host for control plane (Cloud Run vs Fly vs Render).
  • AI provider lock-in vs adapter (Lovable AI Gateway default).
  • Whether the adapter track ever gains an automated publish path post-MVP (currently: no).