APP_NAME=Pressekonto APP_ENV=local APP_KEY= APP_DEBUG=true APP_URL=https://pressekonto.test APP_LOCALE=de APP_FALLBACK_LOCALE=de APP_FAKER_LOCALE=en_US APP_MAINTENANCE_DRIVER=file # APP_MAINTENANCE_STORE=database # HTTP Basic Auth Gate (Staging-Schutz). Nur erzwungen, wenn aktiviert # UND BASIC_AUTH_USER/BASIC_AUTH_PASSWORD gesetzt sind. BASIC_AUTH_ENABLED=true BASIC_AUTH_USER= BASIC_AUTH_PASSWORD= PHP_CLI_SERVER_WORKERS=4 BCRYPT_ROUNDS=12 LOG_CHANNEL=stack # `daily`: eine Datei je Tag (laravel-YYYY-MM-DD.log), Rotation nach # LOG_DAILY_DAYS. Fachliche Meldungen liegen daneben in eigenen Tagesdateien # je Thema (billing-, ki-, monitoring-, market-, admin-slow-*.log) — # siehe config/logging.php. `single` nur noch als Notnagel, wächst unbegrenzt. LOG_STACK=daily LOG_DAILY_DAYS=14 LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug # Betriebs-Alerts (R5.3): fehlgeschlagene Scheduler-Tasks/Queue-Jobs werden als # `critical` geloggt und – wenn aktiviert – zusätzlich an MONITORING_ALERT_EMAIL # gemeldet (Fallback: LEGAL_CONTACT_EMAIL). In Prod echten Mailer voraussetzen. MONITORING_ALERTS_ENABLED=true MONITORING_ALERT_EMAIL= # Zweiter Alarmweg per ntfy (Monitoring-Plan M3) — ohne URL/Topic aus. MONITORING_NTFY_URL= MONITORING_NTFY_TOPIC= MONITORING_NTFY_TOKEN= MONITORING_NTFY_PRIORITY=4 # Tiefer Health-Check /health für den externen Monitor (Bearer oder ?token=). # Ohne Token gibt es den Endpunkt nicht. MONITORING_HEALTH_TOKEN= # Anmeldeversuche mit unbekannter Adresse: Tageszähler statt Verlauf. # Löschfrist in Tagen und Warnschwelle je Tag im Systemstatus (Standardwerte). MONITORING_FAILED_LOGIN_RETENTION_DAYS=90 MONITORING_FAILED_LOGIN_WARN_PER_DAY=1000 # Fehler an GlitchTip (selbst gehostet, Sentry-Protokoll; Monitoring-Plan # 1.1/1.2). Ohne DSN passiert nichts. SENTRY_RELEASE bei jedem Deploy auf # den Git-Hash setzen, dann ordnet GlitchTip Fehler der Version zu. SENTRY_LARAVEL_DSN= SENTRY_BROWSER_DSN= SENTRY_ENVIRONMENT= SENTRY_RELEASE= # --------------------------------------------------------------------------- # Multi-Domain-Setup (config/domains.php) # Hub: pressekonto (Portal-Backend + Hub-Landing) — Spokes: presseecho, # businessportal24. Prod: .test durch echte Domains ersetzen # (pressekonto.de, presseecho.de, businessportal24.com). # --------------------------------------------------------------------------- APP_PROTOCOL="https://" APP_PORTAL_NAME="pressekonto.test" APP_PORTAL_URL="https://pressekonto.test" APP_PORTAL_PRIMARY="#526266" APP_PORTAL_SECONDARY="#82a0a7" # APP_PORTAL_ASSET_URL= APP_PRESSEECHO_NAME=presseecho.test APP_PRESSEECHO_URL=https://presseecho.test APP_PRESSEECHO_PRIMARY="#345636" APP_PRESSEECHO_SECONDARY="#6b8f71" APP_BUSINESSPORTAL_NAME=businessportal24.test APP_BUSINESSPORTAL_URL=https://businessportal24.test APP_BUSINESSPORTAL_PRIMARY="#cf3628" APP_BUSINESSPORTAL_SECONDARY="#f0834a" # Sanctum: Hosts, die stateful (Session-Cookie) auf die API zugreifen dürfen. # Prod: echte Domains kommasepariert eintragen. SANCTUM_STATEFUL_DOMAINS=pressekonto.test,presseecho.test,businessportal24.test DB_CONNECTION=sqlite # DB_HOST=127.0.0.1 # DB_PORT=3306 # DB_DATABASE=laravel # DB_USERNAME=root # DB_PASSWORD= # Wartezeit auf Tabellen-Sperren in Sekunden (siehe config/database.php). # Migrationen auf großen Tabellen ggf. mit DB_LOCK_WAIT_TIMEOUT=300 starten. DB_LOCK_WAIT_TIMEOUT=10 # Aufbewahrung des PM-Ereignis-Logs in Tagen (siehe config/press_releases.php). # Bestimmt zugleich die Tiefe der Verlaufsanzeige. 395 = 13 Monate. PRESS_RELEASE_EVENTS_RETENTION_DAYS=395 # Aufbewahrung der Konversions-Ereignisse in Tagen (siehe config/conversion.php). # Bewusst derselbe Horizont wie oben. 395 = 13 Monate. CONVERSION_EVENTS_RETENTION_DAYS=395 # Mail-Link-Klick (Stufe 1): derselbe Klick je IP und Meldung zählt höchstens # einmal in diesem Fenster (Minuten). Audit 29.09.2026, R-08. CONVERSION_MAIL_CLICK_THROTTLE_MINUTES=30 # --------------------------------------------------------------------------- # Legacy-Datenbanken (Alt-Systeme, read-only für Migration/Abgleich). # Die businessportal-Verbindung ist ein Snapshot-Dump, nicht live. # --------------------------------------------------------------------------- DB_HOST_BUSINESSPORTAL=127.0.0.1 DB_DATABASE_BUSINESSPORTAL= DB_USERNAME_BUSINESSPORTAL= DB_PASSWORD_BUSINESSPORTAL= DB_HOST_PRESSEECHO=127.0.0.1 DB_DATABASE_PRESSEECHO= DB_USERNAME_PRESSEECHO= DB_PASSWORD_PRESSEECHO= SESSION_DRIVER=redis SESSION_LIFETIME=120 SESSION_ENCRYPT=false SESSION_PATH=/ SESSION_DOMAIN=null # Prod: true setzen (Cookies nur über HTTPS). # SESSION_SECURE_COOKIE=true BROADCAST_CONNECTION=log FILESYSTEM_DISK=local QUEUE_CONNECTION=database CACHE_STORE=redis # CACHE_PREFIX= MEMCACHED_HOST=127.0.0.1 REDIS_CLIENT=phpredis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 # Prod: echten Mailer konfigurieren — Default `log` versendet NICHTS. MAIL_MAILER=log MAIL_SCHEME=null MAIL_HOST=127.0.0.1 MAIL_PORT=2525 MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" # Bounce-Behandlung (Roadmap 1b.6): Envelope-Sender für Rückläufer — MUSS auf # der From-Domain liegen (SPF-Ausrichtung), z. B. bounce@pressekonto.com. # Leer = From-Adresse. Schwellen siehe config/bounces.php. MAIL_RETURN_PATH= # IMAP-Zugang zum Bounce-Postfach für `mail:fetch-bounces` (alle 10 Minuten). # Leer = der Befehl tut nichts. BOUNCE_IMAP_HOST= BOUNCE_IMAP_PORT=993 BOUNCE_IMAP_ENCRYPTION=ssl BOUNCE_IMAP_USERNAME= BOUNCE_IMAP_PASSWORD= # Signatur der Bounce-Referenz X-Pk-Ref (Audit 29.09.2026, R-04). Leer = aus # APP_KEY abgeleitet. Ein Wechsel entwertet nur Signaturen bereits versendeter # Mails (deren Rückläufer zählen dann weich). BOUNCE_SIGNING_KEY= # Bounce OHNE Signatur (hart wie weich): policy = nur protokollieren (sicher, # Standard); soft = zählt auf den Schwellwert und ist damit fälschbar. BOUNCE_UNSIGNED_KIND=policy # Aufbewahrung der Rückläufer-Ereignisse (email_bounces) in Tagen; gelöscht von # conversion:purge-events. Die Sperrliste bleibt. BOUNCE_RETENTION_DAYS=395 AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false VITE_APP_NAME="${APP_NAME}" # Lokaler Vite-Dev-Server (dual-port Setup, siehe VITE-SETUP.md). VITE_DEV_SERVER_URL=https://assets.pressekonto.test # --------------------------------------------------------------------------- # Stripe / Billing (Laravel Cashier) # Prod: Live-Keys + Live-Preis-IDs eintragen [EXTERN: R1.2]. # --------------------------------------------------------------------------- STRIPE_KEY= STRIPE_SECRET= STRIPE_WEBHOOK_SECRET= # Stripe-Preis-ID des Einzelkaufs (eine PM, 19 €). STRIPE_PRICE_SINGLE_PM= CASHIER_CURRENCY=eur CASHIER_CURRENCY_LOCALE=de_DE # Umsatzsteuer/Rechnungsangaben. # BILLING_VAT_RATE=0.19 # BILLING_DEFAULT_CURRENCY=EUR # BILLING_MANUAL_DUE_DAYS=14 BILLING_OWN_VAT_ID= # Abo-/Bestandsschutz-Gate (WS-5). Default (auch ohne Env-Key) ist true: # Einreichen zur Prüfung erfordert ein aktives Abo, einen bezahlten Einzelkauf # oder Bestandsschutz (grandfathered) — siehe User::hasActiveBooking(). # Nur für lokale Entwicklung bewusst auf false setzen (Gate offen für alle). BILLING_ENFORCE_BOOKING=true # --------------------------------------------------------------------------- # KI: Klassifikation (Red-Flag-Gate) + Content-Score (config/scoring.php). # Ohne OPENAI_API_KEY laufen die Jobs nicht — Queue-Worker erforderlich. # --------------------------------------------------------------------------- OPENAI_API_KEY= # OPENAI_API_URL= # OPENAI_MODEL= # OPENAI_TIMEOUT=30 # CLASSIFICATION_PROVIDER=openai # CLASSIFICATION_MODEL= # CLASSIFICATION_TIMEOUT=15 # CLASSIFICATION_GREEN_DELAY=0 # CLASSIFICATION_YELLOW_MANUAL=true # CONTENT_SCORE_PROVIDER=openai # CONTENT_SCORE_MODEL= # CONTENT_SCORE_TIMEOUT=30 # CONTENT_SCORE_HOCHWERTIG=80 # CONTENT_SCORE_GEPRUEFT=60 # --------------------------------------------------------------------------- # Newsletter-Sync (config/newsletter.php). Provider `placeholder` bindet den # Null-Client; enabled=true mit anderem Provider wirft bewusst, bis eine # echte Anbindung implementiert ist. # --------------------------------------------------------------------------- NEWSLETTER_SYNC_ENABLED=false NEWSLETTER_SYNC_PROVIDER=placeholder NEWSLETTER_SYNC_ENDPOINT= NEWSLETTER_SYNC_API_KEY= # NEWSLETTER_SYNC_TIMEOUT=10 # Drosselung interner Newsletter-Kampagnen: Wellen à batch_size Mails im # Abstand von batch_interval_minutes (SMTP-Limit/Spam-Schutz). # NEWSLETTER_CAMPAIGN_BATCH_SIZE=50 # NEWSLETTER_CAMPAIGN_BATCH_INTERVAL_MINUTES=15 # Kampagnen-Versand freischalten (E9-Schalter, Audit 29.09.2026). Standard # aus, bis U05–U07 umgesetzt sind; Entwürfe, Test-Mails und Abmeldung gehen # immer. NEWSLETTER_SENDING_ENABLED=false # Google-Login (Laravel Socialite). Die Redirect-URI muss in der Google Cloud # Console EXAKT der Callback-URL der Portal-Domain entsprechen (Login läuft auf # dem Portal-Host, nicht zwingend APP_URL). Prod: https://pressekonto.com/... # Hinweis: Google akzeptiert keine .test-Domains – lokal nur localhost oder ein # https-Tunnel; der echte Round-Trip wird auf Staging/Live getestet. GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= GOOGLE_REDIRECT_URI=https://pressekonto.com/auth/google/callback # Empfänger des öffentlichen Kontaktformulars je Brand. Ohne Wert fällt der # Versand auf MAIL_FROM_ADDRESS zurück. [EXTERN: echte Adressen eintragen] CONTACT_EMAIL_PRESSEKONTO= CONTACT_EMAIL_PRESSEECHO= CONTACT_EMAIL_BUSINESSPORTAL= # Depublikation (T12): Netto-Preis in Cent fuer die freiwillige Entfernung # einer veroeffentlichten PM aus der oeffentlichen Ansicht (Tombstone bleibt). # Default 3500 (35 EUR netto, Entscheidung O6 vom 06.07.2026); 0 deaktiviert. BILLING_DEPUBLICATION_PRICE_CENTS=3500 # Selbst gehostete Umami-Webanalyse (sys.adametz.media; IDs je Brand in # config/domains.php). Erst beim Go-Live der Webseiten auf true setzen — # die Datenschutzerklärung (Abschnitt 5) beschreibt den Einsatz bereits. UMAMI_ENABLED=false # Kundenbereich und Zuordnung zur User-ID getrennt (Monitoring-Plan M6) — # erst nach Ergänzung der Datenschutzerklärung einschalten. UMAMI_PORTAL_ENABLED=false UMAMI_IDENTIFY_USERS=false # Haupt-E-Mail für alle rechtlichen Anliegen (Impressum, Datenschutz, AGB, # Meldeverfahren, Richtlinien) — auf allen drei Domains identisch. # Ohne Wert gilt der Default info@pressekonto.com (config/legal.php). LEGAL_CONTACT_EMAIL= # Optionales separates DSA-Melde-Postfach je Brand (Impressum + /melden). # Ohne Wert fällt die Anzeige auf LEGAL_CONTACT_EMAIL zurück. REPORT_EMAIL_PRESSEKONTO= REPORT_EMAIL_PRESSEECHO= REPORT_EMAIL_BUSINESSPORTAL= # Crawler-Abruf-Protokoll (Roadmap 1c.0): Tag, ab dem Abrufe durch Such- und # KI-Dienste je Meldung erfasst werden — auf den Deploy-Tag setzen. CRAWLER_HITS_RECORDED_SINCE=2026-09-18 # Abruf-Protokoll der RSS-Feeds (Roadmap 3.1): beim Deploy auf den Deploy-Tag setzen. FEED_FETCHES_RECORDED_SINCE=2026-09-21 # Google Search Console, URL Inspection API (Roadmap 1c.4). Läuft nur mit # Service-Konto (JSON-Schlüssel außerhalb von public/), das in beiden # Properties als Nutzer eingetragen ist. Kundenansicht bleibt zu (E8). GSC_ENABLED=false GSC_SERVICE_ACCOUNT_FILE= GSC_PROPERTY_PRESSEECHO=sc-domain:presseecho.de GSC_PROPERTY_BUSINESSPORTAL24=sc-domain:businessportal24.com GSC_DAILY_BUDGET=300 GSC_CUSTOMER_VISIBLE=false # Transparenzseite „kostenlos veröffentlichen": Prüfdatum der Portalliste # (Einträge in config/transparency.php). Leer = Abschnitt erscheint nicht. TRANSPARENCY_FREE_PORTALS_CHECKED_AT= # Doppelveröffentlichung (Roadmap Anhang 2, 1c.8): zweite Fassung verweist per # rel=canonical auf die Erstquelle, Zuordnung je Kategorie in config/canonical.php # (E9, entschieden 18.09.2026 — Standard an). Aus = jede Fassung bleibt ihr # eigenes Canonical. ACHTUNG Reihenfolge beim ersten Deploy: migrate → # press-releases:hash-content → press-releases:assign-canonicals. CANONICAL_ASSIGNMENT_ENABLED=true CANONICAL_FALLBACK=first # Anmeldelinks „Diesen Newsroom verwalten" je Newsroom und Tag (nur versendete # zählen). Audit 29.09.2026, R-09: 3 → 5. NEWSROOM_CLAIM_LINKS_PER_DAY=5 # API-Zuordnung neuer Firmen zu einem bestehenden Newsroom (Roadmap 1a.4, # Audit 29.09.2026, R-01): nur für diese User-IDs (kommagetrennt, z. B. das # connektar-Konto) — sonst nur, wenn der Nutzer der Firma schon angehört. # Leer = keine Freischaltung. NEWSROOM_API_ASSIGNMENT_USER_IDS= # --- Bildkennzeichnung (Formular v2) und Beweisarchiv (Block F) --- # IMAGE_RIGHTS_V2: Formular v2 im Bildmanager und in der API; false = Verhalten wie vor der Umstellung. IMAGE_RIGHTS_V2=false # Eigener Schlüssel für die IP-Ableitung im Bestätigungsprotokoll (Fallback APP_KEY). CONFIRMATION_IP_KEY= # Beweisarchiv: eigener Schlüssel (php artisan archive:key), getrennt sichern — ohne ihn ist das Archiv unlesbar. ARCHIVE_KEY= ARCHIVE_PREVIOUS_KEYS= ARCHIVE_RETENTION_YEARS=3 ARCHIVE_QUARANTINE_DAYS=30 ARCHIVE_SWEEP_PAUSED=false # Zustimmungsgate vor jeder Einreichung (Block G) — erst mit AGB v0.7 einschalten. LEGAL_ACCEPTANCE_GATE=false # IMAGE_PRECHECK: KI-Vorab-Check für Titelbilder (Sichtung auf offensichtliche Probleme, Block K). # Erst nach AVV mit dem Anbieter und DSE-Absatz einschalten. STAGE 1 = nur Stock-Wasserzeichen, 2 = alle Kategorien. IMAGE_PRECHECK=false IMAGE_PRECHECK_STAGE=1 # IMAGE_PRECHECK_MODEL= # IMAGE_PRECHECK_DOWNGRADE= # Proxy-Vertrauen: leer = keinem Proxy (Live, nginx direkt). Lokal ohne Angabe `*` (Traefik). # Steht ein Proxy/CDN davor, dessen Adressbereiche kommagetrennt eintragen. # TRUSTED_PROXIES= # HSTS: ohne Angabe nur bei APP_ENV=production an, max-age 1 Jahr. # SECURITY_HSTS= # SECURITY_HSTS_MAX_AGE=31536000