Seed the 14.0 series branch from the 17.0 baseline: - .odoo-series = 14.0; Dockerfile FROM odoo:14.0; manifest 14.0.0.5.0 - PORTING.md tracks the Odoo-14 checklist (biggest delta: mail templates must revert to Odoo 14's Jinja2 syntax; render API differs) - README retargeted to 14.0 with porting-in-progress notice - CHANGELOG v0.5.0 entry NOTE: seeded from 17.0 — the Odoo-14 port is NOT yet verified (PORTING.md). Not deploy-ready on the production 14.0 instance until the suite is green there. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
285 lines
10 KiB
Markdown
285 lines
10 KiB
Markdown
# ITSulu Blog Publisher — Odoo 14 Addon
|
||
|
||
**Version:** 0.5.0
|
||
|
||
Automated blog post generation and publishing for Odoo 14.0 Community Edition, powered by generative AI (Anthropic Claude, OpenAI, Google Gemini, or Ollama).
|
||
|
||
> ⚠️ **Porting in progress.** This `14.0` branch is the target for the ITSulu production
|
||
> instance. It is seeded from the 17.0 baseline; the Odoo-14 API port (notably the older
|
||
> Jinja-style mail templates) is tracked in [PORTING.md](PORTING.md).
|
||
|
||
> **Versioning** — `MAJOR.MINOR.PATCH` (each 0–999). MAJOR = major release for sale / significant change; MINOR = features or performance improvements; PATCH = a single group of commits. See [CHANGELOG.md](CHANGELOG.md) for release notes and [CLAUDE.md](CLAUDE.md) §15 for the full scheme.
|
||
|
||
> **Odoo version branches** — like [odoo/odoo](https://github.com/odoo/odoo), each Odoo
|
||
> Community release lives on its own branch. Supported targets:
|
||
> **[`19.0`](../../tree/19.0)** (latest stable) and **[`14.0`](../../tree/14.0)** (the version
|
||
> ITSulu runs). Check out the branch matching your Odoo version. Release tags are namespaced by
|
||
> series, e.g. `19.0-v0.5.0`.
|
||
|
||
## Features
|
||
|
||
### ✨ Core Functionality
|
||
|
||
- **On-Demand Generation** — Wizard-driven blog post creation via backend form
|
||
- **Scheduled Generation** — Three configurable daily cron slots (morning, afternoon, evening)
|
||
- **Multi-Provider LLM** — Route requests to Anthropic Claude, OpenAI ChatGPT, Google Gemini, or local Ollama models
|
||
- **SEO Automation** — Auto-populate meta titles, descriptions, keywords, and tags
|
||
- **Social Media Copy** — Generate platform-specific posts for X, BlueSky, Mastodon, and LinkedIn
|
||
- **Auto-Publish** — Publish generated posts immediately or save as drafts for review
|
||
- **Topic Queue** — Priority-based topic queue for scheduled generation
|
||
- **Notification Emails** — Automated emails with generated content and social copy
|
||
- **Generation Audit Trail** — Complete logs with token usage, provider, model, and error tracking
|
||
- **Error Recovery** — Retry button on failed generation logs
|
||
|
||
### 🧠 Supported LLM Providers
|
||
|
||
| Provider | Model Examples | Config Parameter |
|
||
|----------|---|---|
|
||
| **Anthropic Claude** | claude-sonnet-4-20250514, claude-opus-4-1 | `itsulu_blog_publisher.anthropic_api_key` |
|
||
| **OpenAI** | gpt-4o, gpt-4-turbo | `itsulu_blog_publisher.openai_api_key` |
|
||
| **Google Gemini** | gemini-2.0-flash, gemini-pro | `itsulu_blog_publisher.gemini_api_key` |
|
||
| **Ollama** | Any local model (mistral, llama2, etc.) | `itsulu_blog_publisher.ollama_base_url` |
|
||
|
||
### 📊 Test Coverage
|
||
|
||
**69 automated tests**, all passing on the ITSulu Kubernetes test cluster.
|
||
|
||
| Test Suite | Count | Status |
|
||
|---|---|---|
|
||
| Unit Tests (TDD) | 48 | ✅ All Passing |
|
||
| Behaviour Tests (BDD) | 15 | ✅ All Passing |
|
||
| Performance Benchmarks | 6 | ✅ All Passing |
|
||
| **Total** | **69** | **100% ✅** |
|
||
|
||
**Coverage Areas**:
|
||
- Topic queue management (7 tests)
|
||
- Generation audit logs (8 tests)
|
||
- Social media copy (16 tests)
|
||
- Schedule slots (10 tests)
|
||
- LLM router dispatch (7 tests)
|
||
- E2E / behaviour workflows (15 BDD scenarios)
|
||
- Performance SLOs — latency, query count, token usage, concurrency (6 benchmarks)
|
||
|
||
Tests run as ephemeral Kubernetes jobs in the `itsulu-testing` namespace against a
|
||
primed PostgreSQL template database. See [CLAUDE.md](CLAUDE.md) §8 for the K8s test setup.
|
||
|
||
## Installation
|
||
|
||
### Prerequisites
|
||
|
||
- Odoo 14.0 Community
|
||
- Python 3.6–3.8
|
||
- PostgreSQL 10+
|
||
- pip packages: `requests`, `pytest-odoo`, `pytest-bdd`
|
||
|
||
### Steps
|
||
|
||
1. **Clone the repository** into your Odoo addons directory:
|
||
```bash
|
||
git clone https://github.com/itsulu-odoo/itsulu-blog-publisher.git \
|
||
/path/to/odoo/addons/itsulu_blog_publisher
|
||
```
|
||
|
||
2. **Install Python dependencies**:
|
||
```bash
|
||
pip install requests
|
||
```
|
||
|
||
3. **Install the addon** in Odoo (UI or CLI):
|
||
```bash
|
||
odoo -d mydb -i itsulu_blog_publisher --stop-after-init
|
||
```
|
||
|
||
4. **Configure API keys** in Odoo Settings → Technical → Parameters:
|
||
- `itsulu_blog_publisher.anthropic_api_key` (if using Claude)
|
||
- `itsulu_blog_publisher.openai_api_key` (if using OpenAI)
|
||
- `itsulu_blog_publisher.gemini_api_key` (if using Gemini)
|
||
- `itsulu_blog_publisher.ollama_base_url` (if using Ollama, e.g., `http://localhost:11434`)
|
||
|
||
5. **Configure notification emails** in Settings:
|
||
- `itsulu_blog_publisher.notification_emails` (comma-separated list)
|
||
|
||
## Usage
|
||
|
||
### 1. Create a Blog Post On-Demand
|
||
|
||
1. Go to **Blog** → **Blog Publisher** → **Generate Now**
|
||
2. Enter topic/prompt
|
||
3. Select LLM provider and model
|
||
4. Choose auto-publish or draft
|
||
5. Click **Generate**
|
||
|
||
The addon will:
|
||
- Call the selected LLM provider
|
||
- Create a blog.post with generated title, body, SEO fields
|
||
- Generate social media copy for enabled platforms
|
||
- Send notification email if published
|
||
- Log tokens used, provider, model, and generation time
|
||
|
||
### 2. Schedule Automatic Generation
|
||
|
||
1. Go to **Blog** → **Blog Publisher** → **Schedule Slots**
|
||
2. Create/configure 3 slots: Morning, Afternoon, Evening
|
||
3. Set trigger time (UTC hours)
|
||
4. Choose LLM provider and model per slot
|
||
5. Enable auto-publish or save as draft
|
||
6. Save and activate
|
||
|
||
The system will:
|
||
- Run active slots at configured times via cron
|
||
- Pull next topic from queue (if available) or LLM-chosen topic
|
||
- Publish immediately or save for review
|
||
- Send notification emails for published posts
|
||
|
||
### 3. Manage Topic Queue
|
||
|
||
1. Go to **Blog** → **Blog Publisher** → **Topics**
|
||
2. Create topics with title, notes, and priority (Urgent/High/Normal)
|
||
3. Set state to "Pending"
|
||
4. During generation, slots will consume pending topics in priority order
|
||
5. Topics move to "Used" state after generation
|
||
|
||
### 4. Monitor Generation Logs
|
||
|
||
1. Go to **Blog** → **Blog Publisher** → **Generation Logs**
|
||
2. View all generation attempts (success/error)
|
||
3. Check tokens used, provider, model, duration
|
||
4. Retry failed generations using **Retry** button
|
||
|
||
## Configuration
|
||
|
||
### Settings
|
||
|
||
| Parameter | Type | Default | Description |
|
||
|---|---|---|---|
|
||
| `itsulu_blog_publisher.notification_emails` | Char | (empty) | Comma-separated email addresses for notifications |
|
||
| `itsulu_blog_publisher.anthropic_api_key` | Char | (empty) | Anthropic API key for Claude models |
|
||
| `itsulu_blog_publisher.openai_api_key` | Char | (empty) | OpenAI API key for ChatGPT models |
|
||
| `itsulu_blog_publisher.gemini_api_key` | Char | (empty) | Google Gemini API key |
|
||
| `itsulu_blog_publisher.ollama_base_url` | Char | (empty) | Base URL for local Ollama server |
|
||
|
||
### Email Template
|
||
|
||
The addon includes a pre-configured email template (`email_template_blog_published`) that:
|
||
- Displays blog post title and metadata
|
||
- Includes social media copy for each enabled platform
|
||
- Links to the published post
|
||
- Shows generation stats (tokens, model, time)
|
||
|
||
Customize by editing the template in **Email** → **Email Templates**.
|
||
|
||
## Architecture
|
||
|
||
### Models
|
||
|
||
- **itsulu.blog.topic** — Topic queue with priority and state
|
||
- **itsulu.blog.generation.log** — Audit trail for all generation attempts
|
||
- **itsulu.blog.post.social** — Social media copy linked to blog posts
|
||
- **itsulu.blog.schedule** — Configurable cron slots for scheduled generation
|
||
|
||
### Services
|
||
|
||
- **llm_router.py** — Dispatcher that routes requests to provider APIs
|
||
- **anthropic_provider.py** — Anthropic Claude integration
|
||
- **openai_provider.py** — OpenAI ChatGPT integration
|
||
- **gemini_provider.py** — Google Gemini integration
|
||
- **ollama_provider.py** — Local Ollama model integration
|
||
- **image_router.py** — Optional cover image generation (DALL·E, Imagen, Stable Diffusion)
|
||
|
||
## Development
|
||
|
||
### Running Tests
|
||
|
||
```bash
|
||
# All tests
|
||
pytest addons/itsulu_blog_publisher/tests/ -v
|
||
|
||
# Specific test file
|
||
pytest addons/itsulu_blog_publisher/tests/test_blog_topic.py -v
|
||
|
||
# Specific test
|
||
pytest addons/itsulu_blog_publisher/tests/test_blog_topic.py::TestBlogTopicPriority::test_get_next_topic_returns_highest_priority_pending_topic -v
|
||
|
||
# BDD scenarios only
|
||
pytest addons/itsulu_blog_publisher/tests/test_bdd_steps.py -v
|
||
```
|
||
|
||
### TDD Workflow
|
||
|
||
This project follows strict TDD discipline (see [CLAUDE.md](CLAUDE.md)):
|
||
|
||
1. **RED** — Write failing test
|
||
2. **GREEN** — Write minimum code to pass
|
||
3. **REFACTOR** — Clean up while test stays green
|
||
4. **REPEAT** — Next feature
|
||
|
||
### Code Quality
|
||
|
||
Pre-commit hooks enforce:
|
||
- Black code formatting
|
||
- isort import sorting
|
||
- pylint-odoo linting
|
||
|
||
Run before committing:
|
||
```bash
|
||
pre-commit run --all-files
|
||
```
|
||
|
||
## Troubleshooting
|
||
|
||
### "Configuration error: API key not configured"
|
||
|
||
**Cause**: API key parameter not set in Settings
|
||
**Solution**: Go to Settings → Technical → Parameters and add the required key for your LLM provider
|
||
|
||
### "Unknown provider: <name>"
|
||
|
||
**Cause**: Provider name misspelled or provider not supported
|
||
**Solution**: Use one of: `anthropic`, `openai`, `gemini`, `ollama`
|
||
|
||
### "No blog.post record was created"
|
||
|
||
**Cause**: LLM response parsing failed or validation error
|
||
**Check**: Generation log for error message; verify LLM response format
|
||
|
||
### "No email sent for published post"
|
||
|
||
**Cause**: Notification email template not found or recipients not configured
|
||
**Solution**:
|
||
1. Ensure template exists: **Email** → **Email Templates** → "Blog Post Published"
|
||
2. Set notification emails: **Settings** → Technical → Parameters → `itsulu_blog_publisher.notification_emails`
|
||
|
||
## Documentation
|
||
|
||
- [CHANGELOG.md](CHANGELOG.md) — Release notes and version history
|
||
- [CLAUDE.md](CLAUDE.md) — Complete TDD framework, testing patterns, versioning scheme, troubleshooting
|
||
- [ARCHITECTURE.md](ARCHITECTURE.md) — System design, data flow, API contracts
|
||
- [PHASE2_ROADMAP.md](PHASE2_ROADMAP.md) — Phase 2 implementation status
|
||
|
||
## License
|
||
|
||
MIT License. See [LICENSE](LICENSE) for details.
|
||
|
||
## Support
|
||
|
||
For issues, feature requests, or questions, open an issue on GitLab:
|
||
https://gitlab.com/itsulu-odoo/itsulu-blog-publisher/issues
|
||
|
||
## Roadmap
|
||
|
||
### Phase 3 (Runboat E2E)
|
||
- Playwright end-to-end scenarios
|
||
- UI-driven generation workflow testing
|
||
- Multi-user collaboration scenarios
|
||
|
||
### Phase 4 (Performance & Scale)
|
||
- Query optimization (N+1 detection)
|
||
- Batch generation for multiple topics
|
||
- Template caching and pre-rendering
|
||
- Performance benchmarks (throughput, latency)
|
||
|
||
---
|
||
|
||
**Current Status**: v0.4.8 — test suite green (69/69 passing on ITSulu K8s) ✅
|
||
**Last Updated**: 2026-05-30
|
||
**Maintainer**: Nicholas Riegel (nicholasr@itsulu.com)
|