2:I[7012,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],"MarkdownRenderer"]
4:I[9856,["4765","static/chunks/4765-f5afdf8061f456f3.js","9856","static/chunks/9856-3b185291364d9bef.js","6687","static/chunks/app/docs/%5B...slug%5D/page-e07536548216bee4.js"],""]
5:I[4126,[],""]
7:I[9630,[],""]
8:I[4278,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"HeadingProvider"]
9:I[1476,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Header"]
a:I[3167,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"Sidebar"]
b:I[7409,["9856","static/chunks/9856-3b185291364d9bef.js","8172","static/chunks/8172-b3a2d6fe4ae10d40.js","3185","static/chunks/app/layout-2814fa5d15b84fe4.js"],"PageFrame"]
3:T2478,
# Docs Site Deployment and TLS Runbook
**Last Updated:** 2025-11-27
**URL:** https://assistdocs.asimo.io
**Document Root:** `/var/www/assistdocs.asimo.io`
---
## Quick Deployment Checklist
```bash
# 1. Navigate to repo
cd ~/VoiceAssist
# 2. Pull latest changes
git pull origin main
# 3. Install dependencies (if needed)
pnpm install
# 4. Navigate to docs-site
cd apps/docs-site
# 5. Validate metadata and links
pnpm validate:metadata
pnpm check:links
# 6. Generate agent JSON (if docs changed)
pnpm generate-agent-json
# 7. Build the static site
pnpm build
# 8. Deploy to Apache document root
sudo rm -rf /var/www/assistdocs.asimo.io/*
sudo cp -r out/* /var/www/assistdocs.asimo.io/
# 9. Verify deployment
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/agent/index.json
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/agent/docs.json
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/search-index.json
```
---
## Architecture Overview
### Build Process
```
docs/*.md → Next.js static export
apps/docs-site/ → Build artifacts in out/
scripts/generate-agent-json → public/agent/*.json
→ search-index.json
```
### Deployment Architecture
```
┌──────────────────────────────────────────────────┐
│ Apache2 (mod_ssl, mod_rewrite) │
│ - assistdocs.asimo.io-le-ssl.conf │
│ - DocumentRoot: /var/www/assistdocs.asimo.io │
│ - RewriteEngine for clean URLs │
└──────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ Static Files │
│ - /*.html (Next.js pages) │
│ - /agent/*.json (AI agent endpoints) │
│ - /search-index.json (Fuse.js) │
│ - /sitemap.xml │
└──────────────────────────────────────────────────┘
```
---
## Step 1: Prepare for Deployment
### 1.1 Sync Repository
```bash
cd ~/VoiceAssist
git pull origin main
git status # Verify clean state
```
### 1.2 Install Dependencies
```bash
# Root level (pnpm workspace)
pnpm install
# Verify docs-site dependencies
cd apps/docs-site
ls node_modules/.bin/next # Should exist
```
---
## Step 2: Validate Documentation
### 2.1 Metadata Validation
```bash
cd ~/VoiceAssist/apps/docs-site
pnpm validate:metadata
```
**Expected Output:** No errors about missing or invalid frontmatter.
### 2.2 Link Validation
```bash
pnpm check:links
```
**Expected Output:** All internal links resolve correctly.
### 2.3 Fix Common Issues
**Missing frontmatter:**
```yaml
---
title: "Document Title"
slug: "path/to-document"
summary: "Brief description"
status: stable
stability: production
owner: team
lastUpdated: "YYYY-MM-DD"
audience: ["human", "agent"]
tags: ["tag1", "tag2"]
category: category-name
---
```
**Broken links:** Update markdown links to use relative paths from docs/ directory.
---
## Step 3: Generate Agent JSON
The agent JSON files provide machine-readable access to documentation.
### 3.1 Run Generation Script
```bash
cd ~/VoiceAssist/apps/docs-site
pnpm generate-agent-json
```
### 3.2 Verify Output
```bash
# Check index.json
cat public/agent/index.json | jq '.name'
# Should output: "VoiceAssist Documentation"
# Check docs.json count
cat public/agent/docs.json | jq 'length'
# Should output document count (e.g., 220+)
# Check search index
ls -la public/search-index.json
```
---
## Step 4: Build Static Site
### 4.1 Run Build
```bash
cd ~/VoiceAssist/apps/docs-site
pnpm build
```
**Expected Output:**
- `✓ Compiled successfully`
- `Export successful`
- Files in `out/` directory
### 4.2 Verify Build Output
```bash
ls out/
# Should contain: index.html, ai/, docs/, agent/, search-index.json, sitemap.xml
ls out/agent/
# Should contain: index.json, docs.json, schema.json
```
---
## Step 5: Deploy to Apache
### 5.1 Clear Old Files
```bash
sudo rm -rf /var/www/assistdocs.asimo.io/*
```
### 5.2 Copy New Build
```bash
sudo cp -r ~/VoiceAssist/apps/docs-site/out/* /var/www/assistdocs.asimo.io/
```
### 5.3 Set Permissions
```bash
sudo chown -R www-data:www-data /var/www/assistdocs.asimo.io
sudo chmod -R 755 /var/www/assistdocs.asimo.io
```
### 5.4 Reload Apache (if config changed)
```bash
sudo apache2ctl configtest
sudo systemctl reload apache2
```
---
## Step 6: Verify Deployment
### 6.1 Check HTTP Status
```bash
# Main page
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/
# AI agent endpoints
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/agent/index.json
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/agent/docs.json
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/search-index.json
# Clean URLs (should return 200, not 404)
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/ai/onboarding
curl -s -o /dev/null -w "%{http_code}" https://assistdocs.asimo.io/ai/status
```
**Expected:** All should return `200`.
### 6.2 Check Content
```bash
# Verify agent JSON content
curl -s https://assistdocs.asimo.io/agent/index.json | jq '.endpoints'
# Verify sitemap
curl -s https://assistdocs.asimo.io/sitemap.xml | head -20
```
---
## TLS Certificate Management
### Current Certificate Status
```bash
sudo certbot certificates | grep -A 5 "assistdocs.asimo.io"
```
**Current Certificate:**
- **Domain:** assistdocs.asimo.io
- **Issuer:** Let's Encrypt
- **Key Type:** ECDSA
- **Certificate Path:** `/etc/letsencrypt/live/assistdocs.asimo.io/fullchain.pem`
- **Private Key Path:** `/etc/letsencrypt/live/assistdocs.asimo.io/privkey.pem`
- **Expiry:** 2026-02-19 (auto-renewed)
### Automatic Renewal
Certbot automatically renews certificates via systemd timer.
```bash
# Check timer status
sudo systemctl status certbot.timer
# View renewal schedule
sudo systemctl list-timers | grep certbot
# Test renewal (dry run)
sudo certbot renew --dry-run
```
### Manual Renewal (if needed)
```bash
# Renew specific certificate
sudo certbot renew --cert-name assistdocs.asimo.io
# Force renewal
sudo certbot renew --cert-name assistdocs.asimo.io --force-renewal
# Reload Apache after renewal
sudo systemctl reload apache2
```
### New Certificate (if domain changes)
```bash
sudo certbot --apache -d assistdocs.asimo.io
```
---
## Apache Configuration
### Configuration File
**Location:** `/etc/apache2/sites-available/assistdocs.asimo.io-le-ssl.conf`
### Key Configuration
```apache
ServerName assistdocs.asimo.io
DocumentRoot /var/www/assistdocs.asimo.io
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
DirectoryIndex index.html
# Clean URLs for Next.js static export
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.html -f
RewriteRule ^(.*)$ $1.html [L]
# SSL (managed by Certbot)
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/assistdocs.asimo.io/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/assistdocs.asimo.io/privkey.pem
```
### Test Configuration
```bash
sudo apache2ctl configtest
```
### Reload After Changes
```bash
sudo systemctl reload apache2
```
---
## Troubleshooting
### 404 for Clean URLs
**Symptom:** `/ai/onboarding` returns 404 but `/ai/onboarding.html` works.
**Cause:** RewriteEngine rules not applied.
**Fix:**
1. Ensure `mod_rewrite` is enabled: `sudo a2enmod rewrite`
2. Verify rules are inside `` block
3. Reload Apache: `sudo systemctl reload apache2`
### Build Fails
**Symptom:** `pnpm build` fails with errors.
**Checks:**
```bash
# Check for TypeScript errors
pnpm tsc --noEmit
# Check for missing dependencies
pnpm install
# Clear cache
rm -rf .next out
pnpm build
```
### Agent JSON Not Updated
**Symptom:** `/agent/docs.json` shows old documents.
**Fix:**
```bash
# Regenerate agent JSON
pnpm generate-agent-json
# Rebuild and redeploy
pnpm build
sudo cp -r out/* /var/www/assistdocs.asimo.io/
```
### TLS Certificate Expired
**Symptom:** Browser shows certificate error.
**Fix:**
```bash
# Check certificate status
sudo certbot certificates
# Force renewal
sudo certbot renew --cert-name assistdocs.asimo.io --force-renewal
# Reload Apache
sudo systemctl reload apache2
```
---
## Related Documentation
- [Debugging Docs Site](../../debugging/DEBUGGING_DOCS_SITE.md)
- [Implementation Status](../../overview/IMPLEMENTATION_STATUS.md)
- [Internal Docs System](../../INTERNAL_DOCS_SYSTEM.md)
6:["slug","operations/runbooks/DOCS_SITE_DEPLOYMENT_AND_TLS","c"]
0:["X7oMT3VrOffzp0qvbeOas",[[["",{"children":["docs",{"children":[["slug","operations/runbooks/DOCS_SITE_DEPLOYMENT_AND_TLS","c"],{"children":["__PAGE__?{\"slug\":[\"operations\",\"runbooks\",\"DOCS_SITE_DEPLOYMENT_AND_TLS\"]}",{}]}]}]},"$undefined","$undefined",true],["",{"children":["docs",{"children":[["slug","operations/runbooks/DOCS_SITE_DEPLOYMENT_AND_TLS","c"],{"children":["__PAGE__",{},[["$L1",["$","div",null,{"children":[["$","div",null,{"className":"mb-6 flex items-center justify-between gap-4","children":[["$","div",null,{"children":[["$","p",null,{"className":"text-sm text-gray-500 dark:text-gray-400","children":"Docs / Raw"}],["$","h1",null,{"className":"text-3xl font-bold text-gray-900 dark:text-white","children":"Docs Site Deployment and TLS Runbook"}],["$","p",null,{"className":"text-sm text-gray-600 dark:text-gray-400","children":["Sourced from"," ",["$","code",null,{"className":"font-mono text-xs","children":["docs/","operations/runbooks/DOCS_SITE_DEPLOYMENT_AND_TLS.md"]}]]}]]}],["$","a",null,{"href":"https://github.com/mohammednazmy/VoiceAssist/edit/main/docs/operations/runbooks/DOCS_SITE_DEPLOYMENT_AND_TLS.md","target":"_blank","rel":"noreferrer","className":"inline-flex items-center gap-2 rounded-md border border-gray-200 dark:border-gray-700 px-3 py-1.5 text-sm text-gray-700 dark:text-gray-200 hover:border-primary-500 dark:hover:border-primary-400 hover:text-primary-700 dark:hover:text-primary-300","children":"Edit on GitHub"}]]}],["$","div",null,{"className":"rounded-lg border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 p-6","children":["$","$L2",null,{"content":"$3"}]}],["$","div",null,{"className":"mt-6 flex flex-wrap gap-2 text-sm","children":[["$","$L4",null,{"href":"/reference/all-docs","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"← All documentation"}],["$","$L4",null,{"href":"/","className":"inline-flex items-center gap-1 rounded-md bg-gray-100 px-3 py-1 text-gray-700 hover:bg-gray-200 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-700","children":"Home"}]]}]]}],null],null],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children","$6","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[null,["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children","docs","children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":"$undefined","notFoundStyles":"$undefined"}]],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/7f586cdbbaa33ff7.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","className":"h-full","children":["$","body",null,{"className":"__className_f367f3 h-full bg-white dark:bg-gray-900","children":[["$","a",null,{"href":"#main-content","className":"skip-to-content","children":"Skip to main content"}],["$","$L8",null,{"children":[["$","$L9",null,{}],["$","$La",null,{}],["$","main",null,{"id":"main-content","className":"lg:pl-64","role":"main","aria-label":"Documentation content","children":["$","$Lb",null,{"children":["$","$L5",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L7",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]]}]]}]}]],null],null],["$Lc",null]]]]
c:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Docs Site Deployment and TLS Runbook | Docs | VoiceAssist Docs"}],["$","meta","3",{"name":"description","content":"Step-by-step guide for building, deploying, and managing TLS for assistdocs.asimo.io."}],["$","meta","4",{"name":"keywords","content":"VoiceAssist,documentation,medical AI,voice assistant,healthcare,HIPAA,API"}],["$","meta","5",{"name":"robots","content":"index, follow"}],["$","meta","6",{"name":"googlebot","content":"index, follow"}],["$","link","7",{"rel":"canonical","href":"https://assistdocs.asimo.io"}],["$","meta","8",{"property":"og:title","content":"VoiceAssist Documentation"}],["$","meta","9",{"property":"og:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","10",{"property":"og:url","content":"https://assistdocs.asimo.io"}],["$","meta","11",{"property":"og:site_name","content":"VoiceAssist Docs"}],["$","meta","12",{"property":"og:type","content":"website"}],["$","meta","13",{"name":"twitter:card","content":"summary"}],["$","meta","14",{"name":"twitter:title","content":"VoiceAssist Documentation"}],["$","meta","15",{"name":"twitter:description","content":"Comprehensive documentation for VoiceAssist - Enterprise Medical AI Assistant"}],["$","meta","16",{"name":"next-size-adjust"}]]
1:null