Robot U community site frontend and backend
Find a file
kacper ce32eb067c
All checks were successful
CI / check (push) Successful in 17s
CI / deploy (push) Successful in 21s
Restrict deployment workflow to main
2026-04-15 06:39:26 -04:00
.forgejo/workflows Restrict deployment workflow to main 2026-04-15 06:39:26 -04:00
.githooks Initial Robot U site prototype 2026-04-08 06:03:48 -04:00
blogs/building-robot-u-site Render blog posts from Forgejo 2026-04-12 20:23:05 -04:00
docs Complete Forgejo discussion MVP 2026-04-13 18:19:50 -04:00
frontend Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
scripts Add CI deployment to app LXC 2026-04-15 06:28:30 -04:00
tests Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
.dockerignore Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
.env.example Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
.gitignore Add CI deployment to app LXC 2026-04-15 06:28:30 -04:00
.ruff.toml Initial Robot U site prototype 2026-04-08 06:03:48 -04:00
AGENTS.md Restrict deployment workflow to main 2026-04-15 06:39:26 -04:00
app.py Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
auth.py Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
calendar_feeds.py Build Forgejo-backed community prototype 2026-04-12 20:15:33 -04:00
docker-compose.yml Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
Dockerfile Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
forgejo_client.py Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
live_prototype.py Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
prototype_cache.py Complete Forgejo discussion MVP 2026-04-13 18:19:50 -04:00
README.md Restrict deployment workflow to main 2026-04-15 06:39:26 -04:00
requirements.txt Use encrypted cookie sessions 2026-04-12 22:02:47 -04:00
settings.py Prepare deployment and Forgejo CI 2026-04-14 20:17:29 -04:00
update_events.py Complete Forgejo discussion MVP 2026-04-13 18:19:50 -04:00

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

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:

./scripts/start.sh

The script automatically loads .env and .env.local if present.

Optional runtime overrides:

HOST=0.0.0.0 PORT=8800 ./scripts/start.sh

Optional live Forgejo configuration:

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:

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:

cp .env.example .env

Use the site Sign in button for Forgejo OAuth, or query the API directly with:

curl -H "Authorization: token your-forgejo-api-token" http://127.0.0.1:8800/api/prototype

Frontend

cd frontend
~/.bun/bin/bun install
~/.bun/bin/bun run dev

Quality Checks

./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:

export FORGEJO_API_TOKEN=your-forgejo-api-token
./scripts/bootstrap_ci_clone_key.py

Defaults:

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.

Forgejo Actions LXC Deploy Bootstrap

The main branch CI workflow deploys to the current Robot U LXC after checks pass. Create or rotate the deploy SSH key with:

export FORGEJO_API_TOKEN=your-forgejo-api-token
./scripts/bootstrap_lxc_deploy_key.py

Defaults:

FORGEJO_BASE_URL=https://aksal.cloud
FORGEJO_REPO=Robot-U/robot-u-site
LXC_DEPLOY_HOST=192.168.1.220
LXC_DEPLOY_PORT=22
LXC_DEPLOY_USER=root
LXC_DEPLOY_KEY_COMMENT=robot-u-site-actions-deploy
LXC_DEPLOY_SECRET_NAME=DEPLOY_SSH_KEY

The script generates a temporary Ed25519 keypair, appends the public key to the LXC user's authorized_keys, verifies SSH login with the generated key, and stores the private key in the repo Actions secret DEPLOY_SSH_KEY.

The deploy job only runs for pushes to main. It rsyncs the repository into /opt/robot-u-site, preserves production .env files, runs ./scripts/check_deploy_config.py, rebuilds Docker Compose, and verifies http://127.0.0.1:8800/health.

Required Production Settings

Create a production .env from .env.example and set at least:

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:

./scripts/check_deploy_config.py

The Forgejo OAuth app must include this redirect URI:

https://your-site.example/api/auth/forgejo/callback

Docker Compose

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

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:

https://your-site.example/api/forgejo/webhook