# RFC App A single-process FastAPI + SQLite + React + Vite + Tiptap app that materializes the Wiggleverse RFC framework specified in [`SPEC.md`](./SPEC.md). The framework's mission lives in [`PHILOSOPHY.md`](./PHILOSOPHY.md); the spec is the binding contract; this README is how to bring the app up against a local Gitea instance and exercise the slice the build session has shipped so far. The implementation is in progress. See [`docs/DEV.md`](./docs/DEV.md) for the slicing plan and the current state. ## What the app expects to talk to - **A Gitea instance** at `GITEA_URL`. The instance hosts the meta repository and (eventually) one repository per graduated RFC. - **A bot service account** in that Gitea, with a personal access token in `GITEA_BOT_TOKEN`. Per §1 the bot is the only writer in the system — every commit, branch, and PR the app produces flows through one wrapper that applies the §6.5 `On-behalf-of:` trailer and records a row in the `actions` audit log. - **An OAuth2 application** registered against that Gitea, with the callback URL set to `{APP_URL}/auth/callback`. Real human users authenticate via Gitea OAuth (the §18 carryover); the app reads their Gitea profile, provisions a row in `users`, and layers §6's app-owned permission model on top. ## Local bring-up The shortest path from a clean checkout to a working app is: ### 1. Stand up a local Gitea Anything that exposes the Gitea REST API works. The fastest path is Docker: ```sh docker run -d --name gitea \ -p 3000:3000 -p 222:22 \ -v gitea-data:/data \ gitea/gitea:1.21 ``` Open `http://localhost:3000`, walk through the install wizard (SQLite, default port), and create your owner-zero account. ### 2. Create the bot service account In Gitea, sign in as your owner account and **Site Administration → User Accounts → Create User Account**. Give it a name like `rfc-bot` and an email. Then sign in as the bot, open **Settings → Applications → Generate New Token**, and grant it the `write:repository`, `write:user`, and `write:admin` scopes (admin is needed because the bot will create per-RFC repos on graduation; in v1 you can scope down to `repo` and `org` if you want to defer admin until Slice 5). Copy the token; you will paste it into `.env`. ### 3. Create the org that will host the meta repo The seed script creates the meta repo *inside* an org. Create the org (e.g. `wiggleverse`) in Gitea and add `rfc-bot` to it as an **Owner**. ### 4. Register the OAuth2 application In Gitea: **Site Administration → Integrations → OAuth2 Applications → Create**. Name it whatever you like, set the redirect URI to `http://localhost:8000/auth/callback`. Copy the client id and client secret — they go into `.env`. ### 5. Configure the app ```sh cd backend cp .env.example .env $EDITOR .env # fill in every variable ``` Required values: | Variable | What it is | | -------------------------- | --------------------------------------------------------- | | `GITEA_URL` | Base URL of the Gitea instance (no trailing slash). | | `GITEA_BOT_USER` | The bot account's login. | | `GITEA_BOT_TOKEN` | The bot account's access token. | | `GITEA_ORG` | The org that owns the meta repo. | | `META_REPO` | The meta repo's name (default `meta`). | | `OAUTH_CLIENT_ID` | From the OAuth app you registered. | | `OAUTH_CLIENT_SECRET` | Likewise. | | `APP_URL` | The URL the app is reachable at locally. | | `SECRET_KEY` | A long random string for cookie signing. | | `OWNER_GITEA_LOGIN` | Your owner-zero Gitea login — gets the owner role on first sign-in. | | `GITEA_WEBHOOK_SECRET` | A shared secret for the §4.1 webhook signature. | The LLM-provider settings (`ENABLED_MODELS`, `ANTHROPIC_API_KEY`, etc.) are not exercised by Slice 1 but are wired through `config.py` so the next slice can pick them up. ### 6. Install dependencies Backend: ```sh cd backend python3 -m venv .venv .venv/bin/pip install -r requirements.txt ``` Frontend: ```sh cd ../frontend npm install ``` ### 7. Seed the meta repo The seed script creates `wiggleverse/meta` if it does not exist, populates it with `PHILOSOPHY.md`, `README.md`, `CONTRIBUTING.md`, the regenerate-index workflow placeholder, and an empty `rfcs/` directory, and registers the Gitea webhook the app needs: ```sh cd backend .venv/bin/python ../scripts/seed_meta_repo.py ``` Re-running is safe — every step is upsert-shaped. ### 8. Run the app In two terminals: ```sh # Terminal 1 — backend cd backend .venv/bin/uvicorn app.main:app --reload --port 8000 ``` ```sh # Terminal 2 — frontend cd frontend npm run dev ``` Open `http://localhost:5173`. Sign in with your owner-zero Gitea account. The catalog should appear empty; the **+ Propose New RFC** button at the bottom opens the propose modal. ## What slice 1 lets you do End-to-end: propose a new RFC → an idea PR opens against the meta repo → an owner merges from the pending-idea view → the super-draft appears in the catalog → opening it renders the body. This exercises the §4 cache (webhook + reconciler), the §6 permission model (the owner-only merge button, the contributor-only propose modal), the §1 bot wrapper (every Git write goes through it, every commit and PR carries the `On-behalf-of:` trailer), and the §9 propose-merge-render path. Out of scope for slice 1: the active-RFC view (§8), per-branch chat, AI participation, the change-card panel, PRs against per-RFC repos, graduation, notifications, the landing page's full polish. Those slices are listed in [`docs/DEV.md`](./docs/DEV.md). ## Verifying it worked After bring-up: - `http://localhost:8000/docs` lists the API routes the build session has wired so far. - `sqlite3 backend/data/rfc-app.db .schema` shows the §5 schema. - `gitea ls /api/v1/repos/wiggleverse/meta/contents/rfcs` after a proposal merges should show one new `.md`. ## Troubleshooting - **The catalog stays empty after a merge.** Check that the webhook is reaching the app: the reconciler runs every five minutes and will catch up, but a missing or misconfigured webhook is the most common reason for sub-second freshness to fail. The seed script registers the webhook for you; if you bring up Gitea on a different host (e.g. a Codespace, a tunnel), re-run the seed against the new `APP_URL`. - **OAuth callback errors.** The redirect URI in Gitea has to match `APP_URL` exactly, including the protocol and port. - **The bot can't merge.** The bot needs Maintainer or Owner on the meta repo (membership in `GITEA_ORG` as Owner gives it both). ## Where to read further - [`SPEC.md`](./SPEC.md) — the binding contract. Every load-bearing decision is there. - [`PHILOSOPHY.md`](./PHILOSOPHY.md) — why this framework exists. The spec's decisions answer to it. - [`docs/DEV.md`](./docs/DEV.md) — the build's slicing plan, the current state, and the next slice's brief.