- API: Python + Django + Django REST Framework
- Database: PostgreSQL
- Frontend: Next.js (React) App Router + TypeScript
db: PostgreSQL onlocalhost:5432api: Django dev server onlocalhost:8000web: Next.js dev server onlocalhost:3000
- Build & start
docker compose up --build- Open
- API health: http://localhost:8000/health/
- Notes API: http://localhost:8000/api/notes/
- Web: http://localhost:3000
- Admin
- Admin: http://localhost:8000/admin/
- Default credentials: admin@admin.com / admin
docker-compose.yml provides defaults, but you can override by exporting env vars in your shell:
POSTGRES_DB(defaultnotes)POSTGRES_USER(defaultnotes)POSTGRES_PASSWORD(defaultnotes)DJANGO_SECRET_KEY(defaultdev-secret-key)DJANGO_DEBUG(default1)DJANGO_ALLOWED_HOSTS(defaultlocalhost,127.0.0.1,api)NEXT_PUBLIC_API_URL(defaulthttp://localhost:8000)
An example file is provided at .env.example.
The API test suite uses pytest + pytest-django.
- Local (from
api/):
pytest- Docker:
docker compose exec api pytest- Coverage:
docker compose exec api pytest --cov=notes --cov=users --cov-report=term-missingThe web test suite uses Jest + React Testing Library (via next/jest).
- Local (from
web/):
npm test- Docker:
docker compose exec web npm test- Coverage:
docker compose exec web npm run test:coverageThis project was built iteratively with an emphasis on keeping the UI and data layer maintainable as features expanded.
users.User: Custom Django auth user (AbstractBaseUser+PermissionsMixin) using email as the username (USERNAME_FIELD = "email"). Used asAUTH_USER_MODELacross the API.notes.Category: Category owned by a user (Category.user -> AUTH_USER_MODEL) with anameand a hexcolor. Category names are enforced as unique per user.notes.Note: Note owned by a user (Note.user -> AUTH_USER_MODEL) withtitle,content, optionalcategory, and timestamps (created_at,updated_at).
- A
post_savereceiver onusers.Usercreates the initial categories (e.g. Random Thoughts, School, Personal) when a user is first created. - The signal is registered in
users.apps.UsersConfig.ready()(importingusers.signals). - This was implemented as a signal to keep the behavior centralized and automatic across all user creation paths (API signup, Django admin, tests, management commands), without coupling category initialization to any single view or serializer.
- Because the API uses cookie-based session authentication, CSRF protection is needed to prevent a malicious third-party site from triggering state-changing requests (create/update/delete) with a user’s existing session.
- Cookie-based session authentication was chosen to keep the auth flow simple for a same-origin web app (no JWT storage/refresh flow on the client) and to rely on Django’s built-in, well-tested session and permission machinery.
Home UI was built using Base Web components consolidating shared UI helpers.
- The “New Note” flow creates a note immediately with a default title/content, then edits it in place.
- Draft state lives in
useNoteDraftand tracks adirtyflag (only user edits mark the draft dirty). - Changes to title/content/category schedule a debounced save (currently ~900ms after the last edit).
- Only one save runs at a time (a ref-based guard prevents concurrent updates).
- On close, the editor flushes any pending changes before dismissing and then refreshes the notes list.
- This approach reduces request volume, avoids saving immediately on open, and makes the editor feel responsive while still minimizing data loss.
- The frontend fetches
/api/auth/csrf/to set the CSRF cookie and includes credentials (session cookie). - Mutating requests (e.g. login/logout/create/update) include the CSRF token in the
X-CSRFTokenheader.
Added idempotent startup logic to create a default superuser and run migrations.
Cascade was used to help with:
- Project initial structure setup: Docker configuration files and directory structure
- Architecture design and planning: Braintorming design options and solutions pros and cons
- Documentation and testing: Improving documentation clarity, checking test coverage and writing missing tests
- Debugging and troubleshooting: Analyzing errors, identifying root causes and suggesting fixes and improvements
- Code review and optimization: Reviewing code for best practices and suggesting improvements for code quality and performance