# BLIVEO — pełny stack technologiczny i architektura MVP

**Wersja dokumentu:** 1.1  
**Data:** 23 października 2026  
**Status:** rekomendacja architektury do implementacji  
**Hasło:** Blisko, nawet gdy jesteś daleko!

## 1. Decyzja architektoniczna

Bliveo budujemy jako **modularny monolit w .NET**, z frontendem **Angular**, aplikacją mobilną **Flutter** i bazą **PostgreSQL**. Usługi uruchamiamy na VPS w kontenerach zarządzanych przez **Docker Compose**. Publiczny landing, aplikacja rodziny i panel administratora platformy mają osobne punkty wejścia.

Logowanie klientów obsługuje **Microsoft Entra External ID w external tenant**. Google jest dostawcą tożsamości skonfigurowanym w Entra. Klient otrzymuje token do API od Entra, a nie bezpośrednio od Google. Administratorzy platformy logują się kontami organizacyjnymi w osobnym **Entra workforce tenant**, z MFA.

**Administrator rodziny nie jest administratorem platformy.** Rodzina zarządza własną przestrzenią opieki. Panel administracyjny platformy jest dostępny wyłącznie dla jawnie uprawnionych pracowników.

Dokument określa technologie, podział odpowiedzialności, kontrakty i wymagania wdrożeniowe. Przykłady domen i konfiguracji są wzorcami, a nie uruchomioną infrastrukturą. Nie zawiera sekretów ani gotowych rejestracji Entra.


### Zakres opieki: nie tylko seniorzy

Bliveo jest narzędziem organizacji **różnych rodzajów opieki**: nad dziećmi (w tym opiekunka zajmująca się dwojgiem lub większą liczbą dzieci), osobami z niepełnosprawnościami, seniorami oraz osobami potrzebującymi czasowego wsparcia. Typ opieki jest opcjonalną konfiguracją i szablonem planu, a nie odrębną, sztywną wersją produktu. Niepełnosprawność nie oznacza automatycznie ograniczenia samodzielności, decyzyjności ani uprawnień osoby.

**Przestrzeń opieki ma relację 1:N do profili osób pod opieką.** Profil może istnieć bez konta logowania — np. dla małego dziecka. Jedna opiekunka ma jedno konto i może mieć przypisanie do kilku profili. Na ekranie Dzisiaj i w kalendarzu wybieramy „Wszyscy” lub konkretną osobę. Widok „Wszyscy” agreguje wyłącznie profile i dane dostępne dla bieżącego użytkownika.

Leki są opcjonalnym modułem, nie centralnym wymaganiem każdego planu. Dzieci mogą mieć posiłki, drzemki, zajęcia i upoważniony odbiór; dorośli mogą ustalać transport, zakupy lub inne wybrane formy wsparcia. Szablon nie narzuca potrzeb ani nie zastępuje indywidualnych decyzji.

## 2. Docelowy stack

| Obszar | Wybór | Zastosowanie |
|---|---|---|
| Backend | .NET 10 LTS, ASP.NET Core 10, C# zgodny z SDK | REST API i logika produktu |
| Organizacja backendu | Modularny monolit, pionowe przypadki użycia | Jedna baza kodu i transakcji; osobny proces zadań |
| ORM | EF Core 10 + Npgsql tej samej głównej wersji | PostgreSQL, migracje, transakcje |
| Baza | PostgreSQL 18, aktualny patch | Dane produktu, audyt, outbox, sesje |
| API | REST JSON, OpenAPI, Problem Details | Kontrakt dla Angulara i Fluttera |
| Tożsamość klientów | Microsoft Entra External ID | Konta rodzin, opiekunów i osób korzystających ze wsparcia |
| Google | Federacja Google w Entra External ID | Jeden przepływ OIDC i jeden zaufany wystawca tokenów klientów |
| Tożsamość administratorów | Entra workforce tenant + MFA | Osobna aplikacja administracyjna |
| Web | Angular 22, standalone components, Router, Reactive Forms | Aplikacja webowa i oddzielny panel admina |
| Stan web | Signals + RxJS; serwisy funkcjonalne | Bez globalnego store na starcie |
| UI i CSS web | Angular Material/CDK + SCSS + CSS custom properties | Dostępne komponenty i własny wygląd Bliveo |
| Marketing | Angular prerender | Landing, kontakt, funkcje, FAQ i cennik bez runtime SSR |
| Sesja przeglądarki | ASP.NET Core BFF + OIDC + cookie HttpOnly | Tokeny Entra pozostają po stronie serwera |
| Mobile | Flutter stable + Dart z tego SDK | Android i iOS |
| Stan mobile | Riverpod | Stan funkcji i zależności |
| Nawigacja mobile | go_router | Deep linki, ekrany i przekierowania logowania |
| HTTP mobile | Dio + klient generowany z OpenAPI | Typowane wywołania API |
| Logowanie mobile | flutter_appauth, Authorization Code + PKCE | Systemowa przeglądarka, Entra i federacja Google |
| Sekrety mobile | flutter_secure_storage | Token odświeżający w magazynie systemowym |
| Lokalne szkice mobile | Drift/SQLite z szyfrowaniem sprawdzonym na obu platformach | Minimalne szkice; brak pełnej repliki danych zdrowotnych |
| Zadania w tle | .NET Worker Service + PostgreSQL outbox/jobs | Przypomnienia, push, e-mail, pliki i eksporty |
| Push | Firebase Cloud Messaging; APNs dla iOS przez FCM | Firebase wyłącznie do powiadomień, nie logowania |
| E-mail produktu | Adapter SMTP do wybranego dostawcy transakcyjnego | Zaproszenia i powiadomienia; SPF/DKIM/DMARC |
| Pliki | Prywatny wolumen na VPS, abstrakcja IFileStorage | Zdjęcia i załączniki; późniejsza migracja do S3 |
| Płatności | Adapter Stripe Billing, checkout hostowany | Webowy abonament rodzinny, webhooki |
| Reverse proxy | Caddy 2 | HTTPS, routing, certyfikaty |
| Kontenery | Docker Engine + Compose v2 | Wdrożenie na jednym VPS |
| System VPS | Ubuntu Server 24.04 LTS, aktualizowany | Host Linux; należy sprawdzić wsparcie wybranego obrazu .NET |
| Logi i metryki | OpenTelemetry, logi JSON, Prometheus + Grafana | Diagnostyka bez treści medycznych w telemetryce |
| Backup | pgBackRest + szyfrowany backup plików poza VPS | Odtwarzanie bazy i załączników |
| CI/CD | GitHub Actions + prywatny GHCR | Testy, budowa obrazów, staging i produkcja |

### Polityka wersji

