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).
46 lines
1.3 KiB
Go
46 lines
1.3 KiB
Go
package web
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestComputeInsightsReminderOnlyForStory(t *testing.T) {
|
|
now := time.Now()
|
|
r := computeInsightsReminder("feed", now.Add(-time.Hour), now, false)
|
|
if r.Show {
|
|
t.Errorf("expected no reminder for a non-story post type, got %+v", r)
|
|
}
|
|
}
|
|
|
|
func TestComputeInsightsReminderSkippedWhenAlreadySecured(t *testing.T) {
|
|
now := time.Now()
|
|
r := computeInsightsReminder("story", now.Add(-time.Hour), now, true)
|
|
if r.Show {
|
|
t.Errorf("expected no reminder once an insights asset already exists, got %+v", r)
|
|
}
|
|
}
|
|
|
|
func TestComputeInsightsReminderUrgentWithinWindow(t *testing.T) {
|
|
now := time.Now()
|
|
r := computeInsightsReminder("story", now.Add(-2*time.Hour), now, false)
|
|
if !r.Show || !r.Urgent || r.Expired {
|
|
t.Fatalf("expected an urgent, non-expired reminder, got %+v", r)
|
|
}
|
|
}
|
|
|
|
func TestComputeInsightsReminderExpiredAfterWindow(t *testing.T) {
|
|
now := time.Now()
|
|
r := computeInsightsReminder("story", now.Add(-25*time.Hour), now, false)
|
|
if !r.Show || !r.Expired || r.Urgent {
|
|
t.Fatalf("expected an expired reminder, got %+v", r)
|
|
}
|
|
}
|
|
|
|
func TestComputeInsightsReminderSkippedWithoutPublishTime(t *testing.T) {
|
|
r := computeInsightsReminder("story", time.Time{}, time.Now(), false)
|
|
if r.Show {
|
|
t.Errorf("expected no reminder without a known publish time, got %+v", r)
|
|
}
|
|
}
|