TIWAG Business-Hub

    Erste Bugfix Methode: 

    - Laravel Log lokal herunterladen
    - Ins Claude werfen
    - Fragen wo das Problem

    Es gibt drei Instanzen: 

    DEV - https://businesshub.bakehouse.dev/
    TEST - https://businesshub.bakehouse.at/
    PROD - https://businesshub.tiwag.at/

    1. Anmeldung mit ITC

    Wir haben Test User Dev und Prod im Bitwarden. 

    OpenID Connect gegen den TIWAG-internen ITC-Identity-Provider.
    Kein Socialite, sondern direkt League\OAuth2\Client\Provider\GenericProvider.

    Flow (4 Schritte):

    1. User → /auth/redirect → ITC zeigt Login-Seite.
    2. ITC → /auth/callback mit Auth-Code.
    3. App tauscht Code gegen Token, holt User-Info.
    4. User wird in DB angelegt/aktualisiert, PSI-Verträge werden geladen, Redirect ins Dashboard.

    Rollen-Check

    • Pflicht-Rolle im ITC-Token: PSI_MARKET (OpenIDController.php:49)
    • Fehlt sie → User landet auf auth.nopsiclient-View, kann nichts machen.

    User-Felder im OIDC-Token

    sub, name, email, customernumber[], roles[]. Werden in users.sub (eindeutige OIDC-ID), users.name, users.email, users.clients (JSON-Array), users.contracts (JSON-Array) gespeichert.

    Login ohne Customer-Number erlaubt

    Heißt: User ohne Kundennummer im ITC-Token können sich einloggen, sehen aber keine PSI-Daten. Wenn ein User meldet "ich seh keine Verträge mehr", war das nicht ein Regression — das ist Absicht für Mitarbeiter ohne Kundenrolle.

    Schnell-Troubleshoot

    SymptomWo nachschauen
    User landet auf nopsiclientITC hat dem User die PSI_MARKET-Rolle nicht zugewiesen
    User eingeloggt, aber keine Verträgeusers.clients in DB checken — leeres Array? Dann fehlt customernumber im ITC-Token

     

    2. Filament Admin-Panel

    Was: Standard-Filament unter /admin

    Zugang

    • URL: /admin
    • Unsere TEst - User sind alle Admin

     

    3. PSI-Schnittstelle

    PSI hat alle Kundendaten. Dort rufen wir alles ab was wir anzeigen. 
    Was:
    REST-API zum TIWAG-PSI-Backend. Reine HTTP-GET-Calls ohne Auth-Header (PSI-Seite hat IP-Whitelist).
    5-Min-Cache. Keine Retries. PSI ist häufig instabil — der Code reagiert darauf, kann es aber nicht verhindern.

    3.1 Endpoints

    UmgebungBase-URL
    Devhttp://193.108.212.139:6502/psimarketrest/1
    Prodhttp://193.108.212.140:6502/psimarketrest/1

    Konfiguriert über .env:

    PSI_API_URL=http://193.108.212.140:6502/psimarketrest/1
    PSI_CACHE_MINUTES=5

    Eingelesen in config/services.php Z. 37–40 → PsiService.php:23-27.

    Nach .env-Änderung: php artisan config:cache.

    3.2 Alle PSI-Methoden

    Alle Methoden in app/Services/PsiService.php. Caching-Pattern: Cache::remember("psi.{type}.{id}", $ttl, …).

    MethodePSI-EndpointZweck
    getCounterparts()/counterpart/{uid}Kundenliste (filtert 625502 raus)
    getContract($id)/contract/{contractId}Vertragsdetails + Produktmapping
    getContractIntervals()(lokal, nutzt getContract)Zeitintervalle aus Vertrag
    getMailSettings()(lokal)Mail-Settings für Stockprice
    getTransactions()/tranche/list/{contractId}Transaktionen / Tranchen
    getCounterpart($client)/counterpart/{client}Einzelne Kundendaten
    getStockYear($date)/stock/year?year=...Terminpreise pro Jahr
    fetchStockDayPrice()/stock/day?type&year&interval=100000Tagesstockpreise
    getStockComparisons()(nutzt fetchStockDayPrice)Stock-Vergleiche
    getCoverageMonthly()/coverage/{contract}/monthly?startdate=&enddate=Deckungsgrad monatlich
    getPrice()/price/{contractId}Energiepreise monatlich
    getPriceForFixed()/price/{contractId} (monat=0)Tarifierung Jahresfestwerte
    getRepresentative($id)(lokal + DB)Kundenbetreuer via SAP-ID
    getDeliveryPoints()/deliverypoint/list/{extnr2}Lieferpunkte

     

    3.4 Sonderfall Kundennummer 625502

    PsiService::getCounterparts() Z. 36–41 filtert die Kundennummer 625502 explizit raus. Das ist Manuels Privatkonto und bei unseren Test Usern hinterlegt  — die TIWAG kann dafür keinen PSI-Vertrag liefern, sonst gäbe es 500er. Das ist Absicht .und leider notwendig. 

    3.5 Troubleshooting (PSI ist häufig die Ursache, aber wir sind der Support)

    Goldene Regel: Erst Logs, dann curl, dann erst Code anschauen.

    A) Connection-Problem / Timeout / 503-Seite

    1. Logs: Suche nach RequestException oder Log::error("PSI request failed"…).
    2. PSI direkt anpingen:
      curl -m 5 -i http://193.108.212.140:6502/psimarketrest/1/counterpart/<irgendeine-clientid>
      • Antwortet PSI nicht → PSI ist down. Nicht unser Bug. Warten / TIWAG-PSI-Team informieren.
      • Antwortet PSI normal → unser Server kommt nicht raus (Firewall, Routing). DevOps fragen.

    B) "Kunde sieht keine / falsche Verträge"

    1. DB-Check: User::find($id)->clients und ->clients_additional. Beide leer → User hat im ITC keine Customernumber zugewiesen (siehe Abschnitt 1).
    2. Vertrag fehlt obwohl Kundennummer vorhanden:
      curl -m 5 http://193.108.212.140:6502/psimarketrest/1/contract/<contractId>
      PSI liefert leere/fehlerhafte Daten → PSI-Stammdaten-Problem, an TIWAG eskalieren.

    C) Falsche / fehlende Preisdaten

    1. Welcher Endpunkt?
      • Stock-Preise → /stock/year oder /stock/day (getStockYear / fetchStockDayPrice)
      • Coverage → /coverage/{contract}/monthly
      • Energiepreis → /price/{contractId}
    2. Stockpreis fehlt für ein Datum: fetchStockDayPrice() loggt Warnung wenn PSI das Datum nicht zurückgibt. Häufige Ursache: Trading-Holiday — siehe app/Services/StockExchangeHolidayService.php. Wenn TIWAG-Börsenfeiertag → erwartet leer.
    3. Coverage-Werte komisch: Datum-Range prüfen, manchmal liefert PSI inkonsistente startdate/enddate. Curl-Aufruf manuell vergleichen.


    4. E-Mail-Logik

    Templates werden als HTML via HTTP vom TIWAG Newsletter-System geholt geholt, Platzhalter ersetzt, dann mit DKIM signiert via SendHtmlEmailJob versendet.

    4.1 Architektur

    DateiZweck
    app/Jobs/SendHtmlEmailJob.php (Z. 17–58)Queued Job, verschickt HTML-Mail mit DKIM-Signatur via Symfony Mailer
    app/Services/EmailHtmlService.phpWrapper: holt Template, ersetzt Platzhalter, dispatched Job
    app/Services/DkimSignerService.phpDKIM RSA-SHA256, Domain tiwag.at, Selector bh-mail
    app/Services/ReportFailureNotifier.phpSchickt Fehler-Alerts an vertrieb.pfm@tiwag.at, manuel@cookis.at
    app/Services/StockExchangeHolidayService.phpTrading-Day-Check (Wochenende + Feiertage)

     

    4.2 Mail-Konfiguration

    • Versand über die Amazon-Server

    4.3 Was wird wann verschickt

    TriggerCodeTemplate-URL ausWann
    Stock-Daily-Report (Terminpreise)SendDailyStockEmails.phpstock_price.email_template_urlTäglich 07:00 
    außer an Feiertagen
    Spot-ReportsendSpotpriceReports()spot_price.email_template_urlVom Data-Hub extern getriggert (HTTP-Endpoint)
    Failure-AlertReportFailureNotifierWenn ein Report-Versand crasht

     


    4.6 Schnell-Troubleshoot

    SymptomWas prüfen
    Mail kommt nicht an1. Läuft php artisan queue:work?
    2. failed_jobs-Tabelle?
    Stock-Mail kam heute nicht1. Trading-Holiday?
    2. Wurde es vom Business-Hub getriggerred?
    "Vorlage konnte nicht geladen werden"Funktioniert die TIWAG Webseite


    Wenn gar nichts hilft

    Im Zweifel: nichts deployen, Issue auf Eis legen, bis Manuel zurück ist.
    Keine "schnellen Workarounds" in PSI-Mappings — das macht es danach nur schwerer.
    Zur not eine ältere Version einspielen.

    Der Business-Hub ist von unserer Seite eine der stabilsten Dinge die wir haben. Der Fehler kommt fast immer von außen.