- This is a Django project built on Python 3.14.
- User authentication uses
django-allauth. - The front end is mostly standard Django views and templates.
- HTMX and Alpine.js are used to provide single-page-app user experience with Django templates. HTMX is used for interactions which require accessing the backend, and Alpine.js is used for browser-only interactions.
- JavaScript files are kept in the
/assets/folder and built by vite. JavaScript code is typically loaded via the static files framework inside Django templates usingdjango-vite. - APIs use Django Rest Framework, and JavaScript code that interacts with APIs uses an auto-generated OpenAPI-schema-baesd client.
- The front end uses Tailwind (Version 4) and DaisyUI.
- The main database is Postgres.
- Celery is used for background jobs and scheduled tasks.
- Redis is used as the default cache, and the message broker for Celery (if enabled).
The following commands can be used for various tools and workflows.
A Makefile is provided to help centralize commands:
make # List available commandsmake initStart background services:
make start # Run in foreground with logs
make start-bg # Run in backgroundStart the app:
make dev # Run in foreground with logsAccess the app at http://localhost:8000
Stop background services:
make stopmake shell # Open Python / Django shell
make dbshell # Open PostgreSQL shell
make manage ARGS='command' # Run any Django management commandmake migrations # Create new migrations
make migrate # Apply migrationsmake test # Run all tests
make test ARGS='apps.module.tests.test_file' # Run specific test
make test ARGS='path.to.test --keepdb' # Run with optionsmake ruff-format # Format code
make ruff-lint # Lint and auto-fix
make ruff # Run both format and lintmake uv add '<package>' # Add a new package
make uv run '<command> <args>' # Run a Python commandmake npm-install # Install npm packages
make npm-install package-name # Install specific package
make npm-uninstall package-name # Uninstall package
make npm-dev # Run the Vite development server
make npm-build # Build for production
make npm-type-check # Run TypeScript type checkingNote: Vite runs automatically with hot-reload when using make dev.
make uv run 'pegasus startapp <app_name> <Model1> <Model2Name>' # Start a new Django app (models are optional)- Always prefer simple solutions.
- Avoid duplication of code whenever possible, which means checking for other areas of the codebase that might already have similar code and functionality.
- You are careful to only make changes that are requested or you are confident are well understood and related to the change being requested.
- When fixing an issue or bug, do not introduce a new pattern or technology without first exhausting all options for the existing implementation. And if you finally do this, make sure to remove the old implementation afterwards so we don’t have duplicate logic.
- Keep the codebase clean and organized.
- Avoid writing scripts in files if possible, especially if the script is likely only to be run once.
- Try to avoid having files over 200-300 lines of code. Refactor at that point.
- Don't ever add mock data to functions. Only add mocks to tests or utilities that are only used by tests.
- Always think about what other areas of code might be affected by any changes made.
- Never overwrite my .env file without first asking and confirming.
- Follow PEP 8 with 120 character line limit.
- Use double quotes for Python strings (ruff enforced).
- Sort imports with isort (via ruff).
- Try to use type hints in new code. However, strict type-checking is not enforced and you can leave them out if it's burdensome. There is no need to add type hints to existing code if it does not already use them.
Type checking runs with mypy + django-stubs (make type-check). Conventions:
- Routed views leave
requestunannotated (all of them, even views that don't touchrequest.user). mypy can't see the guarantees made by@login_requiredand similar decorators, so annotatingrequest: HttpRequestmakes accesses likerequest.user.<related>fail type checking. Everything that isn't a routed view — middleware, context processors, signal handlers, forms, internal helpers — should annotaterequest: HttpRequestnormally. - In DRF views where a permission class guarantees authentication, get the typed user via
apps.users.helpers.get_authenticated_user(request)rather than castingrequest.userinline.
- Unparenthesized
exceptwith multiple exception types is valid (PEP 758, Python 3.14+).except ValueError, TypeError:is equivalent toexcept (ValueError, TypeError):— it is not Python 2 syntax and will not raise aSyntaxError. Parentheses are still required when usingas(e.g.except (ValueError, TypeError) as e:). Do not "fix" unparenthesized forms unless anasclause is being added.
- Use Django signals sparingly and document them well.
- Always use the Django ORM if possible. Use best practices like lazily evaluating querysets and selecting or prefetching related objects when necessary.
- Use function-based views by default, unless using a framework that relies on class-based views (e.g. Django Rest Framework).
- Always validate user input server-side.
- Handle errors explicitly, avoid silent failures.
- All Django models should extend
apps.utils.models.BaseModel(which addscreated_atandupdated_atfields). - The project's user model is
apps.users.models.CustomUserand should be imported directly.
- Indent templates with two spaces.
- Use standard Django template syntax.
- For multi-line comments, use
{% comment %}...{% endcomment %}. The{# ... #}syntax is single-line only and does NOT work across multiple lines — never write{# first line\n second line #}. - JavaScript and CSS files built with vite should be included with the
{% vite_asset %}template tag provided bydjango-vite(must have{% load django_vite %}at the top of the template) - Any react components also need
{% vite_react_refresh %}for Vite + React's HMR functionality, from the samedjango_vitetemplate library) - Use the Django
{% static %}tag for loading images and external JavaScript / CSS files not managed by vite. - Prefer using alpine.js for page-level JavaScript, and avoid inline
<script>tags where possible. - Break re-usable template components into separate templates with
{% include %}statements. These normally go into acomponentsfolder. - Use DaisyUI styling markup for available components. When not available, fall back to standard TailwindCSS classes.
- Stick with the DaisyUI color palette whenever possible.
- Use ES6+ syntax for JavaScript code.
- Use 2 spaces for indentation in JavaScript, JSX, and HTML files.
- Use single quotes for JavaScript strings.
- End statements with semicolons.
- Use camelCase for variable and function names.
- Use PascalCase for component names (React).
- Use explicit type annotations in TypeScript files.
- Use ES6 import/export syntax for module management.
- When using HTMX, follow progressive enhancement patterns.
- Use Alpine.js for client-side interactivity that doesn't require server interaction.
- Avoid inline
<script>tags wherever posisble. - Validate user input on both client and server side.
- Handle errors explicitly in promise chains and async functions.
- Code is bundled using vite and served with
django-vite.