feat: replace admin auth with cookie-based profile picker

Remove all authentication (login, sessions, bcrypt, itsdangerous) since
the app runs on a private homelab LAN. Replace with a profile picker
landing page and cookie-based profile selection (1-year expiry).

- Add Alembic migration to drop password_hash/is_admin columns
- Delete auth service, auth routes, login template, and auth tests
- Rewrite app/utils/auth.py with NoProfileSelectedError and
  require_active_profile dependency
- Add profile creation flow (GET/POST /profiles/create)
- Rewrite home page as profile picker with card layout
- Update all route files to use profile dependency instead of admin auth
- Remove bcrypt and itsdangerous from requirements
- Remove admin_username/admin_password from config
- Update all tests for new profile-based access model

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 12:40:54 -05:00
parent 3dc0171639
commit 576d3bbb68
44 changed files with 523 additions and 1024 deletions

View File

@@ -28,12 +28,10 @@ class TestModels:
engine = self._create_engine()
user = User(
username="testuser",
password_hash="fakehash",
display_name="Test User",
display_name="Test User",
height="6'0\"",
weight="200 lbs",
goals="Get strong",
is_admin=False,
)
with Session(engine) as session:
session.add(user)
@@ -41,7 +39,6 @@ class TestModels:
session.refresh(user)
assert user.id is not None
assert user.username == "testuser"
assert user.is_admin is False
assert isinstance(user.created_at, datetime)
def test_exercise_model_roundtrip(self) -> None:
@@ -97,7 +94,7 @@ class TestModels:
"""UserExerciseProgram model should persist with FK references."""
engine = self._create_engine()
with Session(engine) as session:
user = User(username="u", password_hash="h", display_name="U")
user = User(username="u", display_name="U")
exercise = Exercise(
name="Test Ex", muscle_group="Test",
workout_day="Push", sets=3, tempo="3-1-2", form_cues="..."
@@ -126,7 +123,7 @@ class TestModels:
"""WorkoutSession model should persist correctly."""
engine = self._create_engine()
with Session(engine) as session:
user = User(username="u", password_hash="h", display_name="U")
user = User(username="u", display_name="U")
day = WorkoutDay(name="Push", day_number=1, description="Push day")
session.add(user)
session.add(day)
@@ -148,7 +145,7 @@ class TestModels:
"""WorkoutLog model should persist correctly."""
engine = self._create_engine()
with Session(engine) as session:
user = User(username="u", password_hash="h", display_name="U")
user = User(username="u", display_name="U")
day = WorkoutDay(name="Push", day_number=1, description="Push day")
exercise = Exercise(
name="Ex", muscle_group="Test",
@@ -187,7 +184,7 @@ class TestModels:
"""ProgressLog model should persist correctly."""
engine = self._create_engine()
with Session(engine) as session:
user = User(username="u", password_hash="h", display_name="U")
user = User(username="u", display_name="U")
exercise = Exercise(
name="Ex", muscle_group="Test",
workout_day="Push", sets=3, tempo="3-1-2", form_cues="..."