Odkrycie: Flask pozwala zarejestrować ten sam URL pod dwoma nazwami
- url_for('login') i url_for('auth.login') mogą współistnieć
- Zero zmian w szablonach podczas wdrożenia blueprintów
Strategia 3 podfaz:
- Faza 2a: Blueprinty + aliasy (niskie ryzyko)
- Faza 2b: Stopniowa migracja szablonów
- Faza 2c: Usunięcie aliasów
Porównanie z Big Bang: 20 vs 125 plików do zmiany naraz
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
418 lines
11 KiB
Markdown
418 lines
11 KiB
Markdown
# Strategia Bezpiecznego Wdrożenia Fazy 2
|
|
|
|
> **Data:** 2026-01-31
|
|
> **Status:** KRYTYCZNE - wymaga starannego planowania
|
|
> **Ryzyko:** Wysokie - 125+ zmian musi być atomowych
|
|
|
|
---
|
|
|
|
## Problem
|
|
|
|
### Obecne nazwy endpointów (bez prefiksu)
|
|
|
|
```python
|
|
# app.py
|
|
@app.route('/')
|
|
def index(): ... # url_for('index')
|
|
|
|
@app.route('/login')
|
|
def login(): ... # url_for('login')
|
|
|
|
@app.route('/dashboard')
|
|
def dashboard(): ... # url_for('dashboard')
|
|
```
|
|
|
|
### Docelowe nazwy endpointów (z prefiksem blueprintu)
|
|
|
|
```python
|
|
# blueprints/public/routes.py
|
|
@bp.route('/')
|
|
def index(): ... # url_for('public.index')
|
|
|
|
# blueprints/auth/routes.py
|
|
@bp.route('/login')
|
|
def login(): ... # url_for('auth.login')
|
|
```
|
|
|
|
### Skala zmian
|
|
|
|
| Lokalizacja | url_for('index') | url_for('login') | url_for('dashboard') | url_for('register') |
|
|
|-------------|------------------|------------------|----------------------|---------------------|
|
|
| app.py | 18 | 10 | 43 | 0 |
|
|
| szablony | 27 | 11 | 6 | 10 |
|
|
| **RAZEM** | **45** | **21** | **49** | **10** |
|
|
|
|
**Łącznie: ~125 miejsc do zmiany ATOMICZNIE**
|
|
|
|
---
|
|
|
|
## Strategie wdrożenia
|
|
|
|
### ❌ Opcja A: Stopniowe wdrażanie (NIEMOŻLIWE)
|
|
|
|
Nie można wdrożyć blueprintu bez zmiany wszystkich url_for.
|
|
Każda częściowa zmiana = awaria.
|
|
|
|
### ⚠️ Opcja B: Aliasy / Redirecty (RYZYKOWNE)
|
|
|
|
```python
|
|
# Po rejestracji blueprintu, dodać alias w app.py:
|
|
@app.route('/_redirect_index')
|
|
def _old_index():
|
|
return redirect(url_for('public.index'))
|
|
|
|
# Ale url_for('index') wciąż nie zadziała!
|
|
```
|
|
|
|
**Problem:** Flask nie wspiera natywnie aliasów endpointów.
|
|
|
|
### ⚠️ Opcja C: Endpoint override (CZĘŚCIOWO)
|
|
|
|
```python
|
|
# W blueprincie - nadpisać nazwę endpointu
|
|
@bp.route('/', endpoint='index') # Bez prefiksu!
|
|
def index_view():
|
|
...
|
|
```
|
|
|
|
**Problem:**
|
|
- `url_for('index')` zadziała ✅
|
|
- `url_for('public.index')` NIE zadziała ❌
|
|
- `utils/decorators.py` wymaga `url_for('public.index')` ❌
|
|
|
|
### ✅ Opcja D: Big Bang z testami (REKOMENDOWANA)
|
|
|
|
1. Przygotować WSZYSTKIE zmiany lokalnie
|
|
2. Uruchomić PEŁNE testy lokalne
|
|
3. Wdrożyć jednym commitem
|
|
4. Mieć gotowy rollback
|
|
|
|
---
|
|
|
|
## Plan wdrożenia Fazy 2 (bezpieczny)
|
|
|
|
### Etap 1: Przygotowanie (lokalnie)
|
|
|
|
```bash
|
|
# 1. Stworzyć nowy branch
|
|
git checkout -b feature/phase2-auth-public
|
|
|
|
# 2. Stworzyć blueprinty
|
|
mkdir -p blueprints/auth blueprints/public
|
|
```
|
|
|
|
### Etap 2: Implementacja blueprintów
|
|
|
|
#### blueprints/auth/routes.py
|
|
- Przenieść: login, logout, register, verify-2fa, forgot-password, reset-password, verify-email, resend-verification
|
|
- Użyć: `from utils.helpers import validate_email, validate_password, sanitize_input`
|
|
|
|
#### blueprints/public/routes.py
|
|
- Przenieść: index, company_detail, search, events, new_members, connections_map, release_notes
|
|
- Użyć: `from utils.helpers import sanitize_input`
|
|
|
|
### Etap 3: Masowa zmiana url_for
|
|
|
|
```bash
|
|
# Zmiana w szablonach
|
|
find templates/ -name "*.html" -exec sed -i '' \
|
|
-e "s/url_for('index')/url_for('public.index')/g" \
|
|
-e "s/url_for('login')/url_for('auth.login')/g" \
|
|
-e "s/url_for('logout')/url_for('auth.logout')/g" \
|
|
-e "s/url_for('register')/url_for('auth.register')/g" \
|
|
-e "s/url_for('dashboard')/url_for('account.dashboard')/g" \
|
|
{} \;
|
|
|
|
# Zmiana w app.py
|
|
sed -i '' \
|
|
-e "s/url_for('index')/url_for('public.index')/g" \
|
|
-e "s/url_for('login')/url_for('auth.login')/g" \
|
|
... \
|
|
app.py
|
|
```
|
|
|
|
### Etap 4: Testy lokalne (KRYTYCZNE!)
|
|
|
|
```bash
|
|
# 1. Uruchomić aplikację
|
|
python3 app.py
|
|
|
|
# 2. Testy manualne - WSZYSTKIE muszą przejść!
|
|
□ Strona główna ładuje się
|
|
□ Menu nawigacji działa
|
|
□ Link "Zaloguj" działa
|
|
□ Formularz logowania działa
|
|
□ Logowanie przekierowuje na dashboard
|
|
□ Dashboard ładuje się
|
|
□ Wylogowanie działa
|
|
□ Rejestracja działa
|
|
□ Reset hasła działa
|
|
□ Wyszukiwarka działa
|
|
□ Profil firmy działa
|
|
□ Wszystkie istniejące blueprinty działają (reports, contacts, etc.)
|
|
```
|
|
|
|
### Etap 5: Wdrożenie
|
|
|
|
```bash
|
|
# 1. Commit
|
|
git add .
|
|
git commit -m "refactor(phase2): Extract auth + public blueprints
|
|
|
|
BREAKING CHANGE: All url_for() calls updated to use blueprint prefixes:
|
|
- url_for('index') -> url_for('public.index')
|
|
- url_for('login') -> url_for('auth.login')
|
|
- url_for('register') -> url_for('auth.register')
|
|
- url_for('dashboard') -> url_for('account.dashboard')
|
|
|
|
~125 files changed atomically."
|
|
|
|
# 2. Push
|
|
git push origin feature/phase2-auth-public
|
|
git checkout master
|
|
git merge feature/phase2-auth-public
|
|
git push origin master && git push inpi master
|
|
|
|
# 3. Deploy
|
|
ssh maciejpi@10.22.68.249 "cd /var/www/nordabiznes && sudo -u www-data git pull && sudo systemctl restart nordabiznes"
|
|
|
|
# 4. Weryfikacja (natychmiast!)
|
|
curl -sI https://nordabiznes.pl/ | head -3
|
|
curl -sI https://nordabiznes.pl/login | head -3
|
|
curl -sI https://nordabiznes.pl/dashboard | head -3
|
|
```
|
|
|
|
### Etap 6: Rollback (jeśli potrzebny)
|
|
|
|
```bash
|
|
# Natychmiastowy rollback
|
|
git revert HEAD
|
|
git push origin master && git push inpi master
|
|
ssh maciejpi@10.22.68.249 "cd /var/www/nordabiznes && sudo -u www-data git pull && sudo systemctl restart nordabiznes"
|
|
```
|
|
|
|
---
|
|
|
|
## Checklist przed wdrożeniem
|
|
|
|
### Przygotowanie
|
|
- [ ] Nowy branch utworzony
|
|
- [ ] Blueprinty auth i public stworzone
|
|
- [ ] Wszystkie routes przeniesione
|
|
- [ ] Wszystkie url_for zmienione w app.py
|
|
- [ ] Wszystkie url_for zmienione w szablonach
|
|
- [ ] utils/decorators.py sprawdzony
|
|
|
|
### Testy lokalne
|
|
- [ ] Aplikacja uruchamia się bez błędów
|
|
- [ ] Strona główna działa
|
|
- [ ] Logowanie działa
|
|
- [ ] Dashboard działa
|
|
- [ ] Wylogowanie działa
|
|
- [ ] Rejestracja działa
|
|
- [ ] Menu nawigacji działa
|
|
- [ ] Istniejące blueprinty działają
|
|
|
|
### Przed wdrożeniem
|
|
- [ ] Backup bazy danych (opcjonalnie)
|
|
- [ ] Czas wdrożenia: niska aktywność użytkowników
|
|
- [ ] Osoba monitorująca: dostępna
|
|
|
|
### Po wdrożeniu
|
|
- [ ] Health check OK
|
|
- [ ] Strona główna OK
|
|
- [ ] Logowanie OK
|
|
- [ ] Brak błędów w logach
|
|
|
|
---
|
|
|
|
## Alternatywa: Endpoint override (bezpieczniejsza?)
|
|
|
|
Zamiast zmieniać 125 miejsc, można użyć endpoint override:
|
|
|
|
```python
|
|
# blueprints/public/__init__.py
|
|
bp = Blueprint('public', __name__)
|
|
|
|
# blueprints/public/routes.py
|
|
@bp.route('/', endpoint='index') # Endpoint = 'index' (bez prefiksu!)
|
|
def index():
|
|
...
|
|
```
|
|
|
|
**Zalety:**
|
|
- `url_for('index')` dalej działa ✅
|
|
- Nie trzeba zmieniać szablonów ✅
|
|
- Mniej ryzykowne ✅
|
|
|
|
**Wady:**
|
|
- `utils/decorators.py` używa `url_for('public.index')` - trzeba zmienić ❌
|
|
- Niespójna konwencja nazewnictwa ❌
|
|
- Trudniejsze debugowanie ❌
|
|
|
|
### Decyzja
|
|
|
|
**REKOMENDACJA:** Użyć endpoint override dla pierwszego wdrożenia, potem stopniowo migrować na pełne nazwy.
|
|
|
|
```python
|
|
# Faza 2a: Endpoint override (bezpieczne)
|
|
@bp.route('/', endpoint='index')
|
|
@bp.route('/login', endpoint='login')
|
|
|
|
# Faza 2b: Stopniowa zmiana szablonów (później)
|
|
# url_for('index') -> url_for('public.index')
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ REKOMENDOWANA STRATEGIA: Dual Endpoints (Alias Bridge)
|
|
|
|
### Dowód koncepcji (przetestowane!)
|
|
|
|
```python
|
|
# Flask pozwala zarejestrować ten sam URL pod dwoma nazwami:
|
|
app.register_blueprint(auth_bp) # Rejestruje /login -> auth.login
|
|
|
|
# Dodanie aliasu dla kompatybilności wstecznej:
|
|
app.add_url_rule('/login', 'login', app.view_functions['auth.login'])
|
|
|
|
# Wynik:
|
|
# /login -> auth.login (nowy)
|
|
# /login -> login (stary alias)
|
|
|
|
# Oba url_for działają:
|
|
# url_for('login') = /login ✓
|
|
# url_for('auth.login') = /login ✓
|
|
```
|
|
|
|
### Plan wdrożenia (3 podfazy)
|
|
|
|
#### Faza 2a: Blueprinty + Aliasy (BEZPIECZNE)
|
|
|
|
```python
|
|
# blueprints/__init__.py
|
|
def register_blueprints(app):
|
|
from blueprints.auth import bp as auth_bp
|
|
from blueprints.public import bp as public_bp
|
|
|
|
app.register_blueprint(auth_bp)
|
|
app.register_blueprint(public_bp)
|
|
|
|
# ALIASY dla kompatybilności wstecznej
|
|
# Szablony dalej używają url_for('login'), url_for('index'), etc.
|
|
_create_endpoint_aliases(app, {
|
|
# stara_nazwa: nowa_nazwa
|
|
'index': 'public.index',
|
|
'login': 'auth.login',
|
|
'logout': 'auth.logout',
|
|
'register': 'auth.register',
|
|
'dashboard': 'public.dashboard', # lub account.dashboard
|
|
'search': 'public.search',
|
|
'company_detail': 'public.company_detail',
|
|
'company_detail_by_slug': 'public.company_detail_by_slug',
|
|
# ... wszystkie inne
|
|
})
|
|
|
|
def _create_endpoint_aliases(app, aliases):
|
|
"""Tworzy aliasy dla starych nazw endpointów."""
|
|
for old_name, new_name in aliases.items():
|
|
if new_name in app.view_functions:
|
|
# Znajdź URL dla nowego endpointu
|
|
for rule in app.url_map.iter_rules():
|
|
if rule.endpoint == new_name:
|
|
app.add_url_rule(
|
|
rule.rule,
|
|
old_name,
|
|
app.view_functions[new_name],
|
|
methods=rule.methods
|
|
)
|
|
break
|
|
```
|
|
|
|
**Efekt Fazy 2a:**
|
|
- ✅ Blueprinty działają
|
|
- ✅ `url_for('login')` działa (alias)
|
|
- ✅ `url_for('auth.login')` działa (nowy)
|
|
- ✅ Szablony NIE wymagają zmian
|
|
- ✅ Zero ryzyka awarii
|
|
|
|
#### Faza 2b: Stopniowa migracja szablonów
|
|
|
|
```bash
|
|
# Można zmieniać po jednym szablonie
|
|
# Każda zmiana = osobny commit
|
|
|
|
# Przykład:
|
|
sed -i '' "s/url_for('login')/url_for('auth.login')/g" templates/base.html
|
|
git commit -m "refactor: Migrate url_for in base.html"
|
|
```
|
|
|
|
**Efekt Fazy 2b:**
|
|
- ✅ Szablony używają nowych nazw
|
|
- ✅ Aliasy dalej działają (dla nieprzemigrowanych)
|
|
- ✅ Można robić stopniowo
|
|
|
|
#### Faza 2c: Usunięcie aliasów (cleanup)
|
|
|
|
```python
|
|
# Po pełnej migracji szablonów:
|
|
# Usunąć _create_endpoint_aliases()
|
|
```
|
|
|
|
**Efekt Fazy 2c:**
|
|
- ✅ Czysty kod
|
|
- ✅ Tylko nowe nazwy endpointów
|
|
- ✅ Pełna migracja zakończona
|
|
|
|
---
|
|
|
|
## Podsumowanie strategii
|
|
|
|
| Faza | Opis | Ryzyko | Szablony |
|
|
|------|------|--------|----------|
|
|
| **2a** | Blueprinty + aliasy | 🟢 Niskie | Bez zmian |
|
|
| **2b** | Migracja szablonów | 🟢 Niskie | Stopniowo |
|
|
| **2c** | Usunięcie aliasów | 🟢 Niskie | Po migracji |
|
|
|
|
### Porównanie z Big Bang
|
|
|
|
| Aspekt | Big Bang | Alias Bridge |
|
|
|--------|----------|--------------|
|
|
| Zmiany na raz | ~125 | ~20 (tylko blueprinty) |
|
|
| Ryzyko awarii | 🔴 Wysokie | 🟢 Niskie |
|
|
| Rollback | Trudny | Łatwy |
|
|
| Testowanie | Wszystko naraz | Etapami |
|
|
| Czas wdrożenia | 1 dzień | 3-5 dni (bezpiecznie) |
|
|
|
|
---
|
|
|
|
## Checklist Fazy 2a
|
|
|
|
### Przygotowanie
|
|
- [ ] Stworzyć `blueprints/auth/__init__.py`
|
|
- [ ] Stworzyć `blueprints/auth/routes.py`
|
|
- [ ] Stworzyć `blueprints/public/__init__.py`
|
|
- [ ] Stworzyć `blueprints/public/routes.py`
|
|
- [ ] Przenieść routes z app.py do blueprintów
|
|
- [ ] Dodać funkcję `_create_endpoint_aliases()`
|
|
- [ ] Zaktualizować `blueprints/__init__.py`
|
|
|
|
### Testy lokalne
|
|
- [ ] Aplikacja uruchamia się
|
|
- [ ] `url_for('index')` działa
|
|
- [ ] `url_for('public.index')` działa
|
|
- [ ] Logowanie działa
|
|
- [ ] Strona główna działa
|
|
- [ ] Istniejące blueprinty działają
|
|
|
|
### Wdrożenie
|
|
- [ ] Commit + push
|
|
- [ ] Deploy na produkcję
|
|
- [ ] Weryfikacja health check
|
|
- [ ] Weryfikacja logowania
|
|
|
|
---
|
|
|
|
**Ostatnia aktualizacja:** 2026-01-31
|
|
**Status:** REKOMENDOWANA STRATEGIA - Alias Bridge
|