Tactical Media Broadcast Hub — initial release
Self-hosted multi-platform broadcast newsroom for activist collectives: publishing pipeline with group approval and DST-proof scheduling, TweetDeck-style column wall with hostile-content-safe rendering, live control room with Auto Director, bridged chat governance with polls and quorum, distributed sandboxed transcode workers, encrypted content-addressed archive, monthly analytics. MIT licensed. See README.md and docs/.
This commit is contained in:
commit
aa5e262f3a
880 changed files with 111042 additions and 0 deletions
130
infra/occupymedia/DEPLOY.md
Normal file
130
infra/occupymedia/DEPLOY.md
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
# Deploy — occupymedia.cc
|
||||
|
||||
**Storage phase-one addendum:** the current deployment uses separate app/chat/
|
||||
PeerTube CTs. New files/docs work is an independent, undeployed scaffold;
|
||||
see [files runbook](files/README.md) and [storage contracts](../../docs/occupymedia-storage.md).
|
||||
The older one-box instructions below do not deploy that stack. Live conduwuit
|
||||
v0.5.0 still has local media; its volumes require backup. R2 durability alone
|
||||
does not back up media or the metadata needed to resolve it.
|
||||
|
||||
One box, everything behind the Cloudflare tunnel (already provisioned: zone
|
||||
`occupymedia.cc`, tunnel `occupymedia` with ingress app/api/tube/chat, R2
|
||||
buckets `occupymedia-media-encrypted`, `-peertube-videos`, `-peertube-playlists`,
|
||||
`-matrix-media`). No inbound ports. All local ports bind to 127.0.0.1.
|
||||
|
||||
## WP3 release on the app CT (150)
|
||||
|
||||
Use `docker compose -f docker-compose.app.yml` in this directory. Before
|
||||
syncing source, create and verify an owner `pg_dump` in
|
||||
`/opt/tactical-media-broadcast-hub/backups/`. Preserve the previous source for rollback.
|
||||
|
||||
Both `DATABASE_URL` and `SCHEDULER_DATABASE_URL` in the CT `.env` must connect
|
||||
as `sp_app`, without superuser or BYPASSRLS privileges. Provision its password
|
||||
with owner access and keep real values only in the CT `.env`. Keep the
|
||||
existing `SUPERPOSTER_KEK`; scheduler inherits it and `TEMPORAL_ADDRESS`.
|
||||
|
||||
Stop the old scheduler, then run the new API migration CLI offline with
|
||||
`SUPER_DATABASE_URL` set to the owner URL:
|
||||
`pnpm --filter @tactical-media-broadcast-hub/api exec tsx src/db/migrate.cli.ts --dir migrations`.
|
||||
The CLI skips recorded migrations; 019 tracks resumable transactional, batch,
|
||||
and concurrent-index phases. Confirm 018 and 019 in `schema_migrations` and
|
||||
check `assertPublishingSchema` using the runtime URL before starting new code.
|
||||
|
||||
Build `api scheduler web`, then run `up -d --no-deps api`, followed by
|
||||
`scheduler` and `web`. Verify API health/readiness, invite regressions, an
|
||||
existing username/password login, scheduler readiness and Temporal connectivity,
|
||||
and the public web app. Defer production publish tests until explicitly requested.
|
||||
For rollback, restore source from the previous commit, re-sync, rebuild and
|
||||
restart the three services; do not undo migrations automatically.
|
||||
|
||||
## 0. Prerequisites on the box
|
||||
|
||||
- Debian 12 / Ubuntu 24.04, 4+ vCPU, 8 GB RAM, 100 GB disk
|
||||
- Docker Engine + compose plugin (`curl -fsSL https://get.docker.com | sh`)
|
||||
- git
|
||||
|
||||
## 1. Get the code + secrets
|
||||
|
||||
```bash
|
||||
git clone git@gitlab.example.com:mediatools/tacticalmediahub.git
|
||||
cd tactical-media-broadcast-hub/infra/occupymedia
|
||||
|
||||
cp .env.example .env
|
||||
# Fill: CLOUDFLARE_TUNNEL_TOKEN, R2_ACCESS_KEY, R2_SECRET_KEY (dashboard → R2 →
|
||||
# Manage API Tokens → Object Read & Write, scoped to the occupymedia-* buckets),
|
||||
# POSTGRES_PASSWORD, PEERTUBE_DB_PASSWORD, S3_KEK (openssl rand -hex 32 — ONE TIME,
|
||||
# it wraps every stored blob; lose it = archive unreadable)
|
||||
|
||||
# peertube.env: set both PEERTUBE_DB_PASSWORD / POSTGRES_PASSWORD lines to the
|
||||
# value from .env, and set a registration/SMTP sender if you have them.
|
||||
```
|
||||
|
||||
## 2. Build + start the core
|
||||
|
||||
```bash
|
||||
docker compose build api scheduler web media-worker
|
||||
docker compose up -d postgres redis temporal peertube-postgres
|
||||
```
|
||||
|
||||
## 3. Apply API migrations (ordered, once)
|
||||
|
||||
```bash
|
||||
cd ../..
|
||||
for f in apps/api/migrations/*.sql; do
|
||||
docker compose -f infra/occupymedia/docker-compose.yml exec -T postgres \
|
||||
psql -U "$(grep -oP '(?<=POSTGRES_USER:)\S+' infra/occupymedia/docker-compose.yml | head -1 | tr -d '${:-occupymedia}')" \
|
||||
-d occupymedia -v ON_ERROR_STOP=1 < "$f" || { echo "FAILED at $f"; break; }
|
||||
done
|
||||
```
|
||||
|
||||
(If psql errors on an already-applied migration — re-runs are idempotent-safe
|
||||
for most files; check the failing file before continuing.)
|
||||
|
||||
## 4. Bring everything up
|
||||
|
||||
```bash
|
||||
docker compose -f infra/occupymedia/docker-compose.yml up -d
|
||||
docker compose ps # everything Up/healthy
|
||||
```
|
||||
|
||||
## 5. First-boot steps
|
||||
|
||||
1. **Tunnel**: `docker compose logs cloudflared` — should show 4 connections
|
||||
registered. Then `https://app.occupymedia.cc` (control room), `/healthz` on
|
||||
api., tube., chat. should all answer.
|
||||
2. **PeerTube admin**: `docker compose logs peertube 2>&1 | grep -i -A3 password`
|
||||
— random root password printed ONCE. Log in at tube.occupymedia.cc, change
|
||||
it, then run the brand sync (`docs/peertube-setup.md`) and create the live
|
||||
channel.
|
||||
3. **Matrix admin**: register the first account at chat.occupymedia.cc with the
|
||||
token from conduwuit.toml, then set `allow_registration = false` and
|
||||
`docker compose restart conduwuit`. Configure Element as client
|
||||
(`docs/matrix-setup.md`).
|
||||
4. **Telegram bridge** (optional now): `docker compose --profile bridges run --rm
|
||||
mautrix-telegram` → interactive login with the bot/user token; then
|
||||
`docker compose --profile bridges up -d mautrix-telegram`.
|
||||
|
||||
## 6. Live ingest (deferred)
|
||||
|
||||
RTMP/SRT cannot traverse the tunnel. Options documented in the session notes:
|
||||
tiny relay VPS + WireGuard to this box (recommended; keeps the home IP out of
|
||||
DNS), or direct port-forward. Until then the 24/7 channel runs playlists/VOD
|
||||
(media-worker pushes to PeerTube internally over the docker network).
|
||||
|
||||
## 7. Operations
|
||||
|
||||
- **Backup**: `docker compose exec postgres pg_dump -U occupymedia occupymedia |
|
||||
gzip > backup-$(date +%F).sql.gz` + `tar` the named volumes (pgdata,
|
||||
peertube_pgdata, conduwuit_data). Media itself is in R2 (durable) — KEK
|
||||
backup matters more than volume backup.
|
||||
- **Update**: `git pull && docker compose build api scheduler web media-worker &&
|
||||
docker compose up -d` (migrations: repeat step 3 for NEW files only).
|
||||
- **Logs**: `docker compose logs -f --tail=100 <service>`.
|
||||
|
||||
## Known simplifications (first-production-pass)
|
||||
|
||||
- observability (otel/prometheus/grafana) not included — add from
|
||||
infra/docker-compose.yml services when needed
|
||||
- single app instance per service (no horizontal scaling — intended at this size)
|
||||
- file-sharing/collab layer: oCIS S3NG + optional Collabora scaffold in
|
||||
`files/compose.yml`; deployment and Matrix migration remain separate prerequisites
|
||||
Loading…
Add table
Add a link
Reference in a new issue