# Konta i uprawnienia (PRE-27) Rozszerzenie kont imiennych z [PRE-17](konta-i-audyt.md): konta zakłada się **z aplikacji**, a każde dostaje własny zestaw funkcji. ## Dwie zasady, z których wynika reszta **1. Konto ograniczone widzi program KOMPLETNY — tylko mniejszy.** Nic nie może zdradzać, że istnieje coś więcej. Żadnych wyszarzonych zakładek, żadnego „brak uprawnień", żadnego 403 — bo **403 samo w sobie jest informacją**, że pod tym adresem coś jest. Ścieżka bez uprawnienia odpowiada **404**, tak samo jak adres, którego nie ma. Z tej zasady wynikło też wyłączenie `/docs`, `/redoc` i `/openapi.json`. Automatyczna dokumentacja FastAPI wypisuje komplet tras — czyli spis wszystkich funkcji programu. Ochrona zakładek nic by nie dała, gdyby obok leżał ich katalog. (Znalezione testem, nie przeglądem kodu.) **2. Konto administracyjne pochodzi WYŁĄCZNIE ze środowiska.** `APP_USER` / `APP_PASSWORD` (albo `APP_USERS`) — jak dotąd. To konto ma wszystkie uprawnienia i jako jedyne zarządza pozostałymi. **Nie leży w pliku kont**, więc nie da się go skasować ani ograniczyć z ekranu — nawet przez pomyłkę, nawet spreparowanym żądaniem. Konto założone w pliku o tym samym loginie **nie przesłoni** administracyjnego (kolejność sprawdzania jest odwrotna). ## Podział funkcji **Ekrany** — zakładki widoczne w nawigacji: | klucz | zakładka | |---|---| | `chart` | Horoskop | | `interpret` | Interpretacje | | `timeline` | Kalendarz | | `synastry` | Synastria | | `significators` | Sygnifikatory | | `compile` | Skompiluj | | `settings` | Ustawienia | **Rozszerzenia** — poziomy złożoności wewnątrz ekranów: | klucz | co daje | |---|---| | `houses_compare` | wybór systemu domów, zestawienie kilku obok siebie, obrót koła | | `extra_charts` | aspektarian, wykres deklinacji, oś antyscji | | `advanced_calc` | stacje planet, tabele żywiołów i faz, aspekty poboczne, zodiaki syderyczne | | `ai` | horoskopy pisane przez model językowy (**każde użycie kosztuje**) | | `export` | pobieranie PDF i Excela | Konto bez `houses_compare` dostaje horoskop w Whole Sign i **nie widzi**, że systemów jest trzynaście. Konto bez `ai` nie zobaczy przycisku generowania ani nie wywoła go z pominięciem interfejsu. ## Gdzie leży granica W handlerze, nie w szablonie. Ukrycie pola w formularzu chroni przed przypadkiem, ale nie przed kimś, kto zna nazwy pól — dlatego `_limit_options()` ścina opcje **po stronie serwera**, a rysunki dodatkowe bez uprawnienia w ogóle nie powstają (nie ma ich nawet w źródle strony). Mapa `trasa → uprawnienie` jest **jedna**, w `app/features.py`. Rozproszenie jej po dekoratorach kończy się trasą, o której ochronie ktoś zapomniał — a taka dziura jest niewidoczna do chwili, gdy ktoś ją znajdzie. Trasa bez wpisu w mapie wymaga uprawnień administracyjnych: **przeoczenie ma zamykać, nie otwierać**. Test przechodzi po wszystkich trasach aplikacji i wymaga, by każda była opisana. ## Gdzie leżą konta Plik JSON wskazany przez `ACCOUNTS_FILE` (domyślnie `/app/state/accounts.json`), na NFS — **własny podkatalog prezentacji**, nie katalog z bazami: zamontowanie tutaj całego udziału obeszłoby bokiem zamknięcie dostępu z DAN-25. Hasła wyłącznie jako hash scrypt, tym samym mechanizmem co `APP_USERS` — jedna implementacja, więc nie ma czego rozjechać. Zapis jest **atomowy** (plik tymczasowy + `os.replace` w tym samym katalogu): przerwanie zapisu nie obetnie pliku, czyli nie skasuje wszystkich kont naraz. ## Czego ten mechanizm NIE robi Nie zastępuje ochrony baz na poziomie sieci ani NFS (DAN-25). Ktoś z dostępem do udziału albo do warstwy danych nadal je odczyta — uprawnienia w aplikacji ograniczają to, co widać **przez aplikację**, i tyle.