Skip to content

Onboarding a New Site ​

Partner Documentation

This guide walks you through the complete process of adding a new customer site to DCS using the official npm packages.

Prerequisites ​

Before starting, ensure you have:

  • [ ] A VitePress or compatible website
  • [ ] Access to the site's GitHub repository
  • [ ] Node.js >= 18.0.0 installed
  • [ ] DCS partner account with admin access
  • [ ] Azure subscription with appropriate permissions (for deployment)

The fastest way to onboard a site is using the official CLI:

bash
# 1. Install the CLI globally
npm install -g @duffcloudservices/cli

# 2. Authenticate with DCS
dcs login

# 3. Navigate to your site's repository
cd /path/to/customer-site

# 4. Initialize DCS integration
dcs init --site-slug customer-site --site-name "Customer Site Name"

# 5. Install the CMS package
pnpm add @duffcloudservices/cms

# 6. Follow the generated integration plans
code .plans/

The CLI creates all necessary configuration files and generates step-by-step integration plans.


Step 1: Initialize DCS Configuration ​

bash
dcs init --site-slug customer-site --site-name "Customer Site Name"

This creates:

  • .dcs/site.yaml — Site identity
  • .dcs/pages.yaml — Page registry
  • .dcs/content.yaml — Text content (portal-managed)
  • .dcs/seo.yaml — SEO configuration (portal-managed)
  • .github/copilot-instructions.md — AI assistant context
  • .plans/ — Integration guides

Manual Setup (Alternative) ​

If you prefer manual setup, create the .dcs/ files by hand. Site identity and deployment settings live in .dcs/site.yaml:

yaml
site_name: Customer Site Name
site_slug: customer-site
portal_api_url: https://portal.duffcloudservices.com
azure:
  client_id: <app-registration-client-id>
  tenant_id: <azure-tenant-id>
  subscription_id: <azure-subscription-id>
swa_resource_id: /subscriptions/<sub>/resourceGroups/<rg>/providers/Microsoft.Web/staticSites/customer-site

See the site.yaml reference for the complete schema. Pages go in .dcs/pages.yaml; content.yaml and seo.yaml are portal-managed.

Step 2: Install & Configure the CMS Package ​

Install Dependencies ​

bash
pnpm add @duffcloudservices/cms

Configure Vite Plugins ​

For VitePress sites:

typescript
// .vitepress/config.ts
import { defineConfig } from 'vitepress'
import { dcsContentPlugin, dcsSeoPlugin } from '@duffcloudservices/cms/plugins'

export default defineConfig({
  vite: {
    plugins: [
      dcsContentPlugin(),
      dcsSeoPlugin()
    ]
  }
})

For standard Vite sites:

typescript
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { dcsContentPlugin, dcsSeoPlugin } from '@duffcloudservices/cms/plugins'

export default defineConfig({
  plugins: [
    vue(),
    dcsContentPlugin(),
    dcsSeoPlugin()
  ]
})

Add Environment Variables ​

bash
# .env
VITE_SITE_SLUG=customer-site
VITE_API_BASE_URL=https://portal.duffcloudservices.com

Step 3: Implement Text Content Integration ​

Use the Composable ​

vue
<script setup lang="ts">
import { useTextContent } from '@duffcloudservices/cms'

const { t } = useTextContent({
  pageSlug: 'home',
  defaults: {
    'hero.title': 'Welcome to Our Site',
    'hero.subtitle': 'Building the future together',
    'cta.primary': 'Get Started'
  }
})
</script>

<template>
  <section class="hero">
    <h1>{{ t('hero.title') }}</h1>
    <p>{{ t('hero.subtitle') }}</p>
    <button>{{ t('cta.primary') }}</button>
  </section>
</template>

Add SEO Integration ​

vue
<script setup lang="ts">
import { useTextContent, useSEO } from '@duffcloudservices/cms'

const { t } = useTextContent({
  pageSlug: 'home',
  defaults: { /* ... */ }
})

// Apply SEO meta tags
const { applyHead } = useSEO('home')
applyHead()
</script>

Step 4: Register Pages ​

Create .dcs/pages.yaml:

