178 lines
5.3 KiB
Markdown
178 lines
5.3 KiB
Markdown
# Robot U Site Prototype
|
|
|
|
Thin frontend layer over Forgejo for community learning content, discussions, and events.
|
|
|
|
## Stack
|
|
|
|
- FastAPI backend
|
|
- Preact + TypeScript frontend built with Vite
|
|
- `bun` for frontend tooling
|
|
- `uv` + `ruff` for Python checks
|
|
|
|
## Local Development
|
|
|
|
### Backend
|
|
|
|
```bash
|
|
python3 -m venv .venv
|
|
.venv/bin/pip install -r requirements.txt
|
|
.venv/bin/python -m uvicorn app:app --reload
|
|
```
|
|
|
|
### Start App
|
|
|
|
Build the frontend and then serve the app from FastAPI:
|
|
|
|
```bash
|
|
./scripts/start.sh
|
|
```
|
|
|
|
The script automatically loads `.env` and `.env.local` if present.
|
|
|
|
Optional runtime overrides:
|
|
|
|
```bash
|
|
HOST=0.0.0.0 PORT=8800 ./scripts/start.sh
|
|
```
|
|
|
|
Optional live Forgejo configuration:
|
|
|
|
```bash
|
|
export APP_BASE_URL="http://kacper-dev-pod:8800"
|
|
export AUTH_SECRET_KEY="$(openssl rand -hex 32)"
|
|
export AUTH_COOKIE_SECURE="false"
|
|
export CORS_ALLOW_ORIGINS="http://kacper-dev-pod:8800"
|
|
export FORGEJO_BASE_URL="https://aksal.cloud"
|
|
export FORGEJO_OAUTH_CLIENT_ID="your-forgejo-oauth-client-id"
|
|
export FORGEJO_OAUTH_CLIENT_SECRET="your-forgejo-oauth-client-secret"
|
|
export FORGEJO_OAUTH_SCOPES="openid profile"
|
|
export FORGEJO_GENERAL_DISCUSSION_REPO="Robot-U/general_forum"
|
|
export FORGEJO_WEBHOOK_SECRET="shared-webhook-secret"
|
|
export FORGEJO_CACHE_TTL_SECONDS="60.0"
|
|
export CALENDAR_FEED_URLS="webcal://example.com/calendar.ics,https://example.com/other.ics"
|
|
```
|
|
|
|
`APP_BASE_URL` must match the URL you use in the browser. Create the OAuth app in Forgejo with this redirect URI:
|
|
|
|
```text
|
|
http://kacper-dev-pod:8800/api/auth/forgejo/callback
|
|
```
|
|
|
|
`AUTH_SECRET_KEY` is required for Forgejo OAuth sign-in. It encrypts the `HttpOnly` browser session cookie that carries the signed-in user's Forgejo token and identity. Set `AUTH_COOKIE_SECURE=true` when serving over HTTPS.
|
|
|
|
`CORS_ALLOW_ORIGINS` defaults to `APP_BASE_URL` when that value is set. Use a comma-separated list if the API must be called from additional browser origins.
|
|
|
|
`FORGEJO_TOKEN` is optional. When set, it is a read fallback for the public content cache. Browser OAuth requests only identity scopes, then the backend uses the signed-in user's Forgejo identity from the encrypted session cookie for public discussion creation and replies. The backend must verify repositories are public before reading discussion data or writing issues/comments.
|
|
|
|
`FORGEJO_CACHE_TTL_SECONDS` controls how long the server reuses the public Forgejo content scan for `/api/prototype`. Set it to `0` to disable caching while debugging discovery behavior.
|
|
|
|
`FORGEJO_GENERAL_DISCUSSION_REPO` should point at the public `owner/repo` used for general discussion threads. Post- and lesson-linked discussions are created in the same repo as the content being discussed.
|
|
|
|
`FORGEJO_WEBHOOK_SECRET` is optional but recommended. Configure Forgejo webhooks to POST to `/api/forgejo/webhook`; matching webhook events invalidate the public content cache and notify open browsers over `/api/events/stream`.
|
|
|
|
Or put those values in `.env`:
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
Use the site `Sign in` button for Forgejo OAuth, or query the API directly with:
|
|
|
|
```bash
|
|
curl -H "Authorization: token your-forgejo-api-token" http://127.0.0.1:8800/api/prototype
|
|
```
|
|
|
|
### Frontend
|
|
|
|
```bash
|
|
cd frontend
|
|
~/.bun/bin/bun install
|
|
~/.bun/bin/bun run dev
|
|
```
|
|
|
|
### Quality Checks
|
|
|
|
```bash
|
|
./scripts/check_python_quality.sh
|
|
./scripts/check_frontend_quality.sh
|
|
```
|
|
|
|
## Deployment
|
|
|
|
### Forgejo Actions SSH Clone Bootstrap
|
|
|
|
If the Forgejo instance only supports SSH clone in Actions, create a repo deploy key and matching Actions secret:
|
|
|
|
```bash
|
|
export FORGEJO_API_TOKEN=your-forgejo-api-token
|
|
./scripts/bootstrap_ci_clone_key.py
|
|
```
|
|
|
|
Defaults:
|
|
|
|
```text
|
|
FORGEJO_BASE_URL=https://aksal.cloud
|
|
FORGEJO_REPO=Robot-U/robot-u-site
|
|
CI_CLONE_KEY_TITLE=robot-u-site-actions-clone
|
|
CI_CLONE_SECRET_NAME=CI_REPO_SSH_KEY
|
|
```
|
|
|
|
The script generates a temporary Ed25519 keypair, adds the public key as a read-only deploy key on the repo, and stores the private key in the repo Actions secret `CI_REPO_SSH_KEY`.
|
|
|
|
### Required Production Settings
|
|
|
|
Create a production `.env` from `.env.example` and set at least:
|
|
|
|
```bash
|
|
APP_BASE_URL=https://your-site.example
|
|
AUTH_SECRET_KEY=$(openssl rand -hex 32)
|
|
AUTH_COOKIE_SECURE=true
|
|
CORS_ALLOW_ORIGINS=https://your-site.example
|
|
FORGEJO_BASE_URL=https://aksal.cloud
|
|
FORGEJO_OAUTH_CLIENT_ID=...
|
|
FORGEJO_OAUTH_CLIENT_SECRET=...
|
|
FORGEJO_GENERAL_DISCUSSION_REPO=Robot-U/general_forum
|
|
FORGEJO_WEBHOOK_SECRET=$(openssl rand -hex 32)
|
|
```
|
|
|
|
Then validate the deployment environment:
|
|
|
|
```bash
|
|
./scripts/check_deploy_config.py
|
|
```
|
|
|
|
The Forgejo OAuth app must include this redirect URI:
|
|
|
|
```text
|
|
https://your-site.example/api/auth/forgejo/callback
|
|
```
|
|
|
|
### Docker Compose
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
$EDITOR .env
|
|
./scripts/check_deploy_config.py
|
|
docker compose up --build -d
|
|
curl -fsS http://127.0.0.1:8800/health
|
|
```
|
|
|
|
The compose file exposes the app on host port `8800` and runs Uvicorn on container port `8000`.
|
|
|
|
### Non-Container Deployment
|
|
|
|
```bash
|
|
python3 -m venv .venv
|
|
.venv/bin/pip install -r requirements.txt
|
|
cd frontend
|
|
~/.bun/bin/bun install
|
|
~/.bun/bin/bun run build
|
|
cd ..
|
|
HOST=0.0.0.0 PORT=8000 ./scripts/run_prod.sh
|
|
```
|
|
|
|
Put a reverse proxy in front of the app for TLS. Preserve long-lived connections for `/api/events/stream`, and configure Forgejo webhooks to POST to:
|
|
|
|
```text
|
|
https://your-site.example/api/forgejo/webhook
|
|
```
|