- .NET 10 jest linią LTS; SDK przypinamy w `global.json`, pakiety centralnie w `Directory.Packages.props`.
- Angular 22: Node 24 w wersji zgodnej z tabelą Angulara, co najmniej 24.15.0; TypeScript 6.0.x w obsługiwanym zakresie `<6.1.0`; RxJS 7.x w zgodnym zakresie. Angular CLI, framework i Material/CDK utrzymujemy w zgodnych wersjach.
- Flutter wybieramy z kanału stable i przypinamy konkretną wersję w FVM. Dart pochodzi z tego samego SDK. Nie podajemy niezweryfikowanego numeru Fluttera.
- Przed pierwszym commitem zatwierdzamy komplet dokładnych patchy i zgodność bibliotek; `package-lock.json`, `pubspec.lock` i locki NuGet są wersjonowane.
- Obrazy produkcyjne wskazujemy przez niezmienny tag wydania i digest. Nie wdrażamy tagu `latest`.

## 3. Architektura i domeny

Domeny poniżej są symboliczne. Właściwą domenę trzeba podstawić po potwierdzeniu jej dostępności.

| Adres | Zawartość | Dostęp |
|---|---|---|
| `https://<domena>` | Landing, funkcje, FAQ, cennik, kontakt, dokumenty | Publiczny |
| `https://app.<domena>` | Angular rodziny + customer BFF | Publiczny shell, dane po zalogowaniu |
| `https://api.<domena>/api/v1` | REST dla aplikacji mobilnej | Token Entra External ID |
| `https://api.<domena>/api/admin/v1` | API administracyjne | Token workforce + uprawnienie PlatformAdmin |
| `https://admin.<domena>` | Angular Admin + admin BFF | Logowanie workforce i polityka administratora przed wydaniem panelu |

```mermaid
flowchart TB
    Web["Angular: rodzina"] --> BFF["Customer BFF"]
    BFF --> API["ASP.NET Core API"]
    Mobile["Flutter: Android / iOS"] --> API
    Admin["Angular Admin"] --> ABFF["Admin BFF"]
    ABFF --> API
    API --> DB[("PostgreSQL")]
    API --> Files["Prywatne pliki"]
    Worker[".NET Worker"] --> DB
    Worker --> Files
    Worker --> Send["Push / e-mail"]
    BFF --> CIAM["Entra External ID"]
    Mobile --> CIAM
    Google["Google"] --> CIAM
    ABFF --> Workforce["Entra workforce + MFA"]
```

Caddy jest wspólną warstwą wejściową HTTPS przed aplikacjami. API, BFF i worker współdzielą moduły produktu, lecz uruchamiają się jako osobne procesy. To nie oznacza podziału domeny na mikroserwisy. BFF przechowuje sesję i przekazuje do API token użytkownika; nie omija autoryzacji API.

## 4. Backend .NET

### Moduły produktu

| Moduł | Odpowiedzialność |
|---|---|
| IdentityAccess | Powiązanie tożsamości Entra z użytkownikiem Bliveo, sesje, blokady |
| CareSpaces | Przestrzeń, wiele profili osób pod opieką, przypisania opiekunów i dostęp per osoba |
| Invitations | Zaproszenia z terminem ważności, akceptacja, unieważnienie |
| CareJournal | Wpisy, komentarze, zdjęcia, odczytanie wpisu, szkice |
| Medication | Plan według zalecenia, wystąpienia i historia potwierdzeń |
| Tasks | Zadania, przydzielenie, terminy, cykliczność i wykonanie |
| Shopping | Produkty, ilości, kupujący, oznaczenie zakupu |
| Calendar | Wizyty, dyżury, transport, odwiedziny i zmiany terminów |
| Notifications | Preferencje, skrzynka powiadomień, push i e-mail |
| Billing | Abonament, uprawnienia planu, checkout i webhooki |
| Audit | Historia dostępu i istotnych operacji |
| Administration | Konta platformy, blokady, limity, rozliczenia i stan usług |

Każdy moduł zawiera model domenowy, przypadki użycia, walidację i warstwę infrastruktury. Jeden `DbContext` oraz osobne schematy/nazwy tabel modułów wystarczą na MVP. Nie wprowadzamy generycznego repozytorium dublującego EF Core, Event Sourcing ani obowiązkowej magistrali komunikatów.

### Biblioteki i standardy

- ASP.NET Core Controllers z `[ApiController]`, wbudowane DI i Options z walidacją konfiguracji przy starcie.
- `Microsoft.Identity.Web` / `JwtBearer` dla API oraz OIDC + cookies w BFF; osobne, nazwane schematy klientów i administracji.
- EF Core + Npgsql, jawne transakcje dla zmian wymagających atomowości.
- FluentValidation lub równoważne walidatory przypadków użycia; błędy jako Problem Details, bez stack trace w odpowiedzi.
- Wbudowane OpenAPI; interaktywna dokumentacja tylko na dev/staging lub za autoryzacją.
- `System.Text.Json`, OpenTelemetry oraz ustrukturyzowane logi do stdout.
- Migracje jako jednorazowy krok wdrożenia. Nie uruchamiamy ich jednocześnie przez każdą replikę API.
- SDK Stripe i FCM przez adaptery; rdzeń produktu nie zależy bezpośrednio od modeli dostawców.

## 5. Entra ID i Google

### 5.1. Klienci Bliveo

Używamy **external tenant przeznaczonego dla klientów**, a nie automatycznego dodawania wszystkich rodzin jako gości B2B w firmowym katalogu.

1. Utworzyć external tenant i odpowiednio oznakowany user flow logowania/rejestracji.
2. Włączyć wybraną metodę lokalną: rekomendowany start to e-mail z kodem jednorazowym; opcję hasła można wybrać na etapie konfiguracji produktu.
3. W Google utworzyć klienta OAuth dla federacji. Dokładne redirect URI pobrać z konfiguracji Entra; nie konstruować go ręcznie.
4. Dodać Google w Entra jako identity provider i przypisać go do user flow.
5. Powiązać rejestracje customer web i mobile z tym flow oraz dodać delegowany scope API.
6. Skonfigurować osobne redirect URI dla dev, staging i prod oraz poprawny logout.

Google działa przez **browser-delegated authentication**. W Flutterze otwieramy systemową przeglądarkę; nie budujemy własnego formularza Google i nie używamy embedded WebView. Native authentication Entra nie jest wybranym trybem dla tego projektu, ponieważ potrzebujemy federacji społecznościowej.

### 5.2. Rejestracje aplikacji

