Die SvelteKit-App liegt unter frontend/, das Backend unter backend/ als eigenständige PocketBase-Instanz mit Dockerfile, docker-compose und versioniertem Schema. - PocketBase-URL über PUBLIC_PB_URL konfigurierbar, Default bleibt die produktive Instanz https://api.stammtisch-hersbruck.de - Schema als Snapshot-Migration der sechs fachlichen Collections (users, teams, events, runs, riders, times), abgezogen von der produktiven Instanz. Verifiziert: ein Erststart gegen leere pb_data legt alle sechs an, Felder und API-Rules stimmen überein. - pb_data und pb_migrations als Bind-Mounts, damit Daten persistieren und im Admin-UI erzeugte Migrationen im Repo landen - Veraltete Dokumentation entfernt: pocketbase_schema.json nannte Collections (stages, results, organizers), die es nicht gibt Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
54 lines
1.8 KiB
TypeScript
54 lines
1.8 KiB
TypeScript
/**
|
|
* Test-Script: prüft was der PB_SUPERUSER_TOKEN tatsächlich darf.
|
|
* Aufruf: npx tsx scripts/test-token.ts
|
|
*/
|
|
import { readFileSync } from 'node:fs'
|
|
|
|
const env = readFileSync('.env', 'utf8').split('\n')
|
|
let lastKey = ''
|
|
for (const line of env) {
|
|
const m = line.match(/^([A-Z_]+)=(.*)$/)
|
|
if (m) {
|
|
process.env[m[1]] = m[2]
|
|
lastKey = m[1]
|
|
} else if (lastKey && line.length > 0) {
|
|
process.env[lastKey] = (process.env[lastKey] ?? '') + line
|
|
}
|
|
}
|
|
|
|
const TOKEN = process.env.PB_SUPERUSER_TOKEN ?? ''
|
|
const API = 'https://api.stammtisch-hersbruck.de'
|
|
|
|
// JWT-Payload dekodieren
|
|
const [, payloadB64] = TOKEN.split('.')
|
|
if (payloadB64) {
|
|
const payload = JSON.parse(Buffer.from(payloadB64, 'base64').toString('utf8'))
|
|
console.log('Token-Payload:', payload)
|
|
console.log('Token-Länge:', TOKEN.length)
|
|
}
|
|
|
|
async function tryEndpoint(label: string, path: string, init?: RequestInit) {
|
|
const res = await fetch(`${API}${path}`, {
|
|
...init,
|
|
headers: { Authorization: TOKEN, 'Content-Type': 'application/json', ...(init?.headers ?? {}) },
|
|
})
|
|
const text = await res.text()
|
|
console.log(`\n${label}: ${res.status}`)
|
|
try {
|
|
console.log(JSON.stringify(JSON.parse(text), null, 2).slice(0, 200))
|
|
} catch {
|
|
console.log(text.slice(0, 200))
|
|
}
|
|
}
|
|
|
|
await tryEndpoint('GET /api/collections', '/api/collections?perPage=1')
|
|
await tryEndpoint('GET /api/collections/_superusers', '/api/collections/_superusers')
|
|
await tryEndpoint('GET /api/collections/events', '/api/collections/events')
|
|
await tryEndpoint('POST /api/collections (Probe)', '/api/collections', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
name: '__probe_temp__',
|
|
type: 'base',
|
|
fields: [{ name: 'foo', type: 'text' }],
|
|
}),
|
|
})
|