2026-09-22 00:50:30 +05:00
2026-09-22 00:50:30 +05:00
2026-09-22 00:50:30 +05:00
2026-09-22 00:50:30 +05:00
2026-09-22 00:50:30 +05:00
2026-09-22 00:50:30 +05:00
2026-09-21 21:28:51 +05:00
2026-08-02 05:09:00 +05:00
2026-09-22 00:50:30 +05:00

sarlinkportal

Monorepo for the SAR Link member portal.

backend/    Django 5.2 + DRF API (knox auth, postgres, procrastinate)
frontend/   Vite + React + TypeScript SPA (served by nginx in production)
.build/prod/  production images and compose

Quick start

cp backend/.env.example backend/.env      # add SMS_API_KEY for real texts
docker compose up --build
docker compose exec backend python manage.py createsuperuser   # asks for a mobile number

Atolls and islands are seeded by migration. With SMS_API_KEY empty, OTP codes are printed to the backend log instead of being texted.

SPA http://localhost:5173
API http://localhost:8000/api/
API docs (DEBUG) http://localhost:8000/api/docs/
Django admin http://localhost:8000/admin/

The root compose.yml just includes backend/compose.yml and frontend/compose.yml, so each side can also be brought up on its own.

How the two talk

The SPA only ever calls a relative /api/...:

  • dev — the vite dev server proxies /api, /admin, /static, /media to the backend container.
  • prod — one nginx serves the built SPA and proxies the same prefixes to gunicorn, so there's a single origin and no CORS.

Authentication

One entry point - the mobile number - and the API decides the second step:

POST /api/auth/start/  {mobile}  ->  next: "password" | "otp"

  password  ->  POST /api/auth/login/password/  {mobile, password}
                  -> next: "dashboard" + knox token

  otp       ->  POST /api/auth/verify/          {mobile, code}
                  -> next: "dashboard" + knox token
                  -> next: "register" + ticket
                     -> POST /api/auth/register/ {ticket, ...form} -> pending account

start gives nothing away: a number with no account gets the same "code sent" response as a member's. Only a confirmed code reveals which it was. New numbers then go form -> pending, and an admin approves the application in the Django admin before the account is usable.

backend/README.md documents the responses, OTP/ticket policy, the SMS gateway and the approval actions; frontend/README.md documents the forms.

Tests

docker compose exec backend python manage.py test --settings=apibase.settings_test
cd frontend && npm run build && npm run lint

Production

See .build/prod/README.md.

S
Description
submodules as mono repo for easier development
Readme
109 KiB
Languages
Python 64.6%
TypeScript 32.6%
Dockerfile 1.6%
Just 0.4%
HTML 0.3%
Other 0.5%