# l4d2 Web Auth Pages Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. Do not use git worktrees. **Goal:** Add a real login page, remove signup, and redirect anonymous users back to their requested page after login when safe. **Architecture:** Keep the current username/password data model and Flask session authentication. Add a small safe-redirect helper in `l4d2web/auth.py`, render login through Jinja, and keep routing changes scoped to auth decorators plus the app root route. **Tech Stack:** Flask, Jinja templates, SQLAlchemy models, pytest, existing custom CSS tokens. --- ## File Structure - `l4d2web/auth.py`: owns password hashing, session helpers, current user lookup, login-required/admin-required decorators, and safe local redirect target validation. - `l4d2web/routes/auth_routes.py`: owns login GET/POST and logout. Signup handlers will be removed from this file. - `l4d2web/app.py`: owns app setup, CSRF exemptions, and public root/health routes. Root will become auth-aware. - `l4d2web/templates/base.html`: owns shared shell navigation. It will hide app navigation for anonymous users. - `l4d2web/templates/login.html`: new server-rendered login page. - `l4d2web/static/css/components.css`: minor form-control styling only if needed for the login form. - `l4d2web/tests/test_auth.py`: auth route tests for login page, signup removal, safe next redirect, and unsafe next fallback. - `l4d2web/tests/test_pages.py`: protected-page redirect and root redirect tests. - `l4d2web/tests/test_security.py`: CSRF/rate-limit regression tests after signup is removed from exemptions. ## Task 1: Remove Signup and Add Login Page Tests **Files:** - Modify: `l4d2web/tests/test_auth.py` - Modify: `l4d2web/tests/test_pages.py` - [ ] **Step 1: Update auth tests for login page, signup removal, and next redirects** Replace `test_public_signup` in `l4d2web/tests/test_auth.py` with these tests, and update existing login test data keys only if needed: ```python def test_login_page_renders_form(client) -> None: response = client.get("/login") text = response.get_data(as_text=True) assert response.status_code == 200 assert '