Plan #7912 — Lager → GitHub + port do et-op (Faza 0: inwentaryzacja)

Issue: #7912 Data: 2026-10-13 Status: Faza 0 zakończona — oczekuje akceptacji właściciela przed Fazą 1


1. Inwentaryzacja GitLab (gitlab.com/pinbox24/et-lager, ID 77031715)

Zebrane 2026-10-13 przez bms-4 worker via GitLab API (GITLAB_ADMIN_PAT — wartości nie są wyświetlane).

1.1 Repozytorium — podstawowe dane

AtrybutWartość
Nazwaet-lager
Namespacepinbox24
Project ID77031715
Default branchmaster (protected, Developers + Maintainers)
Visibilityprivate
Utworzono2025-12-11
Ostatnia aktywność2026-07-05
JęzykiTypeScript 53%, TSX 44%, JavaScript 2%, CSS 1%, Dockerfile 0.1%

1.2 Branche

BranchDomyślnaProtectedOstatni commitAutor
master✓✓2026-07-05Radek Konarski
fix/et-lager-security-p0——2026-07-05Radek Konarski

Wniosek: tylko 1 aktywna gałąź robocza (fix zmerge do master przez MR!1). Czyste środowisko, brak brudnych gałęzi.

1.3 Merge Requests (historyczne)

MRTytułStatusData merge
!1security: fix P0 vulnerabilities - hardcoded MongoDB URI + SSRF proxymerged2026-07-05

Wniosek: 1 MR w historii (fix security). Brak otwartych MR.

1.4 Issues GitLab

Brak (0 issues w GitLab). Tracking odbywa się w GitHub (radieu/p24-infra).

1.5 CI Variables

Brak CI variables w GitLab. Środowisko zarządzane przez Vercel env vars + secrets/et-lager.env.sops (synchronizowane przez secrets-sync.yml).

1.6 CI/CD Pipeline

Brak .gitlab-ci.yml. Pipelines uruchamiane przez Vercel webhook (push → auto-deploy).

Ostatnie pipelines:

  • 2026-07-05: master — success (deploy po MR!1)
  • 2025-12-11: master — success (deploy inicjalny)

1.7 Webhooki

HookURLEventyUtworzono
Vercel auto-deployhttps://api.vercel.com/v1/incoming/gitlab?accountId=team_RuXLTWx5DXK6n0HUKoOUTGY3push, merge_requests2025-12-11

Ważne dla Fazy 1: po przeniesieniu git source w Vercel z GitLab na GitHub, ten webhook staje się nieaktywny i należy go usunąć.

1.8 Protected branches

BranchPushMerge
masterDevelopers + MaintainersDevelopers + Maintainers

2. Analiza struktury kodu Lager

2.1 Struktura route’ów (App Router)

Lager ma dwa równoległe drzewa tras:

Root-level routes (src/app/):

/auth                    — logowanie
/dashboard               — dashboard główny
/invoice-list            — lista faktur (root)
/invoice-protocol        — protokół faktury
/invoice-view            — widok faktury (root)
/invoices                — faktury (root)
/invoices-list2          — lista faktur v2 (root)
/language-selection      — wybór języka
/missing-products        — brakujące produkty (root)
/no-access               — brak dostępu
/no-location-products    — produkty bez lokalizacji
/profile                 — profil użytkownika
/protocol-release        — zwolnienie protokołu
/protocols               — protokoły (root)
/stock                   — stan magazynu (root)
/warehouse-release       — wydanie z magazynu (root)
/workspace               — workspace selector

Workspace-scoped routes (src/app/workspace/[workspaceId]/):

/workspace/[id]/dashboard
/workspace/[id]/invoice-protocol
/workspace/[id]/invoice-view
/workspace/[id]/invoices-list2
/workspace/[id]/missing-products
/workspace/[id]/no-location-products
/workspace/[id]/protocols
/workspace/[id]/stock
/workspace/[id]/warehouse-release

Łącznie ~20 stron root + ~9 workspace-scoped + strony pomocnicze ≈ 37 zidentyfikowanych stron.

2.2 API Routes (src/app/api/)

