尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
Furry-Community mit vertikalem Bilder-Feed (wie TikTok), Gallery, Personensuche, Profilen, Uploads, Likes, Folgen und Meldungen. Nur für Erwachsene: Profile werden nur mit einem Geburtsdatum angelegt, das 18+ ergibt. FSK-18-Bilder sind für alle unkenntlich, die sich nicht in unserem Discord verifiziert haben. Der Server schickt ihnen nur eine 16-Pixel-Vorschau, die verschwommen angezeigt wird — das echte Bild verlässt den Server nie, es lässt sich also auch nicht per Browser „entblurren“.檢視完整 README ↗
Furry-Community mit vertikalem Bilder-Feed (wie TikTok), Gallery, Personensuche, Profilen, Uploads, Likes, Folgen und Meldungen. Nur für Erwachsene: Profile werden nur mit einem Geburtsdatum angelegt, das 18+ ergibt.
FSK-18-Bilder sind für alle unkenntlich, die sich nicht in unserem Discord verifiziert haben. Der Server schickt ihnen nur eine 16-Pixel-Vorschau, die verschwommen angezeigt wird — das echte Bild verlässt den Server nie, es lässt sich also auch nicht per Browser „entblurren“.
Stack: TanStack Start (React 19, Router, Query), Tailwind v4, Better Auth, Postgres (Neon in Produktion, eingebettetes PGLite lokal), Deployment auf Vercel.
npm ci
npm run dev # http://localhost:8080 — ohne DATABASE_URL läuft PGLite im Speicher
| Befehl | Zweck |
|---|---|
npm run build | Produktions-Build + Datenbank-Migrationen (mit DATABASE_URL) |
npm run typecheck | TypeScript prüfen |
npm run lint | ESLint |
npm test | Unit-Tests |
migrations/ SQL-Schema, wird beim Build (Neon) bzw. Start (PGLite) angewendet
0001_auth.sql Better-Auth-Tabellen (nicht von Hand ändern)
0002_schema.sql profiles, posts, likes, follows + Beispieldaten
0003_reports.sql Meldungen zu Bildern
0004_fsk18.sql FSK-18-Markierung, Vorschaubild, Discord-Verknüpfung
public/seed/ Beispielbilder der Seed-Profile
src/routes/ Seiten (dateibasiertes Routing)
__root.tsx HTML-Gerüst, 18+-Abfrage, Provider
login.tsx Anmelden / Registrieren
impressum.tsx Impressum (Platzhalter ausfüllen!)
datenschutz.tsx Datenschutzerklärung (Vorlage)
_app.tsx App-Layout mit Navigation + Onboarding-Gate
_app/index.tsx „Für dich“-Feed
_app/explore.tsx Gallery + Profilliste
_app/upload.tsx Bild hochladen
_app/profile.tsx Eigenes Profil
_app/u.$handle.tsx Fremdes Profil
_app/settings.tsx Profil, Portrait, Hintergrund, FSK-18-Freischaltung, Abmelden
api/discord/ Discord-Login (start.ts), Rückkehr mit Rollenprüfung (callback.ts)
und der Verifizierungs-Bot (interactions.ts)
src/components/ UI-Bausteine (Feed-Karte, Grid, Viewer, Melden-Dialog, …)
src/lib/vela/ Fachlogik: Server-Funktionen, Typen, Alter, Hintergründe, Cache
discord.ts Discord-OAuth, Rollenprüfung und Nachprüfung per Bot
discord-bot.ts Verifizierungs-Bot: Panel, private Kanäle, Freischalten
src/lib/auth/ Better Auth + Middleware (vorkonfiguriert)
src/lib/db.ts Datenbankzugang (Neon oder PGLite)
Alle schreibenden Server-Funktionen in src/lib/vela/server.ts laufen über
authMiddleware und prüfen serverseitig, dass ein volljähriges Profil existiert.
Anmelden geht per E-Mail, Google und Discord. Die Vercel-Adresse der Seite wird automatisch erkannt; eine eigene Domain funktioniert ebenfalls.
| Variable | Inhalt |
|---|---|
BETTER_AUTH_SECRET | Pflicht. Zufälliger Schlüssel, mind. 32 Zeichen (z. B. von generate-secret.vercel.app/32). Ohne ihn gehen Anmeldungen zufällig verloren. |
SITE_URL | Empfohlen bei eigener Domain, z. B. https://furry-gallery.de |
GOOGLE_CLIENT_ID | optional: ist voreingestellt |
GOOGLE_CLIENT_SECRET | Google-Anmeldung |
Discord-Anmeldung nutzt dieselben DISCORD_CLIENT_ID / DISCORD_CLIENT_SECRET wie die
Verifizierung (siehe unten). Ein Anmelde-Button erscheint nur, wenn seine Zugangsdaten
gesetzt sind.
Google: In der Google Cloud Console
→ Anmeldedaten erstellen → OAuth-Client-ID → Webanwendung. Unter Autorisierte
Weiterleitungs-URIs https://DEINE-DOMAIN/api/auth/callback/google eintragen. Den
OAuth-Zustimmungsbildschirm auf Extern stellen und veröffentlichen, sonst können sich nur
Testnutzer*innen anmelden.
Discord: Im Developer Portal unter OAuth2 → Redirects zusätzlich
https://DEINE-DOMAIN/api/auth/callback/discord eintragen.
Euer Discord-Bot verifiziert Mitglieder und gibt ihnen eine Rolle (z. B. „18+ verifiziert“). Die Webseite prüft nur, ob jemand diese Rolle auf eurem Server hat.
https://DEINE-DOMAIN/api/discord/callback eintragen.DISCORD_BOT_TOKEN. Damit
prüft die Seite alle 6 Stunden nach, ob die Rolle noch da ist — wird sie entzogen, sind
die Bilder wieder gesperrt. Der Bot braucht dafür den Server Members Intent.| Variable | Inhalt |
|---|---|
DISCORD_CLIENT_ID | optional: Application ID (ist voreingestellt) |
DISCORD_CLIENT_SECRET | Client Secret |
DISCORD_GUILD_ID | optional: Server-ID (ist voreingestellt) |
DISCORD_VERIFIED_ROLE_ID | optional: Verifiziert-Rolle (ist voreingestellt) |
DISCORD_BOT_TOKEN | optional: Bot-Token für die Nachprüfung |
DISCORD_INVITE_URL | optional: Einladungslink, wird in den Einstellungen gezeigt |
DISCORD_REDIRECT_URI | optional: nur nötig, wenn die Domain automatisch falsch erkannt wird |
Tokens und Secrets niemals in den Code oder ins Repository schreiben — nur in Vercel.
Ein Discord-Konto kann nur ein Profil freischalten. Als FSK 18 markieren kann jedes Mitglied sein eigenes Bild; die Uploader*innen sehen ihre eigenen Bilder immer.
Der Bot läuft in der Webseite mit (Discord schickt Klicks und Befehle an
/api/discord/interactions) — es muss also kein eigener Bot-Prozess rund um die Uhr laufen.
/verify-panel (nur mit „Server verwalten“) postet das Panel mit Verifizieren-Button
in den Verifizierungs-Kanal.verify-<name>, den nur das
Mitglied, das Team und der Bot sehen. Pro Mitglied höchstens einer.Voreingestellt (in src/lib/vela/discord-bot.ts, per Umgebungsvariable änderbar):
| Was | ID | Variable zum Überschreiben |
|---|---|---|
| Server | 1553802179431899266 | DISCORD_GUILD_ID |
| Kanal für das Panel | 1553814568852136097 | DISCORD_VERIFY_CHANNEL_ID |
| Kategorie für Kanäle | 1553815320202973281 | DISCORD_VERIFY_CATEGORY_ID |
| Verifiziert-Rolle | 1553830873365872680 | DISCORD_VERIFIED_ROLE_ID |
| Application ID | 1553811273165307995 | DISCORD_CLIENT_ID |
| Public Key | 5e09597b…405b889b05 | DISCORD_PUBLIC_KEY |
Einrichtung:
DISCORD_MOD_ROLE_ID
(Rolle, die freischalten darf und im Kanal angepingt wird). DISCORD_BOT_TOKEN ist hier
Pflicht.https://DEINE-DOMAIN/api/discord/interactions eintragen und speichern. Discord prüft die
Adresse; dabei registriert die Seite automatisch den Befehl /verify-panel.bot und
applications.commands). Die Bot-Rolle muss in der Rollenliste über der
Verifiziert-Rolle stehen./verify-panel ausführen.Achtung: Mit gesetzter Interactions Endpoint URL bekommt ein anderswo laufendes Bot-Programm mit demselben Token keine Befehle und Button-Klicks mehr.
/admin (Pfote oben rechts): Meldungen, FSK-18-Freigaben, Feedback, Updates,
Sperren. Admin ist, wer auf dem Discord-Server die Rolle Owner (1553843194993582253)
oder Fluff Admin (1553862150710239345) hat und Discord verknüpft bzw. sich damit
angemeldet hat — oder dessen Handle in ADMIN_HANDLES steht (Standard: kitsulife). Die
Rollen zählen auch im Bot als Team; ändern über DISCORD_ADMIN_ROLE_IDS./web-freischalten profil:<handle> und /web-sperren profil:<handle> schalten
FSK 18 auf der Webseite von Hand frei bzw. wieder ab (Mods). Nach dem Deploy einmal
/api/discord/interactions im Browser öffnen, damit neue Befehle angemeldet werden.Der Feed richtet sich nach Likes: Bilder, die Mitglieder mit ähnlichem Geschmack geliked haben
(„wer mag, was du magst, mag auch …“), kommen nach vorn. Dazu zählen Accounts, deren Bilder man
liked (×3), kommentiert (×4) oder ansieht (×1, Bild ≥ 1,5 s im Blick), ein Bonus für gefolgte
Accounts sowie Beliebtheit und Frische. Schon Gesehenes und Geliktes rutscht nach hinten. Gäste
sehen neu + beliebt. Die Gewichte stehen in listFeed (src/lib/vela/server.ts).
Kategorien dienen nur noch dem Filter in der Gallery.
Jede Meldung auf der Webseite postet der Bot in #meldungen in der Kategorie „🚩 Meldungen“
(legt er beim ersten Mal selbst an, nur fürs Team sichtbar): Bild (FSK 18 als Spoiler),
Uploader, Melder*in, Uhrzeit, Begründung und Details — mit Buttons Bild löschen,
Verwerfen und Uploader sperren. Der Bot braucht dafür „Kanäle verwalten“.
Videos (MP4, WebM, MOV, bis 50 MB) liegen im Vercel-Blob-Speicher, Bilder weiter in der Datenbank.
Einmalig einrichten: Vercel → Projekt → Storage → Create → Blob → mit dem Projekt
verbinden (setzt BLOB_READ_WRITE_TOKEN) → neu deployen. Ohne Token können nur Bilder hochgeladen
werden. Das Standbild (Poster) wird im Browser erzeugt; für FSK-18-Videos bekommen nicht
verifizierte Besucher nur die unkenntliche 16-px-Vorschau, nie die Video-Adresse.
Die Befehle funktionieren ohne. Für den grünen Online-Status muss ein kleines Programm dauerhaft laufen (eigener PC, Raspberry Pi, kleiner Server):
DISCORD_BOT_TOKEN=... npm run bot:online
[Platzhalter] in
src/routes/impressum.tsx und src/routes/datenschutz.tsx.reports, z. B.
select r.*, p.image_url from reports r join posts p on p.id = r.post_id order by r.created_at desc;