Der Weg ueber die TikTok-Datei des Creators ist entfernt

Filipe, mit den drei Knoepfen im Bild: "ich will nur dass wir manager
scouts, dogfather oder spicy sachen eintragen koennen und nicht die
creator. ich will keine daten von denen kriegen, nur wir."

Gebaut am Vormittag, am Nachmittag wieder ausgebaut. Der Weg war
technisch in Ordnung -- und er war der einzige, bei dem ein CREATOR uns
etwas gibt: seine eigene Datenkopie aus der TikTok-App. Genau das soll
nicht sein. Es bleiben die beiden Wir-Wege: die eigene Datei und die
Backstage-Tabelle der Agentur.

VOLLSTAENDIG ENTFERNT, NICHT VERSTECKT:
- beide Schnittstellen (/tiktok-datei und /tiktok-datei/vorschau)
- der Leser workspace-tiktok-datei.js (263 Zeilen)
- Knopf, Fenster, Dateiauswahl, Vorschau, Stilregeln
- der fertige Text, der einen Creator um seine Daten bittet
- der Erklaersatz unter der Knopfreihe

Ein Weg, der nur unsichtbar ist, ist weiterhin ein Weg -- wer die
Adresse kennt, benutzt ihn. Und eine Bitte an einen Creator um seine
Daten soll in diesem Haus nirgends mehr stehen, auch nicht in einem
Fenster, das niemand oeffnet.

GEPRUEFT WIRD JETZT DIE ABWESENHEIT, an drei Stellen: Knopf weg,
Fenster weg, und die Schnittstelle antwortet DOGFATHER mit 404 -- dem
staerksten Zugang, den es gibt. Bekommt er 404, bekommt ihn jeder.
Daneben die Gegenprobe, dass der Backstage-Weg weiterhin mit 200
antwortet; sonst bewiese das 404 nur einen Tippfehler.

pruef-tiktok-datei.mjs (47 Pruefungen) faellt mit dem Weg weg. Die
Zahl sinkt dadurch, und das ist hier richtig: Sie pruefte etwas, das
es nicht mehr gibt. Was bleibt, sind sechs Pruefungen, die das
Fehlen sichern -- pruef-backstage-import 63 -> 66.

