Files
QR-master/.env.example
Timo Knuth eb932ebdaa Publish milestones per channel and add Instagram
Consent is bound to the channel it was given for: approving a post on X says
nothing about Instagram. Publishing state moves from the SocialMilestone row
into SocialMilestonePost, one row per channel, where a missing row means no
consent. The dialog asks per channel, shows the text each one will publish and
keeps a separate handle for each; Instagram captions end in hashtags because a
link there is not clickable.

Also fixes three problems in the existing X path:

- A QR code already past several thresholds produced one prompt per threshold,
  and since the post quotes the current scan count, every one of them would
  have published the same number. Only the highest threshold is announced now.
- Detection ran after every unique scan and re-read the QR code's full scan
  history just to hit skipDuplicates. Known milestones are filtered first.
- A failed post stayed failed forever because the consent dialog only opens
  once. The queue now retries three times on its own, spaces first attempts by
  SOCIAL_MILESTONE_MIN_GAP_HOURS, and Settings lists every milestone per
  channel with restart and revoke.

The worker no longer renders the card itself; it downloads the image the app
renders at /s/m/<token>/og, which also serves the new square and portrait
formats. Instagram publishing stays off until SOCIAL_MILESTONE_CHANNELS and
SOCIAL_WORKER_CHANNELS both name it.

Schema changes are manual SQL, see sql/2026-08-16_*.sql. Run both before
deploying this version.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 13:46:13 +02:00

66 lines
2.4 KiB
Plaintext

# Database credentials (used by both db and web services in docker-compose.yml)
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=qrmaster
# Note: DATABASE_URL and DIRECT_URL are auto-generated from POSTGRES_* vars in docker-compose.yml
# You don't need to set them here when using Docker Compose
NODE_ENV=production
PORT=3000
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=CHANGE_ME
NEXT_PUBLIC_APP_URL=http://localhost:3000
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
REDIS_URL=redis://redis:6379
IP_SALT=CHANGE_ME_SALT
ENABLE_DEMO=true
# SMTP & Email Senders (for welcome + retention emails via nodemailer / resend)
SMTP_HOST=smtp.qrmaster.net
SMTP_PORT=465
SMTP_USER=timo@qrmaster.net
SMTP_PASS=
EMAIL_FROM="Timo from QR Master <timo@qrmaster.net>"
EMAIL_FROM_SECURITY="QR Master Security <noreply@qrmaster.net>"
EMAIL_REPLY_TO="support@qrmaster.net"
# Cron job protection — generate with: openssl rand -base64 32
CRON_SECRET=
# Leave empty in production for 1,000 / 10,000 unique scans. Test only, e.g. 1,2.
SOCIAL_MILESTONE_THRESHOLDS=
# Leave empty for immediate publishing after consent. Set 24 to enable a revocation window.
SOCIAL_MILESTONE_POST_DELAY_HOURS=
# Hours between two brand posts (default 24). Set 0 on test to publish back to back.
SOCIAL_MILESTONE_MIN_GAP_HOURS=
SOCIAL_MILESTONE_POSTING_ENABLED=false
SOCIAL_WORKER_INTERVAL_SECONDS=10
X_API_KEY=
X_API_SECRET=
X_ACCESS_TOKEN=
X_ACCESS_TOKEN_SECRET=
# Channels the consent dialog offers (app) and the worker publishes (worker).
# Keep both in sync: x / x,instagram
SOCIAL_MILESTONE_CHANNELS=x
SOCIAL_WORKER_CHANNELS=x
# Instagram Business account for QRMaster.net, see docs/automations/social-accounts-and-jobs.md
INSTAGRAM_USER_ID=
INSTAGRAM_ACCESS_TOKEN=
GRAPH_API_VERSION=v22.0
# Guards POST/DELETE on /api/social-assets, the public image host Instagram
# pulls from. Unrelated to TikTok posting; falls back to TIKTOK_ADMIN_KEY.
SOCIAL_ASSET_ADMIN_KEY=
# TikTok OAuth / posting (server-side only)
# Source of truth for cron posting: QRMaster server .env
# Production example: https://qrmaster.net/api/tiktok/callback
# Local dev example: http://localhost:3000/api/tiktok/callback
# Tokens are saved in the DB after the OAuth callback; do not store access tokens here.
TIKTOK_CLIENT_KEY=
TIKTOK_CLIENT_SECRET=
TIKTOK_REDIRECT_URI=https://qrmaster.net/api/tiktok/callback
TIKTOK_ADMIN_KEY=
TIKTOK_EXPECTED_OPEN_ID=