# VideoSmith — Build Plan and Architecture
**Wrapper PWA for MoneyPrinterTurbo Short-Form Video Generation**

**Document:** `plan_videosmith_2026-07-03.md`  
**Status:** Planning (Pre-build)  
**Date:** 2026-07-03  
**Author:** Claude Code research agent  
**Placeholder Name:** VideoSmith (to be confirmed with user)

---

## Executive Summary

This document outlines a phased approach to building **VideoSmith**, a standalone PWA that wraps the open-source **MoneyPrinterTurbo** engine (GitHub: harry0703/MoneyPrinterTurbo, 95k+ stars, MIT license). MoneyPrinterTurbo auto-generates short-form videos from a topic: script generation → TTS narration → stock B-roll from Pexels/Pixabay/Coverr → subtitle burn-in → video render.

**Key recommendation:** Build VideoSmith as an **isolated standalone PWA** (per ADR-086), following the Blogsmith pattern (`/var/www/Others/Automation/videosmith/`), with its own database, own auth, own subdomain (deferred per user instruction). The MoneyPrinterTurbo engine containers run as internal-only services on `root_default` (no public Traefik labels), reachable only by the VideoSmith wrapper PWA.

**Why wrapper?** MoneyPrinterTurbo's FastAPI backend has **no built-in authentication** (auth code exists but is commented-out in production builds). The Streamlit WebUI is a dev-facing tool, not production-ready for 360LM's client-facing usage. A wrapper PWA provides: PIN-based access control, job history + status tracking, user management, output distribution integration, and 360LM-standard UX.

---

## 1. Architecture Recommendation: Internal Engine, Isolated Wrapper

### 1.1 MoneyPrinterTurbo Deployment Model