NEBENBEI GEDREHT, NICHT GELOESCHT: pruef-leistung-optik behauptete
noch die Regel vom 07.09. ("beim Manager fehlt die Kachel", "die Seite
weist den Creator ab"). Beide Aussagen sind jetzt umgekehrt und messen
zusaetzlich, was vorher niemand gemessen hat: dass die Creatorin auf
der Zahlen-Seite ihre EIGENEN Zahlen sieht und trotzdem keinen
einzigen Knopf zum Eintragen hat -- beides zusammen, denn "keine
Knoepfe" waere auch auf einer leeren Seite wahr. 56 -> 59.

Nicht von mir, nachgemessen gegen den Stand ohne diese Aenderungen:
pruef-struktur meldet dieselben 6 Fehler (crew-index/teamlage nicht
verlinkt, start.css 348 KB, totes CSS .nase, UTC-Datum).

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-11 15:02:21 +02:00
co-authored by Claude Opus 5
parent b34586be91
commit 14ed467928
31 changed files with 427 additions and 1262 deletions
+17 -127
View File
@@ -47,7 +47,6 @@ import {
db, protokolliere, echteIp, sitzungLesen, istLeitung,
sichtbareCreatorIds, ROLLEN_SORTIERUNG, heuteLokal,
} from "./workspace.js";
import { kandidatenFinden, listeAmPfad, zuTagen } from "./workspace-tiktok-datei.js";
export const leistungRouter = express.Router();
@@ -870,137 +869,28 @@ leistungRouter.post("/workspace/api/leistung/netzwerk-import", gleicheHerkunft,
});
/* =====================================================================
DIE EIGENE TIKTOK-DATEI EINES CREATORS (11.09.2026)
DER WEG UEBER DIE TIKTOK-DATEI IST ENTFERNT (11.09.2026)
Der letzte verbliebene Weg aus dem Plan vom 10.09.: Login Kit und
Datenportabilitäts-API hängen beide an einem TikTok-Entwicklerkonto,
und das wird es nicht geben ("hab ich nicht und werd ich nicht
bekommen"). Dieser hier braucht keines -- der Creator lädt seine
eigenen Daten bei TikTok herunter und gibt die Datei her.
Gebaut am 11.09. vormittags, am selben Tag wieder ausgebaut. Filipe,
mit den drei Knoepfen im Bild: *"ich will nur dass wir manager
scouts, dogfather oder spicy sachen eintragen koennen und nicht die
creator. ich will keine daten von denen kriegen, nur wir."*
Das Suchen und Umrechnen steht in workspace-tiktok-datei.js; hier
stehen nur die beiden Wege und die Rechte.
Der Weg war technisch einwandfrei -- und er war der einzige, bei dem
ein CREATOR uns etwas gibt: seine eigene Datenkopie aus der
TikTok-App. Genau das soll nicht sein. Es bleiben die beiden
Wir-Wege: die eigene Datei und die Backstage-Tabelle der Agentur.
DIE DATEI WIRD NICHT GESPEICHERT. Sie wird gelesen, ausgewertet und
fällt danach weg. In ihr stehen auch Direktnachrichten und der
Ansehverlauf -- das ist nichts, was auf einem Server liegen soll,
der es nicht braucht.
VOLLSTAENDIG ENTFERNT, nicht nur versteckt: Schnittstellen, Leser
(workspace-tiktok-datei.js), Knopf, Fenster und der fertige Text an
den Creator. Ein Weg, der nur unsichtbar ist, ist weiterhin da --
wer die Adresse kennt, benutzt ihn. Und ein Text, der einen Creator
um seine Daten bittet, soll in diesem Haus nirgends mehr stehen.
WAS WIR DAMIT NICHT MEHR WISSEN: nichts, was Backstage nicht auch
sagt. Die Datei war die zweite Quelle (COALESCE), nie die erste.
===================================================================== */
leistungRouter.post("/workspace/api/leistung/:creatorId/tiktok-datei/vorschau",
gleicheHerkunft, express.json({ limit: "60mb" }), (req, res) => {
try {
const creatorId = Number(req.params.creatorId);
if (!Number.isInteger(creatorId)) return res.status(400).json({ fehler: "ungueltig" });
if (!darfEintragen(req.person)) return res.status(403).json({ fehler: "nicht_erlaubt" });
if (!darfSehen(req.person, creatorId)) return res.status(404).json({ fehler: "nicht_gefunden" });
const inhalt = req.body?.inhalt;
if (!inhalt || typeof inhalt !== "object") {
return res.status(400).json({ fehler: "Das ist keine gelesene JSON-Datei." });
}
const kandidaten = kandidatenFinden(inhalt);
if (!kandidaten.length) {
return res.status(400).json({
fehler: "In dieser Datei steht keine Liste mit Datumsangaben. "
+ "Wurde beim Herunterladen wirklich JSON gewählt (nicht TXT) und "
+ "„Alles auswählen“ angehakt?",
});
}
/* Zu jedem Vorschlag gleich zeigen, was dabei herauskäme -- sonst
muss der Mensch aus Schlüsselnamen raten, welcher der richtige
ist. */
const mitVorschau = kandidaten.map((k) => {
const { tage } = zuTagen(k.beispiele.length ? listeAmPfad(inhalt, k.pfad) || [] : [], k.vorschlag);
return {
...k,
tage_gesamt: tage.length,
tage_beispiel: tage.slice(-3),
/* Die Beispielzeilen gekürzt: In einem Vollarchiv hängt an
einem Eintrag manchmal ein ganzer Kommentartext. */
beispiele: k.beispiele.map((b) => {
const klein = {};
for (const [s, w] of Object.entries(b)) klein[s] = String(w ?? "").slice(0, 80);
return klein;
}),
};
});
res.json({ kandidaten: mitVorschau });
} catch (fehler) {
console.error("[leistung] TikTok-Datei Vorschau:", fehler?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
leistungRouter.post("/workspace/api/leistung/:creatorId/tiktok-datei",
gleicheHerkunft, express.json({ limit: "60mb" }), (req, res) => {
try {
const creatorId = Number(req.params.creatorId);
if (!Number.isInteger(creatorId)) return res.status(400).json({ fehler: "ungueltig" });
if (!darfEintragen(req.person)) return res.status(403).json({ fehler: "nicht_erlaubt" });
if (!darfSehen(req.person, creatorId)) return res.status(404).json({ fehler: "nicht_gefunden" });
const inhalt = req.body?.inhalt;
const pfad = String(req.body?.pfad || "");
const zuordnung = req.body?.zuordnung;
if (!inhalt || !pfad || !zuordnung?.tag) {
return res.status(400).json({ fehler: "Es fehlt die Auswahl, was gelesen werden soll." });
}
const liste = listeAmPfad(inhalt, pfad);
if (!liste) return res.status(400).json({ fehler: "Diese Liste gibt es in der Datei nicht." });
const { tage, uebersprungen } = zuTagen(liste, zuordnung);
const heute = heuteLokal();
const brauchbar = tage.filter((t) => t.tag <= heute
/* Ein Tag ohne eine einzige Zahl ist keine Messung. Dieselbe
Regel wie beim Backstage-Import. */
&& (t.dauer_min !== null || t.diamanten !== null || t.zuschauer_max !== null));
if (!brauchbar.length) return res.status(400).json({ fehler: "keine_brauchbaren_tage" });
const d = db();
const schreiben = d.prepare(`
INSERT INTO leistung
(creator_id, tag, diamanten, dauer_min, gueltiger_tag, zuschauer_max,
erfasst, erfasst_von, quelle)
VALUES (?,?,?,?,?,?,?,?,'import')
ON CONFLICT(creator_id, tag) DO UPDATE SET
/* NUR FÜLLEN, NICHT ÜBERSCHREIBEN.
Anders als beim Backstage-Import, der die Wahrheit der
Agentur bringt: Diese Datei kommt vom Creator und ist eine
ZWEITE Quelle. Wo schon eine Zahl steht -- von Hand
eingetragen oder aus Backstage --, bleibt sie stehen.
Andersherum würde ein Dateiupload stillschweigend die
offiziellen Zahlen ersetzen, und niemand wüsste hinterher,
welche gilt. */
diamanten = COALESCE(leistung.diamanten, excluded.diamanten),
dauer_min = COALESCE(leistung.dauer_min, excluded.dauer_min),
zuschauer_max = COALESCE(leistung.zuschauer_max, excluded.zuschauer_max),
gueltiger_tag = MAX(leistung.gueltiger_tag, excluded.gueltiger_tag)`);
let geschrieben = 0, ergaenzt = 0;
const vorhanden = d.prepare("SELECT 1 FROM leistung WHERE creator_id = ? AND tag = ?");
d.exec("BEGIN");
try {
for (const t of brauchbar) {
const gabEs = !!vorhanden.get(creatorId, t.tag);
schreiben.run(creatorId, t.tag, t.diamanten, t.dauer_min,
(t.dauer_min ?? 0) > 0 ? 1 : 0, t.zuschauer_max,
new Date().toISOString(), req.person.id);
if (gabEs) ergaenzt++; else geschrieben++;
}
d.exec("COMMIT");
} catch (f) { d.exec("ROLLBACK"); throw f; }
protokolliere("leistung_tiktok_datei", {
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
detail: `Creator #${creatorId}: ${geschrieben} neu, ${ergaenzt} ergaenzt`.slice(0, 120),
});
res.json({ geschrieben, ergaenzt, uebersprungen: uebersprungen.length });
} catch (fehler) {
console.error("[leistung] TikTok-Datei:", fehler?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
/** Vorschau: Was WÜRDE passieren? Schreibt nichts. */
leistungRouter.post("/workspace/api/leistung/:creatorId/import/vorschau", gleicheHerkunft,