| Rejestracja | Katalog | Typ i uprawnienia |
|---|---|---|
| `bliveo-customer-api` | External | Zasób API, delegowany scope np. `access_as_user` |
| `bliveo-customer-web` | External | Confidential web client BFF, dostęp do customer API |
| `bliveo-mobile` | External | Public/native client, PKCE, bez client secret |
| `bliveo-admin-api` | Workforce | Osobny zasób/audience i scope np. `admin.access` |
| `bliveo-admin-web` | Workforce | Confidential web client BFF, dostęp do admin API |

Nazwy scope są propozycją kontraktu. Pełne identyfikatory, audience i issuer muszą wynikać z rzeczywistych rejestracji. Rozdzielenie katalogu workforce i external jest świadomą rekomendacją izolacji administracji.

### 5.3. Web: wzorzec BFF

Angular nie przechowuje tokenów Entra w `localStorage`. Przeglądarka posiada wyłącznie cookie sesyjne `Secure`, `HttpOnly`, odpowiednio ustawione `SameSite`; cookie klienta i admina mają inne nazwy, hosty oraz klucze ochrony. Parametry cookies korelacyjnych OIDC dobieramy do używanego response mode i testujemy w Safari.

Przebieg: Angular → `/bff/login` → Entra → callback BFF → cookie sesji. BFF otrzymuje i odświeża token do własnego API, przechowując go zaszyfrowanego po stronie serwera. Angular wywołuje `/bff/api/...` na tym samym origin; BFF przekazuje żądanie do API z bearer tokenem. Proxy ma allowlistę tras i metod, nigdy dowolny URL dostarczony przez klienta.

Zmiany danych wymagają ochrony CSRF/antiforgery i kontroli Origin. Tokeny i bilety sesji nie trafiają do cookie w formie jawnej ani do logów. Serwerowy magazyn sesji/tokenów wykorzystuje PostgreSQL i szyfrowanie ASP.NET Data Protection. Klucze Data Protection są trwałe, chronione i archiwizowane oddzielnie od bazy; customer BFF i admin BFF mają różne key ringi i `ApplicationName`.

### 5.4. Flutter

- Authorization Code + PKCE S256, `state` i `nonce`, OIDC discovery z przypiętego wystawcy Entra.
- Konfiguracja Android/iOS i redirect URI zgodna z rejestracją native client; weryfikowane App Links/Universal Links, jeśli wspiera je wybrana konfiguracja, inaczej dedykowany poprawnie zarejestrowany schemat callback.
- `flutter_appauth` jest biblioteką społecznościową opartą o AppAuth, nie oficjalnym SDK MSAL dla Fluttera. Integrację Entra/Google sprawdzamy jako pierwszy spike na fizycznym Androidzie i iPhonie.
- Access token w pamięci, refresh token w bezpiecznym magazynie systemowym. Tokenów nie zapisujemy w SQLite ani raportach błędów.
- Jedno współdzielone odświeżenie tokenu dla równoległych żądań. Po niepowodzeniu odświeżenia powrót do logowania, bez pętli retry.
- API otrzymuje access token przeznaczony dla Bliveo. ID token ani token Google nie są credentialem do API.
- Wylogowanie usuwa lokalne tokeny i prywatne szkice zgodnie z wybraną opcją użytkownika; zakończenie lokalnej sesji nie jest obietnicą wylogowania z całego Google.

### 5.5. Walidacja API i identyfikacja osoby

API sprawdza podpis, dozwolony issuer, audience, ważność i wymagany scope. Polityki klienta akceptują wyłącznie schemat customer, a polityki admina wyłącznie workforce. Nie stosujemy dowolnego `common` ani automatycznej akceptacji wszystkich katalogów. API mobilne jest bearer-only; nie dopuszczamy tu przypadkowego fallbacku do cookies BFF.

Użytkownik Bliveo ma wewnętrzny UUID. Tożsamości przechowujemy w `ExternalIdentity` jako przestrzeń nazw wystawcy oraz stabilny identyfikator. Dla Entra preferujemy zweryfikowane `(tid, oid)`, gdy token je udostępnia; `(iss, sub)` pozostaje identyfikatorem konkretnego klienta OIDC i wymaga jawnego mapowania między aplikacjami. Nigdy nie łączymy automatycznie kont po samym adresie e-mail. Logowanie lokalne i Google z tym samym e-mailem mogą wymagać kontrolowanego procesu powiązania.

## 6. Role i autoryzacja

### Przestrzeń opieki

| Rola | Domyślny zakres |
|---|---|
| `CareSpaceOwner` | Członkostwa, plan, ustawienia przestrzeni i abonament |
| `CareSpaceAdmin` | Organizacja opieki i zaproszenia; płatności tylko z dodatkowym uprawnieniem |
| `FamilyMember` | Dane i działania udostępnione konkretnej osobie |
| `Caregiver` | Przydzielone czynności, raporty i przyznane sekcje |
| `CareRecipient` | Opcjonalne konto osoby korzystającej ze wsparcia; dostęp do własnego planu według indywidualnych potrzeb |

Uprawnienia szczegółowe, np. `Journal.Read`, `Journal.Write`, `Medication.Read`, `Medication.Confirm`, `Medication.EditPlan`, `Photos.Read`, `Members.Manage`, `Billing.Manage`, przechowujemy w bazie per członkostwo. Potwierdzanie leków i zmiana planu to różne uprawnienia.

Każdy odczyt i zapis sprawdza: tożsamość, aktywność konta, aktywne członkostwo, `CareSpaceId`, uprawnienie i sam zasób. Identyfikator przestrzeni w URL lub nagłówku nie jest dowodem dostępu. Globalne filtry EF są dodatkowym zabezpieczeniem, a nie jedyną warstwą autoryzacji. Ograniczenia obowiązują również eksporty, zdjęcia, wyszukiwanie i zadania tła.

### Panel administratora platformy

Jedyna rola panelu w MVP to `PlatformAdmin`. To uprawnienie jest nadawane poza samoobsługową rejestracją i zapisane w odrębnej tabeli powiązanej z tożsamością workforce. Nie wynika z domeny e-mail, roli rodzinnej ani danych przesłanych z frontendu.

Warunki wejścia:

1. Uwierzytelnienie w dopuszczonym tenant workforce.
2. Przypisanie do aplikacji administracyjnej w Entra.
3. MFA egzekwowane polityką Entra dla całej aplikacji lub właściwej grupy, nie tylko wbudowanych ról katalogowych. Sprawdzić wymaganą licencję Conditional Access; preferowane phishing-resistant MFA.
4. Aktywna lokalna rola `PlatformAdmin`.
5. Ponowna kontrola uprawnień w admin BFF i dla każdego endpointu admin API.

Osobny Angular Admin budujemy jako osobną aplikację. Jego HTML i zasoby serwuje admin BFF **po autoryzacji**. Nie wystawiamy katalogu plików admina przez publiczny `UseStaticFiles` ani Caddy `file_server` omijający tę kontrolę. Jedynie callback, logowanie, odmowa dostępu i niezbędne publiczne zasoby logowania są jawnie wyłączone z tej reguły. Guard Angulara i ukrycie menu poprawiają UX, ale nie stanowią zabezpieczenia.