yaml
pages:
  - slug: home
    path: /
    type: static
    title: Home
    deletable: false
    textKeys: []

  - slug: about
    path: /about
    type: static
    title: About Us
    deletable: true
    textKeys: []

  - slug: services
    path: /services
    type: static
    title: Services
    deletable: true
    textKeys: []

  - slug: contact
    path: /contact
    type: static
    title: Contact
    deletable: true
    textKeys: []

  - slug: blogs
    path: /blog
    type: index
    title: Blog
    deletable: false
    textKeys: []

Page Types ​

TypeUse CaseNotes
staticRegular pagesUser-editable content
indexCollection pagesBlog index, etc.
dynamicGenerated pagesAuto-created content

Step 5: Set Up GitHub Integration ​

Configure Azure authentication (OIDC) ​

Deployment uses OIDC federated credentials — no long-lived Azure secret and no static Static Web App token are stored in the repo. dcs init writes the three non-secret Azure identifiers into .dcs/site.yaml; you can alternatively set them as repository Variables (Settings → Secrets and variables → Actions → Variables):

AZURE_CLIENT_ID           # app registration (client) ID with a federated credential
AZURE_TENANT_ID           # Azure tenant ID
AZURE_SUBSCRIPTION_ID     # Azure subscription ID

The federated credential on the app registration (mapping master and release/** to the repo) is provisioned during onboarding. See GitHub Setup for details.

AI assistant guidance and deployment workflow ​

dcs init already generated both of these in Step 1:

  • .github/copilot-instructions.md — AI assistant context for the repo. Tailor it to the site (framework, styling conventions, text-content pattern).
  • .github/workflows/site-deploy.yml — the OIDC deployment workflow. It triggers on master (→ Production) and release/** (→ Preview), logs in with azure/login@v2, and fetches a short-lived Static Web App token from the DCS API at run time (POST /api/v1/sites/deployment-tokens). Do not hand-write it or add a static deployment token. See GitHub Setup for the workflow anatomy.

Step 6: Create Azure Resources ​

Static Web App (Development) ​

bash
az staticwebapp create \
  --name customer-site-dev \
  --resource-group dcs-sites-rg \
  --location eastus2 \
  --sku Free

Static Web App (Production) ​

bash
az staticwebapp create \
  --name customer-site-prod \
  --resource-group dcs-sites-rg \
  --location eastus2 \
  --sku Standard

Configure Custom Domain (Production) ​

bash
az staticwebapp hostname set \
  --name customer-site-prod \
  --hostname www.customer-site.com

Step 7: Register in DCS Portal ​

Create Site Record ​

  1. Log into the DCS admin portal
  2. Navigate to Sites → Add Site
  3. Fill in site details:
    • Slug: customer-site
    • Name: Customer Site Name
    • GitHub Repo: owner/customer-site
    • Dev SWA Resource ID: (from Azure)
    • Prod SWA Resource ID: (from Azure)

Assign to Company ​

  1. Navigate to Companies → Select Company
  2. Add site to company
  3. Set appropriate user permissions

Step 8: Verify Integration ​

Validate Configuration ​

bash
dcs validate

Test Text Overrides ​

  1. Create a test override in the portal
  2. Verify it appears on the dev site
  3. Delete the test override

Test Development Requests ​

  1. Submit a test request
  2. Verify GitHub issue is created
  3. Verify Copilot response
  4. Review and close test request

Onboarding Checklist ​

  • [ ] CLI installed and authenticated (dcs login)
  • [ ] Site initialized with dcs init
  • [ ] @duffcloudservices/cms package installed
  • [ ] Vite plugins configured
  • [ ] Text content composable implemented in pages
  • [ ] Pages registered in .dcs/pages.yaml
  • [ ] GitHub secrets configured
  • [ ] Deployment workflows added
  • [ ] Azure SWA resources created
  • [ ] Site registered in DCS portal
  • [ ] Configuration validated (dcs validate)
  • [ ] Integration tested end-to-end
  • [ ] Site owner trained on portal usage

Troubleshooting ​

Text overrides not appearing ​

  1. Check API endpoint in configuration
  2. Verify CORS settings on DCS server
  3. Check browser console for errors

Deployment failing ​

  1. Verify GitHub secrets are correct
  2. Check Azure SWA resource IDs
  3. Review workflow logs

GitHub integration issues ​

  1. Verify webhook configuration
  2. Check service principal permissions
  3. Review DCS server logs

Next Steps ​