django-accounts-framework-fdg 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. django_accounts_framework_fdg-0.1.0/LICENSE +21 -0
  2. django_accounts_framework_fdg-0.1.0/MANIFEST.in +6 -0
  3. django_accounts_framework_fdg-0.1.0/PKG-INFO +264 -0
  4. django_accounts_framework_fdg-0.1.0/README.md +246 -0
  5. django_accounts_framework_fdg-0.1.0/accounts/__init__.py +0 -0
  6. django_accounts_framework_fdg-0.1.0/accounts/admin.py +244 -0
  7. django_accounts_framework_fdg-0.1.0/accounts/apps.py +9 -0
  8. django_accounts_framework_fdg-0.1.0/accounts/checks.py +48 -0
  9. django_accounts_framework_fdg-0.1.0/accounts/conf.py +56 -0
  10. django_accounts_framework_fdg-0.1.0/accounts/email_utils.py +144 -0
  11. django_accounts_framework_fdg-0.1.0/accounts/force_password_middleware.py +67 -0
  12. django_accounts_framework_fdg-0.1.0/accounts/identifiers.py +24 -0
  13. django_accounts_framework_fdg-0.1.0/accounts/migrations/0001_initial.py +98 -0
  14. django_accounts_framework_fdg-0.1.0/accounts/migrations/__init__.py +0 -0
  15. django_accounts_framework_fdg-0.1.0/accounts/models.py +177 -0
  16. django_accounts_framework_fdg-0.1.0/accounts/permissions.py +92 -0
  17. django_accounts_framework_fdg-0.1.0/accounts/role_setup.py +157 -0
  18. django_accounts_framework_fdg-0.1.0/accounts/serializers.py +84 -0
  19. django_accounts_framework_fdg-0.1.0/accounts/services/__init__.py +0 -0
  20. django_accounts_framework_fdg-0.1.0/accounts/services/permission_service.py +49 -0
  21. django_accounts_framework_fdg-0.1.0/accounts/templates/accounts/emails/activation_email.html +16 -0
  22. django_accounts_framework_fdg-0.1.0/accounts/templates/accounts/emails/activation_email.txt +13 -0
  23. django_accounts_framework_fdg-0.1.0/accounts/templates/accounts/emails/base_email.html +26 -0
  24. django_accounts_framework_fdg-0.1.0/accounts/templates/accounts/emails/password_reset_email.html +16 -0
  25. django_accounts_framework_fdg-0.1.0/accounts/templates/accounts/emails/password_reset_email.txt +13 -0
  26. django_accounts_framework_fdg-0.1.0/accounts/templates/accounts/emails/welcome_email.html +6 -0
  27. django_accounts_framework_fdg-0.1.0/accounts/templates/accounts/emails/welcome_email.txt +8 -0
  28. django_accounts_framework_fdg-0.1.0/accounts/templates/admin/accounts/role/change_list.html +10 -0
  29. django_accounts_framework_fdg-0.1.0/accounts/templates/admin/accounts/role/setup_wizard.html +89 -0
  30. django_accounts_framework_fdg-0.1.0/accounts/tests/__init__.py +0 -0
  31. django_accounts_framework_fdg-0.1.0/accounts/tests/test_checks_and_defaults.py +56 -0
  32. django_accounts_framework_fdg-0.1.0/accounts/tests/test_force_password_middleware.py +138 -0
  33. django_accounts_framework_fdg-0.1.0/accounts/tests/test_set_user_active.py +60 -0
  34. django_accounts_framework_fdg-0.1.0/accounts/tests/urls_alt.py +4 -0
  35. django_accounts_framework_fdg-0.1.0/accounts/tests/urls_api.py +4 -0
  36. django_accounts_framework_fdg-0.1.0/accounts/tests/urls_root.py +4 -0
  37. django_accounts_framework_fdg-0.1.0/accounts/urls.py +32 -0
  38. django_accounts_framework_fdg-0.1.0/accounts/views.py +710 -0
  39. django_accounts_framework_fdg-0.1.0/django_accounts_framework_fdg.egg-info/PKG-INFO +264 -0
  40. django_accounts_framework_fdg-0.1.0/django_accounts_framework_fdg.egg-info/SOURCES.txt +43 -0
  41. django_accounts_framework_fdg-0.1.0/django_accounts_framework_fdg.egg-info/dependency_links.txt +1 -0
  42. django_accounts_framework_fdg-0.1.0/django_accounts_framework_fdg.egg-info/requires.txt +2 -0
  43. django_accounts_framework_fdg-0.1.0/django_accounts_framework_fdg.egg-info/top_level.txt +1 -0
  44. django_accounts_framework_fdg-0.1.0/pyproject.toml +42 -0
  45. django_accounts_framework_fdg-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hua Chen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include README.md