Nieudokumentowany endpoint administracyjny również wymaga polityki. Niezalogowane żądanie API zwraca `401`, zalogowany użytkownik bez uprawnienia `403`; API nie przekierowuje na HTML logowania. Odebranie roli w bazie ma blokować następne żądanie, także przy nadal ważnym JWT.

### Zakres panelu

- Konta i blokady, przestrzenie i metadane członkostw, limity oraz stan abonamentów.
- Kolejki powiadomień, błędy przetwarzania, techniczny stan systemu i audyt operacji administratorów.
- Zwykły panel nie daje automatycznego wglądu do treści dziennika, leków i zdjęć wszystkich rodzin.
- Ewentualny dostęp wsparcia do danych opieki wymaga odrębnego, czasowego i audytowanego mechanizmu. Impersonacja jest poza MVP.
- Nie używamy kont Global Administrator Entra do codziennej obsługi Bliveo.

## 7. Angular, CSS i system wizualny

Trzy aplikacje w jednym workspace Angular CLI: `marketing`, `family-web`, `admin-web`. Wspólne biblioteki: `ui`, `design-tokens`, `api-client`, `auth-session`, `i18n` i komponenty domenowe. Landing generujemy przez prerender podczas budowy; nie potrzebuje osobnego serwera Node w produkcji.

Angular Material/CDK dostarcza pola, dialogi, overlay, selektory, focus trap, tabele i dostępność klawiatury. Własne komponenty Bliveo opakowują te elementy; nie pokazujemy domyślnego motywu Material. SCSS służy do organizacji stylów, a CSS custom properties do tokenów i motywów. Nie dokładamy Bootstrap, Tailwind ani drugiej biblioteki komponentów.

```css
:root {
  --bliveo-color-primary: #315c45;
  --bliveo-color-sage: #dbe7d9;
  --bliveo-color-background: #f7f8f4;
  --bliveo-color-surface: #ffffff;
  --bliveo-color-text: #172b22;
  --bliveo-color-border: #e2e7e0;
  --bliveo-color-pending: #fff0d3;
  --bliveo-radius-card: 12px;
  --bliveo-radius-control: 8px;
  --bliveo-space-unit: 4px;
}
```

Wspólny plik `design-tokens.json` jest źródłem kolorów, odstępów, promieni i typografii. Skrypt generuje CSS/SCSS oraz stałe i rozszerzenia `ThemeData` Fluttera. Angular i Flutter współdzielą kontrakt wizualny, nie kod komponentów. Kolory tekstu i stanów sprawdzamy pod kątem kontrastu; sam kolor nie przekazuje statusu.

Wymagania: minimum 16 px tekstu bazowego, duże pola dotykowe docelowo 44–48 px, skalowanie tekstu, poprawna kolejność fokusu, czytelne walidacje, komunikaty dla czytników i cel dostępności WCAG 2.2 AA. Duże nagłówki serif dopuszczamy w marketingu, a interfejs operacyjny ma czytelny sans-serif. Fonty hostujemy lokalnie.

Strony rodziny: Dzisiaj, Dziennik, Leki, Zadania, Zakupy, Kalendarz, Rodzina, Powiadomienia, Profil osoby pod opieką, Preferencje, Abonament i Pomoc. Admin ma odrębną nawigację. Dialogi i formularze mają wspólne reguły anulowania, walidacji, blokowania podwójnego zapisu oraz obsługi niezapisanych zmian.

## 8. Flutter i zachowanie offline

Struktura funkcjonalna: `features/auth`, `care_spaces`, `today`, `journal`, `medication`, `tasks`, `shopping`, `calendar`, `members`, `settings`; wspólne `core/network`, `core/storage`, `core/theme`, `core/errors`. Warstwy funkcji: prezentacja, logika przypadku użycia, repozytorium i źródło danych.

Pakiety: `flutter_riverpod`, `go_router`, `dio`, `flutter_appauth`, `flutter_secure_storage`, `firebase_core`, `firebase_messaging`, `drift`, `freezed`, `json_serializable`, `intl` oraz selektor zdjęć. Każdy musi przejść kontrolę kompatybilności z przypiętym Flutterem i wymaganiami obu sklepów.

- MVP pozwala tworzyć lokalny szkic raportu; pełna synchronizacja offline jest poza MVP.
- Treści medycznych i całych zdjęć nie utrwalamy domyślnie w cache. Szkice mają retencję i są usuwane przy odebraniu dostępu lub wylogowaniu zgodnie z regułą produktu.
- Jeśli szyfrowanie SQLite nie zostanie poprawnie wdrożone na obu platformach, wyłączamy trwałe przechowywanie wrażliwych szkiców; zwykły SQLite nie jest uznawany za zaszyfrowany magazyn.
- Operacje wymagające wiarygodnego potwierdzenia, szczególnie przyjęcie leku, otrzymują stan oczekujący na zapis. Lokalny klik nigdy nie pokazuje fikcyjnego potwierdzenia w chmurze.
- Po powrocie do aplikacji pobieramy aktualne uprawnienia i dane. Push nie jest jedynym mechanizmem synchronizacji.
- Deep link do wpisu lub wizyty wymaga logowania i ponownej kontroli dostępu przez API.

## 9. PostgreSQL i model danych

| Encje | Najważniejsze informacje |
|---|---|
| User, ExternalIdentity | Wewnętrzny UUID, stan konta, mapowanie zweryfikowanej tożsamości |
| CareSpace, CareRecipientProfile | Granica przestrzeni; wiele profili osób pod opieką, niezależnych od kont logowania |
| Membership, PermissionGrant, CaregiverAssignment | Role oraz uprawnienia per przestrzeń i profil osoby; przypisanie opiekuna do wielu osób |
| GuardianRelationship | Relacja opiekuna prawnego/rodzica z konkretnym profilem; odrębna od roli w przestrzeni |
| Invitation | Hash tokenu, ważność, adresat, rola, użycie i unieważnienie |
| JournalEntry, Comment, ReadReceipt | Autor, historia zmian, odczyty i załączniki |
| MedicationPlan, MedicationOccurrence | Plan i wystąpienia konkretnej osoby z obowiązkowym CareRecipientId |
| MedicationConfirmation | Niezmienialny wpis statusu, autor, czas i korekta przez kolejny wpis |
| Task, TaskOccurrence | Reguła powtarzania i oddzielne wykonania |
| ShoppingItem | Ilość, jednostka, właściciel zakupu i stan |
| CalendarEvent, Assignment | Wizyta, dyżur, transport i odpowiedzialność |
| Attachment | Właściciel, przestrzeń, typ, rozmiar, klucz pliku, stan skanowania |
| Notification, DeviceRegistration | Powiadomienia i tokeny urządzeń przypisane do użytkownika |
| Subscription, BillingEvent | Stan abonamentu i identyfikatory dostawcy |
| AuditEvent, OutboxMessage, BackgroundJob | Audyt, niezawodne wysyłanie i zadania |
| PlatformAdminGrant, ServerSession | Uprawnienia administracyjne oraz zaszyfrowane sesje BFF |