ŚcieżkaFunkcjonalność
/api/authLogowanie Pinbox24 JWT
/api/invoicesCRUD faktur, PDF, filtrowanie
/api/invoice-protocolsPowiązanie faktur z protokołami
/api/protocolsCRUD protokołów magazynowych
/api/stockStan magazynu, lookup SKU
/api/warehouse-productsProdukty magazynowe
/api/warehouse-protocolsProtokoły wydań
/api/workspaceWorkspace-scoped warianty powyższych
/api/public/intercars-proxyProxy SSRF do Intercars (z allowlistą)
/api/missing-productsTracking brakujących produktów (Atlas)
/api/bug-reportZgłoszenie błędu
/api/profileProfil użytkownika

Łącznie: 47+ endpoint’ów (wg API_INVENTORY.md).

2.3 Zależności zewnętrzne

ZależnośćTypUwagi
api.w4.pinbox24.comREST APIŹródło prawdy dla magazynu/faktur; JWT użytkownika (MD5, 8h TTL)
Intercars B2B API (api.webapi.intercars.eu)REST OAuth2CLIENT_ID_SECRET nadal hardcoded w src/constants/intercars.constants.ts — #2852 OPEN
MongoDB AtlasStoragenextjs-db-dev.ncgd33w.mongodb.net; 2 kolekcje: missingProducts, processedInvoices
NextAdmin v1.2.1TemplateFree template, działa jako szkielet UI

2.4 Znane problemy (z docs/et-lager-operations.md)

P0 (blokuje Fazę 1):

  • INTERCARS_CLIENT_ID_SECRET hardcoded w src/constants/intercars.constants.ts — śledzone w #2852 (OPEN). Musi być usunięte z kodu i historii git (git filter-repo) zanim kod trafi na GitHub.

P1 (do rozwiązania w Fazie 4/5):

  • Brak token refresh (Pinbox24 JWT wygasa po ~8h)
  • Cookie/header mismatch w middleware (auth przez header, nie przez cookie)
  • Build script broken na Linux (set NODE_OPTIONS=... — Windows CMD)
  • next: "^16.0.7" (nie istnieje — resolves do 15.x)

P2 (tech debt, Faza 5):

  • Brak CI/CD pipeline
  • Duplikacja route’ów workspace vs root
  • 2 pliki MongoDB connection
  • moment + dayjs — zduplikowane
  • Debug console.log w produkcji
  • JWT nie weryfikowany kryptograficznie
  • Stub npm packages (child_process, net)
  • ~20 plików .md z notatkami AI w korzeniu repo (do przeniesienia/usunięcia)

3. Lista decyzji do brainstormu z właścicielem

D1 — Auth/tożsamość użytkownika w et-op

Pytanie: Jak użytkownicy et-lager logują się w zintegrowanym et-op?

OpcjaOpisZaPrzeciw
(a) Supabase login + server-stored Pinbox24 credentialsUżytkownik loguje się przez Supabase (email/hasło). W tabeli pinbox24_credentials przechowujemy jego Pinbox24 email+hasło (zaszyfrowane). Na każdy request pobieramy token Pinbox24 server-side.Jednolity auth stack et-op; ukrywa Pinbox24 przed frontendemPrzechowywanie haseł użytkowników (regulaminowo wątpliwe, Pinbox24 nie ma OAuth); rotacja przy zmianie hasła Pinbox24 wymaga ręcznej aktualizacji
(b) Logowanie Pinbox24 → mapowanie na Supabase sessionUżytkownik loguje się Pinbox24 credentials; serwer wymienia je na Supabase session + przechowuje Pinbox24 token w sesji.Brak duplikacji haseł; flow znany z Lager2 różne flow logowania w et-op — złożoność UX; Supabase session + Pinbox24 JWT = dwa czasy życia tokena
(c) Konto serwisowe Pinbox24 (shared)Jeden account serwisowy Pinbox24 dla całego et-op. Użytkownicy logują się tylko przez Supabase; wywołania Pinbox24 idą pod kontem serwisowym.Najprostsze; brak per-user tokenówPinbox24 workspace access control oparty na per-user workspaces — konto serwisowe może nie mieć dostępu do workspace’ów konkretnych użytkowników

