nordabiz/docs/MODULAR_MONOLITH_DEPLOYMENT_STRATEGY.md
Maciej Pienczyn 9c39ff06ba docs: Strategia Alias Bridge dla bezpiecznego wdrożenia Fazy 2
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>
2026-01-31 06:54:56 +01:00

11 KiB

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)

# 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)

# 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)

# 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)

# 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)

# 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

# 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!)

# 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

# 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)

# 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:

# 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.

# 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!)

# 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)

# 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

# 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)

# 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