Skip to content

feat(site-deployment): multi-tenant per-client deploy targets (MT)#13

Merged
cryptoxdog merged 1 commit into
mainfrom
feat/mt-site-deployment
Jul 19, 2026
Merged

feat(site-deployment): multi-tenant per-client deploy targets (MT)#13
cryptoxdog merged 1 commit into
mainfrom
feat/mt-site-deployment

Conversation

@cryptoxdog

Copy link
Copy Markdown
Collaborator

What & why

Threads a per-client site_deployment transport config end-to-end so each client's autonomous surpass-plan edits write to that client's repo / Vercel deploy hook instead of the single shared WEBSITE_BOT_REPO. This is the C-02 enabler for multi-tenant serp:execute-surpass-plans.

The scheduler fan-out already attaches the full clients.config jsonb as job.data.clientConfig to every per-client job, so this is a surgical thread-through — no schema migration (clients.config is jsonb).

Code-only. The enabled:false → true flip on serp:execute-surpass-plans is intentionally not in this PR — it stays a separate operational change made only after real per-client config is in the DB. Safety is enforced at the siteConfigFromClient boundary, so the flip is safe-by-construction once config exists.

Changes

  • types (src/types/index.ts) — add ClientSiteDeploymentConfig and an optional site_deployment on ClientConfig.
  • site-deployment (src/services/site-deployment.ts)
    • siteConfigFromClient(clientConfig) — builds the per-tenant config with the same dry-run safety invariant as siteConfigFromEnv: absent or blank token/repo (and the NODE_ENV/SITE_DEPLOY_DRY_RUN env kills) force dryRun:true. A half-populated site_deployment never performs a live write.
    • optional trailing config?: SiteDeploymentConfig on all 7 action fns (updateMetaTitle, updateMetaDescription, injectSchema, updateHeading, rewritePageContent, updateFaq, triggerVercelDeploy). Additive — existing no-arg callers still compile.
  • plan-executor (src/services/plan-executor.ts) — widen ActionDispatcher with a 4th siteConfig param (alias updated before any dispatcher body), resolve siteConfigFromClient(job.data.clientConfig ?? {}) in executeSurpassPlans, thread it through every dispatch and the final triggerVercelDeploy. faq_content_update keeps its documented no-op.
  • add-client (scripts/add-client.ts) — prompt for + store config.site_deployment; warn when incomplete (client operates in dry-run).

Tests

  • siteConfigFromClient: full→dryRun:false; missing token→dryRun:true; empty-string repo→dryRun:true (G6); NODE_ENV=test global kill honored even with a full config.
  • updateMetaTitle with an explicit config reads/writes against the injected repo, not the env fallback.
  • plan-executor: configured client routes its edit + final deploy to that client's repo; no site_deployment → dry-run fallback; faq_content_update dispatches no write (G3).

Verification

  • tsc --noEmit = 0 (the sole remaining error is a pre-existing @infisical/sdk module-resolution artifact of this sandbox's dependency install, unrelated to this change and resolved in CI).
  • vitest run40/40 green.

Rollback

If a future enable-flip causes an unintended write: flip enabled:true → false and redeploy; confirm no job re-enqueues next cycle; audit recent gapAnalyses rows at status='executing'.

🤖 Generated with Claude Code


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR threads a per-client site_deployment transport configuration through the surpass-plan execution path so autonomous edits/deploys target each tenant’s own GitHub repo and Vercel hook (instead of the shared env-based WEBSITE_BOT_REPO).

Changes:

  • Adds ClientSiteDeploymentConfig and optional site_deployment on ClientConfig for MT deploy targets.
  • Introduces siteConfigFromClient(...) and threads an explicit SiteDeploymentConfig through site-deployment action functions and the plan executor dispatch path.
  • Extends the add-client onboarding script and adds/updates tests for MT config resolution and routing.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
tests/services/site-deployment.test.ts Adds coverage for siteConfigFromClient dry-run guard and explicit-config repo routing in updateMetaTitle.
tests/services/plan-executor.test.ts Verifies per-client config threading through dispatch + deploy, dry-run fallback, and FAQ no-op behavior.
src/types/index.ts Adds ClientSiteDeploymentConfig and optional site_deployment field to ClientConfig.
src/services/site-deployment.ts Adds siteConfigFromClient and threads optional config through deployment actions / deploy trigger.
scripts/add-client.ts Prompts for and stores config.site_deployment during onboarding, warning when incomplete (dry-run).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/services/site-deployment.ts Outdated
Comment thread src/types/index.ts
Comment thread scripts/add-client.ts Outdated
Comment thread scripts/add-client.ts Outdated
Comment thread scripts/add-client.ts Outdated
Comment thread src/services/site-deployment.ts
Comment thread src/services/site-deployment.ts
Comment thread src/services/site-deployment.ts
Comment thread src/services/site-deployment.ts
Comment thread src/services/site-deployment.ts
Threads a per-client `site_deployment` transport config end-to-end so each
client's autonomous surpass-plan edits write to THAT client's repo/deploy
hook instead of the single shared WEBSITE_BOT_REPO. Unblocks the
multi-tenant serp:execute-surpass-plans fan-out (enable-flip stays a
separate operational change; enabled:false untouched).

- types: ClientSiteDeploymentConfig (all fields optional, JSONB reality) +
  optional site_deployment on ClientConfig (no migration).
- site-deployment: siteConfigFromClient(Partial<ClientConfig>) with the same
  dry-run safety invariant as siteConfigFromEnv (absent/blank token or repo,
  or the NODE_ENV/SITE_DEPLOY_DRY_RUN kills, force dryRun). readFile now
  short-circuits in dry-run (no outbound GET), so an unconfigured tenant is a
  true no-op. Optional config? on all 7 action fns.
- plan-executor: ActionDispatcher gains a 4th siteConfig param; executor
  resolves siteConfigFromClient(job.data.clientConfig) and threads it through
  every dispatch + the final triggerVercelDeploy. faq_content_update stays a
  no-op.
- add-client: prompts for + stores config.site_deployment; process.stdout/
  stderr.write for new output (AGENTS.md no-console.log).
- tests: siteConfigFromClient full/missing/blank(G6)/NODE_ENV; explicit config
  overrides env; dry-run makes no GET/PUT; plan-executor per-client routing,
  dry-run fallback, faq no-write.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VqWfuXWTn5jo8f5fnkSozx
@cryptoxdog
cryptoxdog force-pushed the feat/mt-site-deployment branch from 2ad643c to 5f40db1 Compare July 19, 2026 01:06
@cryptoxdog
cryptoxdog merged commit 3084932 into main Jul 19, 2026
2 checks passed
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants