feat(RECIPE-0003): complete iteration 0 — update icon and add docker deployment

This commit is contained in:
Giancarmine Salucci
2026-02-16 15:56:23 +01:00
parent 08425067e7
commit d55bcf9ae3
12 changed files with 521 additions and 4 deletions

View File

@@ -494,6 +494,210 @@ This document will be updated by subsequent agents:
---
**Document Version:** 1.1
**Last Updated by:** Planner Agent
### [Planner] Research Notes - RECIPE-0003 (2026-02-16)
**Task:** Update application icon and configure Docker deployment
#### PWA Icon Generation - icon-source.png
**Research Date:** 2026-02-16
**Source:** Project analysis, PWA best practices, sharp documentation
**Icon Source File:**
- Location: `static/icon-source.png`
- Size: 672KB PNG file
- Format: PNG with transparency (confirmed via file analysis)
- Destination sizes: 192x192 (favicon.png), 512x512 (icon-512.png)
**PWA Icon Requirements:**
From RECIPE-0002 research and W3C Web App Manifest specification:
1. **Minimum Size**: 192x192 pixels (required for PWA installability)
2. **Recommended Size**: 512x512 pixels (for splash screens, high-DPI displays)
3. **Format**: PNG with transparency support
4. **Purpose**: "any maskable" for optimal Android compatibility
5. **Location**: static/ directory (served at root path)
**Sharp Library Configuration:**
- Version: 0.34.5 (already in dependencies)
- Method: resize() with fit: 'contain' to preserve aspect ratio
- Background: transparent (rgba 0,0,0,0)
- Format: PNG with optimization
- Quality: Default compression for web delivery
**Implementation Pattern:**
```javascript
await sharp('static/icon-source.png')
.resize(192, 192, {
fit: 'contain',
background: { r: 0, g: 0, b: 0, alpha: 0 }
})
.png()
.toFile('static/favicon.png');
```
**Rationale:**
- `fit: 'contain'` preserves aspect ratio without cropping
- Transparent background maintains icon transparency
- PNG format required by Web App Manifest spec
- Same approach for both 192x192 and 512x512 variants
---
#### Docker Volume Configuration
**Research Date:** 2026-02-16
**Source:** Codebase analysis, Dockerfile, scheduler.ts, extraction.ts
**Volume Requirements Analysis:**
From code analysis, only one persistent volume is required:
**1. /app/secrets - Instagram Authentication Storage**
- **Purpose**: Persist Instagram session cookies across container restarts
- **File**: auth.json (Playwright storage state)
- **Usage**:
- scheduler.ts: Checks `/app/secrets/auth.json` for Docker deployments
- extraction.ts: Loads authentication from `/app/secrets/auth.json`
- gen-auth.js: Browser automation saves session to secrets/auth.json
- **Rationale**: Prevents re-login on every container restart
- **Docker Path**: /app/secrets
- **Host Path**: ./secrets (relative to docker-compose.yml)
**Volumes NOT Required:**
- **Database**: Queue uses in-memory storage (QueueManager.ts)
- **Cache**: Service worker cache is ephemeral
- **Uploads**: No file upload functionality
- **Logs**: Console logs to stdout/stderr (Docker logging)
- **Build artifacts**: Built into image at build time
**VOLUME Directive:**
```dockerfile
VOLUME ["/app/secrets"]
```
**docker-compose.yml Volume Mount:**
```yaml
volumes:
- ./secrets:/app/secrets
```
---
#### Environment Variable Inventory
**Research Date:** 2026-02-16
**Source:** queue/config.ts, llm.ts, tandoor-config.ts, scheduler.ts
**Comprehensive Variable List:**
**LLM Configuration (REQUIRED):**
- `OPENAI_BASE_URL` - OpenAI-compatible API endpoint
- `OPENAI_API_KEY` - API authentication key
- `LLM_MODEL` - Model identifier (default: gpt-4o)
**Queue Configuration (OPTIONAL):**
- `QUEUE_CONCURRENCY` - Parallel processing limit (default: 2)
- `QUEUE_MAX_RETRIES` - Retry attempts (default: 3)
**Tandoor Integration (OPTIONAL):**
- `TANDOOR_ENABLED` - Enable Tandoor upload (default: false)
- `TANDOOR_SERVER_URL` - Tandoor base URL
- `TANDOOR_SPACE` - Space ID (default: 1)
- `TANDOOR_TOKEN` - API token
**Push Notifications (OPTIONAL):**
- `VAPID_PUBLIC_KEY` - Web Push public key (has default)
- `VAPID_PRIVATE_KEY` - Web Push private key (has default)
**Authentication Scheduler (OPTIONAL):**
- `AUTH_SCHEDULER_ENABLED` - Enable auto-renewal (default: false)
- `AUTH_SCHEDULER_INTERVAL_MINUTES` - Renewal interval (default: 720)
**Runtime Configuration:**
- `NODE_ENV` - Environment mode (production/development)
- `PORT` - SvelteKit port (default: 3000)
- `DISPLAY` - X11 display for Playwright (set to :99 in docker-compose.yml)
**Default Values:**
All variables have sensible defaults except:
- OPENAI_BASE_URL (required)
- OPENAI_API_KEY (required)
**VAPID Keys:**
Current defaults in queue/config.ts:
- Public: BNextdcB_fQ0BVvyGioM5L8Tf9vKQjs-WnF-rUbnU8MdWIZQYfggIHxBnW21I-lq_0HykLCdMpYj8d5joavWdxQ
- Private: JwxI_KcsBcehYcTOufMcbVWJjCq1QbH5FJmSyQuG680
- Note: These should be regenerated for production deployments
**Variable Access Pattern:**
- Server-side only: Uses `$env/dynamic/private` from SvelteKit
- No client-side environment variable exposure
- Runtime configuration (no build-time substitution)
---
#### Docker Health Check Configuration
**Research Date:** 2026-02-16
**Source:** routes/api/health/+server.ts analysis
**Health Check Endpoint:**
- Path: `/api/health`
- Method: GET
- Response: 200 OK with JSON body
- Implementation: `src/routes/api/health/+server.ts`
**Health Check Response:**
```json
{
"status": "ok",
"timestamp": "2026-02-16T..."
}
```
**Docker Health Check Configuration:**
```yaml
healthcheck:
test: ["CMD", "node", "-e", "fetch('http://localhost:3000/api/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
```
**Rationale:**
- `interval: 30s` - Balance between responsiveness and overhead
- `timeout: 10s` - Sufficient for app initialization
- `retries: 3` - Allow transient failures
- `start_period: 40s` - Accounts for Playwright browser initialization
- Uses internal fetch to avoid curl dependency
---
#### Docker Deployment Constraints
**Research Date:** 2026-02-16
**Source:** Dockerfile, app.server.ts, browser.ts
**Current Dockerfile Analysis:**
- Base: node:22-alpine (minimal, production-ready)
- Chromium: Installed via apk (headless browser for Instagram extraction)
- Fonts: liberation-fonts, noto, noto-cjk (text rendering)
- Build: npm ci + npm run build
- Runtime: Node.js ESM import
- Port: 3000 (EXPOSE)
- Environment: NODE_ENV=production
**Browser Initialization:**
From app.server.ts:
- initializeBrowser() called on server start
- Graceful shutdown handlers (SIGTERM, SIGINT)
- Critical for extraction.ts Playwright usage
**Security Options:**
- `seccomp=unconfined` - Required for Chromium sandbox
- `--no-sandbox` in browser.ts launch args
- Necessary for containerized Chromium
**No Changes Required:**
Current Dockerfile is production-ready, only needs VOLUME addition.
---
**Document Version:** 1.2
**Last Updated by:** Planner Agent (RECIPE-0003)
**Next Update:** Developer Agent