**Recommended:** Internal-only containers, NO public subdomain (contradicts the pre-fetched compose file's DNS setup).

**Rationale:**
- MoneyPrinterTurbo's FastAPI backend is unauthenticated (auth dependency is commented-out in code)
- Enabling auth requires uncommenting Python source + redeploying container, which breaks upgrades
- A 2-core VPS (hardware constraint) + single static x-api-key (even if enabled) = weak security for public exposure
- **Network isolation (Docker network-only, no Traefik label) is the primary security control**
- The Streamlit WebUI is intended for developers, not end users
- VideoSmith wrapper handles user-facing features (auth, job history, distribution)

**Deployment:**
- **Container:** `mpt-api` running FastAPI backend on port 8080 (internal: `http://mpt-api:8080`)
- **Container:** `mpt-webui` running Streamlit on port 8501 (internal only, for debugging by ops; not exposed to Traefik)
- **Network:** `root_default` (same Docker network as wrapper PWA, Traefik, shared services)
- **Compose file:** `/var/www/moneyprinterturbo/docker-compose.yml` (location already established; adjust to remove Traefik labels, add internal-only setup)
- **No subdomain/DNS:** Not exposed via Traefik; VideoSmith is the public-facing interface

### 1.2 VideoSmith Wrapper PWA

**Location:** `/var/www/Others/Automation/videosmith/` (following Blogsmith's path pattern)

**Database:** Own `videosmith` role and database in shared PostgreSQL (isolated, per ADR-086)

**Auth:** Own PIN-based server-side bcrypt auth (follows Blogsmith precedent, not hub-integrated — see ADR-086 criterion section 1.3 below)

**Domain:** Deferred (user said "I dont want you to set up a DNS as of Now"); flag as Phase 2 pending user approval

**Subdomain placeholder:** `videosmith.srv1111289.hstgr.cloud` (when DNS is ready) — requires one CNAME from `360dlm.in` zone

### 1.3 Auth Model: Isolated PIN — **RESOLVED (2026-07-03)**

User confirmed: "same as BlogSmith, part of automation." VideoSmith is an isolated PWA — PIN-based bcrypt auth (Blogsmith pattern), no hub integration, no `hub.pwa_registry` entry, own DB role/schema. This is final, not conditional.

### 1.4 API Contract with MoneyPrinterTurbo

VideoSmith calls MPT's FastAPI backend using the following endpoints:

| Method | Path | Purpose | Request Body (example) |
|--------|------|---------|---|
| **POST** | `/videos` | Create video generation task | `{ "topic": "Best social media marketing strategies 2026", "video_language": "en", "voice_name": "en-US-AriaNeural", "video_size": "1080x1920", ...}` |
| **GET** | `/tasks/{task_id}` | Query task status | — |
| **GET** | `/tasks` | List all tasks (pagination) | — |
| **DELETE** | `/tasks/{task_id}` | Cancel/delete task | — |
| **POST** | `/musics` | Upload custom BGM (MP3) | multipart/form-data |
| **GET** | `/musics` | List available BGM files | — |
| **POST** | `/video_materials` | Upload local video material | multipart/form-data |
| **GET** | `/video_materials` | List uploaded materials | — |

**Task lifecycle (from MoneyPrinterTurbo state machine):**
1. **pending** → request enqueued
2. **researching** → script generation step
3. **drafting** → video render step
4. **completed** → task done; files in `/tasks/{task_id}/` directory
5. **failed** → error; details in task record

**Video download:** `GET /tasks/{task_id}/final-1.mp4` (or `final-2.mp4` if batch; config.toml controls output endpoint URL)

**Task state storage:** MoneyPrinterTurbo uses in-memory task manager by default (`max_concurrent_tasks=5` in config.toml); tasks lost on restart. **Recommend 1 concurrent task** on the 2-core VPS to avoid overload (CPU constraint).

---

## 2. Phased Rollout

### Phase 1: Core Video Generation Pipeline (Weeks 1–2)

**Scope:**
- VideoSmith database schema (users, sessions, jobs, outputs)
- PIN-based auth (register, login, session persistence, logout)
- Job submission form (topic input, LLM provider selection, output format, TTS voice choice)
- Job status polling (GET `/api/jobs`, update UI spinner)
- Job history display (all past jobs, view-video links)
- File download links (browser download of generated MP4)

**Deliverables:**
- `/var/www/Others/Automation/videosmith/` directory structure
- `docker-compose.yml` (wrapper PWA + MoneyPrinterTurbo containers)
- `public/index.html` (single-file PWA, HTML+CSS+JS)
- `videosmith_api.py` (Python backend, auth + MPT proxying)
- Database schema migration SQL
- Traefik labels (internal-only for MPT; pending subdomain for wrapper)
- 30+ Playwright spec tests (auth, job submission, status polling, file download)

**Success criteria:**
- User can register, login, stay logged in across page reloads
- User can submit a video generation job with a topic + optional config
- UI displays job status (pending → researching → drafting → complete)
- Generated MP4 is downloadable via browser

**Known constraints:**
- 2-core CPU → render time ~5–15 min per video (depends on script length, TTS, stock-footage download bandwidth)
- Pexels/Pixabay API keys must be pre-configured in config.toml (no in-app key entry yet)
- No LLM provider selection in UI yet (fixed in Phase 1 via env var; flexible config in Phase 2)

### Phase 2: Credential Configuration UI + LLM Fallback (Weeks 3–4)

**Scope:**
- In-app form for per-user Pexels/Pixabay/Coverr API keys (following Blogsmith's WordPress settings UX pattern)
- Dry-run mode if keys are missing (test without downloading stock footage)
- LLM provider selection UI (OpenAI, Azure, Gemini, OpenRouter, Ollama, etc.; per config.toml's 25+ providers)
- Implement ADR-062 fallback chain (if applicable; open question: does wrapper add fallback, or does single provider suffice?)
- Output format selection (9:16 vertical for TikTok/Reels, 16:9 horizontal for YouTube, square)

**Scope note on LLM tiers — RESOLVED (2026-07-03):** User chose the full ADR-062 tiered chain over MoneyPrinterTurbo's native single-provider model. MoneyPrinterTurbo's `TaskVideoRequest`/`VideoParams` accepts an optional pre-supplied `video_script` field (verified: `app/models/schema.py`, `Field(default="", max_length=8000)`) — when populated, MPT skips its own script generation entirely. **Design:** build a new internal-only proxy `videosmith-ai-proxy` (same shape as `counter-ai`/`print-ai-proxy`) implementing Tier 1 Claude OAuth → Tier 2 OpenRouter → Tier 3 Anthropic REST for script generation; VideoSmith's backend calls this proxy first, then passes the generated script into MPT's `/videos` request. MPT itself is used only for TTS, subtitles, stock footage, and final render — never for the LLM script step. **This moves from "Phase 2 optional" to a Phase 1 requirement** since it's no longer a revisit-later item.

**Success criteria:**
- User can store their own Pexels/Pixabay keys in-app (encrypted at rest)
- User can choose LLM provider from a dropdown
- Dry-run mode generates test jobs without API costs

### Phase 3: Output Distribution + Publishing (Weeks 5–6)

**Scope (example options — user to decide):**
1. **Manual export:** Download MP4, user manually uploads to TikTok/Instagram/YouTube
2. **Auto-upload integration:** Use Upload-Post API (MoneyPrinterTurbo has built-in support; config.toml `upload_post_*` settings) to auto-publish to TikTok/Instagram/YouTube Shorts
3. **Handoff to another 360LM tool:** E.g., drive-consolidator for multi-platform scheduling, or a custom publishing queue
4. **Just storage:** Save videos to a shared folder on VPS; user retrieves manually

**RESOLVED (2026-07-03):** User chose manual export only — "proceed with option 1 and park option 2." Phase 1 ships raw MP4 download (already covered by Phase 1 scope above); auto-publish (Upload-Post / TikTok / Instagram / YouTube integration) is explicitly parked and must not be built until the user un-parks it.

### Phase 4: Analytics, Batch Jobs, and Polish (On-Demand)

**Future scope:**
- Video view/engagement analytics (if publishing to social platforms)
- Batch job submission (generate N videos from a list of topics)
- Video re-render with different settings (same topic, different voice/format)
- Scheduled video generation (cron-like job scheduling)

---

## 3. Deployment Plan

### 3.1 Infrastructure Changes

**Pre-deployment checklist:**

1. **Traefik labels:** MoneyPrinterTurbo compose removes public labels (internal-only). When wrapper goes public, add labels for wrapper's subdomain.
   - MPT (internal): no labels needed; `docker-compose.yml` just declares network
   - VideoSmith (public once DNS ready): Standard Host-based rule (ADR-073)

2. **Network:** Both containers on `root_default` (shared with Traefik, other services)

3. **Docker DNS:** `mpt-api` service is addressable as `http://mpt-api:8080` from VideoSmith container (Docker's embedded DNS)

4. **Volumes:**
   - MoneyPrinterTurbo config: `/var/www/moneyprinterturbo/config.toml` (mounted ro into MPT container)
   - MoneyPrinterTurbo storage: `/var/www/moneyprinterturbo/storage/` (generated videos, temp files)
   - VideoSmith app code: `/var/www/Others/Automation/videosmith/` (app + PWA files)
   - VideoSmith `.env`: `/var/www/Others/Automation/videosmith/.env` (DATABASE_URL, secrets)

5. **Secrets management:** `.env` file (mode 600, root-only) with:
   - `DATABASE_URL=postgresql://videosmith_app:PASSWORD@postgres:5432/videosmith`
   - Any VideoSmith-specific API keys (future: Pexels keys if stored server-side)

### 3.2 Database Setup

Run once before container start:

```sql
-- Create role and database
CREATE ROLE videosmith_app WITH ENCRYPTED PASSWORD 'GENERATED_PASSWORD' LOGIN;
CREATE DATABASE videosmith OWNER videosmith_app;

-- Schema + tables (schema migration run inside container or via psql)
psql -U videosmith_app -d videosmith < /var/www/Others/Automation/videosmith/migrate_videosmith_v1.sql
```

**Schema outline (table details in MDD_videosmith.md):**
- `users` — PIN auth, user metadata
- `sessions` — Bearer token auth, 30-day expiry
- `jobs` — task tracking, input topic, output files, status
- `job_logs` — optional: error details, script preview, intermediate outputs

### 3.3 When DNS Is Ready (Phase 0b)

User to confirm:
1. DNS A record or CNAME for `videosmith.srv1111289.hstgr.cloud` (or custom domain)
2. Traefik cert resolver assignment (default: `mytlschallenge`; if external, consider `zerossl` per ADR-073)

Then:
- Add Traefik labels to VideoSmith docker-compose.yml
- Restart compose (`docker compose up -d`)
- Test HTTPS routing

---

## 4. Open Questions — RESOLVED by User (2026-07-03)

All seven questions were answered interactively, one at a time. Recorded here for the build record; see MDD_videosmith.md §8 for the same resolutions with ADR cross-references.

### 4.1 Scope & Use Case

**Q1: Who are the end users?** → **RESOLVED: isolated auth, same as Blogsmith** (automation-tools content team, not hub-authenticated 360LM employees). Drives the ADR-086 isolated-PWA auth model, confirmed final in §1.3.

**Q2: What is the primary output use case?** → **RESOLVED: Phase 1 = raw MP4 download only.** Auto-publish is parked (see §2 Phase 3 update above), not built now.

**Q3: Who/what feeds the video topics?** → **RESOLVED: manual entry per job**, matching Blogsmith's keyword-field UX. No content calendar or batch import in Phase 1.

### 4.2 Technical Constraints

**Q4: CPU bottleneck — acceptable render time?** → **RESOLVED: yes, 1 job at a time is fine** at ~5–15 min per video. `config.toml max_concurrent_tasks=1`. No hardware upgrade requested.

**Q5: LLM provider strategy?** → **RESOLVED: full ADR-062 tiered fallback chain**, not MPT's native single-provider model. See §1.4/§2 Phase 2 update above for the `videosmith-ai-proxy` design this implies — this is now Phase 1 scope, not deferred.

**Q6: Data retention & cleanup?** → **RESOLVED: archive off-box** (not keep-forever, not simple time-based auto-delete). Exact target (S3 / GCS / reuse the existing `drive-consolidator` Google Drive integration) is a small remaining follow-up — recommend reusing Drive Consolidator's existing OAuth rather than standing up a new S3/GCS credential, but this needs a direct user confirmation before Phase 1 storage code is written.

### 4.3 Naming & Branding

**Q7: Final name?** → **RESOLVED: "VideoSmith"** — final, not a placeholder.

---

## 5. Red-Team: Failure Modes & Mitigations

| Failure Mode | Likelihood | Impact | Mitigation |
|---|---|---|---|
| **Pexels/Pixabay API quota exhausted** | Medium | Video gen fails mid-render with "no stock footage available" | Pre-test with trial keys; monitor quota daily; implement dry-run fallback (use local video materials) |
| **TTS synthesis fails** (edge-tts timeout, quota) | Low (default 30s timeout) | Audio generation fails, no narration → video unwatchable | Retry with Elevenlabs/Azure TTS if edge-tts fails (requires Phase 2 fallback) |
| **LLM script generation fails** | Low (if OpenAI API stable) | No script → no video → user sees error | Implement fallback LLM provider; show "try again" button |
| **MoneyPrinterTurbo container OOM** | Medium (2-core, ~7.8GB RAM total, 4.8GB available) | Task fails silently or crashes container | Set memory limits in compose; implement task timeout (kill after 20 min) |
| **Video output file path traversal / disk full** | Low | Security: uploaded materials outside task dir; or storage exhaustion | Path validation (file_security module in MPT already handles); disk monitoring + cleanup cron |
| **Generated video leaks sensitive topic** | Low | If VideoSmith later becomes multi-tenant, topic "apple iphone marketing strategy" generated for user A might be visible to user B in shared storage | Separate task directories per user; implement ACL checks; don't expose task paths in URLs |
| **MoneyPrinterTurbo container restart → task state lost** | High (in-memory state manager) | Incomplete tasks disappear from UI; user can't resume | Accept as Phase 1 limitation; Phase 2 option: enable Redis (`enable_redis=true` in config.toml) for persistent state |
| **Slow page load if task list is large** | Medium | UI sluggish after 100+ historical jobs | Implement pagination (default 10 jobs/page); add search/filter by date range |
| **Concurrent users race condition on job status** | Low | Two users create jobs simultaneously; one overwrites the other's metadata | Isolated database per user (schema-level isolation, not multi-tenant); not applicable |

---

## 6. Success Criteria & Sign-Off Gate

**Phase 1 MVP acceptance criteria:**
- [ ] VideoSmith PWA accessible at `videosmith.srv1111289.hstgr.cloud` (or localhost:3200 in dev)
- [ ] New user can register (PIN: 4–8 digits), login, and stay logged in across refreshes
- [ ] User can submit a video generation job with a topic
- [ ] Job status updates in real-time (pending → researching → drafting → complete)
- [ ] Generated MP4 downloads successfully via browser
- [ ] 30+ Playwright spec tests pass (auth, job flow, download, edge cases)
- [ ] MoneyPrinterTurbo config.toml has valid Pexels/Pixabay keys (or dry-run mode tested)
- [ ] 2-core CPU constraint acknowledged: single concurrent task, ~5–15 min per video acceptable

**Before Phase 2:** User signs off on Phase 1 deliverables + clarifies Q1–Q7 (open questions)

---

## 7. Implementation Backlog

**Pre-Phase-1 (blockers):**
1. Clarify Q1 (user population → auth model decision)
2. Clarify Q2 (output distribution goal → Phase 3 scope)
3. Confirm MoneyPrinterTurbo config.toml values (Pexels API keys, LLM provider, TTS voice default)
4. Create Videosmith database role and schema in PostgreSQL
5. Decide on container image: custom Dockerfile vs. prebuild publish to registry (recommend custom Dockerfile in `/var/www/Others/Automation/videosmith/`)

**Phase 1 backlog:**
- [ ] PWA HTML/CSS/JS (index.html, public/sw.js, manifest.json)
- [ ] Python API (videosmith_api.py: auth, MPT proxy, job tracking)
- [ ] Database schema migration (users, sessions, jobs tables)
- [ ] Dockerfile + docker-compose.yml
- [ ] Traefik labels (deferred until DNS ready)
- [ ] Playwright spec tests (50+ test cases)
- [ ] User onboarding docs (for ops running the app)

---

## 8. References

- **Upstream:** https://github.com/harry0703/MoneyPrinterTurbo (MIT license, actively maintained)
- **MPT Config:** `/var/www/moneyprinterturbo/config.toml` (unfilled template, 450+ lines, 25+ LLM providers supported)
- **Precedent (Blogsmith):** `/var/www/Others/Automation/blogsmith/` (ADR-097, live since 2026-07-02)
- **ADR-086:** Isolated PWA architecture decision framework
- **ADR-073:** Traefik label conventions
- **ADR-062:** Live AI pipeline contract (if implementing LLM fallback chain)

---

**Next step:** User clarifies open questions (§4); then draft commences with Phase 1 MDD (Module Design Document).
