Commit Graph
13 Commits
Author SHA1 Message Date
lgooseandClaude Bot 1f0a92b6f6 fix(ci): stabilne sprawdzenie proxy w jobie image panelu
Panel / Lint, typy i build (pull_request) Successful in 4m56s
Panel / Testowy build obrazu (pull_request) Successful in 18s
Krok padał na runnerze bez żadnego komunikatu. Powód był podwójny:

- asercja zakładała, że bez backendu nginx odpowie 502, a to zależy od
  tego, jak szybko zawiedzie DNS. Na runnerze zapytanie wisiało 30 sekund,
  aż do domyślnego resolver_timeout.
- grep bez dopasowania kończy się kodem 1, a Gitea uruchamia kroki w
  bash -e -o pipefail, więc podstawienie zmiennej przerywało cały krok,
  zanim zdążył wypisać powód. Lokalnie tego nie było widać, bo zsh nie
  ustawia tych flag.

Zamiast opierać się na tym, że proxy zawiedzie, job stawia teraz atrapę
backendu pod nazwą discord-bot - dokładnie tą, którą wskazuje nginx.conf
i compose.yaml - i sprawdza, że przez proxy wraca treść z atrapy. Test
przechodzi więc wtedy, gdy przekazywanie faktycznie działa, a nie wtedy,
gdy zawodzi w oczekiwany sposób. Sprawdzane jest też /ws.

Pozostałe usztywnienia: limit czasu na każde zapytanie, || true tam, gdzie
brak dopasowania jest poprawnym wynikiem, jawne komunikaty błędów z logiem
kontenera oraz sprzątanie kontenerów i sieci przez trap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:44:07 +02:00
lgooseandClaude Bot c5e016605b ci: pipeline panelu dla Gitea Actions
Panel / Lint, typy i build (pull_request) Successful in 4m55s
Panel / Testowy build obrazu (pull_request) Failing after 49s
Workflow .gitea/workflows/frontend.yaml z dwoma jobami:

- verify  npm ci, ESLint, kontrola typów, build produkcyjny i test dymny
- image   walidacja compose.yaml, build obrazu panelu i sprawdzenie
          działającego kontenera; job czeka na verify

Test dymny działa na zbudowanym artefakcie, a nie na źródłach, więc
sprawdza dokładnie to, co trafia do obrazu.

Job image weryfikuje trzy rzeczy w uruchomionym kontenerze: czy nginx
oddaje panel, czy nieznana ścieżka wraca jako index.html (fallback SPA)
oraz czy /api jest przekazywane do backendu. Backendu w tym kroku nie ma,
więc oczekiwaną odpowiedzią jest błąd bramy - 502 dowodzi, że reguła proxy
istnieje i celuje w usługę discord-bot, podczas gdy 404 oznaczałoby, że
nginx potraktował /api jak ścieżkę aplikacji.

Filtry paths ograniczają uruchomienia do zmian w katalogu frontend,
compose.yaml i samym workflow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:34:55 +02:00
lgooseandClaude Bot 1b424eaa7d fix(panel): healthcheck obrazu odpytuje 127.0.0.1 zamiast localhost
nginx nasłuchuje wyłącznie na IPv4, a w obrazie alpine localhost rozwiązuje
się najpierw na ::1. Healthcheck kończył się więc odmową połączenia i
kontener nigdy nie osiągał stanu healthy - wyszło to przy pisaniu CI,
gdzie ten sam sposób odpytania nie działał.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:34:55 +02:00
lgooseandClaude Bot 105f3e6c6a chore(frontend): ESLint dla Vue i TypeScriptu
Konfiguracja we flat configu: zalecane zestawy js, typescript-eslint oraz
eslint-plugin-vue. Bloki <script setup lang="ts"> obsługuje vue-eslint-parser
przekazujący zawartość do parsera TypeScriptu.

Odstępstwa od domyślnych reguł:

- vue/multi-word-component-names wyłączone - kafelki panelu mają nazwy
  własne i nie każda jest dwuczłonowa