Zasady:

- Wszystkie encje przestrzeni mają `CareSpaceId`; indeksy uwzględniają przestrzeń i pola wyszukiwania.
- Czas zdarzeń zapisujemy w UTC. Strefa IANA, np. `Europe/Warsaw`, należy do przestrzeni; cykliczne godziny lokalne przechowujemy wraz ze strefą, aby obsłużyć DST.
- Optymistyczna współbieżność przez jawny token wersji/ETag. Konflikt edycji zwraca `409` lub `412`, zgodnie z kontraktem.
- Powtórne kliknięcie i ponowienie żądania nie tworzą drugiej czynności: idempotency key, unikalne indeksy i transakcja.
- Potwierdzenia leków nie są zwykłym booleanem `done`. Korekty zachowują poprzedni wpis, autora i przyczynę.
- Audyt jest append-only z ograniczonymi uprawnieniami bazy; operacyjne konto API nie służy do kasowania audytu.
- Retencja i usuwanie obejmują bazę, pliki, eksporty i harmonogram wygasania backupów. Soft delete nie oznacza trwałego usunięcia danych.
- RLS PostgreSQL można dodać jako drugą barierę po testach; nie deklarujemy go jako działającego bez migracji i testów izolacji.


### Powiązanie danych z osobami

- `CareRecipientProfile` ma `Id`, `CareSpaceId`, nazwę wyświetlaną, opcjonalną datę urodzenia, preferencje, wymagane wsparcie i opcjonalne powiązanie z kontem użytkownika. Nie wymaga pola choroby ani diagnozy.
- `CaregiverAssignment` wiąże aktywne członkostwo opiekuna z konkretnymi profilami; opiekunka dwojga dzieci otrzymuje dwa przypisania.
- `PermissionGrant` może mieć zakres całej przestrzeni lub wskazanego `CareRecipientId`. Dostęp do jednej osoby nie daje dostępu do pozostałych.
- `MedicationPlan`, `MedicationOccurrence` i `MedicationConfirmation` wskazują dokładnie jedną osobę. Potwierdzenie nigdy nie obejmuje jednocześnie dwojga dzieci.
- Zadania, wizyty i wpisy mają jawne powiązania z jedną lub wieloma osobami, np. przez `TaskRecipient`, `CalendarEventRecipient` i `JournalEntryRecipient`. Wydarzenie „spacer Oli i Kuby” może dotyczyć obojga; czynności wspólne gospodarstwa mają osobny, jawny zakres.
- Jeżeli wpis, komentarz lub zdjęcie zawiera dane kilku osób, odbiorca musi mieć dostęp do całego zakresu informacji. W MVP taki wpis jest ukrywany przed osobą bez kompletu uprawnień; nie ujawniamy go na podstawie dostępu do tylko jednego z dzieci. W przeciwnym razie należy utworzyć osobne wpisy.
- Rodzic/opiekun prawny jest relacją do wskazanego profilu, nie automatycznym uprawnieniem do wszystkich profili w przestrzeni. Samo bycie administratorem rodziny nie potwierdza takiej relacji.
- Osoba pełnoletnia może współtworzyć plan i zarządzać swoim kontem zgodnie z nadanymi uprawnieniami. Rola i interfejs nie wynikają automatycznie z niepełnosprawności ani wieku.

## 10. Kontrakt REST API

Prefiks klienta: `/api/v1`. OpenAPI jest źródłem kontraktu, z którego generujemy klienta TypeScript i Dart; zmiany kontraktu kontroluje CI.

| Endpoint / grupa | Zadanie |
|---|---|
| `GET /me` | Konto, przestrzenie, uprawnienia i możliwości planu |
| `POST /care-spaces` | Utworzenie przestrzeni |
| `/care-spaces/{id}/care-recipients` | Lista i zarządzanie wieloma profilami osób pod opieką |
| `/care-spaces/{id}/care-recipients/{recipientId}/caregivers` | Przypisanie opiekunów do wybranej osoby |
| `GET /care-spaces/{id}/today?recipientId={recipientId}` | Plan wybranej osoby; brak filtra oznacza tylko dozwoloną agregację |
| `/care-spaces/{id}/members` | Członkowie i uprawnienia |
| `/care-spaces/{id}/invitations` | Tworzenie i unieważnianie zaproszeń |
| `POST /invitations/accept` | Akceptacja zaproszenia przez zalogowaną osobę |
| `/care-spaces/{id}/journal-entries` | Wpisy i komentarze |
| `/care-spaces/{id}/medication-plans` | Plan zgodny z zaleceniem |
| `POST /care-spaces/{id}/medication-occurrences/{occurrenceId}/confirmations` | Nowy wpis potwierdzenia statusu |
| `/care-spaces/{id}/tasks`, `/shopping-items`, `/calendar-events` | Organizacja dnia |
| `/care-spaces/{id}/attachments` | Autoryzowany upload i pobieranie plików |
| `/notifications`, `/device-registrations` | Skrzynka i rejestracja urządzeń |
| `/care-spaces/{id}/subscription` | Abonament i checkout dla uprawnionej osoby |
| `POST /billing/webhooks/stripe` | Webhook z walidacją podpisu, bez sesji klienta |
| `/api/admin/v1/*` | Osobny kontrakt administracji i audience workforce |

Endpointy kolekcji mają paginację, limit rozmiaru strony, kontrolowane sortowanie i filtry. Zapis zwraca identyfikator i wersję; usunięcie ma jawnie określoną semantykę. `401`, `403`, `404`, `409`, `412`, `422` i `429` mają wspólny format błędu z `code`, `traceId` i błędami pól. Przy próbie dostępu do cudzej przestrzeni można zwracać `404`, aby nie ujawniać jej istnienia; kontrakt musi być konsekwentny.

Rate limiting obejmuje kontakt, zaproszenia, upload, eksporty i kosztowne zapytania. CORS ma dokładną allowlistę, bez `*` z credentials; BFF działa same-origin. Kontakt publiczny wymaga walidacji, limitów i ochrony przed spamem.

## 11. Zadania w tle i powiadomienia

