V2 lives entirely under v2/ and is built around three asks the team raised about V1: per-video assets sometimes drifted onto the wrong trend, hashtag scrapes returned junk that wasn't filterable per-client, and there was no multi-user model behind Microsoft SSO. Highlights: - Stable TikTok numeric-id key for every per-video asset; URL form drift is logged loudly to drift_log.jsonl and never silently nulls assets. Stage 5 manifest hard-gates Stage 6 if any selected video is missing any required asset; --drop-failing auto-backfills from the next-best recipe candidates. - Per-brief engagement floor (min_likes / min_plays / min_stl_pct), applied at Apify scrape time and re-validated locally; spend_log.json records raw_returned vs kept_after_floor per scrape. - Users + teams + memberships with owner/admin/editor/viewer roles; SSO upserts a user keyed on Azure oid, auto-creates a personal team, and a super-admin is bootstrapped via BOOTSTRAP_SUPER_ADMIN_EMAIL on first sign-in. Phase A integration test: 16/16 pass. - 10-stage TS pipeline (brief → seed → scrape1 → select → scrape2 → validate → analyse → insights → trends → qa → build) wired through one CLI; each stage idempotent + resumable from disk via .state sentinels. §4.5 rubrics shipped under prompts/ and loaded into Claude calls. - React 18 + Vite + TS + Tailwind operator SPA: brief intake form, team management, super-admin user list, help/FAQ ported from V1. - Separate Docker Compose project (name: social-reporting-v2, port 3457, Postgres 5437) with deploy/setup-v2.sh, deploy-v2.sh, rollback-to-v1.sh scripts that take over V1's /social-reports URL and let us roll back. Verification: 62 unit tests pass (auth/session, ids extractor with full URL fixture, engagement floor, recipes, manifest, linking-fix, MoM compare). Live smoke run on a Dove brief: 1400 raw → 253 kept (82% culled) → 21 fully-bundled videos → 25 editorial trends across 8 brief-driven categories, with drift=0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
55 lines
1.8 KiB
YAML
55 lines
1.8 KiB
YAML
# Per CLAUDE.md compose-name policy: every compose file MUST pin a unique top-level `name:`.
|
|
# This keeps V2 from colliding with V1 (project name `social-listening`) on shared hosts.
|
|
name: social-reporting-v2
|
|
|
|
services:
|
|
db-v2:
|
|
image: postgres:16-alpine
|
|
ports:
|
|
- "${DB_V2_PORT:-5437}:5432"
|
|
environment:
|
|
POSTGRES_DB: social_reporting_v2
|
|
POSTGRES_USER: srv2_user
|
|
POSTGRES_PASSWORD: ${DB_V2_PASSWORD:-change-me-please}
|
|
volumes:
|
|
- pgdata-v2:/var/lib/postgresql/data
|
|
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U srv2_user -d social_reporting_v2"]
|
|
interval: 3s
|
|
timeout: 3s
|
|
retries: 10
|
|
|
|
app-v2:
|
|
build:
|
|
context: ..
|
|
dockerfile: v2/Dockerfile.v2
|
|
ports:
|
|
- "127.0.0.1:${APP_V2_PORT:-3457}:3457"
|
|
env_file:
|
|
- .env
|
|
depends_on:
|
|
db-v2:
|
|
condition: service_healthy
|
|
volumes:
|
|
# Pipeline outputs land here; shared with the host so we can inspect/back up.
|
|
- ../briefs:/app/briefs
|
|
environment:
|
|
- PORT=3457
|
|
- NODE_ENV=${NODE_ENV:-development}
|
|
- DATABASE_URL=postgresql://srv2_user:${DB_V2_PASSWORD:-change-me-please}@db-v2:5432/social_reporting_v2
|
|
- SESSION_SECRET=${SESSION_SECRET:-}
|
|
- ALLOWED_ORIGIN=${ALLOWED_ORIGIN:-}
|
|
- AZURE_TENANT_ID=${AZURE_TENANT_ID:-}
|
|
- AZURE_CLIENT_ID=${AZURE_CLIENT_ID:-}
|
|
- ALLOW_PASSWORD_FALLBACK=${ALLOW_PASSWORD_FALLBACK:-false}
|
|
- DASH_USER=${DASH_USER:-admin}
|
|
- DASH_PASS=${DASH_PASS:-}
|
|
- BOOTSTRAP_SUPER_ADMIN_EMAIL=${BOOTSTRAP_SUPER_ADMIN_EMAIL:-}
|
|
- APIFY_TOKEN=${APIFY_TOKEN:-}
|
|
- APIFY_LIVE_APPROVED=${APIFY_LIVE_APPROVED:-false}
|
|
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
|
|
- COMPOSE_PROJECT_NAME=social-reporting-v2
|
|
|
|
volumes:
|
|
pgdata-v2:
|