- no-unused-vars przepuszcza nazwy z prefiksem podkreślenia
- no-console wyłączone dla testu dymnego, który raportuje wynik na stdout

Szablony przepuszczone przez eslint --fix, co ujednoliciło łamanie
atrybutów i domykanie znaczników. Po zmianach kontrola typów, build
i test dymny nadal przechodzą.

Dochodzą skrypty npm: lint (z --max-warnings 0) oraz lint:fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:34:55 +02:00
lgooseandClaude Bot 1b5ce2109b docs(frontend): opis panelu, struktury i uruchamiania
README opisuje pracę lokalną (npm run dev z proxy na backend), budowanie,
uruchomienie kontenera oraz strukturę katalogu src z rolą każdego pliku.
Spisane też zasady, które utrzymują panel spójnym: stan płynie z serwera,
zero innerHTML, ikony jako komponenty zamiast skryptu z CDN.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:09:02 +02:00
lgooseandClaude Bot 2feb963e6a test(frontend): test dymny zbudowanego panelu
Ładuje artefakt z dist/ w jsdom, podstawiając atrapy WebSocketu i fetcha,
a następnie sprawdza dwie rzeczy naraz:

- czy dane z serwera faktycznie renderują się w interfejsie (aktualny utwór,
  kolejka, historia, baza plików, głośność, tryb zapętlania, odmiana
  liczebników, formatowanie czasu)
- czy kliknięcia trafiają we właściwe endpointy - każdy przycisk sterujący
  porównywany jest z oczekiwaną parą metoda + ścieżka

Razem 31 sprawdzeń, uruchamiane przez npm run smoke po npm run build.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:09:02 +02:00
lgooseandClaude Bot bbd8a321f4 build: panel w osobnym kontenerze za nginxem
Rozdzielenie na dwie niezależne usługi:

- frontend/Dockerfile buduje panel w etapie node:22-alpine, a artefakt
  serwuje nginx:1.27-alpine. Obraz nie zawiera Node'a ani źródeł.
- frontend/nginx.conf serwuje aplikację jednostronicową (nieznane ścieżki
  wracają jako index.html), cache'uje /assets z sumą kontrolną w nazwie,
  a /api i /ws przekazuje do usługi discord-bot. Przeglądarka widzi jedno
  źródło, więc backend nie potrzebuje CORS-u.
  Adres backendu siedzi w zmiennej nginxa, więc nazwa jest rozwiązywana
  przy żądaniu i panel wstaje niezależnie od kolejności startu kontenerów.
- Proxy nie limituje rozmiaru ciała żądania i nie buforuje go, żeby
  wysyłka dużych plików wideo/audio przechodziła bez zmian w backendzie.
  Timeouty podniesione, bo panel trzyma WebSocket otwarty na stałe.
- Root Dockerfile wraca do samego Pythona i wystawia port 8000.
- compose.yaml uruchamia obie usługi we wspólnej sieci: panel na :80,
  API na :8000 (wystawione do diagnostyki).
- Katalog static/ znika z repozytorium - nie ma już czego serwować.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:08:50 +02:00
lgooseandClaude Bot 8d32d5afc6 feat(api): backend wystawia wyłącznie API i steruje botem
Panel działa w osobnym kontenerze, więc serwis Pythona przestaje serwować
pliki statyczne:

- usunięty mount StaticFiles na "/" wraz z importem
- tytuł aplikacji zmieniony na "ŻyrarBOT API"
- GET / zwraca opis usługi zamiast panelu, żeby wejście pod adres backendu
  nie kończyło się nic niemówiącym 404
- GET /api/health informuje, czy bot zdążył połączyć się z Discordem;
  przydaje się jako healthcheck kontenera i przy diagnozie proxy

