fix(api): Log-Flut begrenzen und Appwrite-Fehler strenger behandeln

- Kein Zugriffsprotokoll je Anfrage mehr (abgewiesene Anfragen an das
  unauthentifizierte /api/melden loggten sonst unbegrenzt); nur noch
  Ereignis- und 5xx-Zeilen, höchstens 120 pro Minute mit Sammelzeile
- Compose: logging json-file, max-size 5m, max-file 2
- appwrite.js: 404 nur mit Typ row_not_found/storage_file_not_found als
  "fehlt", listRows ohne rows-Array wirft, redirect: error
- Appwrite-Fehler: 502 bei 0/429/5xx, sonst 500 "Interner Fehler."
- Veröffentlichen legt beide Dateien auf die sichtbaren Rechte fest
  (erst nach dem Anlegen der Zeile, Rollback bei Fehler)
- setFilePermissions mit Promise.allSettled, gemeinsamer safeToken-Helfer
- Tests: 85 (Log-Flut, Log-Budget, 404-Typen, Auth-Header, Konto-Antworten)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-04 14:24:05 +00:00
1 parent dd1597862a
commit cd55d4c891
8 files changed
+423 -31

No files matched your search

+11 -1
View File
@@ -16,6 +16,8 @@
const http = require('node:http');
const BUCKETS = ['gallery-images', 'card-images'];
const COLUMNS = {
gallery: {
title: { size: 60, required: true },
@@ -49,6 +51,11 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
users.set(jwt, { $id: id, email: `${id}@example.test`, labels });
}
/** Beliebige Konto-Antwort für `GET /account` (z. B. ohne labels oder mit ungültiger ID). */
function addRawUser(jwt, account) {
users.set(jwt, account);
}
function addFile({ id, bucket = 'gallery-images', owner, permissions, mimeType = 'image/png', size = 1000 }) {
files.set(id, {
$id: id,
@@ -157,7 +164,8 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
// Zeilen
if (segments[1] === 'tablesdb' && segments[3] === 'tables' && segments[5] === 'rows') {
const table = segments[4];
if (segments[2] !== database || !tables[table]) return error(404, 'table_not_found');
if (segments[2] !== database) return error(404, 'database_not_found');
if (!tables[table]) return error(404, 'table_not_found');
const store = tables[table];
if (segments.length === 6 && req.method === 'POST') {
@@ -200,6 +208,7 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
// Dateien
if (segments[1] === 'storage' && segments[2] === 'buckets' && segments[4] === 'files' && segments.length === 6) {
if (!BUCKETS.includes(segments[3])) return error(404, 'storage_bucket_not_found');
const file = files.get(segments[5]);
if (!file) return error(404, 'storage_file_not_found');
if (req.method === 'GET') return reply(200, file);
@@ -229,6 +238,7 @@ async function startFakeAppwrite({ project = 'proj-test', key = 'KEY-test-secret
key,
calls,
addUser,
addRawUser,
addFile,
addRow,
failNext,