A full-stack Django application where organizations post volunteer opportunities and volunteers discover and sign up for them. Built on top of a Django + Tailwind + DaisyUI starter template, extended with a custom role-based user system, a complete opportunities/sign-up feature, Progressive Web App support, and a production deployment.
Live site: https://volunteer-board-nccd.onrender.com Repository: https://github.com/13getid/django-starter
Note: the live site is hosted on Render's free tier, which spins down after periods of inactivity. The first request after idle time may take 30–60 seconds to respond while the server wakes up — this is expected, not a bug.
Reviewers can log in directly instead of signing up:
| Role | Password | |
|---|---|---|
| Organization | demo.org@example.com |
DemoPass123! |
| Volunteer | demo.volunteer@example.com |
DemoPass123! |
The Organization demo account has an active posted opportunity, and the Volunteer demo account is already signed up for it, so both roles have real data to explore immediately.
- Registration with role selection (Organization / Volunteer)
- Login / logout
- Password reset ("forgot password") via email
- Password change (while logged in)
- Profile page with avatar upload
- Organizations can post opportunities and view a dashboard of everything they've posted.
- Volunteers can browse, search, and sign up for opportunities, and view a dashboard of everything they've joined.
- Role checks are enforced at the view level — an Organization account cannot sign up for opportunities, and a Volunteer account cannot post one; both attempts are rejected with a proper 403, not just hidden UI.
- Public, searchable/filterable list of opportunities (search by title, filter by location)
- Detail page per opportunity with a cover image, description, date, location, and live spot count
- One-click sign up / cancel sign-up for volunteers
- Role-specific dashboards ("My Opportunities" for organizations, "My Sign-Ups" for volunteers)
- User avatars, uploaded from the profile page
- Opportunity cover images, uploaded when posting
- Both stored on Cloudinary in production, so uploads persist across deploys (Render's free-tier disk is ephemeral and would otherwise wipe them)
- Web app manifest — installable to home screen/desktop, with name, icons, and theme color
- Service worker — caches key pages for offline use
- Offline fallback page — a custom "You're offline" page instead of the browser's default error when there's no connection
- Tailwind CSS + DaisyUI throughout, including a custom-themed landing page, styled forms, and a role-aware navigation bar
| Layer | Choice |
|---|---|
| Backend | Django 6, django-allauth (auth), Django REST Framework |
| Frontend build | Vite, Tailwind CSS, DaisyUI |
| Database | PostgreSQL |
| Media storage | Cloudinary |
| Brevo (transactional email API) | |
| Deployment | Docker on Render |
| Package management | uv (Python), npm (JS) |
- Custom user model (
apps/users) extends Django'sAbstractUserwith arolefield (organization/volunteer) and an avatar field. Role is collected at signup via a customdjango-allauthsignup form and saved through allauth'scustom_signup()hook. - Opportunities app (
apps/opportunities) contains theOpportunityandSignUpmodels, with view-level permission checks based onrequest.user.role. - Single-instance production setup: to keep the deployment footprint small on a free-tier host, Redis and Celery's worker/broker are not used in production — the cache falls back to Django's in-memory cache, and any Celery tasks run synchronously (
CELERY_TASK_ALWAYS_EAGER). This is a deliberate simplification for a single-web-service deployment, not an oversight.
Requirements: uv, Node.js.
git clone https://github.com/13getid/django-starter.git
cd django-starter
copy .env.example .env # Windows; use `cp` on macOS/Linux
uv sync
npm install
uv run python manage.py migrateRun in two terminals:
# Terminal 1
uv run python manage.py runserver
# Terminal 2
npm run devVisit http://localhost:8000. A superuser (admin@example.com / admin) is auto-created in debug mode.
Deployed on Render as a Docker web service, using the repo's existing production Dockerfile.
- Database: Render PostgreSQL (free tier)
- Media storage: Cloudinary (avatars and opportunity cover images)
- Email: Brevo, via
django-anymail's HTTP API backend — not SMTP. Render's free tier blocks outbound SMTP ports (25/587), so the SMTP backend was replaced with Anymail's Brevo API backend, which sends over standard HTTPS instead. - Static files: WhiteNoise, collected at deploy time
- Start command: a small
render-start.shscript runs migrations, collects static files, then starts Gunicorn
Password reset and other transactional emails are sent via Brevo. If the sending address and the recipient address are both @gmail.com, Gmail's anti-spoofing protections may temporarily defer the message (visible in Brevo's logs as a 421-4.7.28 deferral, not a permanent failure). This is a Gmail-side protection against third-party services relaying mail that appears to originate from a Gmail address — it is not an application bug. Emails to non-Gmail addresses deliver normally, and deferred messages typically deliver successfully on retry. A production fix would involve authenticating a custom sending domain in Brevo rather than using a free email provider as the sender.
apps/
users/ # custom user model, role field, avatar, signup form
opportunities/ # Opportunity + SignUp models, views, templates
web/ # landing page, home routing, PWA routes
templates/
opportunities/ # list, detail, create, dashboard templates
web/ # landing page components, offline page
sw.js # service worker
render-start.sh # production start script (migrate, collectstatic, gunicorn)
Built on top of the django-starter template by Chris Achinga, adapted from SaaS Pegasus. The starter's own detailed reference documentation (full make command list, Docker production stack details, testing, code quality tooling) is preserved in STARTER_TEMPLATE_REFERENCE.md.