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 .dcs/config.yaml:

yaml
site:
  slug: customer-site
  name: Customer Site Name

api:
  endpoint: https://portal.duffcloudservices.com/api

features:
  textOverrides: true
  seoMetadata: true
  blog: true
  analytics: true

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

Add Repository Secrets

In GitHub Settings → Secrets and variables → Actions:

AZURE_CLIENT_ID=<service-principal-id>
AZURE_CLIENT_SECRET=<service-principal-secret>
AZURE_TENANT_ID=<azure-tenant-id>
AZURE_SUBSCRIPTION_ID=<subscription-id>
DCS_SERVER_URL=https://portal.duffcloudservices.com

Add Copilot Instructions

Create .github/copilot-instructions.md:

markdown
# Copilot Instructions for [Site Name]

## Project Overview
This is a VitePress marketing site integrated with DCS.

## Text Content
Use the `useTextContent` composable for all user-editable text:
\`\`\`vue
const { t } = useTextContent()
// t('key', 'default value')
\`\`\`

## Development Guidelines
- Follow Vue 3 Composition API patterns
- Use Tailwind CSS for styling
- Test changes in dev environment before production

Add Deployment Workflow

Create .github/workflows/draft-release-deploy.yml:

yaml
name: Draft Release Deploy

on:
  issues:
    types: [labeled]

jobs:
  deploy-draft:
    if: github.event.label.name == 'draft-release'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: '22'
          
      - name: Install pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 9
          
      - name: Install dependencies
        run: pnpm install
        
      - name: Build
        run: pnpm build
        
      - name: Deploy to Azure
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_SWA_TOKEN }}
          action: 'upload'
          app_location: '.vitepress/dist'

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

Duff Cloud Services Documentation