# Runbook

> Attempt #2's only setup instructions lived in a plan file describing an architecture
> that had already been deleted, so they were actively wrong. Keep this file honest:
> if a command here doesn't work, fix it or delete it.

## Status

Milestone 0 is in progress and the app doesn't boot yet. Everything below marked
**(#2)** is carried from the previous attempt and needs re-verifying against Topcoat
before it can be trusted.

## Dev setup

```bash
cargo install topcoat-cli     # dev server, asset bundling, watch mode
cargo run                     # or the topcoat CLI once routing is wired
```

Topcoat's CLI builds the app, bundles assets, and watches source directories for
rebuilds. How that interacts with the embedded SSH server is unresolved — see
[current.md](current.md#open-questions).

## Configuration (#2)

Env vars, `STEID_` prefixed, loaded with `dotenvy` + `envy`. From attempt #2's
`.env.dev`:

```
STEID_REGISTRATION=personal          # personal | invite | open
STEID_OWNER_EMAIL=admin@localhost.dev
STEID_OWNER_PASSWORD=changeme
STEID_OWNER_USERNAME=admin
STEID_DATABASE_URL=sqlite:steid.db?mode=rwc
STEID_LISTEN_ADDR=127.0.0.1:3000
STEID_DATA_DIR=./data                # bare repos live here
```

In `personal` mode the owner account is bootstrapped from `STEID_OWNER_*` on first
boot. Keep `.env.prod` out of git.

## Repo layout on disk (#2)

Bare repos at `{STEID_DATA_DIR}/{org}/{repo}.git`. Created empty — no initial commit.

## SSH (#2)

The SSH server is embedded (russh), not OpenSSH — there is no `authorized_keys`
configuration and no forced command. Users register public keys through the web UI at
`/{owner}/keys`, and the server matches incoming keys by SHA256 fingerprint.

Host key generation and persistence was never written down. Sort it out during
Milestone 3 and document it here — a host key regenerated on each boot means every
client gets a changed-host-key warning.

```bash
git clone git@host:owner/repo
```

## Manual verification checklist (#2)

Attempt #2 verified these by hand each milestone but never wrote down the steps. They
are the smoke test for Milestones 2–4:

- [ ] Create a repo via the web UI → bare repo appears at
      `{data_dir}/{org}/{repo}.git`
- [ ] `git clone` an empty repo → succeeds
- [ ] `git clone` a repo with history → succeeds
- [ ] `git clone` a non-existent repo → clean error, not a hang or panic
- [ ] First push to an empty repo → succeeds
- [ ] Push to a repo with history → succeeds
- [ ] Clone with an unregistered key → `Permission denied`, exit 128
- [ ] Register key via `/{owner}/keys` → clone and push both succeed
- [ ] Revoke key via web UI → subsequent clone rejected at auth
- [ ] Clone a private repo as a non-member → rejected
- [ ] Push as a non-owner member → rejected

Worth automating as an integration test rather than re-running by hand a fourth time.

## Suggested `.gitignore` additions

Not applied yet — no code to ignore. When the app lands:

```
/data
*.db
*.db-shm
*.db-wal
.env.prod
```

**Do not add `/plans`.** Attempt #2 did, and that is why these docs had to be
hand-carried between repos.
