Documentation Deployment Strategy
Deploy ATOM SaaS documentation to a public-facing URL for easy access by users, developers, and administrators.
---
Deployment Options
Option 1: Vercel (Recommended)
**Pros:**
- Free for public projects
- Automatic HTTPS
- Global CDN
- Preview deployments
- Excellent markdown support
**Setup:**
# 1. Install Vercel CLI
npm i -g vercel
# 2. Navigate to docs directory
cd docs
# 3. Create vercel.json config
cat > vercel.json << 'EOF'
{
"version": 2,
"name": "atom-saas-docs",
"buildCommand": "echo 'No build required for markdown'",
"outputDirectory": ".",
"routes": [
{
"src": "/(.*)",
"dest": "/$1",
"headers": {
"Cache-Control": "public, max-age=3600"
}
}
],
"redirects": [
{
"src": "/",
"dest": "/README.md"
}
]
}
EOF
# 4. Deploy
vercel --prod**URL:** https://docs.atomagentos.com or https://atom-saas-docs.vercel.app
---
Option 2: Dedicated Subdomain on Production App
**Pros:**
- Consistent branding (docs.atomagentos.com)
- Same deployment pipeline
- Easy to maintain
**Implementation:**
1. Create Documentation Route
**File:** src/app/docs/[[...slug]]/page.tsx
import fs from 'fs';
import path from 'path';
import { notFound } from 'next/navigation';
// Docs directory path
const DOCS_PATH = path.join(process.cwd(), 'docs');
interface DocMetadata {
title: string;
description?: string;
lastUpdated: string;
}
export default async function DocsPage({
params,
}: {
params: { slug?: string[] };
}) {
// Resolve file path
const filePath = params.slug
? path.join(DOCS_PATH, ...params.slug) + '.md'
: path.join(DOCS_PATH, 'README.md');
// Read markdown file
let content: string;
try {
content = fs.readFileSync(filePath, 'utf-8');
} catch (error) {
notFound();
}
// Extract metadata
const metadata = extractMetadata(content);
return (
<div className="docs-container">
<DocsNavigation currentPath={params.slug || []} />
<main className="docs-content">
<h1>{metadata.title}</h1>
{metadata.description && (
<p className="description">{metadata.description}</p>
)}
<MarkdownRenderer content={content} />
</main>
<TableOfContents content={content} />
</div>
);
}
function extractMetadata(content: string): DocMetadata {
const titleMatch = content.match(/^# (.+)$/m);
const title = titleMatch ? titleMatch[1] : 'Documentation';
return {
title,
lastUpdated: new Date().toISOString(),
};
}2. Create Docs Navigation Component
**File:** src/components/docs/DocsNavigation.tsx
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
interface DocsSection {
title: string;
items: DocItem[];
}
interface DocItem {
title: string;
path: string;
children?: DocItem[];
}
const docsStructure: DocsSection[] = [
{
title: 'Getting Started',
items: [
{ title: 'Quick Start', path: '/docs/getting-started/quick-start' },
{ title: 'Understanding Agents', path: '/docs/user-guides/agents/understanding-agents' },
{ title: 'Agent Maturity', path: '/docs/user-guides/agents/maturity-levels' },
],
},
{
title: 'Architecture',
items: [
{ title: 'Overview', path: '/docs/architecture/overview' },
{ title: 'Brain Systems', path: '/docs/architecture/brain-systems/overview' },
{ title: 'Multi-Tenancy', path: '/docs/architecture/multi-tenancy/overview' },
],
},
{
title: 'API Reference',
items: [
{ title: 'API Overview', path: '/docs/api/overview' },
{ title: 'Agent APIs', path: '/docs/api/agents/overview' },
{ title: 'Graduation APIs', path: '/docs/api/graduation/overview' },
],
},
{
title: 'Development',
items: [
{ title: 'Local Setup', path: '/docs/development/setup/local-setup' },
{ title: 'Code Standards', path: '/docs/development/standards/code-style' },
{ title: 'Testing Guide', path: '/docs/development/testing/overview' },
],
},
];
export function DocsNavigation() {
const pathname = usePathname();
return (
<nav className="docs-nav">
<div className="docs-nav-header">
<Link href="/docs">Documentation</Link>
</div>
{docsStructure.map((section) => (
<div key={section.title} className="docs-nav-section">
<h3>{section.title}</h3>
<ul>
{section.items.map((item) => (
<li key={item.path}>
<Link
href={item.path}
className={pathname === item.path ? 'active' : ''}
>
{item.title}
</Link>
{item.children && (
<ul>
{item.children.map((child) => (
<li key={child.path}>
<Link
href={child.path}
className={pathname === child.path ? 'active' : ''}
>
{child.title}
</Link>
</li>
))}
</ul>
)}
</li>
))}
</ul>
</div>
))}
</nav>
);
}3. Create Markdown Renderer
**File:** src/components/docs/MarkdownRenderer.tsx
'use client';
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism';
interface MarkdownRendererProps {
content: string;
}
export function MarkdownRenderer({ content }: MarkdownRendererProps) {
return (
<ReactMarkdown
components={{
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
style={vscDarkPlus}
language={match[1]}
PreTag="div"
{...props}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className={className} {...props}>
{children}
</code>
);
},
mermaid({ node, ...props }) {
// Handle Mermaid diagrams
return <MermaidDiagram {...props} />;
},
}}
>
{content}
</ReactMarkdown>
);
}
function MermaidDiagram({ children }: { children: string }) {
// Use mermaid library to render diagrams
return (
<div className="mermaid">
{children}
</div>
);
}4. Update Dependencies
npm install react-markdown react-syntax-highlighter
npm install -D @types/react-syntax-highlighter5. Add Styling
**File:** src/app/docs/globals.css
.docs-container {
display: grid;
grid-template-columns: 250px 1fr 200px;
gap: 2rem;
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
}
.docs-nav {
position: sticky;
top: 2rem;
height: fit-content;
}
.docs-nav-section h3 {
font-size: 0.875rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.5rem;
margin-top: 1.5rem;
color: #6b7280;
}
.docs-nav ul {
list-style: none;
padding: 0;
margin: 0;
}
.docs-nav li {
margin-bottom: 0.25rem;
}
.docs-nav a {
display: block;
padding: 0.375rem 0.5rem;
border-radius: 0.25rem;
color: #374151;
text-decoration: none;
font-size: 0.875rem;
transition: all 0.2s;
}
.docs-nav a:hover {
background-color: #f3f4f6;
color: #111827;
}
.docs-nav a.active {
background-color: #dbeafe;
color: #1e40af;
font-weight: 500;
}
.docs-content {
min-height: 100vh;
}
.docs-content h1 {
font-size: 2.5rem;
font-weight: 700;
margin-bottom: 1rem;
color: #111827;
}
.docs-content h2 {
font-size: 2rem;
font-weight: 600;
margin-top: 3rem;
margin-bottom: 1rem;
color: #111827;
}
.docs-content h3 {
font-size: 1.5rem;
font-weight: 600;
margin-top: 2rem;
margin-bottom: 0.75rem;
color: #111827;
}
.docs-content p {
font-size: 1rem;
line-height: 1.75;
color: #374151;
margin-bottom: 1rem;
}
.docs-content code {
background-color: #f3f4f6;
padding: 0.2rem 0.4rem;
border-radius: 0.25rem;
font-size: 0.875rem;
font-family: 'Monaco', 'Menlo', monospace;
}
.docs-content pre {
background-color: #1e1e1e;
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
margin: 1rem 0;
}
.docs-content pre code {
background-color: transparent;
padding: 0;
color: #d4d4d4;
}
.docs-content ul,
.docs-content ol {
margin-left: 1.5rem;
margin-bottom: 1rem;
}
.docs-content li {
margin-bottom: 0.5rem;
line-height: 1.75;
color: #374151;
}
.docs-content a {
color: #2563eb;
text-decoration: none;
font-weight: 500;
}
.docs-content a:hover {
text-decoration: underline;
}
.docs-content table {
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
}
.docs-content th,
.docs-content td {
border: 1px solid #e5e7eb;
padding: 0.75rem;
text-align: left;
}
.docs-content th {
background-color: #f9fafb;
font-weight: 600;
}
.docs-content blockquote {
border-left: 4px solid #2563eb;
padding-left: 1rem;
margin: 1.5rem 0;
color: #6b7280;
font-style: italic;
}
.mermaid {
display: flex;
justify-content: center;
margin: 2rem 0;
padding: 1rem;
background-color: #f9fafb;
border-radius: 0.5rem;
}
@media (max-width: 1024px) {
.docs-container {
grid-template-columns: 1fr;
}
.docs-nav {
display: none;
}
}6. Configure DNS
Add DNS record for docs.atomagentos.com:
Type: CNAME
Name: docs
Value: atom.ai (or your production app URL)
TTL: 3600---
Option 3: Static Site Generator (Docusaurus)
**Pros:**
- Designed specifically for documentation
- Built-in search
- Versioning support
- Excellent markdown support
**Setup:**
# 1. Initialize Docusaurus
npx create-docusaurus@latest docs-website classic
# 2. Copy existing docs to docusaurus/docs
cp -r docs/* docusaurus/docs/
# 3. Configure docusaurus.config.js
# Update baseUrl: '/docs/'
# 4. Deploy
cd docusaurus
npm run build
# Deploy to GitHub Pages, Netlify, or Vercel---
Recommended Deployment: Next.js Route
I recommend **Option 2** (Dedicated Subdomain on Production App) because:
- **Consistent Branding:**
docs.atomagentos.comaligns with main app - **Same Infrastructure:** Uses existing deployment pipeline
- **Easy Maintenance:** Docs updated with app deployments
- **No Extra Costs:** No additional hosting fees
- **Version Control:** Docs versioned with code
- **Preview Deployments:** Test docs with PRs
---
Implementation Steps
Step 1: Create Documentation Route (5 minutes)
# Create the route file
touch src/app/docs/[[...slug]]/page.tsxStep 2: Install Dependencies (2 minutes)
npm install react-markdown react-syntax-highlighter mermaid
npm install -D @types/react-syntax-highlighterStep 3: Add Navigation Component (10 minutes)
Create src/components/docs/DocsNavigation.tsx with structure.
Step 4: Add Markdown Renderer (5 minutes)
Create src/components/docs/MarkdownRenderer.tsx.
Step 5: Add Styling (5 minutes)
Create src/app/docs/globals.css.
Step 6: Test Locally (2 minutes)
npm run dev
# Visit http://localhost:3000/docsStep 7: Deploy (3 minutes)
git add .
git commit -m "feat: add public documentation viewer"
git push origin mainStep 8: Configure DNS (5 minutes)
Add CNAME record for docs.atomagentos.com.
---
Additional Features
Search Functionality
Add client-side search:
// src/components/docs/DocsSearch.tsx
'use client';
import { useState } from 'react';
export function DocsSearch() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const searchDocs = async (q: string) => {
// Simple client-side search
// Or use Algolia DocSearch for better results
};
return (
<div className="docs-search">
<input
type="search"
placeholder="Search documentation..."
value={query}
onChange={(e) => {
setQuery(e.target.value);
searchDocs(e.target.value);
}}
/>
{results.length > 0 && (
<ul className="search-results">
{results.map((result) => (
<li key={result.path}>
<a href={result.path}>{result.title}</a>
</li>
))}
</ul>
)}
</div>
);
}Version Selector
If you maintain multiple documentation versions:
// src/components/docs/VersionSelector.tsx
'use client';
const versions = [
{ label: 'v8.0 (Latest)', value: 'latest' },
{ label: 'v7.0', value: 'v7' },
{ label: 'v6.0', value: 'v6' },
];
export function VersionSelector() {
return (
<select className="version-selector">
{versions.map((v) => (
<option key={v.value} value={v.value}>
{v.label}
</option>
))}
</select>
);
}Edit on GitHub Link
Add "Edit this page" link:
// src/components/docs/EditLink.tsx
const EDIT_BASE_URL = 'https://github.com/your-org/atom-saas/edit/main/docs';
export function EditLink({ filePath }: { filePath: string }) {
return (
<a
href={`${EDIT_BASE_URL}${filePath}`}
target="_blank"
rel="noopener noreferrer"
className="edit-link"
>
Edit this page on GitHub →
</a>
);
}---
SEO Optimization
Add metadata for search engines:
// src/app/docs/layout.tsx
export const metadata = {
title: 'ATOM SaaS Documentation',
description: 'Complete documentation for ATOM SaaS - The First AI Workforce You Can Actually Trust',
keywords: ['AI', 'agents', 'documentation', 'SaaS', 'multi-tenant'],
openGraph: {
title: 'ATOM SaaS Documentation',
description: 'Complete documentation for ATOM SaaS platform',
url: 'https://docs.atomagentos.com',
siteName: 'ATOM SaaS',
images: [{
url: 'https://docs.atomagentos.com/og-image.png',
width: 1200,
height: 630,
}],
locale: 'en_US',
type: 'website',
},
};---
Analytics
Add documentation analytics:
// src/app/docs/layout.tsx
import { Analytics } from '@vercel/analytics/react';
export default function DocsLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
);
}---
Monitoring
Set up uptime monitoring for documentation:
# Using UptimeRobot or similar
# Monitor: https://docs.atomagentos.com
# Check interval: 5 minutes
# Alert on: Down for 2 minutes---
Migration Checklist
- [ ] Create documentation route (
src/app/docs/[[...slug]]/page.tsx) - [ ] Install markdown dependencies
- [ ] Create navigation component
- [ ] Create markdown renderer with syntax highlighting
- [ ] Add Mermaid diagram support
- [ ] Add styling
- [ ] Test locally
- [ ] Deploy to production
- [ ] Configure DNS (
docs.atomagentos.com) - [ ] Add search functionality
- [ ] Add analytics
- [ ] Set up monitoring
- [ ] Test all links work
- [ ] Verify Mermaid diagrams render
- [ ] Verify code syntax highlighting
- [ ] Mobile responsive test
- [ ] SEO metadata check
---
**Estimated Time:** 2-3 hours
**Complexity:** Low
**Priority:** High
---
**Last Updated:** 2025-02-06
**Status:** Ready to Implement