Rekomendacja: (b) — Logowanie Pinbox24 → mapowanie na Supabase session. Zachowuje istniejący model auth Lager (Pinbox24 JWT), ale integruje z istniejącym Supabase session management et-op. Niski koszt adaptacji w Fazie 5; brak przechowywania haseł.

Ryzyko wymagające potwierdzenia: Czy workspace access w Pinbox24 API jest per-user (JWT-based)? Jeśli tak, opcja (c) odpada definitywnie.


D5 — Definicja „1:1” (layout + metoda akceptacji wizualnej)

Pytanie: Co konkretnie jest nienowocjonowalne w layoucie Lager? Jak weryfikujemy 1:1?

OpcjaOpisZaPrzeciw
(a) Screenshot baseline Playwright (pixel-level)Dla każdej z 37 stron Lager robimy baseline screenshot (Playwright + Percy/Argos). et-op musi przejść expect(screenshot).toMatchSnapshot() z progiem ≈5% odchylenia.Obiektywny kontrakt; weryfikowalny automatycznie~2-3 tygodnie setup; wrażliwy na różnice dark/light, viewport; NextAdmin vs shadcn = inne klasy CSS, wymaga per-pixel tolerancji
(b) Functional parity + layout audit przez właścicielaDefiniujemy listę kryteriów funkcjonalnych (tabela X, filtr Y, przycisk Z) + layout guideline (kolumny, sidebar, pagination). Akceptacja przez ręczny przegląd właściciela po każdej fazie.Pragmatyczna; uwzględnia świadome różnice stylistyczne (shadcn vs NextAdmin)Subiektywna; możliwe spory przy odbiorze
(c) Komponent po komponencie — visual diff przez StorybookKażdy przeniesiony komponent ma storybookowy screenshot. Diff tylko changed components.Granularny; łatwy w utrzymaniuWymaga pełnego Storybook setup; nie testuje integracji stron

Rekomendacja: (b) z dokumentem lager-visual-acceptance-criteria.md zawierającym screenshoty kluczowych widoków Lager jako reference obrazy (załącznik do issue Fazy 2). Pełny Playwright screenshot suite jest opcjonalny jako narzędzie pomocnicze (Faza 2), ale nie jako twarda blokada.


D6 — Big-bang vs Strangler Fig

Pytanie: Jak wdrażamy funkcjonalność Lager do et-op?

OpcjaOpisZaPrzeciw
(a) Big-bangJedna implementacja (Faza 5) zastępuje zarówno et-lager jak i aktualny wh-staff w et-op. Cutover jednorazowy.Prosta architektura; brak równoległego utrzymaniaRyzyko ~46 osobodni bez działającego produktu; brak rollback’u
(b) Strangler Fig (moduł po module)Każdy ekran Lager jest implementowany w et-op jako osobny PR. Użytkownicy mogą być odsyłani do et-lager.vercel.app dla niezaimplementowanych modułów.Ciągłe dostawy; rollback per-modułDwupunktowy stan (~6-8 miesięcy dual maintenance)
(c) Feature flag + parallel runNowe ekrany dostępne za feature flagą. Et-lager pozostaje primary, et-op jako shadow. Cutover dopiero gdy wszystkie ekrany gotowe.Zero-risk cutoverWymaga feature flag infrastructure (mamy p24_feature_permissions?)

Rekomendacja: (b) Strangler Fig — realizm wyceny (~46 osobodni real) wymaga iteracyjnych dostaw. et-lager pozostaje aktywny jako fallback. Moduły wdrażane w kolejności: stock/protocols (Faza 5a) → invoices (Faza 5b) → missing-products (Faza 5c). Cutover po Fazie 5c.


D7 — Limity Vercel/proxy + wspólna warstwa Intercars

Pytanie: Jak zarządzać Intercars API w et-op (nowe proxy w et-op vs shared via bms-4)?

