尚未检测到更新。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;