register and sign in pages
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# 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
|
||||
|
||||
```sh
|
||||
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
|
||||
|
||||
```sh
|
||||
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`](.build/prod/README.md).
|
||||
Reference in New Issue
Block a user