OpcjaOpisZaPrzeciw
(a) Next.js API route w et-op (jak w Lager)/api/intercars-proxy w et-op — analogicznie do Lager. INTERCARS_CLIENT_ID_SECRET w Vercel env et-op.Izolacja; prosta migracjaDuplikacja proxy logiki; oba projekty potrzebują osobnych sekretów Intercars
(b) Shared proxy na bms-4 (n8n lub dedykowana usługa)n8n workflow lub nowa Hono/Express usługa na bms-4 obsługuje Intercars. et-op używa wewnętrznego URL.Jeden punkt obsługi Intercars; łatwiejsza rotacja sekretu; cache możliwyZależność od bms-4 uptime; SSRF risk przesunięty na bms-4; latency
(c) CF Worker jako Intercars proxyDedykowany CF Worker (intercars-proxy-worker) na koncie Cloudflare. Sekret trzymany jako CF Secret.Globalny CDN; zero cold start; bez Vercel limitsKolejny serwis do utrzymania; Intercars może blokować CF IP ranges

Rekomendacja: (a) na start — analogicznie do Lager. Wyciągnięcie do shared proxy to osobna decyzja architektoniczna po weryfikacji limitów (Faza 4 spike). Vercel free tier: 100GB/miesiąc bandwidth, 1000 serverless invocations/day (Hobby) vs Vercel Pro (bez limitów) — sprawdzić tier et-op.

Do weryfikacji: czy et-op ma Vercel Pro (bez limitu invocations)? Jeśli Hobby, 1000 invocations/day może być za mało dla aktywnego użycia Intercars.


D8 — Workspaces GENERAL/ACCOUNTING → role vs p24_feature_permissions

Pytanie: Jak modelować workspace access control z Pinbox24 w et-op?

Lager używa workspace kontekstu z Pinbox24 API — użytkownik należy do workspace’ów (GENERAL, ACCOUNTING, itd.), co bramkuje dostęp do funkcji.

OpcjaOpisZaPrzeciw
(a) Rola Supabase per workspaceKażdy workspace to rola Supabase (wh_general, wh_accounting). Przypisanie roli = dostęp do workspace.Spójne z Supabase RLS modelWymaga synchronizacji Pinbox24 workspace membership → Supabase roles (gdzie/kiedy sync?)
(b) p24_feature_permissions (istniejące w et-op)Reusing istniejącego mechanizmu feature flags et-op (tabela p24_feature_permissions?). Workspace access to feature.Reuse kodu; spójne z istniejącymi wzorcami et-opWymaga weryfikacji: czy p24_feature_permissions istnieje i jak działa w et-op?
(c) Pass-through: workspace info z Pinbox24 JWTPrzy każdym logowaniu Pinbox24, pobieramy workspace memberships z API i przechowujemy w Supabase session metadata. Kontrola dostępu server-side na podstawie JWT claims.Zero drift między Pinbox24 a et-opKażdy page load weryfikuje workspace — latency; zależy od Pinbox24 API availability

Rekomendacja: (c) jako Faza 5 baseline — minimal viable, pass-through z Pinbox24. Opcja (b) jako ewolucja jeśli p24_feature_permissions jest odpowiednia (weryfikacja w Fazie 4).

Do weryfikacji przez właściciela: czy tabela p24_feature_permissions istnieje w et-op i co obsługuje?


D9 — Czy Faza 3 (stabilizacja Lager) ma sens?

Pytanie: Czy warto stabilizować et-lager (naprawiać P1/P2 bugi) przed portem do et-op?

Faza 3 obejmowałaby: token refresh, cookie/header fix, CI pipeline, routing cleanup, test coverage. Wycena: 0–5 osobodni.

OpcjaOpisRekomendacja
(a) Pominąć Fazę 3Port Lager do et-op to okazja do naprawy — nie warto naprawiać skazańcaZALECANE — Faza 3 to dług techniczny, który et-op i tak trzeba przepisać
(b) Realizować Fazę 3Stabilizacja przed portem zmniejsza zakres Fazy 5Uzasadnione tylko jeśli et-lager ma być utrzymywany przez >6 miesięcy po Fazie 0

Rekomendacja: pominąć Fazę 3. Et-lager zastępuje się modułem wh-staff w et-op — inwestycja w stabilizację Lager ma ROI ≤ 0. Wyjątek: jeśli właściciel planuje utrzymywać et-lager w produkcji przez ≥6 miesięcy po Fazie 1.


