Skip to content

Configuration Files

Partner Documentation

Complete reference for all DCS configuration files.

The .dcs/ directory

dcs init creates the .dcs/ directory with four files. There is no config.yaml — configuration is split across these:

FilePurpose
.dcs/site.yamlSite identity, Azure resource IDs, and deployment settings
.dcs/pages.yamlPage registry
.dcs/content.yamlText content overrides (portal-managed)
.dcs/seo.yamlSEO metadata (portal-managed)

See the site.yaml reference for the full deployment and identity schema. The sections below cover page registration and the surrounding project configuration.

.dcs/pages.yaml

Registry of pages for the portal.

Full Schema

yaml
pages:
  - slug: home                     # URL-safe identifier
    path: /                        # Route path
    type: static                   # Page type: static, index, dynamic
    title: Home                    # Display title
    deletable: false               # Can be deleted via portal
    textKeys:                      # Text keys (auto-discovered if empty)
      - home.hero.title
      - home.hero.subtitle
    meta:                          # Optional metadata
      template: landing            # Template name
      priority: high               # sitemap priority
      changefreq: weekly           # sitemap change frequency

Page Types

TypeDescriptionExample
staticStandard pages/about, /services
indexCollection landing/blog
dynamicGenerated from data/blog/:slug

Required Pages

Every site should have:

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

Environment Variables

Variables read by @duffcloudservices/cms

Your generated deployment workflow injects these at build time from your site configuration — most sites never set them by hand.

bash
# .env — all optional
VITE_API_BASE_URL=https://portal.duffcloudservices.com   # DCS API base URL (this is the default)
VITE_TEXT_OVERRIDE_MODE=commit                           # Text-content override mode (editing/preview)
# VITE_SITE_SLUG is deprecated: the site is resolved server-side from the request host

Environment Files

FilePurpose
.envDefault variables
.env.localLocal overrides (git-ignored)
.env.developmentDevelopment mode
.env.productionProduction mode

GitHub Configuration

Azure authentication (OIDC)

Deployment uses OIDC federated credentials — there are no long-lived Azure secrets and no static Static Web App token in the repository. The generated .github/workflows/site-deploy.yml logs in with azure/login@v2 and requests a short-lived deployment token from the DCS API at run time.

The three Azure identifiers are non-secret and are written into .dcs/site.yaml by dcs init. If you prefer, set them as repository Variables (Settings → Secrets and variables → Actions → Variables) instead:

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

The workflow also needs permissions: id-token: write. See GitHub Setup for the federated-credential setup.

AI assistant guidance file

dcs init generates .github/copilot-instructions.md, a repo-level guidance file the automated development pipeline reads for context. Tailor it to the site:

markdown
# AI assistant guidance for [Site Name]

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

## Architecture
- Framework: VitePress
- Styling: Tailwind CSS
- DCS Integration: useTextContent composable

## Text Content Pattern
Use the `useTextContent` composable for editable text:
\`\`\`vue
import { useTextContent } from '@duffcloudservices/cms'
const { t } = useTextContent()
// Usage: t('key', 'default value')
\`\`\`

## Key Conventions
- Use Composition API with TypeScript
- Keep components small and focused

## Pages Configuration
Update `.dcs/pages.yaml` when adding new pages.

## Development Workflow
1. Create feature branch
2. Make changes
3. Test locally
4. Submit PR to release branch

Azure SWA Configuration

staticwebapp.config.json

json
{
  "navigationFallback": {
    "rewrite": "/index.html",
    "exclude": [
      "/images/*",
      "/fonts/*",
      "/*.ico",
      "/*.xml",
      "/*.json"
    ]
  },
  "routes": [
    {
      "route": "/api/*",
      "rewrite": "/api/{*}"
    }
  ],
  "responseOverrides": {
    "404": {
      "rewrite": "/404.html"
    }
  },
  "mimeTypes": {
    ".webmanifest": "application/manifest+json"
  },
  "globalHeaders": {
    "X-Content-Type-Options": "nosniff",
    "X-Frame-Options": "DENY",
    "Referrer-Policy": "strict-origin-when-cross-origin"
  }
}

VitePress Configuration

typescript
import { defineConfig } from 'vitepress'

export default defineConfig({
  title: 'My Site',
  description: 'A DCS-powered website',
  
  head: [
    ['link', { rel: 'icon', href: '/favicon.ico' }],
    ['meta', { name: 'theme-color', content: '#7c969e' }],
  ],
  
  themeConfig: {
    logo: '/logo.svg',
    siteTitle: 'My Site',
    
    nav: [
      { text: 'Home', link: '/' },
      { text: 'About', link: '/about' },
      { text: 'Blog', link: '/blog/' },
    ],
    
    socialLinks: [
      { icon: 'twitter', link: 'https://twitter.com/...' },
      { icon: 'github', link: 'https://github.com/...' }
    ],
    
    footer: {
      message: 'Powered by DCS',
      copyright: `© ${new Date().getFullYear()} My Company`
    }
  },
  
  sitemap: {
    hostname: 'https://mysite.com'
  },
  
  lastUpdated: true
})

TypeScript Configuration

json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "jsx": "preserve",
    "paths": {
      "@/*": ["./src/*"]
    },
    "types": ["vitepress/client"]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.vue",
    ".vitepress/**/*.ts",
    ".vitepress/**/*.vue"
  ]
}

Validation

Validate your .dcs/ configuration with the CLI:

bash
dcs validate

If you want a lightweight local check, verify the real .dcs/ files exist:

typescript
// scripts/validate-config.ts
import { existsSync } from 'fs'

function validateConfig() {
  const errors: string[] = []

  const requiredFiles = [
    '.dcs/site.yaml',
    '.dcs/pages.yaml',
    '.env'
  ]

  for (const file of requiredFiles) {
    if (!existsSync(file)) {
      errors.push(`Missing required file: ${file}`)
    }
  }

  if (errors.length > 0) {
    console.error('Configuration errors:')
    errors.forEach(e => console.error(`  - ${e}`))
    process.exit(1)
  }

  console.log('✓ Configuration valid')
}

validateConfig()

Next Steps