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).
86 lines
2.7 KiB
HTML
86 lines
2.7 KiB
HTML
{{define "beitrag"}}<!doctype html>
|
|
<html lang="de">
|
|
<head>{{template "head" .}}</head>
|
|
<body>
|
|
{{template "nav" .Nav}}
|
|
<div class="page">
|
|
<p><a href="/beitraege">← Alle Beiträge</a></p>
|
|
<h1>{{.Platform}} · {{.PostType}}</h1>
|
|
<p class="hinweis">Angelegt am {{.CreatedAt}} — Status: <span class="status status-{{.Status}}">{{.Status}}</span></p>
|
|
<p>{{.Caption}}</p>
|
|
|
|
<h2>Findings</h2>
|
|
{{if .Findings}}
|
|
<ul class="findings">
|
|
{{range .Findings}}
|
|
<li class="finding finding-{{.Severity}}">
|
|
<strong>{{.RuleID}} v{{.Version}}</strong> ({{.Severity}}) — {{.Title}}
|
|
<p>Korrektur: {{.Fix}}</p>
|
|
{{if .Sources}}
|
|
<p>Fundstellen: {{range $i, $s := .Sources}}{{if $i}}; {{end}}{{$s}}{{end}}</p>
|
|
{{end}}
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
{{else}}
|
|
<p class="keine-findings">Keine Kennzeichnungsrisiken nach aktuellem Regelwerk gefunden.</p>
|
|
{{end}}
|
|
|
|
{{if .CanArchive}}
|
|
<form hx-post="/veroeffentlichen" hx-target="#archiv-ergebnis" hx-swap="innerHTML">
|
|
<input type="hidden" name="submission_id" value="{{.SubmissionID}}">
|
|
<button type="submit">Als veröffentlicht markieren & archivieren</button>
|
|
</form>
|
|
<div id="archiv-ergebnis"></div>
|
|
{{end}}
|
|
{{if .IsPublished}}
|
|
<p><a href="{{.DossierURL}}">Nachweis-Dossier (PDF) herunterladen</a></p>
|
|
|
|
{{if .InsightsReminder.Show}}
|
|
<div class="{{if .InsightsReminder.Expired}}fehler{{else}}rueckfrage{{end}}">
|
|
<p>{{.InsightsReminder.Message}}</p>
|
|
<form method="post" action="/beitraege/{{.SubmissionID}}/insights" enctype="multipart/form-data">
|
|
<label for="insights_standbild">Insights-Screenshot</label>
|
|
<input type="file" id="insights_standbild" name="insights_standbild" accept="image/*" required>
|
|
<button type="submit">Insights jetzt sichern</button>
|
|
</form>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{if .InsightsAssets}}
|
|
<h2>Gesicherte Insights-Nachweise</h2>
|
|
<ul class="beteiligte">
|
|
{{range .InsightsAssets}}
|
|
<li class="beteiligter">
|
|
<div class="beteiligter-kopf">{{.CreatedAt}} — SHA-256: {{.SHA256}}</div>
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
{{end}}
|
|
{{end}}
|
|
|
|
<h2>Verantwortungsmatrix</h2>
|
|
{{template "beteiligte-liste" .}}
|
|
|
|
<form hx-post="/beitraege/{{.SubmissionID}}/beteiligte" hx-target="#beteiligte" hx-swap="outerHTML">
|
|
<label for="role">Rolle</label>
|
|
<select id="role" name="role" required>
|
|
<option value="creator">Creator</option>
|
|
<option value="agentur">Agentur</option>
|
|
<option value="marke">Marke</option>
|
|
<option value="kanzlei">Kanzlei</option>
|
|
</select>
|
|
<label for="name">Name</label>
|
|
<input type="text" id="name" name="name" required>
|
|
<button type="submit">Beteiligten hinzufügen</button>
|
|
</form>
|
|
|
|
<p class="disclaimer">
|
|
Diese Prüfung ist keine Rechtsberatung und ersetzt keine anwaltliche
|
|
Prüfung im Einzelfall.
|
|
</p>
|
|
</div>
|
|
</body>
|
|
</html>
|
|
{{end}}
|