D10 — Które ekrany (/invoice-list, /invoices-list2, /invoice-view) są realnie używane?

Pytanie: Mamy zduplikowane ekrany faktur — które są w użyciu produkcyjnym?

RouteOdpowiednik workspaceStatus
/invoice-list/workspace/[id]/ (brak?)Duplication root — prawdopodobnie stary widok
/invoices-list2/workspace/[id]/invoices-list2”v2” — prawdopodobnie nowszy
/invoice-view/workspace/[id]/invoice-viewZduplikowany
/invoicesbrak w workspaceRoot-only?

Potrzebna weryfikacja przez właściciela:

  1. Który z widoków faktur jest domyślny (użytkownicy wchodzą przez który URL)?
  2. Czy /invoice-list (root, bez workspaceId) jest w ogóle używany?
  3. Czy /invoices-list2 to “docelowy” widok faktur (najnowszy)?

Rekomendacja dla Fazy 5: portować TYLKO widoki w użyciu. Zalecam portem zająć /workspace/[id]/invoices-list2 i /workspace/[id]/invoice-view jako kanoniczne — root-level duplicates pominąć. Potwierdzenie przez właściciela wymagane.


4. Proponowane issue-dzieci (do stworzenia PO akceptacji przez właściciela)

Faza 1 — Przeniesienie na GitHub (2,5 d)

Prerequisite: #2852 (OPEN — Intercars secret hardcoded) musi być zamknięty PRZED stworzeniem tego issue. git filter-repo wymagane do wyczyszczenia historii.

Issue 1.1: feat(et-lager): mirror repository from GitLab to GitHub with git history

  • Scope: git clone --mirror z GitLab → git filter-repo --path src/constants/intercars.constants.ts --invert-paths → push na nowe GitHub repo radieu/et-lager (lub et-lager jako subpath) → weryfikacja historii
  • Prereq: zamknięty #2852, nowe repozytorium GitHub utworzone
  • Labels: infra-task (wymaga SSH/git push na bms-4 lub windows-dev)
  • Waga: light

Issue 1.2: feat(et-lager): switch Vercel git source from GitLab to GitHub

  • Scope: Vercel project et-lager → Settings → Git → zmiana git source na GitHub + usunięcie GitLab webhook → test deploy
  • Labels: infra-task
  • Waga: light

Issue 1.3: docs(et-lager): add CI pipeline (GitHub Actions: type-check, lint, build)

  • Scope: .github/workflows/ci.yml dla nowego repo et-lager — npm run type-check, eslint, npm run build; naprawić build script (set NODE_OPTIONS → cross-env)
  • Labels: dev-issue
  • Waga: light

Issue 1.4: docs(p24-infra): update et-lager-operations.md for GitHub migration

  • Scope: aktualizacja docs/et-lager-operations.md — nowe URLs, git source, obselete GitLab webhook
  • Labels: dev-issue
  • Waga: light

Faza 2 — Security review + baseline screenshots (3 d)

Issue 2.1: sec(et-lager): full security audit post-migration

  • Scope: przegląd wszystkich 47+ API endpoints pod kątem auth gaps, injection, SSRF; weryfikacja że INTERCARS_CLIENT_ID_SECRET usunięty z historii; audyt zależności npm (npm audit)
  • Labels: sec, dev-issue
  • Waga: heavy

Issue 2.2: test(et-lager): Playwright visual baseline — 37 pages screenshot contract

  • Scope: Playwright setup w repozytorium et-lager; screenshot każdej z 37 stron przy zalogowanym test user; artefakty jako PR attachment; lager-visual-acceptance-criteria.md jako dokument referencyjny
  • Labels: dev-issue
  • Waga: heavy

Faza 4 — Spec + characterization tests w et-op (4,5 d)

Issue 4.1: design(et-op/wh-staff): Lager port architecture spec

  • Scope: design document w docs/plans/ — mapowanie ekranów Lager → komponenty et-op; decyzje D1/D5-D10 zebrane i potwierdzone przez właściciela; schema Supabase dla missingProducts + processedInvoices (migracja z MongoDB Atlas)
  • Labels: plan, dev-issue
  • Waga: heavy