Na start wystarczy PostgreSQL zamiast Redis/RabbitMQ. Zmiana domenowa i `OutboxMessage` zapisują się w jednej transakcji. Worker pobiera rekordy z leasingiem i blokadą, np. `FOR UPDATE SKIP LOCKED`, a po wykonaniu aktualizuje stan. Po awarii lease wygasa i inny przebieg może podjąć zadanie.

Gwarancja przetwarzania to **at least once**, dlatego każde działanie ma klucz deduplikacji. Retry jest ograniczony, z backoffem i jitterem; trwale nieudane zadania trafiają do osobnego stanu wymagającego obsługi. Operacje wysyłania uwzględniają możliwe duplikaty u dostawcy.

Przed wysyłką worker sprawdza aktualne członkostwo, preferencje, ciszę nocną i stan czynności. Przeplanowanie lub anulowanie wizyty musi unieważniać poprzednie przypomnienia. Obsługujemy zmianę czasu, opóźnione zadania i restart VPS bez powielania wystąpień.

FCM/APNs dostają neutralny komunikat, np. „Nowa informacja w Bliveo”, oraz techniczny identyfikator. Szczegóły leków i zdrowia użytkownik pobiera po autoryzacji. API usuwa nieaktywne tokeny urządzeń. Push i e-mail są kanałami best effort, a nie gwarancją odebrania przypomnienia czy systemem alarmowym.

## 12. Zdjęcia i załączniki

- Prywatny wolumen współdzielony przez API i worker; pliki poza katalogiem publicznego web serwera.
- Losowy klucz pliku i powiązanie z `CareSpaceId`; nazwa użytkownika nie jest ścieżką na dysku.
- Limit wielkości, liczby plików i dozwolonych formatów; weryfikacja sygnatury pliku, nie tylko deklarowanego MIME.
- Upload w kwarantannie do czasu walidacji i skanowania; ClamAV jako opcjonalny kontener skanera, wymagany przed włączeniem szerszego zestawu załączników.
- Zdjęcia przetwarzane w kontrolowanym workerze, limit rozdzielczości i zasobów; usuwanie EXIF, generowanie miniatur.
- Pobieranie przez endpoint sprawdzający dostęp. Brak publicznych trwałych linków i indeksowania zdjęć.
- Backup musi obejmować metadane oraz odpowiadające im pliki. Przejście do S3 nie zmienia kontraktu domenowego.

## 13. Abonamenty

Jedna płacąca przestrzeń opieki, nie osobna opłata za każdą osobę. Plan `Start`: jedna osoba pod opieką, do trzech członków rodziny. Plan `Rodzina`: obsługa wielu osób pod opieką oraz członkowie rodziny i opiekunowie bez limitu. Liczba profili osób pod opieką jest osobnym parametrem planu; musi umożliwiać co najmniej scenariusz opieki nad dwojgiem dzieci. Nie oznacza to automatycznie nielimitowanego storage ani nielimitowanej liczby profili. Limity miejsca i załączników są oddzielnymi parametrami planu. Cena 14,90 zł/mies. pozostaje propozycją produktu, nie stałą zaszytą w kliencie.

API wyznacza uprawnienia planu z lokalnego, zweryfikowanego stanu subskrypcji. Powrót z checkoutu nie aktywuje samodzielnie planu; rozstrzyga podpisany webhook i synchronizacja z dostawcą. Webhooki są idempotentne, mogą przyjść ponownie lub w innej kolejności. Admin nie ma dostępu do danych karty.

W MVP rekomendujemy zakup abonamentu w web. Przed publikacją płatnej aplikacji mobilnej trzeba osobno zatwierdzić model sprzedaży i wymagania rozliczeniowe iOS/Android; nie zakładamy automatycznie dopuszczalności linkowania do web checkoutu. Zakup w sklepie, jeśli potrzebny, wymaga osobnego adaptera i serwerowej weryfikacji transakcji.

## 14. Docker Compose na VPS

### Procesy i sieci

| Serwis | Zawartość | Publiczny port hosta |
|---|---|---|
| `edge` | Caddy, landing i proxy | `80`, `443` |
| `web-bff` | .NET customer BFF + build Angular family | Brak |
| `admin-bff` | .NET admin BFF + chroniony build Angular Admin | Brak |
| `api` | ASP.NET Core REST | Brak; wystawiane przez Caddy |
| `worker` | Zadania domenowe, wysyłka, przetwarzanie plików | Brak |
| `postgres` | Baza | Brak |
| `backup` | Harmonogram pgBackRest i kopii plików | Brak |
| `prometheus`, `grafana` | Monitoring | Brak publicznego dostępu; tunel/VPN |
| `clamav` | Skaner plików po włączeniu obsługi uploadu | Brak |

Sieci: `edge-net` dla proxy i hostów aplikacji; `data-net` dla procesów potrzebujących bazy. Tylko wybrane kontenery mają dostęp do PostgreSQL. Procesy wymagające Entra, SMTP, FCM lub backupu zachowują kontrolowany ruch wychodzący; ustawienie `internal: true` nie może przypadkowo odciąć im Internetu.

Wolumeny: `postgres-data`, `attachments`, `caddy-data`, `caddy-config`, osobne key ringi BFF i dane monitoringu. Dla PostgreSQL 18 mount i `PGDATA` dobieramy do **konkretnego oficjalnego obrazu**, weryfikując jego dokumentację zamiast kopiować ścieżkę z konfiguracji starszego PostgreSQL. Wolumen nie jest backupem.

### Standard kontenerów

- Multi-stage build: SDK służy do budowania, runtime do uruchamiania; Angular kompilowany w etapie Node.
- Osobne entrypointy API, workera i obu BFF. Jeden tag wydania całego systemu.
- Użytkownik non-root tam, gdzie pozwala obraz; brak `privileged`, brak montowania Docker socket do aplikacji.
- `read_only` i `tmpfs` tam, gdzie możliwe; zapisy tylko do jawnych wolumenów.
- Sekrety jako chronione pliki montowane do kontenera. `Docker Compose secrets` nie jest samodzielnym szyfrowanym sejfem; źródłowe pliki hosta wymagają ochrony i backupu.
- Limity pamięci/CPU, rotacja logów, `restart: unless-stopped`, kontrola poprawnego zatrzymania i healthchecki.
- `depends_on` z healthcheckiem porządkuje start, ale aplikacja nadal musi obsługiwać utratę bazy i restart zależności.
- Proxy przekazuje forwarded headers tylko od zaufanych adresów. Nie ufamy dowolnemu `X-Forwarded-For` z Internetu.
- Dokumentacja API, metryki, baza, skaner i narzędzia operatorskie nie są anonimowo wystawione.

### Parametry początkowe

