- Replaced custom admin check with `is_org_admin` in `custom_field_views.py`, `organization_views.py`, `user_views.py`, and `macros/views.py` for consistency and clarity. - Removed the unused `_is_admin` function from `custom_field_views.py` and `macros/views.py`. - Updated organization-related views to streamline admin checks and improve error handling. - Removed `SWAGGER_ROOT_URL` and `GOOGLE_REDIRECT_URI` settings from `settings.py` as they were not utilized. - Cleaned up Swagger parameters across various modules to remove the now-irrelevant `org` header. - Adjusted documentation to reflect the removal of `GOOGLE_REDIRECT_URI` and clarify Google OAuth configuration. - Added database indexes for `Order` and `OrderLineItem` models to improve query performance.
5.3 KiB
Environment variables
backend/crm/settings.py is read once, at process import time, by every Django entry point:
manage.py runserver, manage.py migrate, a Gunicorn/Uvicorn worker, a Celery worker, a management
command. This page explains where those values come from and which ones you actually have to set
yourself; the exhaustive per-variable table lives in the Reference section.
How configuration is loaded
backend/crm/settings.py calls load_dotenv() (from python-dotenv) near the top of the module,
before any setting is read, so a .env file next to manage.py, created by copying
backend/.env.example, per Manual setup, is loaded into the
process environment automatically. docker-compose.yml does the equivalent for containers by
listing .env.docker and then the optional, gitignored .env.docker.local under each service's
env_file:, in that order, so values in .env.docker.local win.
Almost every setting in crm/settings.py follows the same pattern: os.environ.get("NAME", <default>), so an unset variable falls back to a working (usually dev-oriented) default rather than
failing. SECRET_KEY, DEBUG, ALLOWED_HOSTS, DBNAME/DBUSER/DBPASSWORD/DBHOST/DBPORT,
EMAIL_BACKEND, CELERY_BROKER_URL/CELERY_RESULT_BACKEND, GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET,
DOMAIN_NAME and FRONTEND_URL are all read this way. A
smaller set of variables has no default at all: backend/crm/server_settings.py (imported only when
ENV_TYPE=prod, see Production deployment) reads AWS_BUCKET_NAME,
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SES_REGION_NAME, AWS_SES_REGION_ENDPOINT and
SENTRY_DSN with plain os.environ[...]. A missing one is a KeyError at import time, which means
the process refuses to start at all rather than starting with something half-configured.
Because all of this runs at import time, not per-request, a changed environment variable only takes
effect the next time the process restarts: editing .env while runserver is already running does
nothing until you restart it (or, for the Docker Compose setup, until the container restarts, which
happens automatically on docker compose up --build).
The minimum for a working install
The values in .env.example and .env.docker are enough to bring the stack up and use it locally;
you do not need to touch anything else to follow Docker quick start
or Manual setup. Before anyone other than you can reach the
instance, the variables that actually need a real value are: SECRET_KEY (a unique secret, not the
shipped django-insecure-... placeholder), DEBUG=False, ALLOWED_HOSTS (your real hostname(s)),
CSRF_TRUSTED_ORIGINS (each entry needs a scheme, e.g. https://crm.example.com), DBUSER pointed
at a non-superuser PostgreSQL role, and CELERY_BROKER_URL/CELERY_RESULT_BACKEND pointed at a
Redis instance you control. Production deployment covers
the full list and exactly what each one guards against; PostgreSQL and RLS
covers why the database role matters as much as any of the Django settings.
Database
DATABASES["default"] in crm/settings.py reads DBNAME (default crm_db), DBUSER (default
postgres), DBPASSWORD (default postgres), DBHOST (default localhost) and DBPORT (default
5432). The default DBUSER is the PostgreSQL superuser account on most installations, and a
superuser silently bypasses every Row-Level Security policy this project relies on for tenant
isolation. See PostgreSQL and RLS for how to create and verify a
non-superuser role before pointing these variables at anything but a local, throwaway database.
EMAIL_BACKEND defaults to django.core.mail.backends.console.EmailBackend, so outbound mail
(welcome emails, magic-link sign-in emails, comment-mention notifications) prints to stdout instead
of being sent anywhere. .env.example sets EMAIL_BACKEND to that same console backend explicitly;
.env.docker doesn't set EMAIL_BACKEND at all, only a comment noting the console backend is
what's active, so it's relying on the identical default rather than setting it. DEFAULT_FROM_EMAIL
and ADMIN_EMAIL default to noreply@localhost/admin@localhost. Switching to a real mail backend,
and the Amazon SES-specific variables that come with it, is covered in full in
Email and Celery.
Integrations
GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET both default to empty strings in crm/settings.py,
and .env.docker and .env.example ship both blank. Google sign-in stays off until they are set, on
both the backend and the SvelteKit frontend. There is no GOOGLE_REDIRECT_URI setting: the redirect
URI used in the token exchange is the one the frontend sends in the request body on each call, so a
setting of that name was read into Django and never referenced again. See
Google OAuth for what each one does and where to get the values.
SENTRY_DSN is read (with no default) only inside server_settings.py, i.e. only when
ENV_TYPE=prod; it's not consulted at all otherwise.
Full reference
Every variable this project reads, its default, and the file that reads it is tabulated in full in the Reference section.