Issue 4.2: test(et-op/wh-staff): characterization tests for Pinbox24/Intercars contract

  • Scope: testy kontraktu HTTP dla Pinbox24 API endpoints używanych w Lager (snapshot request/response); testy Intercars OAuth flow; MSW mocks dla unit testów
  • Labels: dev-issue
  • Waga: heavy

Issue 4.3: feat(et-op): Supabase migration — pinbox24_missing_products + pinbox24_processed_invoices

  • Scope: migration SQL dla 2 tabel zastępujących MongoDB; RLS; dev_r_services update; script migracji danych z Atlas → Supabase
  • Labels: dev-issue
  • Waga: heavy

Faza 5 — Implementacja w et-op (≈46 d, podzielona na sub-issues)

Faza 5 jest dekompozycją do podjęcia DOPIERO po zatwierdzeniu spec z Fazy 4.

Issue 5.1: feat(et-op/wh-staff): Pinbox24 auth layer — JWT login flow in Pages Router

  • Scope: nowy hook usePinbox24Auth, interceptor axios, token refresh (naprawienie P1 z Lager), server-side session storage Pinbox24 JWT w Supabase session

Issue 5.2: feat(et-op/wh-staff): stock + product lookup module

  • Scope: port /stock, /warehouse-products + /workspace/[id]/stock; shadcn DataTable; Pinbox24 register API

Issue 5.3: feat(et-op/wh-staff): protocols module (PZ/WZ/ZW + warehouse release)

  • Scope: port protocols, warehouse-release, protocol-release; et-op wh_protocols integration; Faza 5 nakłada na istniejące src/pages/wh-staff/*

Issue 5.4: feat(et-op/wh-staff): invoices module (list + view + close)

  • Scope: port invoices-list2, invoice-view, invoice-protocols; Intercars proxy; PDF download

Issue 5.5: feat(et-op/wh-staff): missing products + invoice processing

  • Scope: port missing-products, no-location-products; Supabase tables zamiast MongoDB Atlas

Issue 5.6: feat(et-op/wh-staff): i18n pl+de for all ported screens

  • Scope: klucze i18n z Lager (1650 kluczy → ~500 kluczy po filtrze pl+de niekompletnych); tłumaczenia pl+de

Issue 5.7: feat(et-op/wh-staff): workspace access control (Pinbox24 workspace membership)

  • Scope: implementacja D8 (wybrany wariant); page guards; useAuth integration

5. Podsumowanie ryzyk (ranking dla właściciela)

RyzykoPrawdopodobieństwoWpływMitygacja
Intercars secret w historii git — push na GitHub bez filter-repoWysokiP0 (data leak)Blokuje Fazę 1 — #2852 musi być zamknięty najpierw
App Router → Pages Router przepisanieWysoki+20% nakład Fazy 5Shadcn działa w Pages Router; priorytet integracji istniejącego wh-staff
Niezgodny model auth Pinbox24 JWT vs SupabaseWysokiFaza 4 cała może być redesignemD1 musi być podjęta i potwierdzona przed Fazą 4
Nakładanie z istniejącym wh-staff w et-opŚredniDuplikacja kodu, spory o “który ekran”D5 (visual acceptance) + kontrakt w Fazie 4
Praktyczny brak testów w LagerWysokiFaza 5 bez regression safetyFaza 2 issue 2.2 + Faza 4 issue 4.2 tworzą safety net
Duplikacja ekranów faktur (root vs workspace)ŚredniPraca na błędnym screenieD10 — właściciel musi wskazać kanoniczne ekrany

6. Kolejne kroki

  1. Właściciel: przejrzyj decyzje D1, D5, D6, D8, D10 i zatwierdź rekomendacje lub wybierz alternatywy
  2. Po akceptacji D1-D10: stwórz issue-dzieci (Fazę 1 pierwsze — prereq: zamknięty #2852)
  3. Faza 1 startuje dopiero po: zamknięciu #2852 (Intercars secret rotation)

Wygenerowano przez bms-4 worker (job #13210) · 2026-10-13 · Faza 0 zamknięta