Practice and reinforce the concepts from Lesson 6
By the end of this activity, you will:
Master the art of professional documentation and web deployment. This workshop transforms you from a code writer to a technical communicator, essential for career advancement and open-source contribution.
Scenario: Tech recruiters spend 6-10 seconds reviewing portfolios Solution: Deploy a fast, professional GitHub Pages site Impact: 73% higher callback rate with deployed portfolio sites
# Create portfolio repository with proper structure
mkdir professional-portfolio && cd professional-portfolio
git init
# Create essential directories
mkdir -p assets/{css,js,images} docs/{api,guides} projects
# Initialize with professional .gitignore
echo "# OS Files
.DS_Store
Thumbs.db
# Build artifacts
dist/
build/
*.log
# Environment
.env
.env.local" > .gitignore
git add .
git commit -m "Initial commit: Professional portfolio structure"
Create index.html
with SEO optimization and performance best practices:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{/* SEO Meta Tags */}
<title>John Doe - Full Stack Developer Portfolio</title>
<meta name="description" content="Professional portfolio of John Doe, Full Stack Developer specializing in React, Node.js, and cloud architecture. View projects and technical expertise.">
<meta name="keywords" content="full stack developer, react developer, node.js, portfolio, software engineer">
<meta name="author" content="John Doe">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://YOUR_USERNAME.github.io/">
<meta property="og:title" content="John Doe - Full Stack Developer Portfolio">
<meta property="og:description" content="Professional portfolio showcasing full-stack development projects and technical expertise">
<meta property="og:image" content="https://YOUR_USERNAME.github.io/assets/images/og-image.png">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://YOUR_USERNAME.github.io/">
<meta property="twitter:title" content="John Doe - Full Stack Developer Portfolio">
{/* Performance Optimization */}
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://www.google-analytics.com">
{/* Structured Data for SEO */}
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Person",
"name": "John Doe",
"jobTitle": "Full Stack Developer",
"url": "https://YOUR_USERNAME.github.io",
"sameAs": [
"https://github.com/YOUR_USERNAME",
"https://linkedin.com/in/YOUR_USERNAME"
]
}
</script>
<style>
/* Critical CSS - Inline for performance */
:root {
--primary-color: #2563eb;
--secondary-color: #7c3aed;
--text-primary: #1f2937;
--text-secondary: #6b7280;
--bg-primary: #ffffff;
--bg-secondary: #f9fafb;
--border-color: #e5e7eb;
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
line-height: 1.6;
color: var(--text-primary);
background-color: var(--bg-primary);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Navigation */
nav {
position: fixed;
top: 0;
width: 100%;
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
box-shadow: var(--shadow-sm);
z-index: 1000;
}
nav ul {
display: flex;
list-style: none;
padding: 1rem 0;
gap: 2rem;
}
nav a {
color: var(--text-primary);
text-decoration: none;
font-weight: 500;
transition: color 0.2s;
}
nav a:hover {
color: var(--primary-color);
}
/* Hero Section */
.hero {
padding: 120px 0 80px;
text-align: center;
background: linear-gradient(135deg, var(--bg-secondary) 0%, var(--bg-primary) 100%);
}
.hero h1 {
font-size: 3rem;
font-weight: 800;
margin-bottom: 1rem;
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.hero p {
font-size: 1.25rem;
color: var(--text-secondary);
margin-bottom: 2rem;
}
.cta-buttons {
display: flex;
gap: 1rem;
justify-content: center;
flex-wrap: wrap;
}
.btn {
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
text-decoration: none;
font-weight: 600;
transition: all 0.2s;
display: inline-block;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: #1d4ed8;
transform: translateY(-2px);
box-shadow: var(--shadow-md);
}
.btn-secondary {
border: 2px solid var(--primary-color);
color: var(--primary-color);
}
.btn-secondary:hover {
background: var(--primary-color);
color: white;
}
/* Projects Section */
.projects {
padding: 80px 0;
}
.section-title {
text-align: center;
font-size: 2.5rem;
margin-bottom: 3rem;
color: var(--text-primary);
}
.project-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 2rem;
}
.project-card {
background: var(--bg-primary);
border: 1px solid var(--border-color);
border-radius: 0.75rem;
padding: 1.5rem;
transition: all 0.3s;
cursor: pointer;
}
.project-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
border-color: var(--primary-color);
}
.project-header {
display: flex;
justify-content: space-between;
align-items: start;
margin-bottom: 1rem;
}
.project-title {
font-size: 1.25rem;
font-weight: 700;
color: var(--text-primary);
}
.project-links {
display: flex;
gap: 0.75rem;
}
.project-link {
color: var(--text-secondary);
transition: color 0.2s;
}
.project-link:hover {
color: var(--primary-color);
}
.project-description {
color: var(--text-secondary);
margin-bottom: 1rem;
}
.tech-stack {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tech-tag {
padding: 0.25rem 0.75rem;
background: var(--bg-secondary);
border-radius: 9999px;
font-size: 0.875rem;
color: var(--text-secondary);
}
/* Skills Section */
.skills {
padding: 80px 0;
background: var(--bg-secondary);
}
.skills-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 2rem;
}
.skill-category {
background: var(--bg-primary);
padding: 2rem;
border-radius: 0.75rem;
box-shadow: var(--shadow-sm);
}
.skill-category h3 {
color: var(--primary-color);
margin-bottom: 1rem;
}
.skill-list {
list-style: none;
}
.skill-list li {
padding: 0.5rem 0;
color: var(--text-secondary);
display: flex;
align-items: center;
}
.skill-list li::before {
content: "▸";
color: var(--primary-color);
margin-right: 0.5rem;
}
/* Footer */
footer {
padding: 40px 0;
text-align: center;
border-top: 1px solid var(--border-color);
}
.social-links {
display: flex;
justify-content: center;
gap: 1.5rem;
margin-bottom: 1rem;
}
.social-link {
color: var(--text-secondary);
font-size: 1.5rem;
transition: color 0.2s;
}
.social-link:hover {
color: var(--primary-color);
}
/* Responsive Design */
@media (max-width: 768px) {
.hero h1 {
font-size: 2rem;
}
nav ul {
flex-wrap: wrap;
gap: 1rem;
}
.project-grid {
grid-template-columns: 1fr;
}
}
/* Dark Mode Support */
@media (prefers-color-scheme: dark) {
:root {
--text-primary: #f9fafb;
--text-secondary: #d1d5db;
--bg-primary: #111827;
--bg-secondary: #1f2937;
--border-color: #374151;
}
}
</style>
</head>
<body>
{/* Navigation */}
<nav>
<div class="container">
<ul>
<li><a href="#home">Home</a></li>
<li><a href="#projects">Projects</a></li>
<li><a href="#skills">Skills</a></li>
<li><a href="#contact">Contact</a></li>
<li><a href="/blog">Blog</a></li>
</ul>
</div>
</nav>
{/* Hero Section */}
<section id="home" class="hero">
<div class="container">
<h1>John Doe</h1>
<p>Full Stack Developer | Cloud Architect | Open Source Contributor</p>
<div class="cta-buttons">
<a href="#projects" class="btn btn-primary">View Projects</a>
<a href="https://github.com/YOUR_USERNAME" class="btn btn-secondary">GitHub Profile</a>
</div>
</div>
</section>
{/* Projects Section */}
<section id="projects" class="projects">
<div class="container">
<h2 class="section-title">Featured Projects</h2>
<div class="project-grid">
<article class="project-card">
<div class="project-header">
<h3 class="project-title">E-Commerce Platform</h3>
<div class="project-links">
<a href="https://github.com/YOUR_USERNAME/ecommerce" class="project-link" aria-label="GitHub">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</a>
<a href="https://demo.example.com" class="project-link" aria-label="Live Demo">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
</a>
</div>
</div>
<p class="project-description">
Scalable e-commerce platform built with microservices architecture. Features include real-time inventory management, payment processing, and analytics dashboard.
</p>
<div class="tech-stack">
<span class="tech-tag">React</span>
<span class="tech-tag">Node.js</span>
<span class="tech-tag">PostgreSQL</span>
<span class="tech-tag">Redis</span>
<span class="tech-tag">Docker</span>
</div>
</article>
<article class="project-card">
<div class="project-header">
<h3 class="project-title">DevOps Dashboard</h3>
<div class="project-links">
<a href="https://github.com/YOUR_USERNAME/devops-dashboard" class="project-link" aria-label="GitHub">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</a>
</div>
</div>
<p class="project-description">
Comprehensive monitoring solution for CI/CD pipelines. Real-time metrics, deployment tracking, and automated alerting for DevOps teams.
</p>
<div class="tech-stack">
<span class="tech-tag">Vue.js</span>
<span class="tech-tag">Go</span>
<span class="tech-tag">Prometheus</span>
<span class="tech-tag">Grafana</span>
<span class="tech-tag">Kubernetes</span>
</div>
</article>
<article class="project-card">
<div class="project-header">
<h3 class="project-title">ML Pipeline Framework</h3>
<div class="project-links">
<a href="https://github.com/YOUR_USERNAME/ml-pipeline" class="project-link" aria-label="GitHub">
<svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</a>
</div>
</div>
<p class="project-description">
Open-source framework for building and deploying machine learning pipelines. Supports distributed training and model versioning.
</p>
<div class="tech-stack">
<span class="tech-tag">Python</span>
<span class="tech-tag">TensorFlow</span>
<span class="tech-tag">Apache Airflow</span>
<span class="tech-tag">MLflow</span>
</div>
</article>
</div>
</div>
</section>
{/* Skills Section */}
<section id="skills" class="skills">
<div class="container">
<h2 class="section-title">Technical Skills</h2>
<div class="skills-grid">
<div class="skill-category">
<h3>Frontend</h3>
<ul class="skill-list">
<li>React / Next.js</li>
<li>TypeScript</li>
<li>Tailwind CSS</li>
<li>GraphQL</li>
<li>Webpack / Vite</li>
</ul>
</div>
<div class="skill-category">
<h3>Backend</h3>
<ul class="skill-list">
<li>Node.js / Express</li>
<li>Python / Django</li>
<li>PostgreSQL / MongoDB</li>
<li>Redis / RabbitMQ</li>
<li>REST / GraphQL APIs</li>
</ul>
</div>
<div class="skill-category">
<h3>DevOps & Cloud</h3>
<ul class="skill-list">
<li>AWS / GCP / Azure</li>
<li>Docker / Kubernetes</li>
<li>CI/CD (GitHub Actions)</li>
<li>Terraform / Ansible</li>
<li>Monitoring & Logging</li>
</ul>
</div>
</div>
</div>
</section>
{/* Footer */}
<footer id="contact">
<div class="container">
<div class="social-links">
<a href="https://github.com/YOUR_USERNAME" class="social-link" aria-label="GitHub">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
</svg>
</a>
<a href="https://linkedin.com/in/YOUR_USERNAME" class="social-link" aria-label="LinkedIn">
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
</svg>
</a>
<a href="mailto:john.doe@example.com" class="social-link" aria-label="Email">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path>
<polyline points="22,6 12,13 2,6"></polyline>
</svg>
</a>
</div>
<p>© 2024 John Doe. Built with GitHub Pages.</p>
</div>
</footer>
{/* Analytics */}
<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'GA_MEASUREMENT_ID');
</script>
</body>
</html>
# Commit your portfolio
git add index.html
git commit -m "feat: Add SEO-optimized portfolio with structured data"
git push origin main
# Enable GitHub Pages
# 1. Settings → Pages
# 2. Source: Deploy from branch (main)
# 3. Wait 2-3 minutes for deployment
💡 Pro Tip GitHub Pages supports custom domains. Add a CNAME file with your domain:
bash
echo "portfolio.yourdomain.com" > CNAME
Scenario: 67% of developers abandon poorly documented APIs Solution: Create comprehensive, interactive API documentation Impact: 3x faster integration time with good documentation
Create docs/api-reference.md
following OpenAPI standards:
# User Management API
## API Version: 2.0.0
Base URL: `https://api.yourdomain.com/v2`
## Authentication
All API requests require authentication using Bearer tokens.
```http
Authorization: Bearer YOUR_API_TOKEN
Plan | Requests/Hour | Burst |
---|---|---|
Free | 1,000 | 50/min |
Pro | 10,000 | 500/min |
Enterprise | Unlimited | Custom |
Retrieve a paginated list of users.
Query Parameters:
Parameter | Type | Required | Description |
---|---|---|---|
page | integer | No | Page number (default: 1) |
limit | integer | No | Results per page (default: 20, max: 100) |
sort | string | No | Sort field (created_at, updated_at, name) |
order | string | No | Sort order (asc, desc) |
filter | string | No | JSON filter object |
Example Request:
curl -X GET "https://api.yourdomain.com/v2/users?page=1&limit=10" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-H "Accept: application/json"
Success Response (200 OK):
\{
"data": [
\{
"id": "usr_1234567890",
"email": "john.doe@example.com",
"name": "John Doe",
"role": "developer",
"status": "active",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-20T14:45:00Z",
"metadata": {
"team": "engineering",
"location": "San Francisco"
\}
\}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 156,
"pages": 16
},
"links": {
"self": "https://api.yourdomain.com/v2/users?page=1&limit=10",
"next": "https://api.yourdomain.com/v2/users?page=2&limit=10",
"prev": null
\}
\}
Create a new user.
Request Body:
\{
"email": "jane.smith@example.com",
"name": "Jane Smith",
"password": "SecurePassword123!",
"role": "developer",
"metadata": {
"team": "frontend",
"skills": ["React", "TypeScript", "GraphQL"]
\}
\}
Validation Rules:
Success Response (201 Created):
\{
"data": {
"id": "usr_0987654321",
"email": "jane.smith@example.com",
"name": "Jane Smith",
"role": "developer",
"status": "pending_verification",
"created_at": "2024-01-25T09:15:00Z"
},
"meta": {
"verification_email_sent": true
\}
\}
Retrieve a specific user by ID.
Path Parameters:
Example Request:
curl -X GET "https://api.yourdomain.com/v2/users/usr_1234567890" \
-H "Authorization: Bearer YOUR_API_TOKEN"
Update user information.
Request Body:
\{
"name": "John Updated Doe",
"metadata": {
"team": "backend",
"skills": ["Node.js", "Python", "Go"]
\}
\}
Soft delete a user account.
Success Response (204 No Content)
All errors follow RFC 7807 Problem Details standard:
\{
"type": "https://api.yourdomain.com/errors/validation",
"title": "Validation Failed",
"status": 400,
"detail": "The request body contains invalid fields",
"instance": "/users",
"errors": [
\{
"field": "email",
"message": "Email already exists",
"code": "DUPLICATE_EMAIL"
\}
],
"timestamp": "2024-01-25T10:30:00Z",
"trace_id": "abc123def456"
\}
Code | Description |
---|---|
200 | Success |
201 | Created |
204 | No Content |
400 | Bad Request |
401 | Unauthorized |
403 | Forbidden |
404 | Not Found |
409 | Conflict |
429 | Too Many Requests |
500 | Internal Server Error |
503 | Service Unavailable |
Configure webhooks to receive real-time events:
\{
"event": "user.created",
"data": {
"id": "usr_1234567890",
"email": "john.doe@example.com"
},
"timestamp": "2024-01-25T10:30:00Z",
"signature": "sha256=..."
\}
import { UserAPI } from '@yourdomain/sdk';
const api = new UserAPI({
apiKey: process.env.API_KEY,
baseURL: 'https://api.yourdomain.com/v2'
});
// Get users with error handling
try {
const users = await api.users.list({
page: 1,
limit: 20,
sort: 'created_at',
order: 'desc'
});
console.log(users);
} catch (error) {
if (error.status === 429) {
console.error('Rate limit exceeded');
\}
\}
from yourdomain import UserAPI
from yourdomain.exceptions import RateLimitError
api = UserAPI(api_key=os.environ['API_KEY'])
try:
users = api.users.list(page=1, limit=20)
for user in users:
print(f"{user.name} ({user.email})")
except RateLimitError:
print("Rate limit exceeded, please retry later")
Use our sandbox environment for testing:
https://sandbox-api.yourdomain.com/v2
test_key_XXXXXXXXXXXX
### Task 5: Technical Writing Best Practices
Create `docs/writing-guide.md` for documentation standards:
# Main Topic
## Overview
Brief introduction to the concept.
## Prerequisites
- Required knowledge
- System requirements
## Implementation
### Step 1: Setup
Clear instructions...
### Step 2: Configuration
Detailed steps...
## Troubleshooting
Common issues and solutions.
/**
* Calculates the compound annual growth rate (CAGR)
*
* @param {number} beginningValue - Initial investment value
* @param {number} endingValue - Final investment value
* @param {number} years - Number of years
* @returns {number} CAGR as a percentage
* @throws {Error} If years is zero or negative
*
* @example
* // Calculate CAGR for investment that grew from $1000 to $2000 in 5 years
* const rate = calculateCAGR(1000, 2000, 5);
* console.log(`CAGR: ${rate.toFixed(2)}%`); // CAGR: 14.87%
*/
function calculateCAGR(beginningValue, endingValue, years) {
if (years <= 0) {
throw new Error('Years must be positive');
\}
return (Math.pow(endingValue / beginningValue, 1 / years) - 1) * 100;
\}
/api/v2/users/{id}/preferences:
put:
summary: Update user preferences
description: |
Updates preferences for the specified user. Only the user
themselves or an admin can update preferences.
tags:
- Users
parameters:
- name: id
in: path
required: true
schema:
type: string
description: User ID
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
theme:
type: string
enum: [light, dark, auto]
description: UI theme preference
notifications:
type: object
properties:
email:
type: boolean
push:
type: boolean
language:
type: string
pattern: '^[a-z]{2}-[A-Z]{2}$'
example: en-US
responses:
200:
description: Preferences updated successfully
400:
description: Invalid request body
401:
description: Authentication required
403:
description: Insufficient permissions
Error: Invalid input
Error: Email validation failed
- Email must contain @ symbol
- Domain must be valid (e.g., example.com)
- Special characters not allowed except . and -
Example: user@example.com
# Project Name
One-line description of what this project does.
## Table of Contents
- [Installation](#installation)
- [Quick Start](#quick-start)
- [API Reference](#api-reference)
- [Configuration](#configuration)
- [Contributing](#contributing)
- [License](#license)
## Installation
### Prerequisites
- Node.js 18+ (check with `node --version`)
- PostgreSQL 14+ running locally or remotely
- Redis 6+ for caching (optional)
### Steps
1. Clone the repository:
__CODE_BLOCK_22__`
2. Install dependencies:
```bash
npm install
```
3. Configure environment:
```bash
cp .env.example .env
# Edit .env with your settings
```
4. Initialize database:
```bash
npm run db:migrate
npm run db:seed # Optional: add sample data
```
## Quick Start
```
# Development mode with hot reload
npm run dev
# Production build
npm run build
npm start
# Run tests
npm test
```
Visit [http://localhost:3000](http://localhost:3000) to see the application.
## API Reference
See [API Documentation](/courses/github/docs/api.md) for detailed endpoint information.
### Authentication
All API requests require a Bearer token:
```
curl -H "Authorization: Bearer YOUR_TOKEN" \
https://api.example.com/v1/users
```
## Configuration
| Variable | Description | Default | Required |
| ------------- | ---------------------------- | ------- | -------- |
| DATABASE\_URL | PostgreSQL connection string | - | Yes |
| REDIS\_URL | Redis connection string | - | No |
| JWT\_SECRET | Secret for JWT signing | - | Yes |
| PORT | Server port | 3000 | No |
## Contributing
We welcome contributions! Please see [CONTRIBUTING.md](/courses/github/CONTRIBUTING.md) for details.
### Development Workflow
1. Fork the repository
2. Create your feature branch: `git checkout -b feature/amazing-feature`
3. Commit your changes: `git commit -m 'Add amazing feature'`
4. Push to the branch: `git push origin feature/amazing-feature`
5. Open a Pull Request
## License
This project is licensed under the MIT License - see [LICENSE](/courses/github/LICENSE) for details.
Scenario: 93% of online experiences begin with search engines Solution: Implement comprehensive SEO and analytics Impact: 5x increase in organic documentation traffic
Create seo-optimized-docs.html
with structured data:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Primary Meta Tags -->
<title>API Documentation - YourProject | Complete Developer Guide</title>
<meta name="title" content="API Documentation - YourProject | Complete Developer Guide">
<meta name="description" content="Comprehensive API documentation for YourProject. Learn authentication, endpoints, SDKs, and best practices. Get started in 5 minutes.">
<meta name="keywords" content="API documentation, REST API, developer guide, SDK, authentication, webhooks">
<meta name="robots" content="index, follow">
<meta name="language" content="English">
<meta name="author" content="Your Company">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://docs.yourproject.com/">
<meta property="og:title" content="API Documentation - YourProject">
<meta property="og:description" content="Complete developer guide with code examples, SDKs, and best practices">
<meta property="og:image" content="https://docs.yourproject.com/assets/og-docs.png">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://docs.yourproject.com/">
<meta property="twitter:title" content="API Documentation - YourProject">
<meta property="twitter:description" content="Complete developer guide with code examples, SDKs, and best practices">
<meta property="twitter:image" content="https://docs.yourproject.com/assets/twitter-docs.png">
<!-- Canonical URL -->
<link rel="canonical" href="https://docs.yourproject.com/">
<!-- Structured Data for Documentation -->
<script type="application/ld+json">
\{
"@context": "https://schema.org",
"@type": "TechArticle",
"headline": "YourProject API Documentation",
"description": "Complete guide to using YourProject API",
"author": {
"@type": "Organization",
"name": "Your Company",
"url": "https://yourcompany.com"
},
"datePublished": "2024-01-01",
"dateModified": "2024-01-25",
"publisher": {
"@type": "Organization",
"name": "Your Company",
"logo": {
"@type": "ImageObject",
"url": "https://yourcompany.com/logo.png"
\}
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://docs.yourproject.com/"
},
"inLanguage": "en-US"
\}
</script>
{/* API Documentation Schema */}
<script type="application/ld+json">
\{
"@context": "https://schema.org",
"@type": "APIReference",
"name": "YourProject API",
"description": "RESTful API for YourProject services",
"url": "https://api.yourproject.com",
"documentation": "https://docs.yourproject.com",
"termsOfService": "https://yourproject.com/terms",
"provider": {
"@type": "Organization",
"name": "Your Company"
\}
\}
</script>
{/* Sitemap */}
<link rel="sitemap" type="application/xml" href="/sitemap.xml">
{/* RSS Feed for Changelog */}
<link rel="alternate" type="application/rss+xml" title="API Changelog" href="/changelog.xml">
<style>
/* Critical CSS for above-the-fold content */
body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
.hero { padding: 80px 20px; text-align: center; background: #f8f9fa; }
.search-box { max-width: 600px; margin: 0 auto; }
</style>
</head>
<body>
{/* Implement search with Algolia DocSearch or similar */}
<div class="search-box">
<input type="search" placeholder="Search documentation..." aria-label="Search">
</div>
{/* Analytics with privacy-first approach */}
<script>
// Google Analytics 4 with consent management
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Check for user consent
if (localStorage.getItem('analytics-consent') === 'true') {
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX', {
'anonymize_ip': true,
'link_attribution': true
});
\}
</script>
</body>
</html>
Add these records to your domain provider:
Type Name Value TTL
A @ 185.199.108.153 300
A @ 185.199.109.153 300
A @ 185.199.110.153 300
A @ 185.199.111.153 300
CNAME www YOUR_USERNAME.github.io 300
# Add CNAME file to repository
echo "docs.yourdomain.com" > CNAME
# Commit and push
git add CNAME
git commit -m "Add custom domain"
git push origin main
# In GitHub Settings → Pages:
# 1. Enter custom domain
# 2. Wait for DNS check (up to 24 hours)
# 3. Enable "Enforce HTTPS"
💡 Pro Tip Use Cloudflare for free SSL, DDoS protection, and CDN:
- Add your domain to Cloudflare
- Update nameservers at registrar
- Set SSL/TLS to "Full"
- Enable "Always Use HTTPS"
Create scripts/generate-docs.js
for automated API documentation:
/**
* Automated Documentation Generator
* Generates API docs from OpenAPI spec and JSDoc comments
*/
const fs = require('fs').promises;
const path = require('path');
const SwaggerParser = require('@apidevtools/swagger-parser');
const jsdoc2md = require('jsdoc-to-markdown');
class DocumentationGenerator {
constructor(config) {
this.config = {
openApiSpec: './openapi.yaml',
sourceDir: './src',
outputDir: './docs',
templateDir: './docs/templates',
...config
};
\}
async generate() {
console.log('📚 Starting documentation generation...');
try {
// Parse OpenAPI specification
const apiSpec = await this.parseOpenAPISpec();
// Generate API documentation
await this.generateAPIDocumentation(apiSpec);
// Generate code documentation from JSDoc
await this.generateCodeDocumentation();
// Generate SDK examples
await this.generateSDKExamples(apiSpec);
// Create search index
await this.createSearchIndex();
// Generate sitemap
await this.generateSitemap();
console.log('✅ Documentation generated successfully!');
} catch (error) {
console.error('❌ Documentation generation failed:', error);
process.exit(1);
\}
\}
async parseOpenAPISpec() {
const api = await SwaggerParser.validate(this.config.openApiSpec);
console.log(`API: ${api.info.title} v${api.info.version}`);
return api;
\}
async generateAPIDocumentation(spec) {
const endpoints = [];
// Extract all endpoints
for (const [path, pathItem] of Object.entries(spec.paths)) {
for (const [method, operation] of Object.entries(pathItem)) {
if (['get', 'post', 'put', 'delete', 'patch'].includes(method)) {
endpoints.push({
path,
method: method.toUpperCase(),
...operation
});
\}
\}
\}
// Generate markdown for each endpoint
const markdown = this.generateEndpointMarkdown(endpoints, spec);
await fs.writeFile(
path.join(this.config.outputDir, 'api-reference.md'),
markdown
);
\}
generateEndpointMarkdown(endpoints, spec) {
let markdown = `# ${spec.info.title}\n\n`;
markdown += `Version: ${spec.info.version}\n\n`;
markdown += `${spec.info.description}\n\n`;
// Group endpoints by tags
const grouped = this.groupByTags(endpoints);
for (const [tag, tagEndpoints] of Object.entries(grouped)) {
markdown += `## ${tag}\n\n`;
for (const endpoint of tagEndpoints) {
markdown += this.formatEndpoint(endpoint, spec);
\}
\}
return markdown;
\}
formatEndpoint(endpoint, spec) {
let md = `### ${endpoint.method} ${endpoint.path}\n\n`;
md += `${endpoint.summary}\n\n`;
if (endpoint.description) {
md += `${endpoint.description}\n\n`;
\}
// Parameters
if (endpoint.parameters && endpoint.parameters.length > 0) {
md += '**Parameters:**\n\n';
md += '| Name | In | Type | Required | Description |\n';
md += '|------|-----|------|----------|-------------|\n';
for (const param of endpoint.parameters) {
const required = param.required ? 'Yes' : 'No';
md += `| ${param.name} | ${param.in} | ${param.schema?.type || 'string'} | ${required} | ${param.description || ''} |\n`;
\}
md += '\n';
\}
// Request body
if (endpoint.requestBody) {
md += '**Request Body:**\n\n';
const content = endpoint.requestBody.content['application/json'];
if (content && content.example) {
md += '\`\`\`json\n';
md += JSON.stringify(content.example, null, 2);
md += '\n\`\`\`\n\n';
\}
\}
// Responses
md += '**Responses:**\n\n';
for (const [code, response] of Object.entries(endpoint.responses)) {
md += `- \`${code}\`: ${response.description}\n`;
\}
md += '\n';
// Example
md += this.generateExample(endpoint, spec);
md += '\n---\n\n';
return md;
\}
generateExample(endpoint, spec) {
const baseUrl = spec.servers[0]?.url || 'https://api.example.com';
let example = '**Example:**\n\n\`\`\`bash\n';
example += `curl -X ${endpoint.method} "${baseUrl}${endpoint.path}"`;
if (endpoint.security) {
example += ' \\\n -H "Authorization: Bearer YOUR_TOKEN"';
}
if (endpoint.requestBody) {
example += ' \\\n -H "Content-Type: application/json"';
example += ' \\\n -d \'{"example": "data"}\'';
}
example += '\n\`\`\`\n';
return example;
\}
async generateCodeDocumentation() {
const jsDocConfig = {
files: `${this.config.sourceDir}/**/*.js`,
configure: './jsdoc.json'
};
const markdown = await jsdoc2md.render(jsDocConfig);
await fs.writeFile(
path.join(this.config.outputDir, 'code-reference.md'),
markdown
);
\}
async generateSDKExamples(spec) {
const examples = {
javascript: this.generateJavaScriptExample(spec),
python: this.generatePythonExample(spec),
curl: this.generateCurlExample(spec)
};
for (const [lang, code] of Object.entries(examples)) {
await fs.writeFile(
path.join(this.config.outputDir, `examples/${lang}.md`),
code
);
\}
\}
generateJavaScriptExample(spec) {
return `# JavaScript SDK Example
\`\`\`javascript
import { ApiClient } from '@yourcompany/sdk';
// Initialize the client
const client = new ApiClient({
apiKey: process.env.API_KEY,
baseURL: '${spec.servers[0]?.url}'
});
// Example: List users
async function listUsers() {
try {
const response = await client.users.list({
page: 1,
limit: 20
});
console.log('Users:', response.data);
console.log('Total:', response.pagination.total);
} catch (error) {
console.error('Error:', error.message);
\}
\}
// Example: Create user with error handling
async function createUser(userData) {
try {
const user = await client.users.create(userData);
console.log('Created user:', user);
} catch (error) {
if (error.response?.status === 400) {
console.error('Validation errors:', error.response.data.errors);
} else {
console.error('Unexpected error:', error);
\}
\}
\}
\`\`\``;
}
generatePythonExample(spec) {
return `# Python SDK Example
\`\`\`python
from yourcompany import ApiClient
from yourcompany.exceptions import ValidationError, RateLimitError
import os
# Initialize the client
client = ApiClient(
api_key=os.environ['API_KEY'],
base_url='${spec.servers[0]?.url}'
)
# Example: List users
def list_users():
try:
response = client.users.list(page=1, limit=20)
for user in response.data:
print(f"{user.name} - {user.email}")
print(f"Total users: {response.pagination.total}")
except RateLimitError:
print("Rate limit exceeded. Please try again later.")
except Exception as e:
print(f"Error: {e}")
# Example: Async operations
import asyncio
async def async_operations():
async with client.async_session() as session:
# Fetch multiple resources concurrently
users, projects = await asyncio.gather(
session.users.list(),
session.projects.list()
)
print(f"Found {len(users.data)} users and {len(projects.data)} projects")
\`\`\``;
}
generateCurlExample(spec) {
return `# cURL Examples
## Authentication
\`\`\`bash
# Set your API key
export API_KEY="your_api_key_here"
\`\`\`
## List Users
\`\`\`bash
curl -X GET "${spec.servers[0]?.url}/users" \\
-H "Authorization: Bearer $API_KEY" \\
-H "Accept: application/json"
\`\`\`
## Create User
\`\`\`bash
curl -X POST "${spec.servers[0]?.url}/users" \\
-H "Authorization: Bearer $API_KEY" \\
-H "Content-Type: application/json" \\
-d '{
"email": "user@example.com",
"name": "New User",
"role": "developer"
}'
\`\`\`
## Error Handling
\`\`\`bash
# Save response with headers
curl -i -X GET "${spec.servers[0]?.url}/users/invalid" \\
-H "Authorization: Bearer $API_KEY" \\
-o response.txt
# Check status code
curl -w "%{http_code}" -X GET "${spec.servers[0]?.url}/users" \\
-H "Authorization: Bearer $API_KEY" \\
-o /dev/null -s
\`\`\``;
}
async createSearchIndex() {
// Create search index for documentation
const searchData = {
version: '1.0.0',
fields: ['title', 'text', 'tags'],
documents: []
};
// Add your search indexing logic here
await fs.writeFile(
path.join(this.config.outputDir, 'search-index.json'),
JSON.stringify(searchData, null, 2)
);
}
async generateSitemap() {
const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://docs.yourproject.com/</loc>
<lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
<priority>1.0</priority>
</url>
<url>
<loc>https://docs.yourproject.com/api-reference</loc>
<lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
<priority>0.9</priority>
</url>
<url>
<loc>https://docs.yourproject.com/guides</loc>
<lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
<priority>0.8</priority>
</url>
</urlset>`;
await fs.writeFile(
path.join(this.config.outputDir, 'sitemap.xml'),
sitemap
);
}
groupByTags(endpoints) {
const grouped = {};
for (const endpoint of endpoints) {
const tag = endpoint.tags?.[0] || 'General';
if (!grouped[tag]) {
grouped[tag] = [];
}
grouped[tag].push(endpoint);
}
return grouped;
}
}
// Run the generator
if (require.main === module) {
const generator = new DocumentationGenerator();
generator.generate();
}
module.exports = DocumentationGenerator;
__CODE_BLOCK_32__
name: Generate Documentation
on:
push:
branches: [main]
paths:
- 'src/**'
- 'openapi.yaml'
- 'docs/**'
workflow_dispatch:
jobs:
generate-docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Generate documentation
run: npm run docs:generate
- name: Build documentation site
run: npm run docs:build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/_site
cname: docs.yourproject.com
__CODE_BLOCK_33__
portfolio-checklist:
seo:
- Meta tags with keywords
- Open Graph preview images
- Structured data (JSON-LD)
- Sitemap.xml
- Robots.txt
performance:
- PageSpeed score > 90
- Lazy loading images
- Critical CSS inline
- Preconnect to external domains
accessibility:
- WCAG 2.1 AA compliant
- Semantic HTML
- ARIA labels
- Keyboard navigation
analytics:
- Google Analytics 4
- Hotjar heatmaps
- Custom event tracking
__CODE_BLOCK_34__
docs/
├── README.md # Project overview
├── CONTRIBUTING.md # Contribution guidelines
├── CODE_OF_CONDUCT.md # Community standards
├── SECURITY.md # Security policies
├── API.md # API reference
├── CHANGELOG.md # Version history
├── guides/
│ ├── quick-start.md # 5-minute tutorial
│ ├── installation.md # Setup instructions
│ ├── configuration.md # Config options
│ └── troubleshooting.md # Common issues
├── tutorials/
│ ├── basic-usage.md # Beginner tutorial
│ ├── advanced-features.md # Advanced guide
│ └── best-practices.md # Pro tips
└── reference/
├── cli.md # CLI commands
├── config.md # Config reference
└── api/ # API endpoints
__CODE_BLOCK_35__
# Check Jekyll build locally
bundle exec jekyll build --verbose
# Common fixes:
# 1. Remove unsupported plugins
# 2. Check for syntax errors in _config.yml
# 3. Ensure all includes exist
# 4. Verify Gemfile dependencies
__CODE_BLOCK_36__
# Verify DNS propagation
dig yourdomain.com
nslookup yourdomain.com
# Check CNAME file
cat CNAME # Should contain: yourdomain.com
# Wait 24-48 hours for full propagation
__CODE_BLOCK_37__
# Test with Google tools
# 1. PageSpeed Insights
# 2. Mobile-Friendly Test
# 3. Rich Results Test
# 4. Search Console
# Common improvements:
# - Add schema markup
# - Optimize images
# - Improve Core Web Vitals
# - Create quality content
__CODE_BLOCK_38__
// Performance metrics to achieve
const requirements = {
lighthouse: {
performance: 95,
accessibility: 100,
bestPractices: 100,
seo: 100
},
analytics: {
bounceRate: '< 40%',
avgTimeOnPage: '> 3 minutes',
searchUsage: '> 60%'
},
deployment: {
ci: 'GitHub Actions',
hosting: 'GitHub Pages + Cloudflare',
monitoring: 'Sentry + Google Analytics'
}
};
Your documentation will be evaluated on:
Before submitting your work, ensure you have:
https://YOUR_USERNAME.github.io
Ready to submit? Your professional documentation portfolio demonstrates real-world skills that employers value. This is your digital business card - make it count!
Remember: Documentation is your opportunity to showcase not just what you built, but how well you can communicate complex ideas. Quality documentation is a superpower in the tech industry!