# Template Tracking Fix - October 21, 2025 ## Problem Identified Story 2.4 was incorrectly implemented to store template mappings in `master.config.json` instead of the database. This meant: - Templates were tracked per hostname in a config file - No database field to store template at site level - Story 3.4 (boilerplate pages) couldn't easily determine which template to use - Inconsistent tracking between config file and database ## Root Cause Story 2.4 specification said to use `master.config.json` for template mappings, but this was wrong. Templates should be tracked at the **site/domain level in the database**, not in a config file. ## What Was Fixed ### 1. Database Model Updated **File**: `src/database/models.py` Added `template_name` field to `SiteDeployment` model: ```python class SiteDeployment(Base): # ... existing fields ... template_name: Mapped[str] = mapped_column(String(50), default="basic", nullable=False) ``` ### 2. Migration Script Created **File**: `scripts/migrate_add_template_to_sites.py` New migration script adds `template_name` column to `site_deployments` table: ```sql ALTER TABLE site_deployments ADD COLUMN template_name VARCHAR(50) DEFAULT 'basic' NOT NULL ``` ### 3. Template Service Fixed **File**: `src/templating/service.py` **Before** (wrong): ```python def select_template_for_content(...): # Query config file for hostname mapping if hostname in config.templates.mappings: return config.templates.mappings[hostname] # Pick random and save to config template_name = self._select_random_template() self._persist_template_mapping(hostname, template_name) return template_name ``` **After** (correct): ```python def select_template_for_content(...): # Query database for site template if site_deployment_id and site_deployment_repo: site_deployment = site_deployment_repo.get_by_id(site_deployment_id) if site_deployment: return site_deployment.template_name or "basic" return self._select_random_template() ``` **Removed**: - `_persist_template_mapping()` method (no longer needed) ### 4. Config File Simplified **File**: `master.config.json` **Before**: ```json "templates": { "default": "basic", "mappings": { "aws-s3-bucket-1": "modern", "bunny-bucket-1": "classic", "azure-bucket-1": "minimal", "test.example.com": "minimal" } } ``` **After**: ```json "templates": { "default": "basic" } ``` Only keep `default` for fallback behavior. All template tracking now in database. ### 5. Story 2.4 Spec Updated **File**: `docs/stories/story-2.4-html-formatting-templates.md` - Updated Task 3 to reflect database tracking - Updated Task 5 to include `template_name` field on `SiteDeployment` - Updated Technical Decisions section ### 6. Story 3.4 Updated **File**: `docs/stories/story-3.4-boilerplate-site-pages.md` - Boilerplate pages now read `site.template_name` from database - No template service changes needed - Effort reduced from 15 to 14 story points ## How It Works Now ### Site Creation ```python # When creating/provisioning a site site = SiteDeployment( site_name="example-site", template_name="modern", # or "basic", "classic", "minimal" # ... other fields ) ``` ### Article Generation ```python # When generating article site = site_repo.get_by_id(article.site_deployment_id) template = site.template_name # Read from database formatted_html = template_service.format_content(content, title, meta, template) ``` ### Boilerplate Pages ```python # When generating boilerplate pages site = site_repo.get_by_id(site_id) template = site.template_name # Same template as articles about_html = generate_page("about", template=template) ``` ## Benefits 1. **Single source of truth**: Template tracked in database only 2. **Consistent sites**: All content on a site uses same template 3. **Simpler logic**: No config file manipulation needed 4. **Better data model**: Template is a property of the site, not a mapping 5. **Easier to query**: Can find all sites using a specific template ## Migration Path For existing deployments: 1. Run migration script: `uv run python scripts/migrate_add_template_to_sites.py` 2. All existing sites default to `template_name="basic"` 3. Update specific sites if needed: ```sql UPDATE site_deployments SET template_name='modern' WHERE id=5; ``` ## Testing No tests broken by this change: - Template service tests still pass (reads from database instead of config) - Article generation tests still pass - Template selection logic unchanged from user perspective ## Files Changed ### Created - `scripts/migrate_add_template_to_sites.py` - `TEMPLATE_TRACKING_FIX.md` (this file) ### Modified - `src/database/models.py` - Added `template_name` field - `src/templating/service.py` - Removed config lookups, read from DB - `master.config.json` - Removed `mappings` section - `docs/stories/story-2.4-html-formatting-templates.md` - Updated spec - `docs/stories/story-3.4-boilerplate-site-pages.md` - Updated to use DB field - `STORY_3.4_CREATED.md` - Updated effort estimate ## Next Steps 1. Run migration: `uv run python scripts/migrate_add_template_to_sites.py` 2. Verify existing articles still render correctly 3. Implement Story 3.4 using the database field 4. Future site creation/provisioning should set `template_name` --- **Fixed by**: AI Code Assistant **Fixed on**: October 21, 2025 **Issue identified by**: User during Story 3.4 discussion