feat: implement initial admin setup (Story 1.1)

Add complete initial admin setup functionality including:
- SetupForm with email, password, and password confirmation fields
- Password validation (minimum 12 characters) and confirmation matching
- Email format validation
- Setup route with GET (display form) and POST (process setup) handlers
- bcrypt password hashing before storing admin credentials
- Auto-login after successful setup with session management
- First-run detection middleware that redirects to /setup if no admin exists
- Setup page returns 404 after admin account is created
- Base HTML template with Pico CSS integration
- Admin dashboard placeholder template
- 404 error template

All tests pass with 90.09% code coverage (exceeds 80% requirement).
Code passes ruff linting and mypy type checking.

Story: 1.1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-22 11:40:38 -07:00
parent b077112aba
commit 6a2ac7a8a7
15 changed files with 536 additions and 15 deletions

5
src/routes/__init__.py Normal file
View File

@@ -0,0 +1,5 @@
"""Route blueprints for Sneaky Klaus application."""
from src.routes.setup import setup_bp
__all__ = ["setup_bp"]

15
src/routes/admin.py Normal file
View File

@@ -0,0 +1,15 @@
"""Admin routes for Sneaky Klaus application."""
from flask import Blueprint, render_template
admin_bp = Blueprint("admin", __name__, url_prefix="/admin")
@admin_bp.route("/dashboard")
def dashboard():
"""Display admin dashboard.
Returns:
Rendered admin dashboard template.
"""
return render_template("admin/dashboard.html")

53
src/routes/setup.py Normal file
View File

@@ -0,0 +1,53 @@
"""Setup route for initial admin account creation."""
from flask import Blueprint, abort, redirect, render_template, session, url_for
from src.app import bcrypt, db
from src.forms import SetupForm
from src.models import Admin
setup_bp = Blueprint("setup", __name__)
@setup_bp.route("/setup", methods=["GET", "POST"])
def setup():
"""Handle initial admin account setup.
GET: Display the setup form if no admin exists.
POST: Process the setup form, create admin account, and log in.
Returns:
On GET: Rendered setup form template.
On POST success: Redirect to admin dashboard.
On POST error: Re-render form with validation errors.
404 if admin already exists.
"""
# Check if admin already exists
admin_count = db.session.query(Admin).count()
if admin_count > 0:
abort(404)
form = SetupForm()
if form.validate_on_submit():
# Create admin account
password_hash = bcrypt.generate_password_hash(form.password.data).decode(
"utf-8"
)
admin = Admin(
email=form.email.data,
password_hash=password_hash,
)
db.session.add(admin)
db.session.commit()
# Log in the admin by setting session
session["admin_id"] = admin.id
session["admin_email"] = admin.email
# Redirect to admin dashboard
return redirect(url_for("admin.dashboard"))
return render_template("setup.html", form=form)