# memberapi.ose.tw backend
## Quick start
```bash
cd backend
python -m venv .venv
source .venv/bin/activate
pip install -e .
cp .env.example .env
./scripts/start_dev.sh
```
## Required DB setup
1. Initialize API client whitelist table with `docs/API_CLIENTS_SQL.sql`.
2. Initialize core tables with `backend/scripts/init_schema.sql`.
3. Generate `api_key_hash` and update `api_clients` records, e.g.:
```bash
python scripts/generate_api_key_hash.py 'YOUR_PLAIN_KEY'
```
## IdP JWT setup(Keycloak 優先)
- 若設定 `KEYCLOAK_BASE_URL` + `KEYCLOAK_REALM`,後端會優先走 Keycloak。
- 未設定 Keycloak 時,才走 `AUTHENTIK_*`。
### Keycloak
- 必填:
- `KEYCLOAK_BASE_URL`
- `KEYCLOAK_REALM`
- `KEYCLOAK_CLIENT_ID`
- `KEYCLOAK_CLIENT_SECRET`
- 可選:
- `KEYCLOAK_ISSUER`(預設:`/realms/`)
- `KEYCLOAK_JWKS_URL`(預設:`/protocol/openid-connect/certs`)
- `KEYCLOAK_TOKEN_ENDPOINT`(預設:`/protocol/openid-connect/token`)
- `KEYCLOAK_USERINFO_ENDPOINT`(預設:`/protocol/openid-connect/userinfo`)
- `KEYCLOAK_AUDIENCE`
- `KEYCLOAK_VERIFY_TLS`(預設 true)
### Authentik(備援)
- Configure at least one of:
- `AUTHENTIK_JWKS_URL`
- `AUTHENTIK_ISSUER` (the service infers `/jwks/`)
- Optional:
- `AUTHENTIK_AUDIENCE` (enables audience claim validation)
- `AUTHENTIK_CLIENT_ID` (used by `/auth/login`, fallback to `AUTHENTIK_AUDIENCE`)
- `AUTHENTIK_CLIENT_SECRET` (required if your access/id token uses HS256 signing)
- `AUTHENTIK_TOKEN_ENDPOINT` (default: `/application/o/token/`)
- `AUTHENTIK_USERINFO_ENDPOINT` (optional, default inferred from issuer/base URL; used to fill missing email/name claims)
## IdP Admin API setup
- Keycloak(優先)
- `KEYCLOAK_BASE_URL`
- `KEYCLOAK_REALM`
- `KEYCLOAK_ADMIN_CLIENT_ID`
- `KEYCLOAK_ADMIN_CLIENT_SECRET`
- `KEYCLOAK_ADMIN_REALM`(可選,預設同 `KEYCLOAK_REALM`)
- Authentik(備援)
- `AUTHENTIK_BASE_URL`
- `AUTHENTIK_ADMIN_TOKEN`
- `AUTHENTIK_VERIFY_TLS`
## Main APIs
- `GET /healthz`
- `GET /auth/oidc/url`
- `POST /auth/oidc/exchange`
- `GET /me` (Bearer token required)
- `GET /me/permissions/snapshot` (Bearer token required)
- `POST /internal/users/upsert-by-sub`
- `GET /internal/permissions/{user_sub}/snapshot`
- `POST /internal/idp/users/ensure`(相容:`/internal/authentik/users/ensure`)
- `POST /admin/permissions/grant`
- `POST /admin/permissions/revoke`
- `GET|POST /admin/systems`
- `GET|POST /admin/modules`
- `GET|POST /admin/companies`
- `GET|POST /admin/sites`
- `GET /admin/members`
- `GET|POST /admin/permission-groups`
- `POST|DELETE /admin/permission-groups/{group_key}/members/{user_sub}`
- `POST /admin/permission-groups/{group_key}/permissions/grant|revoke`
- `GET /internal/systems`
- `GET /internal/modules`
- `GET /internal/companies`
- `GET /internal/sites`
- `GET /internal/members`