docs: add comprehensive CMS documentation
Add complete documentation for the Content Management System: Feature Documentation (docs/features/): - content-management-system.md - Complete CMS overview * Two-tier architecture explanation * Database schema and relationships * API reference for all endpoints * Usage workflows for admin/vendor/customer * Best practices and examples - cms-implementation-guide.md - Step-by-step implementation * Activation checklist * Code integration instructions * Testing procedures * Troubleshooting guide Quick Start Guide (docs/getting-started/): - cms-quick-start.md - Quick reference * Setup commands * Access URLs * Managing content (API, admin panel, vendor dashboard) * Two-tier system explained with examples * Common tasks and troubleshooting Updated Seeder Docs: - Add CMS to enhanced seeder coverage list - Add dedicated CMS section with table of pages - Document integration with db-setup workflow - Update best practices MkDocs Configuration: - Add "Features" section with CMS documentation - Add CMS Quick Start to "Getting Started" - Add CDN Fallback Strategy to "Frontend Development" - Complete navigation structure All documentation builds cleanly with no warnings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
562
docs/features/content-management-system.md
Normal file
562
docs/features/content-management-system.md
Normal file
@@ -0,0 +1,562 @@
|
||||
# Content Management System (CMS)
|
||||
|
||||
## Overview
|
||||
|
||||
The Content Management System allows platform administrators and vendors to manage static content pages like About, FAQ, Contact, Shipping, Returns, Privacy Policy, Terms of Service, etc.
|
||||
|
||||
**Key Features:**
|
||||
- ✅ Platform-level default content
|
||||
- ✅ Vendor-specific overrides
|
||||
- ✅ Fallback system (vendor → platform default)
|
||||
- ✅ Rich text content (HTML/Markdown)
|
||||
- ✅ SEO metadata
|
||||
- ✅ Published/Draft status
|
||||
- ✅ Navigation management (footer/header)
|
||||
- ✅ Display order control
|
||||
|
||||
## Architecture
|
||||
|
||||
### Two-Tier Content System
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ CONTENT LOOKUP FLOW │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
|
||||
Request: /about
|
||||
|
||||
1. Check for vendor-specific override
|
||||
↓
|
||||
SELECT * FROM content_pages
|
||||
WHERE vendor_id = 123 AND slug = 'about' AND is_published = true
|
||||
↓
|
||||
Found? ✅ Return vendor content
|
||||
❌ Continue to step 2
|
||||
|
||||
2. Check for platform default
|
||||
↓
|
||||
SELECT * FROM content_pages
|
||||
WHERE vendor_id IS NULL AND slug = 'about' AND is_published = true
|
||||
↓
|
||||
Found? ✅ Return platform content
|
||||
❌ Return 404 or default template
|
||||
```
|
||||
|
||||
### Database Schema
|
||||
|
||||
```sql
|
||||
CREATE TABLE content_pages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
|
||||
-- Vendor association (NULL = platform default)
|
||||
vendor_id INTEGER REFERENCES vendors(id) ON DELETE CASCADE,
|
||||
|
||||
-- Page identification
|
||||
slug VARCHAR(100) NOT NULL, -- about, faq, contact, shipping, returns
|
||||
title VARCHAR(200) NOT NULL,
|
||||
|
||||
-- Content
|
||||
content TEXT NOT NULL, -- HTML or Markdown
|
||||
content_format VARCHAR(20) DEFAULT 'html', -- html, markdown
|
||||
|
||||
-- SEO
|
||||
meta_description VARCHAR(300),
|
||||
meta_keywords VARCHAR(300),
|
||||
|
||||
-- Publishing
|
||||
is_published BOOLEAN DEFAULT FALSE NOT NULL,
|
||||
published_at TIMESTAMP WITH TIME ZONE,
|
||||
|
||||
-- Navigation
|
||||
display_order INTEGER DEFAULT 0,
|
||||
show_in_footer BOOLEAN DEFAULT TRUE,
|
||||
show_in_header BOOLEAN DEFAULT FALSE,
|
||||
|
||||
-- Timestamps
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
|
||||
|
||||
-- Author tracking
|
||||
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
updated_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
|
||||
-- Constraints
|
||||
CONSTRAINT uq_vendor_slug UNIQUE (vendor_id, slug)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_vendor_published ON content_pages (vendor_id, is_published);
|
||||
CREATE INDEX idx_slug_published ON content_pages (slug, is_published);
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Platform Administrator Workflow
|
||||
|
||||
**1. Create Platform Default Pages**
|
||||
|
||||
Platform admins create default content that all vendors inherit:
|
||||
|
||||
```bash
|
||||
POST /api/v1/admin/content-pages/platform
|
||||
{
|
||||
"slug": "about",
|
||||
"title": "About Us",
|
||||
"content": "<h1>About Us</h1><p>We are a marketplace...</p>",
|
||||
"content_format": "html",
|
||||
"meta_description": "Learn more about our marketplace",
|
||||
"is_published": true,
|
||||
"show_in_footer": true,
|
||||
"display_order": 1
|
||||
}
|
||||
```
|
||||
|
||||
**Common Platform Defaults:**
|
||||
- `about` - About Us
|
||||
- `contact` - Contact Us
|
||||
- `faq` - Frequently Asked Questions
|
||||
- `shipping` - Shipping Information
|
||||
- `returns` - Return Policy
|
||||
- `privacy` - Privacy Policy
|
||||
- `terms` - Terms of Service
|
||||
- `help` - Help Center
|
||||
|
||||
**2. View All Content Pages**
|
||||
|
||||
```bash
|
||||
GET /api/v1/admin/content-pages/
|
||||
GET /api/v1/admin/content-pages/?vendor_id=123 # Filter by vendor
|
||||
GET /api/v1/admin/content-pages/platform # Only platform defaults
|
||||
```
|
||||
|
||||
**3. Update Platform Default**
|
||||
|
||||
```bash
|
||||
PUT /api/v1/admin/content-pages/1
|
||||
{
|
||||
"title": "Updated About Us",
|
||||
"content": "<h1>About Our Platform</h1>...",
|
||||
"is_published": true
|
||||
}
|
||||
```
|
||||
|
||||
### Vendor Workflow
|
||||
|
||||
**1. View Available Pages**
|
||||
|
||||
Vendors see their overrides + platform defaults:
|
||||
|
||||
```bash
|
||||
GET /api/v1/vendor/{code}/content-pages/
|
||||
```
|
||||
|
||||
Response:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 15,
|
||||
"slug": "about",
|
||||
"title": "About Wizamart", // Vendor override
|
||||
"is_vendor_override": true,
|
||||
"is_platform_default": false
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"slug": "shipping",
|
||||
"title": "Shipping Information", // Platform default
|
||||
"is_vendor_override": false,
|
||||
"is_platform_default": true
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**2. Create Vendor Override**
|
||||
|
||||
Vendor creates custom "About" page:
|
||||
|
||||
```bash
|
||||
POST /api/v1/vendor/{code}/content-pages/
|
||||
{
|
||||
"slug": "about",
|
||||
"title": "About Wizamart",
|
||||
"content": "<h1>About Wizamart</h1><p>We specialize in...</p>",
|
||||
"is_published": true
|
||||
}
|
||||
```
|
||||
|
||||
This overrides the platform default for this vendor only.
|
||||
|
||||
**3. View Only Vendor Overrides**
|
||||
|
||||
```bash
|
||||
GET /api/v1/vendor/{code}/content-pages/overrides
|
||||
```
|
||||
|
||||
Shows what the vendor has customized (excludes platform defaults).
|
||||
|
||||
**4. Delete Override (Revert to Platform Default)**
|
||||
|
||||
```bash
|
||||
DELETE /api/v1/vendor/{code}/content-pages/15
|
||||
```
|
||||
|
||||
After deletion, platform default will be shown again.
|
||||
|
||||
### Shop Frontend (Public)
|
||||
|
||||
**1. Get Page Content**
|
||||
|
||||
```bash
|
||||
GET /api/v1/shop/content-pages/about
|
||||
```
|
||||
|
||||
Automatically uses vendor context from middleware:
|
||||
- Returns vendor override if exists
|
||||
- Falls back to platform default
|
||||
- Returns 404 if neither exists
|
||||
|
||||
**2. Get Navigation Links**
|
||||
|
||||
```bash
|
||||
GET /api/v1/shop/content-pages/navigation
|
||||
```
|
||||
|
||||
Returns all published pages for footer/header navigation.
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── models/database/
|
||||
│ └── content_page.py ← Database model
|
||||
│
|
||||
├── services/
|
||||
│ └── content_page_service.py ← Business logic
|
||||
│
|
||||
├── api/v1/
|
||||
│ ├── admin/
|
||||
│ │ └── content_pages.py ← Admin API endpoints
|
||||
│ ├── vendor/
|
||||
│ │ └── content_pages.py ← Vendor API endpoints
|
||||
│ └── shop/
|
||||
│ └── content_pages.py ← Public API endpoints
|
||||
│
|
||||
└── templates/shop/
|
||||
├── about.html ← Content page template
|
||||
├── faq.html
|
||||
├── contact.html
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Template Integration
|
||||
|
||||
### Generic Content Page Template
|
||||
|
||||
Create a reusable template for all content pages:
|
||||
|
||||
```jinja2
|
||||
{# app/templates/shop/content-page.html #}
|
||||
{% extends "shop/base.html" %}
|
||||
|
||||
{% block title %}{{ page.title }}{% endblock %}
|
||||
|
||||
{% block meta_description %}
|
||||
{{ page.meta_description or page.title }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
||||
|
||||
{# Breadcrumbs #}
|
||||
<nav class="mb-6">
|
||||
<a href="{{ base_url }}" class="text-primary hover:underline">Home</a>
|
||||
<span class="mx-2">/</span>
|
||||
<span class="text-gray-600">{{ page.title }}</span>
|
||||
</nav>
|
||||
|
||||
{# Page Title #}
|
||||
<h1 class="text-4xl font-bold text-gray-900 dark:text-gray-100 mb-8">
|
||||
{{ page.title }}
|
||||
</h1>
|
||||
|
||||
{# Content #}
|
||||
<div class="prose dark:prose-invert max-w-none">
|
||||
{% if page.content_format == 'markdown' %}
|
||||
{{ page.content | markdown }}
|
||||
{% else %}
|
||||
{{ page.content | safe }}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{# Last updated #}
|
||||
{% if page.updated_at %}
|
||||
<div class="mt-12 pt-6 border-t text-sm text-gray-500">
|
||||
Last updated: {{ page.updated_at }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
### Route Handler
|
||||
|
||||
```python
|
||||
# app/routes/shop_pages.py
|
||||
|
||||
from app.services.content_page_service import content_page_service
|
||||
|
||||
@router.get("/{slug}", response_class=HTMLResponse)
|
||||
async def content_page(
|
||||
slug: str,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""
|
||||
Generic content page handler.
|
||||
|
||||
Loads content from database with vendor override support.
|
||||
"""
|
||||
vendor = getattr(request.state, 'vendor', None)
|
||||
vendor_id = vendor.id if vendor else None
|
||||
|
||||
page = content_page_service.get_page_for_vendor(
|
||||
db,
|
||||
slug=slug,
|
||||
vendor_id=vendor_id,
|
||||
include_unpublished=False
|
||||
)
|
||||
|
||||
if not page:
|
||||
raise HTTPException(status_code=404, detail=f"Page not found: {slug}")
|
||||
|
||||
return templates.TemplateResponse(
|
||||
"shop/content-page.html",
|
||||
get_shop_context(request, page=page)
|
||||
)
|
||||
```
|
||||
|
||||
### Dynamic Footer Navigation
|
||||
|
||||
Update footer to load links from database:
|
||||
|
||||
```jinja2
|
||||
{# app/templates/shop/base.html #}
|
||||
|
||||
<footer>
|
||||
<div class="grid grid-cols-3">
|
||||
|
||||
<div>
|
||||
<h4>Quick Links</h4>
|
||||
<ul>
|
||||
{% for page in footer_pages %}
|
||||
<li>
|
||||
<a href="{{ base_url }}{{ page.slug }}">
|
||||
{{ page.title }}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</footer>
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Content Formatting
|
||||
|
||||
**HTML Content:**
|
||||
```html
|
||||
<h1>About Us</h1>
|
||||
<p>We are a <strong>leading marketplace</strong> for...</p>
|
||||
<ul>
|
||||
<li>Quality products</li>
|
||||
<li>Fast shipping</li>
|
||||
<li>Great support</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
**Markdown Content:**
|
||||
```markdown
|
||||
# About Us
|
||||
|
||||
We are a **leading marketplace** for...
|
||||
|
||||
- Quality products
|
||||
- Fast shipping
|
||||
- Great support
|
||||
```
|
||||
|
||||
### 2. SEO Optimization
|
||||
|
||||
Always provide meta descriptions:
|
||||
|
||||
```json
|
||||
{
|
||||
"meta_description": "Learn about our marketplace, mission, and values. We connect vendors with customers worldwide.",
|
||||
"meta_keywords": "about us, marketplace, e-commerce, mission"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Draft → Published Workflow
|
||||
|
||||
1. Create page with `is_published: false`
|
||||
2. Preview using `include_unpublished=true` parameter
|
||||
3. Review and edit
|
||||
4. Publish with `is_published: true`
|
||||
|
||||
### 4. Navigation Management
|
||||
|
||||
Use `display_order` to control link ordering:
|
||||
|
||||
```python
|
||||
# Platform defaults
|
||||
"about": display_order=1
|
||||
"shipping": display_order=2
|
||||
"returns": display_order=3
|
||||
"privacy": display_order=4
|
||||
"terms": display_order=5
|
||||
|
||||
# Result in footer:
|
||||
About | Shipping | Returns | Privacy | Terms
|
||||
```
|
||||
|
||||
### 5. Content Reversion
|
||||
|
||||
To revert vendor override back to platform default:
|
||||
|
||||
```bash
|
||||
# Vendor deletes their custom page
|
||||
DELETE /api/v1/vendor/{code}/content-pages/15
|
||||
|
||||
# Platform default will now be shown automatically
|
||||
```
|
||||
|
||||
## Common Page Slugs
|
||||
|
||||
Standard slugs to implement:
|
||||
|
||||
| Slug | Title | Description | Show in Footer |
|
||||
|------|-------|-------------|----------------|
|
||||
| `about` | About Us | Company/vendor information | Yes |
|
||||
| `contact` | Contact Us | Contact information and form | Yes |
|
||||
| `faq` | FAQ | Frequently asked questions | Yes |
|
||||
| `shipping` | Shipping Info | Shipping policies and rates | Yes |
|
||||
| `returns` | Returns | Return and refund policy | Yes |
|
||||
| `privacy` | Privacy Policy | Privacy and data protection | Yes |
|
||||
| `terms` | Terms of Service | Terms and conditions | Yes |
|
||||
| `help` | Help Center | Support resources | Yes |
|
||||
| `size-guide` | Size Guide | Product sizing information | No |
|
||||
| `careers` | Careers | Job opportunities | No |
|
||||
|
||||
## Security Considerations
|
||||
|
||||
1. **HTML Sanitization**: If using HTML format, sanitize user input to prevent XSS
|
||||
2. **Authorization**: Vendors can only edit their own pages
|
||||
3. **Published Status**: Only published pages visible to public
|
||||
4. **Vendor Isolation**: Vendors cannot see/edit other vendor's content
|
||||
|
||||
## Migration Strategy
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1. **Create Platform Defaults**:
|
||||
```bash
|
||||
python scripts/create_default_content_pages.py
|
||||
```
|
||||
|
||||
2. **Migrate Existing Static Templates**:
|
||||
- Convert existing HTML templates to database content
|
||||
- Preserve existing URLs and SEO
|
||||
|
||||
3. **Update Routes**:
|
||||
- Add generic content page route handler
|
||||
- Remove individual route handlers for each page
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Possible improvements:
|
||||
|
||||
- **Version History**: Track content changes over time
|
||||
- **Rich Text Editor**: WYSIWYG editor in admin/vendor panel
|
||||
- **Image Management**: Upload and insert images
|
||||
- **Templates**: Pre-built page templates for common pages
|
||||
- **Localization**: Multi-language content support
|
||||
- **Scheduled Publishing**: Publish pages at specific times
|
||||
- **Content Approval**: Admin review before vendor pages go live
|
||||
|
||||
## API Reference Summary
|
||||
|
||||
### Admin Endpoints
|
||||
|
||||
```
|
||||
GET /api/v1/admin/content-pages/ # List all pages
|
||||
GET /api/v1/admin/content-pages/platform # List platform defaults
|
||||
POST /api/v1/admin/content-pages/platform # Create platform default
|
||||
GET /api/v1/admin/content-pages/{id} # Get specific page
|
||||
PUT /api/v1/admin/content-pages/{id} # Update page
|
||||
DELETE /api/v1/admin/content-pages/{id} # Delete page
|
||||
```
|
||||
|
||||
### Vendor Endpoints
|
||||
|
||||
```
|
||||
GET /api/v1/vendor/{code}/content-pages/ # List all (vendor + platform)
|
||||
GET /api/v1/vendor/{code}/content-pages/overrides # List vendor overrides only
|
||||
GET /api/v1/vendor/{code}/content-pages/{slug} # Get specific page
|
||||
POST /api/v1/vendor/{code}/content-pages/ # Create vendor override
|
||||
PUT /api/v1/vendor/{code}/content-pages/{id} # Update vendor page
|
||||
DELETE /api/v1/vendor/{code}/content-pages/{id} # Delete vendor page
|
||||
```
|
||||
|
||||
### Shop (Public) Endpoints
|
||||
|
||||
```
|
||||
GET /api/v1/shop/content-pages/navigation # Get navigation links
|
||||
GET /api/v1/shop/content-pages/{slug} # Get page content
|
||||
```
|
||||
|
||||
## Example: Complete Workflow
|
||||
|
||||
**1. Platform Admin Creates Defaults:**
|
||||
```bash
|
||||
# Create "About" page
|
||||
curl -X POST /api/v1/admin/content-pages/platform \
|
||||
-H "Authorization: Bearer <admin_token>" \
|
||||
-d '{
|
||||
"slug": "about",
|
||||
"title": "About Our Marketplace",
|
||||
"content": "<h1>About</h1><p>Default content...</p>",
|
||||
"is_published": true
|
||||
}'
|
||||
```
|
||||
|
||||
**2. All Vendors See Platform Default:**
|
||||
- Vendor A visits: `vendor-a.com/about` → Shows platform default
|
||||
- Vendor B visits: `vendor-b.com/about` → Shows platform default
|
||||
|
||||
**3. Vendor A Creates Override:**
|
||||
```bash
|
||||
curl -X POST /api/v1/vendor/vendor-a/content-pages/ \
|
||||
-H "Authorization: Bearer <vendor_token>" \
|
||||
-d '{
|
||||
"slug": "about",
|
||||
"title": "About Vendor A",
|
||||
"content": "<h1>About Vendor A</h1><p>Custom content...</p>",
|
||||
"is_published": true
|
||||
}'
|
||||
```
|
||||
|
||||
**4. Now:**
|
||||
- Vendor A visits: `vendor-a.com/about` → Shows Vendor A custom content
|
||||
- Vendor B visits: `vendor-b.com/about` → Still shows platform default
|
||||
|
||||
**5. Vendor A Reverts to Default:**
|
||||
```bash
|
||||
curl -X DELETE /api/v1/vendor/vendor-a/content-pages/15 \
|
||||
-H "Authorization: Bearer <vendor_token>"
|
||||
```
|
||||
|
||||
**6. Result:**
|
||||
- Vendor A visits: `vendor-a.com/about` → Shows platform default again
|
||||
Reference in New Issue
Block a user