Punkt startowy do pilotażu: VPS w UE z **4 vCPU, 8 GB RAM i dyskiem NVMe**, osobny staging i zaszyfrowany backup poza tym VPS. To założenie pojemnościowe, nie gwarancja obsługi konkretnej liczby rodzin. ClamAV i pełny monitoring mogą wymagać większej pamięci; w razie potrzeby monitoring przenosimy na osobny host. Wielkość dysku wynika z limitów zdjęć i retencji.

Jeden VPS jest pojedynczym punktem awarii. Docker Compose nie zapewnia automatycznie HA ani wdrożenia bez przerwy. Pierwsza ścieżka rozwoju: osobny PostgreSQL, zewnętrzny storage zdjęć i drugi host aplikacji.

## 15. CI/CD i wydania

1. Pull request: formatowanie, lint, analizatory, kompilacja .NET/Angular/Flutter, testy i kontrola sekretów.
2. Weryfikacja kontraktu OpenAPI i regeneracji klientów TypeScript/Dart.
3. Testy integracyjne na rzeczywistym PostgreSQL w Testcontainers; testy izolacji i uprawnień.
4. Build obrazów, skan podatności i SBOM; publikacja prywatnych obrazów do GHCR z tagiem commit SHA i digest.
5. Automatyczny deploy staging, migracja oraz smoke testy logowania, sesji i przepływów produktu.
6. Wydanie produkcyjne: sprawdzenie backupu i miejsca, migracja kompatybilna wstecz, `docker compose pull`, jednorazowy migrator, `docker compose up -d`.
7. Sprawdzenie liveness/readiness oraz smoke testu po wdrożeniu. Nie uznajemy uruchomionego kontenera za poprawne wydanie.
8. Przy błędzie przywrócenie poprzednich digestów aplikacji. Cofnięcie obrazu nie cofa schematu ani danych; destrukcyjne migracje wykonujemy etapowo i mają osobny plan odzyskania.

Klucze SSH i token rejestru są dedykowane do deployu. Konto należące do grupy Docker traktujemy jako uprzywilejowane na hoście. Runner CI nie otrzymuje pełnego dowolnego dostępu do VPS z niezaufanych pull requestów.

Flutter: Android budowany w CI, iOS na runnerze macOS z Xcode; VPS Linux nie buduje ani nie publikuje aplikacji iOS. Podpisywanie i publikacja w sklepach mają osobne sekrety, profile i pipeline. Aplikacja mobilna nie jest kontenerem uruchamianym na VPS — korzysta z API na VPS.

## 16. Monitoring, backup i odzyskiwanie

Metryki: dostępność, p95 opóźnień, błędy 5xx, 401/403, opóźnienie outbox, nieudane joby, połączenia z bazą, zużycie dysku, stan certyfikatów i wiek ostatniego backupu. Awaria Entra lub SMTP ma być odróżnialna od awarii API. Zewnętrzny uptime check działa poza VPS.

Logi zawierają `traceId`, identyfikator operacji i techniczne identyfikatory. Nie logujemy bearer tokenów, cookies, kodów zaproszeń, pełnych payloadów, treści raportów, leków ani adresów w URL. Metryki nie zawierają identyfikatorów użytkowników jako etykiet o wysokiej kardynalności. Dane audytu są oddzielone od zwykłych logów diagnostycznych.

**Cele operacyjne do potwierdzenia testem:** RPO bazy do 15 minut dzięki archiwizacji WAL, RTO do 4 godzin dla pilotażu. Pliki wymagają niezależnej częstości kopiowania i uzgodnienia z metadanymi bazy; nie przypisujemy im automatycznie RPO bazy. Do czasu wdrożenia i testu WAL obowiązuje faktyczny odstęp między poprawnymi kopiami.

Backup: regularne pełne/różnicowe kopie PostgreSQL + WAL, szyfrowane kopie załączników i konfiguracji, wysyłka do niezależnego magazynu S3-compatible poza VPS. Klucze deszyfrujące nie mogą istnieć wyłącznie na utraconym serwerze. Oddzielne uprawnienia do zapisu backupu i ograniczenie możliwości jego usunięcia.

Przed produkcją oraz cyklicznie odtwarzamy kopię na czystym środowisku: baza, pliki, wersja aplikacji, Data Protection, powiadomienia wyłączone na czas testu. Mierzymy RPO/RTO i kompletność zdjęć. Alert „backup wykonany” bez testu odtworzenia nie spełnia kryterium odbioru.

## 17. Testy i kryteria odbioru

| Warstwa | Narzędzia | Kluczowe scenariusze |
|---|---|---|
| .NET | xUnit, WebApplicationFactory | Przypadki użycia, polityki i kontrakty błędów |
| Baza | Testcontainers PostgreSQL | Izolacja przestrzeni, migracje, blokady i idempotencja |
| Angular | Runner zgodny z Angular CLI, Playwright E2E | Formularze, sesja BFF, dostęp admina, dostępność |
| Flutter | flutter_test, integration_test | Nawigacja, duży tekst, utrata sesji i szkice |
| Tożsamość | Dedykowane konta testowe Entra + fizyczne urządzenia | Google przez Entra, callback, anulowanie, refresh i logout |
| Operacje | Smoke test + próbne odtworzenie | Restart, niesprawna zależność, rollback i backup |

Warunki wydania:

- Użytkownik rodziny A nie odczytuje ani nie zmienia danych, plików i eksportów rodziny B, także po podmianie UUID.
- Opiekunka z prawem potwierdzenia nie edytuje planu leków bez dodatkowego uprawnienia.
- Opiekunka przypisana do Oli i Kuby widzi oboje, może filtrować plan i nie uzyskuje dostępu do trzeciej osoby.
- Przyjęcie leku, raport i zgoda odnoszą się do właściwej osoby, również po zmianie filtra i ponowieniu zapisu.
- Rodzic mający dostęp tylko do Oli nie widzi informacji o Kubie w agregatach, wspólnych wpisach, zdjęciach, eksporcie i powiadomieniach.
- Rodzinny administrator oraz konto Google nie mają dostępu do panelu admina ani admin API.
- Customer JWT jest odrzucany przez admin API; workforce JWT z błędnym audience/scope również.
- Odebranie roli platformowej lub członkostwa blokuje kolejne żądanie mimo ważnego tokenu.
- Bezpośredni URL do admin HTML, chunk JS i endpointu nie omija kontroli dostępu.
- BFF odrzuca CSRF, dowolne cele proxy i niezaufane nagłówki forwardowane.
- Przypomnienie o leku nie jest prezentowane jako potwierdzone przyjęcie; ponowienie nie dubluje wpisu.
- Powiadomienie po odebraniu dostępu lub anulowaniu czynności nie ujawnia danych.
- Restart API/workera nie gubi outboxu, sesji i oczekujących operacji.
- Buildy web, Android i iOS przechodzą test logowania z Google przez Entra.
- Działa odtworzenie danych z kopii poza VPS.