2
+ include LICENSE
3
+
4
+ recursive-include accounts/templates *.html *.txt
5
+ recursive-include accounts/migrations *.py
6
+ recursive-include accounts/static *
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-accounts-framework-fdg
3
+ Version: 0.1.0
4
+ Summary: Reusable Django authentication, user management, and role framework
5
+ Author: Hua Chen
6
+ License-Expression: MIT
7
+ Keywords: django,authentication,accounts,permissions,roles,rest-framework
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Framework :: Django
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Requires-Python: >=3.13
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: Django<7.0,>=6.0
16
+ Requires-Dist: djangorestframework<4.0,>=3.16
17
+ Dynamic: license-file
18
+
19
+ # Django Accounts Framework FDG
20
+
21
+ A reusable Django authentication and role-management application built with **Django REST Framework**. It provides email-based accounts, session authentication, activation and password recovery, a custom user model with public UUIDs, user administration, and Django Group-based roles.
22
+
23
+ > **Release status:** `0.1.0` is an initial packaging candidate. Test it in a fresh Django project before publishing or using it in production. This package provides its own user model and is intended primarily for **new** Django projects.
24
+
25
+ ## Features
26
+
27
+ - Email-based registration, sign-in, sign-out, account activation, and password reset.
28
+ - User profile and administrative account APIs.
29
+ - A custom `accounts.User` model with a random, unique `public_id` UUID for public API references.
30
+ - Forced-password-change middleware with configurable protected paths and exemptions.
31
+ - Django Groups, multiple roles per user, permission checks, and a Django Admin Role Setup Wizard.
32
+ - Configurable project branding, frontend links, activation behavior, and email templates.
33
+ - Django system checks for important configuration requirements.
34
+
35
+ **Security boundary:** UUIDs are opaque identifiers, not authorization. Each project must still enforce authentication, permissions, and object ownership. The Accounts app does not replace a project's CORS, CSRF, HTTPS, or session-cookie configuration.
36
+
37
+ ## Requirements and installation
38
+
39
+ The package metadata currently declares **Python 3.13+**, **Django 6.x**, and **Django REST Framework 3.16+**. These are declared compatibility ranges, not a claim that all combinations have been independently tested.
40
+
41
+ To install a local editable copy from the package repository:
42
+
43
+ ```bash
44
+ python -m pip install -e .
45
+ ```
46
+
47
+ After building a wheel with `python -m build`, you can also install that wheel into a **fresh virtual environment** to validate the packaged distribution:
48
+
49
+ ```bash
50
+ python -m pip install path/to/django_accounts_framework_fdg-0.1.0-py3-none-any.whl
51
+ ```
52
+
53
+ After publication on PyPI, installation would use:
54
+
55
+ ```bash
56
+ python -m pip install django-accounts-framework-fdg
57
+ ```
58
+
59
+ This last command applies only after the distribution has actually been published.
60
+
61
+ > **Import-name note:** The installed distribution is named `django-accounts-framework-fdg`, but the Django application is imported as `accounts`. Avoid installing another package that uses the same top-level Python module name.
62
+
63
+ ## Configure a new Django project
64
+
65
+ ### 1. Install and configure the custom User model
66
+
67
+ In your project's `settings.py`, add the app and set the custom user model **before running initial migrations**:
68
+
69
+ ```python
70
+ INSTALLED_APPS = [
71
+ "django.contrib.admin",
72
+ "django.contrib.auth",
73
+ "django.contrib.contenttypes",
74
+ "django.contrib.sessions",
75
+ "django.contrib.messages",
76
+ "django.contrib.staticfiles",
77
+ "rest_framework",
78
+ "accounts.apps.AccountsConfig",
79
+ ]
80
+
81
+ AUTH_USER_MODEL = "accounts.User"
82
+ ```
83
+
84
+ If your project already has users and migrations using a different user model, switching to `accounts.User` is **not** a drop-in operation. Plan a dedicated data and schema migration instead.
85
+
86
+ ### 2. Configure middleware
87
+
88
+ Keep your project's normal Django security, session, CSRF, authentication, and message middleware. Place the Accounts middleware **after** `AuthenticationMiddleware`:
89
+
90
+ ```python
91
+ MIDDLEWARE = [
92
+ "django.middleware.security.SecurityMiddleware",
93
+ "django.contrib.sessions.middleware.SessionMiddleware",
94
+ "django.middleware.common.CommonMiddleware",
95
+ "django.middleware.csrf.CsrfViewMiddleware",
96
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
97
+ "accounts.force_password_middleware.ForcePasswordChangeMiddleware",
98
+ "django.contrib.messages.middleware.MessageMiddleware",
99
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
100
+ ]
101
+ ```
102
+
103
+ ### 3. Mount Accounts URLs
104
+
105
+ In the host project's `urls.py`:
106
+
107
+ ```python
108
+ from django.contrib import admin
109
+ from django.urls import include, path
110
+
111
+ urlpatterns = [
112
+ path("admin/", admin.site.urls),
113
+ path("api/", include("accounts.urls")),
114
+ ]
115
+ ```
116
+
117
+ The `/api/` mount point is only an example. Accounts' own routes use `auth/…` and a `permissions/` endpoint relative to wherever you mount them. Named URLs let the forced-password middleware identify its essential account exemptions even when the mount point changes. Ensure your frontend calls the corresponding paths.
118
+
119
+ ### 4. Configure branding and account behavior
120
+
121
+ Add an application-specific `ACCOUNTS_FRAMEWORK` dictionary to `settings.py`:
122
+
123
+ ```python
124
+ ACCOUNTS_FRAMEWORK = {
125
+ "SITE_NAME": "Example Application",
126
+ "FRONTEND_URL": "https://app.example.com",
127
+ "SITE_URL": "https://api.example.com/",
128
+ "LOGO_URL": "https://example.com/static/logo.png",
129
+ "SUPPORT_EMAIL": "support@example.com",
130
+ "BRAND_COLOR": "#0F766E",
131
+ "ENABLE_SELF_REGISTRATION": True,
132
+ "REQUIRE_EMAIL_ACTIVATION": True,
133
+ "ACTIVATION_PATH": "/activate-account",
134
+ "PASSWORD_RESET_PATH": "/reset-password",
135
+ "ACTIVATION_TOKEN_EXPIRY_HOURS": 24,
136
+ "PASSWORD_RESET_EXPIRY_HOURS": 2,
137
+ "SEND_WELCOME_EMAIL": False,
138
+ "ROLE_PRESETS": [], # Define the new project's groups/permissions.
139
+ "MANAGER_ASSIGNABLE_ROLES": [],
140
+ }
141
+ ```
142
+
143
+ Set up a working Django email backend and sender identity in the host project. Ensure activation and reset paths exist in your frontend. Never commit SMTP credentials, database passwords, or Django secret keys.
144
+
145
+ ### 5. Run initial setup
146
+
147
+ With your database configured, run:
148
+
149
+ ```bash
150
+ python manage.py check
151
+ python manage.py migrate
152
+ python manage.py createsuperuser
153
+ ```
154
+
155
+ Sign in to Django Admin and open the **Role Setup Wizard** to create your configured Groups. Business apps should define their own permissions and use `user.has_perm("app_label.codename")`; keep those domain-specific permission definitions outside Accounts.
156
+
157
+ ## Forced password changes: protected paths versus allowed paths
158
+
159
+ When a signed-in user has `must_change_password=True`, `ForcePasswordChangeMiddleware` restricts access until their password is changed. Two settings let each project control the scope:
160
+
161
+ | Setting | Default | Purpose |
162
+ | --- | --- | --- |
163
+ | `ACCOUNTS_FORCE_PASSWORD_PROTECTED_PREFIXES` | `("/",)` | **Where to enforce** the password-change restriction. The default covers the whole website. |
164
+ | `ACCOUNTS_FORCE_PASSWORD_ALLOWED_PREFIXES` | `()` | **Exceptions** that the user may still reach before changing their password. |
165
+
166
+ For example, a project might enforce the rule for API routes while allowing a token-based public download endpoint:
167
+
168
+ ```python
169
+ ACCOUNTS_FORCE_PASSWORD_PROTECTED_PREFIXES = (
170
+ "/api/",
171
+ )
172
+
173
+ ACCOUNTS_FORCE_PASSWORD_ALLOWED_PREFIXES = (
174
+ "/api/public-downloads/",
175
+ )
176
+ ```
177
+
178
+ With `must_change_password=True`:
179
+
180
+ | Example request | Middleware behavior |
181
+ | --- | --- |
182
+ | `/api/private-data/` | Blocked with HTTP 403 |
183
+ | `/api/public-downloads/file-token/` | Permitted past this middleware |
184
+ | `/api/auth/change-password/` | Permitted by Accounts' built-in account-route exception |
185
+ | `/dashboard/` | Outside the configured protected scope |
186
+
187
+ **Important:** Allowed paths **do not clear** `must_change_password`; they only bypass this middleware check. Views must still enforce their own authentication, token validation, and permissions. Keep prefix exemptions narrow, because a prefix also exempts all paths underneath it. Necessary built-in account endpoints and static assets are also exempted so users can complete the password-change flow.
188
+
189
+ ## Public identifiers and account administration
190
+
191
+ - `accounts.User.public_id` is the UUID intended for public account identifiers; internal integer database primary keys remain an implementation detail.
192
+ - Administration endpoints that target users accept `user_public_id` rather than exposing a database ID.
193
+ - Django Groups and permissions are referenced by Group name and permission code (`app_label.codename`), not public numeric IDs.
194
+ - A non-superuser holding `accounts.manage_users` may assign only Groups listed in `MANAGER_ASSIGNABLE_ROLES`. Keep this allowlist limited to low-privilege roles; the `Administrator` role is superuser-only to assign.
195
+
196
+ Representative routes when mounted under `/api/`:
197
+
198
+ | Endpoint | Purpose |
199
+ | --- | --- |
200
+ | `/api/auth/csrf/` | Obtain CSRF cookie/token support |
201
+ | `/api/auth/register/` | Register account |
202
+ | `/api/auth/activate/` | Activate account |
203
+ | `/api/auth/login/`, `/api/auth/logout/` | Session authentication |
204
+ | `/api/auth/me/` | Current user/profile |
205
+ | `/api/auth/change-password/` | Change password |
206
+ | `/api/auth/password-reset/request/` | Start password reset |
207
+ | `/api/auth/password-reset/check/` | Validate reset flow |
208
+ | `/api/auth/password-reset/confirm/` | Complete reset |
209
+ | `/api/auth/roles/`, `/api/auth/assign-role/` | Roles and assignments |
210
+ | `/api/auth/set-active/` | User active status |
211
+ | `/api/auth/admin-set-password/` | Administrative password action |
212
+
213
+ See `accounts/urls.py` and the corresponding serializers/views for supported methods, request payloads, and permission requirements.
214
+
215
+ ## Email templates
216
+
217
+ The package includes text and HTML templates under:
218
+
219
+ ```text
220
+ accounts/templates/accounts/emails/
221
+ ├── activation_email.html
222
+ ├── activation_email.txt
223
+ ├── password_reset_email.html
224
+ ├── password_reset_email.txt
225
+ ├── welcome_email.html
226
+ └── welcome_email.txt
227
+ ```
228
+
229
+ Confirm these templates are present in the built wheel. The containing Django project must enable app template loading (`APP_DIRS=True`) or configure equivalent template loaders.
230
+
231
+ ## Testing and release preparation
232
+
233
+ In a newly created Django integration project (with **no** business-specific apps installed), run:
234
+
235
+ ```bash
236
+ python manage.py check
237
+ python manage.py makemigrations --check --dry-run
238
+ python manage.py migrate
239
+ python manage.py test accounts
240
+ ```
241
+
242
+ Test registration, session login, activation and password recovery, CSRF/cookies, forced password changes, administrative permissions, and the Role Setup Wizard. Validate against each database engine and Python/Django version you intend to support.
243
+
244
+ To build and validate the distribution from this repository:
245
+
246
+ ```bash
247
+ python -m pip install --upgrade build twine
248
+ python -m build
249
+ python -m twine check dist/*
250
+ unzip -l dist/*.whl
251
+ ```
252
+
253
+ Verify that the wheel includes `accounts/migrations/` and email templates, and that the metadata contains this README as its long description. **Passing package checks does not replace clean-install integration tests.**
254
+
255
+ ## Scope and compatibility notes
256
+
257
+ - This package ships a concrete custom User model. Adopt it at project initialization, not as an unplanned replacement for an established user schema.
258
+ - The account API's JSON shapes and internal route names are part of its public integration contract.
259
+ - The package does not host your frontend, configure SMTP credentials, or automatically manage allowed cross-origin browser requests.
260
+ - Its current distribution name and version are proposed release values; confirm availability and legal/licensing choices before publishing publicly.
261
+
262
+ ## License
263
+
264
+ This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for the full license text.
@@ -0,0 +1,246 @@
1
+ # Django Accounts Framework FDG
2
+
3
+ A reusable Django authentication and role-management application built with **Django REST Framework**. It provides email-based accounts, session authentication, activation and password recovery, a custom user model with public UUIDs, user administration, and Django Group-based roles.
4
+
5
+ > **Release status:** `0.1.0` is an initial packaging candidate. Test it in a fresh Django project before publishing or using it in production. This package provides its own user model and is intended primarily for **new** Django projects.
6
+
7
+ ## Features
8
+
9
+ - Email-based registration, sign-in, sign-out, account activation, and password reset.
10
+ - User profile and administrative account APIs.
11
+ - A custom `accounts.User` model with a random, unique `public_id` UUID for public API references.
12
+ - Forced-password-change middleware with configurable protected paths and exemptions.
13
+ - Django Groups, multiple roles per user, permission checks, and a Django Admin Role Setup Wizard.
14
+ - Configurable project branding, frontend links, activation behavior, and email templates.
15
+ - Django system checks for important configuration requirements.
16
+
17
+ **Security boundary:** UUIDs are opaque identifiers, not authorization. Each project must still enforce authentication, permissions, and object ownership. The Accounts app does not replace a project's CORS, CSRF, HTTPS, or session-cookie configuration.
18
+
19
+ ## Requirements and installation
20
+
21
+ The package metadata currently declares **Python 3.13+**, **Django 6.x**, and **Django REST Framework 3.16+**. These are declared compatibility ranges, not a claim that all combinations have been independently tested.
22
+
23
+ To install a local editable copy from the package repository:
24
+
25
+ ```bash
26
+ python -m pip install -e .
27
+ ```
28
+
29
+ After building a wheel with `python -m build`, you can also install that wheel into a **fresh virtual environment** to validate the packaged distribution:
30
+
31
+ ```bash
32
+ python -m pip install path/to/django_accounts_framework_fdg-0.1.0-py3-none-any.whl
33
+ ```
34
+
35
+ After publication on PyPI, installation would use:
36
+
37
+ ```bash
38
+ python -m pip install django-accounts-framework-fdg
39
+ ```
40
+
41
+ This last command applies only after the distribution has actually been published.
42
+
43
+ > **Import-name note:** The installed distribution is named `django-accounts-framework-fdg`, but the Django application is imported as `accounts`. Avoid installing another package that uses the same top-level Python module name.
44
+
45
+ ## Configure a new Django project
46
+
47
+ ### 1. Install and configure the custom User model
48
+
49
+ In your project's `settings.py`, add the app and set the custom user model **before running initial migrations**:
50
+
51
+ ```python
52
+ INSTALLED_APPS = [
53
+ "django.contrib.admin",
54
+ "django.contrib.auth",
55
+ "django.contrib.contenttypes",
56
+ "django.contrib.sessions",
57
+ "django.contrib.messages",
58
+ "django.contrib.staticfiles",
59
+ "rest_framework",
60
+ "accounts.apps.AccountsConfig",
61
+ ]
62
+
63
+ AUTH_USER_MODEL = "accounts.User"
64
+ ```
65
+
66
+ If your project already has users and migrations using a different user model, switching to `accounts.User` is **not** a drop-in operation. Plan a dedicated data and schema migration instead.
67
+
68
+ ### 2. Configure middleware
69
+
70
+ Keep your project's normal Django security, session, CSRF, authentication, and message middleware. Place the Accounts middleware **after** `AuthenticationMiddleware`:
71
+
72
+ ```python
73
+ MIDDLEWARE = [
74
+ "django.middleware.security.SecurityMiddleware",
75
+ "django.contrib.sessions.middleware.SessionMiddleware",
76
+ "django.middleware.common.CommonMiddleware",
77
+ "django.middleware.csrf.CsrfViewMiddleware",
78
+ "django.contrib.auth.middleware.AuthenticationMiddleware",
79
+ "accounts.force_password_middleware.ForcePasswordChangeMiddleware",
80
+ "django.contrib.messages.middleware.MessageMiddleware",
81
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
82
+ ]
83
+ ```
84
+
85
+ ### 3. Mount Accounts URLs
86
+
87
+ In the host project's `urls.py`:
88
+
89
+ ```python
90
+ from django.contrib import admin
91
+ from django.urls import include, path
92
+
93
+ urlpatterns = [
94
+ path("admin/", admin.site.urls),
95
+ path("api/", include("accounts.urls")),
96
+ ]
97
+ ```
98
+
99
+ The `/api/` mount point is only an example. Accounts' own routes use `auth/…` and a `permissions/` endpoint relative to wherever you mount them. Named URLs let the forced-password middleware identify its essential account exemptions even when the mount point changes. Ensure your frontend calls the corresponding paths.
100
+
101
+ ### 4. Configure branding and account behavior
102
+
103
+ Add an application-specific `ACCOUNTS_FRAMEWORK` dictionary to `settings.py`:
104
+
105
+ ```python
106
+ ACCOUNTS_FRAMEWORK = {
107
+ "SITE_NAME": "Example Application",
108
+ "FRONTEND_URL": "https://app.example.com",
109
+ "SITE_URL": "https://api.example.com/",
110
+ "LOGO_URL": "https://example.com/static/logo.png",
111
+ "SUPPORT_EMAIL": "support@example.com",
112
+ "BRAND_COLOR": "#0F766E",
113
+ "ENABLE_SELF_REGISTRATION": True,
114
+ "REQUIRE_EMAIL_ACTIVATION": True,
115
+ "ACTIVATION_PATH": "/activate-account",
116
+ "PASSWORD_RESET_PATH": "/reset-password",
117
+ "ACTIVATION_TOKEN_EXPIRY_HOURS": 24,
118
+ "PASSWORD_RESET_EXPIRY_HOURS": 2,
119
+ "SEND_WELCOME_EMAIL": False,
120
+ "ROLE_PRESETS": [], # Define the new project's groups/permissions.
121
+ "MANAGER_ASSIGNABLE_ROLES": [],
122
+ }
123
+ ```
124
+
125
+ Set up a working Django email backend and sender identity in the host project. Ensure activation and reset paths exist in your frontend. Never commit SMTP credentials, database passwords, or Django secret keys.
126
+
127
+ ### 5. Run initial setup
128
+
129
+ With your database configured, run:
130
+
131
+ ```bash
132
+ python manage.py check
133
+ python manage.py migrate
134
+ python manage.py createsuperuser
135
+ ```
136
+
137
+ Sign in to Django Admin and open the **Role Setup Wizard** to create your configured Groups. Business apps should define their own permissions and use `user.has_perm("app_label.codename")`; keep those domain-specific permission definitions outside Accounts.
138
+
139
+ ## Forced password changes: protected paths versus allowed paths
140
+
141
+ When a signed-in user has `must_change_password=True`, `ForcePasswordChangeMiddleware` restricts access until their password is changed. Two settings let each project control the scope:
142
+
143
+ | Setting | Default | Purpose |
144
+ | --- | --- | --- |
145
+ | `ACCOUNTS_FORCE_PASSWORD_PROTECTED_PREFIXES` | `("/",)` | **Where to enforce** the password-change restriction. The default covers the whole website. |
146
+ | `ACCOUNTS_FORCE_PASSWORD_ALLOWED_PREFIXES` | `()` | **Exceptions** that the user may still reach before changing their password. |
147
+
148
+ For example, a project might enforce the rule for API routes while allowing a token-based public download endpoint:
149
+
150
+ ```python
151
+ ACCOUNTS_FORCE_PASSWORD_PROTECTED_PREFIXES = (
152
+ "/api/",
153
+ )
154
+
155
+ ACCOUNTS_FORCE_PASSWORD_ALLOWED_PREFIXES = (
156
+ "/api/public-downloads/",
157
+ )
158
+ ```
159
+
160
+ With `must_change_password=True`:
161
+
162
+ | Example request | Middleware behavior |
163
+ | --- | --- |
164
+ | `/api/private-data/` | Blocked with HTTP 403 |
165
+ | `/api/public-downloads/file-token/` | Permitted past this middleware |
166
+ | `/api/auth/change-password/` | Permitted by Accounts' built-in account-route exception |
167
+ | `/dashboard/` | Outside the configured protected scope |
168
+
169
+ **Important:** Allowed paths **do not clear** `must_change_password`; they only bypass this middleware check. Views must still enforce their own authentication, token validation, and permissions. Keep prefix exemptions narrow, because a prefix also exempts all paths underneath it. Necessary built-in account endpoints and static assets are also exempted so users can complete the password-change flow.
170
+
171
+ ## Public identifiers and account administration
172
+
173
+ - `accounts.User.public_id` is the UUID intended for public account identifiers; internal integer database primary keys remain an implementation detail.
174
+ - Administration endpoints that target users accept `user_public_id` rather than exposing a database ID.
175
+ - Django Groups and permissions are referenced by Group name and permission code (`app_label.codename`), not public numeric IDs.
176
+ - A non-superuser holding `accounts.manage_users` may assign only Groups listed in `MANAGER_ASSIGNABLE_ROLES`. Keep this allowlist limited to low-privilege roles; the `Administrator` role is superuser-only to assign.
177
+
178
+ Representative routes when mounted under `/api/`:
179
+
180
+ | Endpoint | Purpose |
181
+ | --- | --- |
182
+ | `/api/auth/csrf/` | Obtain CSRF cookie/token support |
183
+ | `/api/auth/register/` | Register account |
184
+ | `/api/auth/activate/` | Activate account |
185
+ | `/api/auth/login/`, `/api/auth/logout/` | Session authentication |
186
+ | `/api/auth/me/` | Current user/profile |
187
+ | `/api/auth/change-password/` | Change password |
188
+ | `/api/auth/password-reset/request/` | Start password reset |
189
+ | `/api/auth/password-reset/check/` | Validate reset flow |
190
+ | `/api/auth/password-reset/confirm/` | Complete reset |
191
+ | `/api/auth/roles/`, `/api/auth/assign-role/` | Roles and assignments |
192
+ | `/api/auth/set-active/` | User active status |
193
+ | `/api/auth/admin-set-password/` | Administrative password action |
194
+
195
+ See `accounts/urls.py` and the corresponding serializers/views for supported methods, request payloads, and permission requirements.
196
+
197
+ ## Email templates
198
+
199
+ The package includes text and HTML templates under:
200
+
201
+ ```text
202
+ accounts/templates/accounts/emails/
203
+ ├── activation_email.html
204
+ ├── activation_email.txt
205
+ ├── password_reset_email.html
206
+ ├── password_reset_email.txt
207
+ ├── welcome_email.html
208
+ └── welcome_email.txt
209
+ ```
210
+
211
+ Confirm these templates are present in the built wheel. The containing Django project must enable app template loading (`APP_DIRS=True`) or configure equivalent template loaders.
212
+
213
+ ## Testing and release preparation
214
+
215
+ In a newly created Django integration project (with **no** business-specific apps installed), run:
216
+
217
+ ```bash
218
+ python manage.py check
219
+ python manage.py makemigrations --check --dry-run
220
+ python manage.py migrate
221
+ python manage.py test accounts
222
+ ```
223
+
224
+ Test registration, session login, activation and password recovery, CSRF/cookies, forced password changes, administrative permissions, and the Role Setup Wizard. Validate against each database engine and Python/Django version you intend to support.
225
+
226
+ To build and validate the distribution from this repository:
227
+
228
+ ```bash
229
+ python -m pip install --upgrade build twine
230
+ python -m build
231
+ python -m twine check dist/*
232
+ unzip -l dist/*.whl
233
+ ```
234
+
235
+ Verify that the wheel includes `accounts/migrations/` and email templates, and that the metadata contains this README as its long description. **Passing package checks does not replace clean-install integration tests.**
236
+
237
+ ## Scope and compatibility notes
238
+
239
+ - This package ships a concrete custom User model. Adopt it at project initialization, not as an unplanned replacement for an established user schema.
240
+ - The account API's JSON shapes and internal route names are part of its public integration contract.
241
+ - The package does not host your frontend, configure SMTP credentials, or automatically manage allowed cross-origin browser requests.
242
+ - Its current distribution name and version are proposed release values; confirm availability and legal/licensing choices before publishing publicly.
243
+
244
+ ## License
245
+
246
+ This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for the full license text.