Ausgangspunkt: Instagram hält Story-Insights nach eigener Aussage nur
24 Stunden vor, auch der offizielle Datenexport enthält sie nicht mehr
danach. Der Standbild-Screenshot beim Prüfen entsteht direkt beim
Veröffentlichen, bevor nennenswerte Kennzahlen existieren — er kann
das strukturell nicht auffangen. Eine OAuth-Anbindung allein löst das
auch nicht: selbst mit API-Zugriff bräuchte es einen Abruf innerhalb
desselben 24h-Fensters.
- Migration 0007: asset.purpose ('initial' | 'insights', Default
'initial' erhält die Bedeutung aller Bestandszeilen). Ein Beitrag
kann jetzt mehrere Insights-Nachweise über die Zeit bekommen.
GetLatestAssetForSubmission berücksichtigt weiterhin nur 'initial',
damit ein späterer Insights-Upload nie den beim Archivieren
referenzierten Original-Screenshot verdrängt.
- internal/web/insights_reminder.go: computeInsightsReminder — reine,
ungetestete gegen echte Instagram-Daten, aber isoliert testbare
Logik fürs Erinnerungs-Timing (Produktentscheidung, keine Rechtsnorm,
daher nicht in rules/*.yaml).
- GET /beitraege/{id} zeigt die Erinnerung bei veröffentlichten
"story"-Beiträgen ohne existierendes insights-Asset; POST
/beitraege/{id}/insights speichert einen weiteren Screenshot (gleiche
Validierung wie das initiale Standbild, wiederverwendet über
readUploadedAsset/storeAsset mit purpose-Parameter).
- Bewusst nur In-App-Banner in dieser Ausbaustufe, kein Mail-/Push-
Versand — dafür fehlt aktuell ein SMTP-Relay/Versanddienst, siehe
CLAUDE.md-Hinweis dazu.
Volle Testsuite inkl. echter Postgres-Tests grün; End-to-End gegen
einen laufenden Server verifiziert (Story archivieren → Erinnerung
sichtbar → Insights-Upload → Erinnerung verschwindet, Nachweis
gelistet, Mandantentrennung beim Upload durchgesetzt).
48 lines
1.9 KiB
Go
48 lines
1.9 KiB
Go
package web
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// storyInsightsWindow ist das Zeitfenster, in dem Instagram nach
|
|
// eigener Aussage Story-Insights überhaupt vorhält — danach sind sie
|
|
// auch über den offiziellen Datenexport nicht mehr zu bekommen. Reine
|
|
// Produktentscheidung (Erinnerungs-Timing), keine Rechtsnorm — bewusst
|
|
// hier als Konstante und nicht in rules/*.yaml, das ist ausschließlich
|
|
// für die Kennzeichnungsprüfung reserviert (siehe CLAUDE.md).
|
|
const storyInsightsWindow = 24 * time.Hour
|
|
|
|
// insightsReminder beschreibt, ob und wie dringend eine Erinnerung
|
|
// angezeigt werden soll, die Kennzahlen (Insights) eines veröffentlichten
|
|
// Beitrags per Screenshot zu sichern, bevor sie unwiederbringlich
|
|
// verschwinden.
|
|
type insightsReminder struct {
|
|
Show bool
|
|
Urgent bool // Fenster läuft noch
|
|
Expired bool // Fenster ist wahrscheinlich schon vorbei
|
|
Message string
|
|
}
|
|
|
|
// computeInsightsReminder berechnet den Erinnerungsstatus. Nur für
|
|
// "story"-Beiträge relevant (siehe storyInsightsWindow); alle anderen
|
|
// Beitragstypen bekommen keine Erinnerung, da ihre Kennzahlen nicht auf
|
|
// dieselbe Art flüchtig sind.
|
|
func computeInsightsReminder(postType string, publishedAt time.Time, now time.Time, hasInsightsAsset bool) insightsReminder {
|
|
if postType != "story" || hasInsightsAsset || publishedAt.IsZero() {
|
|
return insightsReminder{}
|
|
}
|
|
elapsed := now.Sub(publishedAt)
|
|
if elapsed >= storyInsightsWindow {
|
|
return insightsReminder{
|
|
Show: true, Expired: true,
|
|
Message: "Das Zeitfenster für Story-Insights ist bei Instagram nach eigener Aussage abgelaufen (24 Stunden) — die Kennzahlen sind wahrscheinlich nicht mehr abrufbar.",
|
|
}
|
|
}
|
|
remainingHours := int((storyInsightsWindow - elapsed).Hours()) + 1
|
|
return insightsReminder{
|
|
Show: true, Urgent: true,
|
|
Message: fmt.Sprintf("Noch ca. %d Stunde(n), um die Story-Insights zu sichern, bevor sie bei Instagram verschwinden.", remainingHours),
|
|
}
|
|
}
|