The backend for LANMS. For the frontend, see the frontend readme or the root readme.
Run the commands below from the backend/ directory at the repository root.
For the backend to be able to run in all environments these environment variables need to be set:
-
ENV
The following values are allowed:
devorlocalfor developers and local environmentstagingfor test environment that is set up like prod but only used for testingproductionorprodfor your production environment
-
JWT_PUBLIC_KEY
PEM-encoded public half of an RSA key pair, used to verify JWTs (default algorithm is
RS256). In.env, you can embed newlines as literal\nsequences; the app normalizes them on load. -
JWT_PRIVATE_KEY
PEM-encoded private half of the same RSA key pair, used to sign access and refresh tokens. Keep this secret and never commit it. Same newline rules as
JWT_PUBLIC_KEY. -
PORTAL_URL — ex.
https://portal.lanms.netThe URL for the frontend where that is hosted; used for links in emails.
-
OTP_SECRET_KEY
Secret used for OTP generation (TOTP-style). Use a strong value; in development you can use a Base32-style string similar to
.env.example.
CODE_BUILDDEBUGDATABASE_DEBUG— when set, enables SQLAlchemy echo loggingDB_HOST,DB_USERNAME,DB_PASSWORD,DB_PORT,DB_DIALECT,DB_NAMEJWT_ALGORITHMACCESS_TOKEN_EXPIRE_MINUTES,REFRESH_TOKEN_EXPIRE_MINUTESFROM_EMAILSENTRY_DSNSENDGRID_API_KEY,POSTMARK_API_KEYPASSWORD_MIN_LENGTHMAX_IMAGE_SIZE_KB,MAX_FILE_SIZE_KBSUPER_ADMINS- First deployment only:
INITIAL_USER_EMAILandINITIAL_USER_PASSWORD— used bycreate_initial_user.pyto create the first login user after migrations (see Bootstrap initial user). Leave unset or empty when not running that script.
Make a copy of the .env.example file and rename it to .env. Fill in the required environment variables.
cp .env.example .envInstall uv, then install dependencies (runtime and dev):
uv sync --all-groupsActivate pre-commit hooks:
uv run pre-commit installWe use Ruff for code styling and formatting. To run code styling check manually you can run:
uv run ruff check --fixFor formatting code you can run:
uv run ruff formatUse pre-commit to do this automatically.
Run the test suite with:
uv run pytestTests set ENV=test and use an in-memory SQLite database (see tests/conftest.py); you do not need Postgres running locally for them. Pull requests that touch backend/** run Ruff and pytest in CI.
To create a new migration, run the following command:
uv run alembic revision --autogenerate -m "migration message"To run the migrations, run the following command:
uv run alembic upgrade headFor a new environment you can create the first login user from the environment (see .env.example):
INITIAL_USER_EMAIL— email used to sign inINITIAL_USER_PASSWORD— must be at leastPASSWORD_MIN_LENGTHcharacters (default 12)
Set these only when you intend to run the bootstrap command; the API does not require them for normal operation.
After the database exists and migrations have been applied:
uv run alembic upgrade head
uv run python create_initial_user.pyThe script uses the same .env as the application. It is idempotent: if an active user with that email already exists, it exits successfully and does nothing. The user is created with a verified email and accepted terms/privacy timestamps so they can use the normal login flow without completing OTP signup.
On first deploy, run this once after migrations if you rely on env-driven bootstrap. Clear or rotate INITIAL_USER_PASSWORD in your secrets store afterward if your policy requires it.
The backend is deployed to the staging environment automatically when a commit is pushed to the develop branch. Create a pull request from your branch to develop; once it is merged, the backend is deployed to staging.