## 18. Struktura repozytorium

```text
bliveo/
  src/
    backend/
      Bliveo.Api/
      Bliveo.WebBff/
      Bliveo.AdminBff/
      Bliveo.Worker/
      Bliveo.Modules/
      Bliveo.Shared/
      Bliveo.Migrations/
    web/
      projects/marketing/
      projects/family-web/
      projects/admin-web/
      projects/ui/
      projects/api-client/
    mobile/
      lib/core/
      lib/features/
      test/
      integration_test/
  contracts/openapi/
  design/design-tokens.json
  tests/backend/
  tests/web-e2e/
  deploy/
    compose.yaml
    compose.production.yaml
    Caddyfile
    env.example
    scripts/
  docs/architecture/
  .github/workflows/
  global.json
  Directory.Packages.props
```

MVP pozostaje w jednym repozytorium. Każda aplikacja ma osobny build, ale jedno wydanie synchronizuje kontrakt API i klientów. `env.example` zawiera nazwy zmiennych i placeholdery, nigdy produkcyjne dane.

## 19. Konfiguracja wymagana przed uruchomieniem

| Grupa | Przykładowe klucze / dane |
|---|---|
| Customer Entra | Authority/issuer, TenantId, ApiAudience, Scope, WebClientId, MobileClientId |
| Admin Entra | WorkforceTenantId, Authority/issuer, AdminApiAudience, AdminScope, AdminWebClientId |
| Poufne BFF | Ścieżka do certyfikatu lub sekretu klienta, token store, osobne key ringi |
| Baza | Connection string przez chroniony plik, osobne konta migratora i runtime |
| Routing | Publiczne originy, redirect URI, trusted proxies i dokładna allowlista CORS |
| Pliki | Root prywatnego storage, limity, kwarantanna, retencja |
| Powiadomienia | FCM service account, APNs w projekcie Firebase, SMTP i domena nadawcy |
| Billing | Stripe secret, webhook signing secret, identyfikatory cen i produktów |
| Backup | Repozytorium offsite, credential, klucze szyfrowania, retencja |
| Operacje | GHCR, domeny/DNS, alerty, konta pierwszych administratorów i procedura awaryjna |

Rejestracje dev/staging/prod są odseparowane; mają własne callbacki, sekrety, bazy, storage oraz projekty powiadomień. Dane produkcyjne nie są kopiowane do deweloperskiego środowiska bez odrębnego uzasadnienia i anonimizacji.

## 20. Kolejność realizacji

1. **Spike tożsamości:** external tenant, Google, BFF i Flutter na Android/iOS; admin workforce i MFA; testy audience oraz rozróżnienia administratorów.
2. **Fundament:** rozwiązanie .NET, workspace Angular, projekt Flutter, PostgreSQL, design tokens, pipeline oraz staging Docker.
3. **Przestrzenie:** konto Bliveo, profile osób pod opieką, członkostwa, zaproszenia, szczegółowe uprawnienia i audyt.
4. **Opieka:** Dzisiaj, dziennik, zadania, zakupy i kalendarz wraz z formularzami i stanami błędu.
5. **Leki i pliki:** jawne statusy, historia potwierdzeń, kontrola współbieżności, prywatne uploady.
6. **Powiadomienia:** outbox/worker, e-mail, FCM/APNs, preferencje i odporność na powtórzenia.
7. **Administracja i abonament:** metadane, blokady, stan usług, checkout i webhooki.
8. **Gotowość produkcyjna:** testy izolacji, dostępności, obciążenia, aktualizacji, backupu i odtworzenia.

Na start nie dokładamy Kubernetes, mikroserwisów, Redis, Elasticsearch ani AI. Techniczne rozszerzenia wprowadzamy po wykazaniu potrzeby pomiarami. Apple jako dodatkowy provider logowania, zakupy sklepowe, agencje opiekuńcze, pełne offline i podsumowania AI wymagają osobnych decyzji produktowych.

## 21. Źródła i zakres weryfikacji

Wybór architektury, BFF, podział katalogów i komponentów jest rekomendacją dla Bliveo. Poniższe źródła potwierdzają możliwości platform i zgodność podstawowych wersji; przed implementacją należy ponownie sprawdzić dokładne patche, zależności i licencje. Dokument nie jest deklaracją uzyskanej zgodności prawnej ani certyfikacji bezpieczeństwa.

1. [.NET — polityka wsparcia](https://dotnet.microsoft.com/en-us/platform/support/policy) — linia .NET 10 LTS.
2. [Angular — zgodność wersji](https://angular.dev/reference/versions) — Angular, Node, TypeScript i RxJS.
3. [Angular — wydania](https://angular.dev/reference/releases) — cykl aktualizacji.
4. [Angular Material — theming](https://material.angular.dev/guide/theming) — komponenty i własny motyw.
5. [Entra External ID — metody uwierzytelniania](https://learn.microsoft.com/en-us/entra/external-id/customers/concept-authentication-methods-customers) — konta lokalne, federacja i ograniczenia native authentication.
6. [Entra External ID — Google](https://learn.microsoft.com/en-us/entra/external-id/customers/how-to-google-federation-customers) — federacja Google w external tenant.
7. [Microsoft identity platform — Authorization Code + PKCE](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow) — przepływ OIDC/OAuth.
8. [Microsoft — ochrona API .NET](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-web-api-dotnet-protect-app) — walidacja i dostęp do API.
9. [Microsoft — scopes i permissions](https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc) — zakresy dostępu.
10. [Microsoft — MFA administratorów](https://learn.microsoft.com/en-us/entra/identity/conditional-access/policy-old-require-mfa-admin) — polityki administracyjne; wymagania należy odnieść do własnej aplikacji/grupy.
11. [Flutter — archiwum SDK](https://docs.flutter.dev/install/archive) — wybór kanału stable.
12. [flutter_appauth — dokumentacja pakietu](https://pub.dev/packages/flutter_appauth) — integracja AppAuth/OIDC.
13. [Npgsql — EF Core provider](https://www.npgsql.org/efcore/) — PostgreSQL i EF Core.
14. [PostgreSQL — polityka wersjonowania](https://www.postgresql.org/support/versioning/) — wsparcie głównych wersji.
15. [Docker — Compose w produkcji](https://docs.docker.com/compose/how-tos/production/) — wdrożenie na jednym hoście.
16. [Caddy — Automatic HTTPS](https://caddyserver.com/docs/automatic-https) — certyfikaty i HTTPS.
17. [FCM — Flutter](https://firebase.google.com/docs/cloud-messaging/flutter/get-started) — konfiguracja push na platformach mobilnych.
