# Architecture walkthrough

## Goal

A scheduled, hands-off pipeline that turns niche signals (creator style + Italian IT news + ERP docs) into ready-to-publish social assets, stores them in Drive, and pings Telegram.

## High-level flow

```mermaid
flowchart TD
  cron[cPanel cron] --> cli[bin/run_pipeline.py]
  cli --> news[RSS Italian IT news]
  cli --> profiles[data/profiles]
  cli --> erp[data/erp]
  news --> claude[Claude ideation JSON]
  profiles --> claude
  erp --> claude
  claude --> assets[Pillow carousels/images]
  claude --> video[ffmpeg short MP4]
  assets --> local[storage/runs/batch_*]
  video --> local
  local --> drive[Google Drive folder]
  local --> tg[Telegram notification]
```

## Components

### 1. Scheduler
`cron/run.sh` activates the project venv (if present) and runs the CLI. No always-on worker, no queue broker — one process per batch.

### 2. Signal ingestion
- **NewsService** — HTTP fetch of public Italian tech RSS feeds (`ANSA Tech`, `Hardware Upgrade`, `HTML.it`, …). Failures on individual feeds are swallowed so one dead feed never blocks a run.
- **KnowledgeService** — walks `data/profiles` and `data/erp` for `.md`/`.txt` (and PDF text extract). Truncates to keep Claude prompts bounded.

### 3. Claude (ideation + asset briefs)
`ClaudeService` wraps the Anthropic Messages API with light retries.

**Ideation prompt** asks for a fixed-size JSON array. Each idea includes format, hook, caption, hashtags, visual brief, optional slides / video_script, and source refs (which news item or ERP section inspired it).

**Why JSON?** Deterministic downstream rendering — generators never scrape free-form prose.

### 4. Asset production (local)
`VisualRenderer` (Pillow) draws branded 1080×1080 slides:

- Left accent bar, brand wordmark, hook, body  
- Carousel progress dots + `n/total`  

`AssetProducer`:

- `image` → `post.png` + `caption.txt`  
- `carousel` → `slide_01.png` … + caption  
- `video` → frames → `ffmpeg` concat → `short.mp4` (~`VIDEO_MAX_SECONDS`)

This intentionally avoids Midjourney/DALL·E so the only AI vendor remains Anthropic. Brand consistency stays under your CSS-like color vars.

**Video feasibility:** shipping today as captioned motion slides (Ken-burns-ready frames held on screen). True avatar/VO AI video would add vendors and cost; easy extension point later (swap `_assemble_video`).

### 5. Storage
`DriveUploader` uses a Google Cloud **service account** with Drive scope `drive.file`, creates `content_batch_<timestamp>/`, uploads artifacts (skips raw frame dumps when MP4 exists).

Share the destination Drive folder with the service-account email (Editor).

### 6. Notification
`TelegramNotifier` posts a short summary + Drive folder URL via Bot API (`sendMessage`).

## Configuration surface

All knobs live in `.env` (see `.env.example`): batch size, brand colors, locale, video on/off, dry-run.

## Failure & ops model

- Logs: `storage/logs/pipeline.log` (rotating) + cron stdout redirect  
- Retries: Claude HTTP via `tenacity` (3 attempts)  
- Dry-run / demo modes for safe testing  
- Secrets never committed (`.gitignore` covers `.env` and the SA JSON)

## Extension points

| Want | Where to change |
|---|---|
| More/different news sources | `src/services/news.py` → `DEFAULT_FEEDS` |
| AI photographic images | new generator calling one image API; keep Claude for prompts |
| TTS voiceover | generate audio then `ffmpeg -i audio -i frames` |
| Multi-brand | multiple `.env` files + cron entries |
| Approval gate | pause before Drive upload; wait for Telegram callback |

## Security notes

- Service account should only have access to the content output folder  
- Telegram bot token is a secret — rotate if leaked  
- Anthropic key restricted by spend limits in the Anthropic console  
- Cron user should own the project directory; do not expose `storage/` via public HTTP
