Big-Link-Man/docs/stories/story-2.4-html-formatting-t...

140 lines
6.0 KiB
Markdown

# Story 2.4: HTML Formatting with Multiple Templates
## Status
Completed
## Story
**As a developer**, I want a module that takes the generated text content and formats it into a standard HTML file using one of a few predefined CSS templates, assigning one template per bucket/subdomain, so that all deployed content has a consistent look and feel per site.
## Acceptance Criteria
- A directory of multiple, predefined HTML/CSS templates exists.
- The master JSON configuration file maps a specific template to each deployment target (e.g., S3 bucket, subdomain).
- A function accepts the generated content and a target identifier (e.g., bucket name).
- The function correctly selects and applies the appropriate template based on the configuration mapping.
- The content is structured into a valid HTML document with the selected CSS.
- The final HTML content is stored and associated with the project in the database.
## Dependencies
- **Story 2.5**: Deployment Target Assignment must run before this story to set `site_deployment_id` on GeneratedContent
- If `site_deployment_id` is null, a random template will be selected
## Tasks / Subtasks
### 1. Create Template Infrastructure
**Effort:** 3 story points
- [x] Create template file structure under `src/templating/templates/`
- Basic template (default)
- Modern template
- Classic template
- Minimal template
- [x] Each template should include:
- HTML structure with placeholders for title, meta, content
- Embedded or inline CSS for styling
- Responsive design (mobile-friendly)
- SEO-friendly structure (proper heading hierarchy, meta tags)
### 2. Implement Template Loading Service
**Effort:** 3 story points
- [x] Implement `TemplateService` class in `src/templating/service.py`
- [x] Add `load_template(template_name: str)` method that reads template file
- [x] Add `get_available_templates()` method that lists all templates
- [x] Handle template file not found errors gracefully with fallback to default
- [x] Cache loaded templates in memory for performance
### 3. Implement Template Selection Logic
**Effort:** 2 story points
- [x] Add `select_template_for_content(site_deployment_id: Optional[int])` method
- [x] If `site_deployment_id` exists:
- Query SiteDeployment table and return `site.template_name`
- Template is tracked at site/domain level in database
- [x] If `site_deployment_id` is null: randomly select template (don't persist)
- [x] Return template name
### 4. Implement Content Formatting
**Effort:** 5 story points
- [x] Create `format_content(content: str, title: str, meta_description: str, template_name: str)` method
- [x] Parse HTML content and extract components
- [x] Replace template placeholders with actual content
- [x] Ensure proper escaping of HTML entities where needed
- [x] Validate output is well-formed HTML
- [x] Return formatted HTML string
### 5. Database Integration
**Effort:** 2 story points
- [x] Add `template_name` field to `SiteDeployment` model (String(50), default='basic', not null)
- [x] Add `formatted_html` field to `GeneratedContent` model (Text type, nullable)
- [x] Add `template_used` field to `GeneratedContent` model (String(50), nullable)
- [x] Add `site_deployment_id` field to `GeneratedContent` model (FK to site_deployments, nullable, indexed)
- [x] Create database migration script (`scripts/migrate_add_template_to_sites.py`)
- [x] Update repository to save formatted HTML and template_used alongside raw content
### 6. Integration with Content Generation Flow
**Effort:** 2 story points
- [x] Update `src/generation/service.py` to call template service after content generation
- [x] Template service reads `site_deployment_id` from GeneratedContent
- [x] Store formatted HTML and template_used in database
- [x] Handle template formatting errors without breaking content generation
### 7. Unit Tests
**Effort:** 3 story points
- [x] Test template loading with valid and invalid names
- [x] Test template selection with site_deployment_id present
- [x] Test template selection with site_deployment_id null (random)
- [x] Test content formatting with different templates
- [x] Test fallback behavior when template not found
- [x] Test error handling for malformed templates
- [x] Achieve >80% code coverage for templating module
### 8. Integration Tests
**Effort:** 2 story points
- [x] Test end-to-end flow: content generation → template application → database storage
- [x] Test with site_deployment_id assigned (consistent template per site)
- [x] Test with site_deployment_id null (random template)
- [x] Verify formatted HTML is valid and renders correctly
- [x] Test new site gets random template assigned and persisted to config
## Dev Notes
### Current State
- `master.config.json` already has templates section with mappings (lines 52-59)
- `src/templating/service.py` exists but is empty (only 2 lines)
- `src/templating/templates/` directory exists but only contains `__init__.py`
- `GeneratedContent` model stores raw content in Text field but no formatted HTML field yet
### Dependencies
- Story 2.2/2.3: Content must be generated before it can be formatted
- Story 2.5: Deployment target assignment (optional - defaults to random if not assigned)
- Configuration system: Uses existing master.config.json structure
### Technical Decisions
1. **Template format:** Simple string replacement with {{ placeholders }}
2. **CSS approach:** Embedded `<style>` tags in HTML template
3. **Storage:** Store both raw content AND formatted HTML
4. **Template selection:**
- Has site_deployment_id → use site.template_name from database
- No site_deployment_id → pick random, don't persist
5. **Template tracking:** Stored at site level in `site_deployments.template_name` field
6. Story 2.4 owns ALL template selection logic
### Suggested Template Structure
```
src/templating/templates/
├── basic.html
├── modern.html
├── classic.html
└── minimal.html
```
### Testing Approach
- Unit tests: Test each service method in isolation
- Integration tests: Test full content → template → storage flow
- Manual QA: Visual inspection of rendered HTML in browser