|
| 1 | +# Authentication and Access Control |
| 2 | + |
| 3 | +Sprint 1 establishes the StudyBuddy identity baseline and the first protected |
| 4 | +product surface. |
| 5 | + |
| 6 | +The current goal is a real SaaS-shaped authentication journey without |
| 7 | +overbuilding permissions before study-session workflows exist. |
| 8 | + |
| 9 | +## User Model |
| 10 | + |
| 11 | +StudyBuddy uses `apps.users.CustomUser`. |
| 12 | + |
| 13 | +The model extends Django's `AbstractUser`, keeps Django's standard permission |
| 14 | +fields, and changes the login identifier to email: |
| 15 | + |
| 16 | +```python |
| 17 | +USERNAME_FIELD = "email" |
| 18 | +``` |
| 19 | + |
| 20 | +Email addresses are unique and required. Usernames still exist for Django |
| 21 | +compatibility, but account creation can generate one from the email local part |
| 22 | +when the signup form leaves `username` blank. |
| 23 | + |
| 24 | +The active auth setting is: |
| 25 | + |
| 26 | +```python |
| 27 | +AUTH_USER_MODEL = "users.CustomUser" |
| 28 | +``` |
| 29 | + |
| 30 | +## Authentication Routes |
| 31 | + |
| 32 | +User-facing authentication routes live under `/accounts/`: |
| 33 | + |
| 34 | +- `users:signup` -> `/accounts/signup/` |
| 35 | +- `users:login` -> `/accounts/login/` |
| 36 | +- `users:logout` -> `/accounts/logout/` |
| 37 | +- `users:profile` -> `/accounts/profile/` |
| 38 | + |
| 39 | +Signup and login redirect authenticated users to the dashboard: |
| 40 | + |
| 41 | +```python |
| 42 | +LOGIN_URL = "users:login" |
| 43 | +LOGIN_REDIRECT_URL = "dashboard:index" |
| 44 | +LOGOUT_REDIRECT_URL = "home" |
| 45 | +``` |
| 46 | + |
| 47 | +The protected dashboard route is: |
| 48 | + |
| 49 | +- `dashboard:index` -> `/dashboard/` |
| 50 | + |
| 51 | +## Signup Flow |
| 52 | + |
| 53 | +`apps.users.forms.CustomUserCreationForm` validates email uniqueness, optional |
| 54 | +username uniqueness, and password confirmation through Django's user creation |
| 55 | +form behavior. |
| 56 | + |
| 57 | +A successful signup: |
| 58 | + |
| 59 | +- creates a valid `CustomUser`; |
| 60 | +- authenticates the new user; |
| 61 | +- redirects to `dashboard:index`. |
| 62 | + |
| 63 | +Duplicate email addresses are rejected at the form layer before creating a user. |
| 64 | + |
| 65 | +## Login Flow |
| 66 | + |
| 67 | +The login page uses Django's `LoginView` with `users/login.html`. |
| 68 | + |
| 69 | +Users log in with their email address and password because the custom user model |
| 70 | +uses email as `USERNAME_FIELD`. |
| 71 | + |
| 72 | +Authenticated users who visit login or signup are redirected to the dashboard. |
| 73 | + |
| 74 | +## Profile Flow |
| 75 | + |
| 76 | +`users:profile` is login-protected and renders `templates/users/profile.html`. |
| 77 | + |
| 78 | +The profile displays the current user's display name, email, username, and |
| 79 | +assigned StudyBuddy roles. |
| 80 | + |
| 81 | +## Roles |
| 82 | + |
| 83 | +StudyBuddy roles are modeled by `apps.roles.Role`. |
| 84 | + |
| 85 | +Roles have: |
| 86 | + |
| 87 | +- `slug`; |
| 88 | +- `display_name`; |
| 89 | +- optional `description`; |
| 90 | +- timestamps; |
| 91 | +- a many-to-many relation to the custom user model. |
| 92 | + |
| 93 | +The user-side relation is: |
| 94 | + |
| 95 | +```python |
| 96 | +user.studybuddy_roles |
| 97 | +``` |
| 98 | + |
| 99 | +Use this relation in templates, views, factories, tests, and permission helpers. |
| 100 | +Do not use `user.roles`; that is not the current related name. |
| 101 | + |
| 102 | +## Permission Helpers |
| 103 | + |
| 104 | +`apps.roles.permissions` provides lightweight role-aware helpers: |
| 105 | + |
| 106 | +- `user_has_role(user, role_slug)`; |
| 107 | +- `user_has_any_role(user, role_slugs)`; |
| 108 | +- `role_required(role_slug)`. |
| 109 | + |
| 110 | +Anonymous users fail role checks. Superusers pass role checks. Regular users |
| 111 | +pass only when `user.studybuddy_roles` contains the requested slug. |
| 112 | + |
| 113 | +## Dashboard Access |
| 114 | + |
| 115 | +The dashboard is the Sprint 1 post-login product destination. |
| 116 | + |
| 117 | +It is intentionally a protected shell until Sprint 2 adds study-session data. |
| 118 | +It displays placeholder study metrics, an empty-session state, account access, |
| 119 | +and role-aware messaging backed by `user.studybuddy_roles`. |
| 120 | + |
| 121 | +## Validation |
| 122 | + |
| 123 | +The authentication journey is covered by HTTP-level tests, not just isolated |
| 124 | +model creation. Tests verify: |
| 125 | + |
| 126 | +- signup page render; |
| 127 | +- signup user creation; |
| 128 | +- duplicate email rejection; |
| 129 | +- signup redirect-follow behavior; |
| 130 | +- login with email and password; |
| 131 | +- login redirect-follow behavior; |
| 132 | +- authenticated redirects away from login/signup; |
| 133 | +- profile protection; |
| 134 | +- authenticated profile rendering; |
| 135 | +- logout redirect behavior; |
| 136 | +- dashboard access for authenticated users. |
0 commit comments