CWC Blog Infrastructure Protocol
CWC Blog Infrastructure Protocol
A Reusable LAMP-Based Content Management System
Document ID: CNL-PR-2025-005
Version: 1.0
Date: December 4, 2025
Author: Michael P. Hamilton, Ph.D.
AI Assistance Disclosure: This protocol was developed with assistance from Claude (Anthropic, claude-sonnet-4-20250514). The AI contributed to code development, documentation drafting, and systematic refactoring patterns. The author takes full responsibility for the content, accuracy, and conclusions.
Abstract
This protocol documents the Coffee with Claude (CWC) blog infrastructure, a lightweight LAMP-based content management system designed for personal publishing, essay archiving, and newsletter distribution. The system emphasizes simplicity, maintainability, and portability across multiple website deployments. Originally developed for coffeewithclaude.com, the architecture has been successfully adapted for digitalnaturalist.com migration, demonstrating its reusability. This document provides specifications for database schema, file structure, configuration patterns, and migration methodology suitable for deploying additional instances.
1. Introduction
1.1 Purpose
The CWC infrastructure addresses a specific need: a simple, maintainable blog system for long-form essay publishing with supporting features (images, citations, tags, newsletters) without the complexity of WordPress or similar platforms. The system is designed for:
- Single-author publishing workflows
- Essay-centric content with academic citation support
- Image management with metadata
- Optional newsletter functionality
- Markdown-based content storage
- Easy migration and multi-site deployment
1.2 Scope
This protocol covers:
- Database schema design
- PHP file architecture
- Configuration and path management
- Migration methodology for new deployments
- Import/export workflows
1.3 Technology Stack
| Component | Specification |
|---|---|
| Web Server | Apache 2.x |
| PHP | 8.3+ (mysqli, no PDO) |
| Database | MySQL 8.4+ |
| Content Format | Markdown |
| Styling | Custom CSS (no frameworks) |
| JavaScript | Vanilla JS, Chart.js for analytics |
2. Database Schema
2.1 Core Tables
The system uses eight primary tables with supporting junction tables for many-to-many relationships.
2.1.1 posts
Primary content storage for essays.
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| title | varchar(255) | Essay title |
| slug | varchar(255), unique | URL-safe identifier |
| content | text | Markdown content |
| excerpt | text | Homepage preview text |
| published_date | date | Publication date |
| is_pinned | tinyint(1) | Pin to top of listing |
| display_order | int | Manual sort order |
| created_date | datetime | Record creation |
| updated_date | datetime | Last modification |
| status | enum('draft','published') | Publication status |
| visibility | enum('visible','hidden') | Display visibility |
| view_count | int | Page view counter |
| featured_image | varchar(255) | Hero image path |
| newsletter_sent_date | datetime | Newsletter tracking |
2.1.2 tags
Content categorization.
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| tag_name | varchar(100) | Display name |
| slug | varchar(100), unique | URL-safe identifier |
| created_date | datetime | Record creation |
2.1.3 post_tags
Junction table for post-tag relationships.
| Column | Type | Description |
|---|---|---|
| post_id | int, FK | References posts.id |
| tag_id | int, FK | References tags.id |
2.1.4 citations
Academic citation storage.
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| citation_text | text | Full formatted citation |
| source_url | varchar(500) | Source URL |
| author | varchar(255) | Author name(s) |
| publication | varchar(255) | Publication venue |
| date_published | date | Publication date |
| access_date | date | Access date for URLs |
| notes | text | Internal notes |
| created_date | timestamp | Record creation |
| updated_date | timestamp | Last modification |
2.1.5 post_citations
Junction table for post-citation relationships.
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| post_id | int, FK | References posts.id |
| citation_id | int, FK | References citations.id |
| display_order | int | Citation order in post |
| assigned_date | timestamp | Assignment date |
2.1.6 images
Image metadata storage.
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| filename | varchar(255) | Stored filename |
| original_filename | varchar(255) | Upload filename |
| title | varchar(255) | Display title |
| description | text | Caption/description |
| alt_text | varchar(255) | Accessibility text |
| photographer | varchar(100) | Photo credit |
| photo_date | date | Date taken |
| location | varchar(255) | Location metadata |
| upload_date | datetime | Upload timestamp |
| file_size | int | File size in bytes |
| width | int | Image width pixels |
| height | int | Image height pixels |
| mime_type | varchar(50) | MIME type |
2.1.7 image_tags and image_tag_assignments
Parallel tagging system for images (structure mirrors post tags).
2.1.8 pages
Static page content (About, Contact, etc.).
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| title | varchar(255) | Page title |
| slug | varchar(255), unique | URL identifier |
| content | text | Markdown content |
| featured_image | varchar(500) | Header image |
| updated_date | datetime | Last modification |
2.1.9 subscribers
Newsletter subscriber management.
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| varchar(255), unique | Email address | |
| name | varchar(255) | Subscriber name |
| confirmation_token | varchar(64) | Email verification |
| status | enum('pending','active','unsubscribed') | Subscription state |
| subscribed_date | datetime | Initial signup |
| confirmed_date | datetime | Email confirmed |
| unsubscribed_date | datetime | Opt-out date |
| ip_address | varchar(45) | Signup IP |
2.1.10 admin_users
Authentication for admin interface.
| Column | Type | Description |
|---|---|---|
| id | int, PK, auto | Primary key |
| username | varchar(50), unique | Login username |
| password_hash | varchar(255) | bcrypt hash |
| varchar(255) | Admin email | |
| created_date | datetime | Account creation |
2.2 Foreign Key Constraints
All junction tables use CASCADE DELETE to maintain referential integrity when parent records are removed.
3. File Architecture
3.1 Directory Structure
/Library/WebServer/Documents/[SITE]/
├── css/
│ ├── style.css # Public styles
│ └── admin.css # Admin interface styles
├── js/
│ └── lightbox.js # Image lightbox
├── images/
│ ├── heroes/ # Featured images (auto-generated)
│ └── thumbnails/ # Thumbnail images (auto-generated)
├── includes/
│ ├── config.php # Site configuration
│ ├── functions.php # Shared functions
│ ├── header.php # HTML header template
│ ├── footer.php # HTML footer template
│ ├── cache.php # Page caching
│ └── newsletter_functions.php # Email utilities
├── admin/
│ ├── index.php # Admin dashboard
│ ├── login.php # Authentication
│ ├── logout.php # Session termination
│ ├── essays.php # Essay editor
│ ├── images.php # Image manager
│ ├── pages.php # Static page editor
│ ├── tags.php # Tag management
│ ├── citations.php # Citation management
│ ├── subscribers.php # Subscriber management
│ ├── newsletter.php # Newsletter composition
│ ├── send_notification.php # Email dispatch
│ ├── analytics.php # Corpus analytics
│ ├── import.php # Markdown import
│ └── export.php # Collection export
├── index.php # Homepage/essay listing
├── post.php # Single essay view
├── about.php # About page
├── contact.php # Contact form
├── subscribe.php # Newsletter signup
├── confirm.php # Email confirmation
└── unsubscribe.php # Newsletter opt-out
3.2 Configuration (config.php)
The configuration file defines site-wide constants:
<?php
// Database credentials (external file)
require_once('/Library/WebServer/secure/credentials/[site]_db_config.php');
// Site configuration
define('BASE_PATH', '/NDN'); // Subdirectory or empty for root
define('SITE_NAME', 'Site Title');
define('SITE_TAGLINE', 'Site Subtitle');
define('ADMIN_EMAIL', 'admin@example.com');
// Database connection
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
mysqli_set_charset($conn, 'utf8mb4');
// Session management
session_start();
3.3 Credential Storage
Database credentials stored outside web root:
/Library/WebServer/secure/credentials/[site]_db_config.php
Format:
<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'site_user');
define('DB_PASS', 'secure_password');
define('DB_NAME', 'site_database');
?>
4. Migration Methodology
4.1 Overview
Deploying a new site instance requires:
- Database creation and schema import
- Credential file setup
- File copying and path refactoring
- Color scheme customization
- Content migration
4.2 Database Setup
CREATE DATABASE newsite_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'newsite_user'@'localhost' IDENTIFIED BY 'secure_password';
GRANT ALL PRIVILEGES ON newsite_db.* TO 'newsite_user'@'localhost';
FLUSH PRIVILEGES;
Import schema from reference SQL file.
4.3 Path Refactoring Pattern
All files require systematic updates for new deployment:
| Pattern | Find | Replace |
|---|---|---|
| Header comment path | /Documents/CwC/ |
/Documents/[SITE]/ |
| Stylesheet paths | href="/css/ |
href="<?php echo BASE_PATH; ?>/css/ |
| Navigation links | href="/ |
href="<?php echo BASE_PATH; ?>/ |
| Admin links | href="/admin/ |
href="<?php echo BASE_PATH; ?>/admin/ |
| Form actions | action="/admin/ |
action="<?php echo BASE_PATH; ?>/admin/ |
| PHP redirects | Location: /admin/ |
Location: ' . BASE_PATH . '/admin/ |
| Site name | Hardcoded text | <?php echo SITE_NAME; ?> |
4.4 Color Scheme Customization
Two primary colors define site identity:
| Element | CSS Variable | Example |
|---|---|---|
| Primary accent | Links, buttons, highlights | #5c8a4d (sage green) |
| Dark accent | Headers, footer | #2d3b2d (forest green) |
Search and replace in CSS and inline styles:
- CWC blue (#3498db) → Site primary
- CWC dark (#2c3e50) → Site dark
4.5 Admin User Creation
Generate bcrypt hash:
echo password_hash('password_here', PASSWORD_DEFAULT);
Insert via SQL:
INSERT INTO admin_users (username, email, password_hash, created_date)
VALUES ('username', 'email@example.com', '$2y$...hash...', NOW());
4.6 Directory Permissions
mkdir -p /Library/WebServer/Documents/[SITE]/images/heroes
mkdir -p /Library/WebServer/Documents/[SITE]/images/thumbnails
sudo chown -R _www:_www /Library/WebServer/Documents/[SITE]/images
chmod 755 /Library/WebServer/Documents/[SITE]/images
5. Content Import Format
5.1 Markdown Essay Format
Essays are imported via standardized markdown with metadata header:
**Title:** Essay Title Here
**Date:** Month Day, Year
**Excerpt:** 1-2 sentence preview for homepage display.
**Suggested Tags:** tag1, tag2, tag3
**Citations:**
- Author (Year). "Title." *Publication*. URL
- Additional citations on separate lines
## Markdown Content

Essay body in standard markdown format...
## Section Heading
Additional content with **bold** and *italic* formatting.
5.2 Import Processing
The parse_imported_essay() function in functions.php:
- Splits content on
## Markdown Contentdelimiter - Extracts metadata fields via regex
- Parses tags into array
- Parses citations into structured data
- Returns associative array for database insertion
5.3 Image Handling
Images referenced in markdown:
- Must exist in
/[SITE]/images/directory - Alt text becomes accessibility attribute
- First image can optionally become featured image
- Database lookup provides captions for registered images
6. Feature Summary
6.1 Public Features
| Feature | Description |
|---|---|
| Essay listing | Paginated homepage with excerpts |
| Single essay view | Full content with citations |
| Tag filtering | Browse by topic |
| Static pages | About, Contact |
| Newsletter signup | Double opt-in subscription |
| Image lightbox | Enlarged image viewing |
6.2 Admin Features
| Feature | Description |
|---|---|
| Essay editor | Rich editing with image/citation browsers |
| Image manager | Upload, resize, metadata, tagging |
| Tag manager | CRUD with merge capability |
| Citation manager | Structured citation storage |
| Page editor | Static page management |
| Subscriber management | View, add, manage subscribers |
| Newsletter composition | Full-essay email distribution |
| Analytics dashboard | Corpus statistics, word frequency, charts |
| Import | Markdown essay ingestion |
| Export | Full collection backup |
7. Deployment Checklist
7.1 New Site Deployment
- [ ] Create MySQL database and user
- [ ] Import schema SQL
- [ ] Create credential file outside web root
- [ ] Copy PHP files to site directory
- [ ] Update BASE_PATH in config.php
- [ ] Update SITE_NAME and SITE_TAGLINE
- [ ] Refactor all path references
- [ ] Apply color scheme
- [ ] Create image directories with permissions
- [ ] Create admin user
- [ ] Test login and all admin functions
- [ ] Remove unused features (e.g., newsletter links)
7.2 Content Migration
- [ ] Copy images to /images/ directory
- [ ] Convert legacy content to markdown format
- [ ] Import via admin interface
- [ ] Set publication status and visibility
- [ ] Assign featured images
- [ ] Verify all internal links
8. Known Limitations
- Single-author design: No multi-user permissions
- No WYSIWYG editor: Markdown-only content
- Manual image registration: Imported images need database entry for captions
- No media library browser: Images selected by path
- Basic caching: File-based, no Redis/Memcached
9. References
[1] PHP Documentation. "mysqli Extension." https://www.php.net/manual/en/book.mysqli.php (accessed December 4, 2025).
[2] MySQL Documentation. "MySQL 8.4 Reference Manual." https://dev.mysql.com/doc/refman/8.4/en/ (accessed December 4, 2025).
[3] Gruber, J. "Markdown: Syntax." https://daringfireball.net/projects/markdown/syntax (accessed December 4, 2025).
Appendix A: Complete SQL Schema
See accompanying file: CNL-PR-2025-005_schema.sql
Appendix B: Color Scheme Reference
B.1 CWC Original (Blue)
- Primary: #3498db
- Dark: #2c3e50
B.2 NDN Adaptation (Green)
- Primary: #5c8a4d (sage green)
- Dark: #2d3b2d (forest green)
B.3 Suggested Palettes
| Site Type | Primary | Dark |
|---|---|---|
| Nature/Environment | #5c8a4d | #2d3b2d |
| Technology | #3498db | #2c3e50 |
| Academic | #8b4513 | #2f1810 |
| Creative | #9b59b6 | #4a235a |
Document History
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2025-12-04 | Initial release |
End of Protocol
Permanent URL: https://canemah.org/archive/CNL-PR-2025-005
Cite This Document
BibTeX
Permanent URL: https://canemah.org/archive/document.php?id=CNL-PR-2025-005