Pozostałe endpointy oraz WebSocket pozostają bez zmian.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:08:50 +02:00
lgooseandClaude Bot d3408da2ed refactor: usunięcie starego panelu ze statycznych plików
static/app.js (1196 linii imperatywnego JS operującego na getElementById)
oraz static/index.html zastąpione w całości aplikacją z frontend/.
Arkusz stylów został wcześniej przeniesiony, nie usuwamy go ponownie.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:08:31 +02:00
lgooseandClaude Bot 038fa2ead4 feat(frontend): komponenty panelu
Widok rozbity na komponenty odpowiadające kafelkom pulpitu:

- AppHeader, VoiceChannelPanel, PlayerPanel, AddTrackPanel
- UploadsPanel wraz z UploadedFileRow współdzielonym z oknem modalnym
- QueuePanel i QueueItem - przeciąganie, zmiana kolejności, limit odtworzeń
- HistoryPanel, ModalShell, SettingsModal, UploadsLibraryModal, ToastHost

Arkusz stylów przeniesiony ze static/style.css bez zmian w wyglądzie.
Style, które app.js wstrzykiwał inline przy budowaniu HTML-a, przeniesione
do klas współdzielonych i bloków scoped w komponentach.

Poprawki bezpieczeństwa wynikające z przepisania:

- Tytuły utworów i nazwy plików nie trafiają już do innerHTML. Poprzednia
  wersja składała wiersze kolejki, historii i listy plików ze stringów,
  więc tytuł zawierający znaczniki HTML był wstawiany do DOM bez escapowania.
- Nazwy plików nie są już wklejane do atrybutów onclick z ręcznym
  escapowaniem apostrofu, które i tak nie obejmowało cudzysłowu. Zdarzenia
  podpina Vue, bez generowania kodu w stringach.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:08:31 +02:00
lgooseandClaude Bot 119bff00a3 feat(frontend): composables ze stanem panelu
Logika, która w app.js żyła w zmiennych globalnych, trafia do czterech
composables o wyraźnym zakresie odpowiedzialności:

- useBotStatus     jedno połączenie WebSocket na aplikację, z licznikiem
                   subskrybentów i ponawianiem po zerwaniu. Flaga paused
                   wstrzymuje aktualizacje na czas przeciągania utworów.
- useToasts        kolejka powiadomień wraz z helperem run(), który
                   opakowuje wywołanie API w parę komunikatów sukces/błąd.
- useTrackProgress płynny pasek postępu - między pakietami z serwera czas
                   dopisujemy lokalnie, a każdy pakiet resynchronizuje licznik.
- useUploads       serwerowa baza plików, współdzielona przez kafelek na
                   pulpicie i okno z pełną listą.

Dochodzi też utils/plural.ts z polską odmianą liczebników, zamiast
powtarzanego w kilku miejscach warunku count < 5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:08:04 +02:00
lgooseandClaude Bot 6bfa9b2a77 feat(frontend): kontrakt danych i typowany klient API
- types/status.ts spisuje kształt odpowiedzi /api/status oraz pakietów
  rozgłaszanych po WebSockecie. Dotąd struktura tych danych istniała
  wyłącznie w głowie autora i w rozsianych po kodzie odwołaniach.
- api/client.ts zbiera wszystkie adresy endpointów w jednym miejscu i
  ujednolica obsługę błędów: pole "detail" z odpowiedzi FastAPI trafia do
  wyjątku ApiError, więc warstwa widoku dostaje gotowy komunikat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:08:04 +02:00
lgooseandClaude Bot ab3c980597 build(frontend): szkielet projektu Vue 3 + TypeScript + Vite
Panel przestaje być zestawem plików statycznych serwowanych przez backend
i staje się osobnym projektem w katalogu frontend/.

- Vue 3 z Composition API jako framework - szablony komponentów są bliskie
  dotychczasowemu HTML-owi, więc migracja nie wymaga przepisywania widoków
  na inny model mentalny.
- TypeScript w trybie strict; kontrakt danych z API będzie opisany typami.
- Vite jako bundler, z aliasem @ na src/ i budowaniem do dist/.
- Serwer deweloperski przekierowuje /api i /ws na backend; adres można
  nadpisać zmienną VITE_BACKEND_URL.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 01:07:47 +02:00