chore(handoff): portabel machen + Doku/Onboarding glaetten (Review-Umsetzung)
Ampel / ampel (push) Successful in 27s

Aus dem Weitergabe-Review. Kein Verhaltenswechsel fuer den Ursprungs-Host
(alle Defaults = bisheriges Verhalten):

Portabilitaet:
- Laufwerk-Geraeteknoten via .env parametrisiert (OPTICAL_SR/OPTICAL_SG,
  Defaults sr0/sg1) - der #1-Blocker: auf Fremdhosts liegt das sg-Node woanders.
- deploy.sh generisch (RIPPY_VM/RIPPY_REPO_URL/... aus der Umgebung) - keine
  festen Besitzer-Adressen (interne IP + DDNS) mehr im Repo.
- POSTGRES_PASSWORD in compose durchverdrahtet (Default rippy) - war No-op.

Aufraeumen (toter/irrefuehrender Code):
- udev/ entfernt (fehlende Regeldatei, falscher Container-Name; durch ioctl-
  Polling ersetzt - reine Altlast).
- docker/postgres/*, docker/redis/*, init.sql entfernt (nie eingebunden).

Onboarding:
- FirstRunWizard verdrahtet: App.tsx fragt GET /setup und zeigt den
  Einrichtungs-Assistenten beim ersten Start (war gebaut, aber nie gerendert).

Doku:
- README: Laufwerk-Abschnitt auf .env, ENV-Tabelle (OPTICAL_*/POSTGRES),
  rshared-Anleitung, neuer Abschnitt "Haertung fuer fremde/exponierte Netze".
- config_validation.py: TMDB Pflicht->empfohlen, Zeichensalat-Tippfehler gefixt.
- .env.example: TMDB-Wording, OPTICAL_*-Variablen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-24 23:32:59 +02:00
parent 6a082cf77c
commit 0832ef777c
15 changed files with 130 additions and 401 deletions
+6 -4
View File
@@ -14,12 +14,14 @@ def validate_config() -> Settings:
try:
settings = Settings()
# TMDB API Key ist Pflicht (gemäß KONZEPT.md)
# TMDB-Key ist EMPFOHLEN, nicht zwingend: main.py fängt diesen Fehler ab und
# gibt nur eine Warnung aus — die API startet auch ohne Key, und der Key lässt
# sich jederzeit im UI (Einstellungen → System) nachtragen.
if not settings.tmdb_api_key:
raise ConfigValidationError(
"TMDB_API_KEY ist erforderlich für Metadaten-Lookup.\n"
"Hole dir einen免费en Key auf https://www.themoviedb.org/\n"
"Setze ihn als Umgebungsvariable: TMDB_API_KEY=dein_key"
"TMDB_API_KEY ist nicht gesetzt (empfohlen für Metadaten-Lookup).\n"
"Kostenlosen Key auf https://www.themoviedb.org/ holen und als\n"
"Umgebungsvariable TMDB_API_KEY setzen — oder später im UI eintragen."
)
return settings
-6
View File
@@ -1,6 +0,0 @@
FROM postgres:16
COPY init.sql /docker-entrypoint-initdb.d/
EXPOSE 5432
-3
View File
@@ -1,3 +0,0 @@
CREATE DATABASE rippy;
CREATE USER rippy WITH PASSWORD 'rippy123';
GRANT ALL PRIVILEGES ON DATABASE rippy TO rippy;
-5
View File
@@ -1,5 +0,0 @@
FROM redis:7-alpine
COPY redis.conf /usr/local/etc/redis/redis.conf
CMD ["redis-server", "/usr/local/etc/redis/redis.conf"]
-6
View File
@@ -1,6 +0,0 @@
appendonly yes
appendfsync everysec
timeout 0
tcp-keepalive 300
loglevel notice
databases 16
+15 -1
View File
@@ -1,14 +1,25 @@
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { LayoutDashboard, BookOpen, FileText, Settings as SettingsIcon } from 'lucide-react'
import Dashboard from './pages/Dashboard'
import SettingsPage from './pages/Settings'
import LogsPage from './pages/Logs'
import AnleitungPage from './pages/Anleitung'
import FirstRunWizard from './components/FirstRunWizard'
import { api } from './lib/api'
type Page = 'dashboard' | 'anleitung' | 'logs' | 'settings'
export default function App() {
const [currentPage, setCurrentPage] = useState<Page>('dashboard')
// First-Run: solange der Einrichtungs-Assistent nicht abgeschlossen ist, zeigen wir
// ihn statt des Dashboards. null = /setup noch nicht geprüft (kein Aufblitzen).
const [setupDone, setSetupDone] = useState<boolean | null>(null)
useEffect(() => {
api.get('/setup')
.then((r) => setSetupDone(Boolean(r.data?.done)))
.catch(() => setSetupDone(true)) // API/Setup nicht erreichbar → nicht blockieren
}, [])
const navItems: { id: Page; label: string; icon: any }[] = [
{ id: 'dashboard', label: 'Dashboard', icon: LayoutDashboard },
@@ -17,6 +28,9 @@ export default function App() {
{ id: 'settings', label: 'Einstellungen', icon: SettingsIcon },
]
if (setupDone === null) return null // kurzer Moment, bis /setup geantwortet hat
if (!setupDone) return <FirstRunWizard onDone={() => setSetupDone(true)} />
return (
<div className="min-h-screen bg-[#080b11] text-slate-100 font-sans selection:bg-amber-500/30 selection:text-amber-300">
{/* Top Header Navigation Bar */}