docs: add changelog, contributor guide, release process, and runner setup

- CHANGELOG.md: Keep-a-Changelog format, [26.0-alpha] entry covering
  everything shipped so far (installer webapp, drive scoring, base
  archinstall config, wireframes, competitor analysis, wizard flow spec)
- CONTRIBUTING.md: dev setup, conventional commit format, code style
- RELEASING.md: calendar versioning rules (YY.N-stage, no "v" prefix)
  and the release workflow (bump changelog, commit, tag, push, create
  Forgejo Release)
- docs/runner-setup.md: install + register a forgejo-runner so the
  upcoming CI workflow actually executes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Maksymilian Syrnicki 2026-04-13 20:23:48 +02:00
parent decab35fbf
commit 7759574481
4 changed files with 301 additions and 0 deletions

35
CHANGELOG.md Normal file
View file

@ -0,0 +1,35 @@
# Changelog
All notable changes to Homebase will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
This project uses calendar versioning: `YY.N-stage` (e.g. `26.0-alpha` = 2026, release 0, alpha stage).
## [Unreleased]
## [26.0-alpha] - 2026-04-13
First tagged snapshot. Pre-alpha — the installer does not yet boot, but the design is locked and the prototype components are shaped.
### Added
- **Installer webapp prototype** (`webinstaller/`) — Flask app with 3-step wizard (hostname → drive → overview), serves drive list via `drives.py::list_scored_devices()`.
- **Drive scoring module** (`webinstaller/drives.py`) — scores attached disks by type (NVMe/SSD/HDD), SMART health (`smartctl -H`), and size. Consumed by the installer and usable as a CLI.
- **Base archinstall configuration** (`archinstall/user_configuration.json`) — systemd-boot, ext4, Docker + Compose preinstalled, server profile, SSH. Credentials template at `archinstall/user_credentials.example.json` (real credentials gitignored).
- **Installer wireframes** (`docs/installer-wireframes.md`) — Robert's hand-drawn 4-screen UX sketches.
- **Competitor analysis** (`docs/competitors.md`) — CasaOS, Umbrel, YunoHost reviewed across install flow, hardware detection, app store UX, reverse proxy/SSL, user complaints. Key finding: device-aware wizard + managed gateway are uncontested differentiators.
- **Wizard flow spec** (`docs/wizard-flow.md`) — 8-screen first-boot flow extending Robert's wireframe with YunoHost-style domain/SSL/diagnostic/confirm screens. Locked tech picks with rejected alternatives.
- **Project README** — vision, principles, architecture, key decisions, landscape, roadmap.
### Decisions locked
- **Reverse proxy:** Caddy (auto Let's Encrypt, simplest config)
- **Identity provider:** Authentik (bundled SSO, every app auto-wired at install)
- **Managed gateway DNS:** NS delegation to `ns1.homebase.cloud` / `ns2.homebase.cloud` (wildcard cert via Let's Encrypt DNS-01)
- **Local HTTPS:** Local CA installed by user once (no browser warnings on `*.proksi.local`)
- **Base OS:** Arch (rolling, Debian remains fallback)
- **Containers:** Docker + Compose
- **License:** AGPL-3.0
[Unreleased]: https://forgejo.sourcegate.online/daniel/homebase/compare/26.0-alpha...HEAD
[26.0-alpha]: https://forgejo.sourcegate.online/daniel/homebase/releases/tag/26.0-alpha

80
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,80 @@
# Contributing to Homebase
Two-person project right now (Daniel + Robert). This doc exists so the conventions don't get lost as the team grows.
## Dev setup
```bash
git clone https://forgejo.sourcegate.online/daniel/homebase.git
cd homebase
python -m venv .venv
source .venv/bin/activate
# Flask installer
pip install -r webinstaller/requirements.txt
python webinstaller/app.py # serves on http://localhost:5000
# Dev tooling (lint + tests)
pip install -e ".[dev]"
ruff check .
pytest
```
Required system tools (used by `webinstaller/drives.py`):
- `lsblk` (util-linux)
- `smartctl` (smartmontools) — `sudo pacman -S smartmontools` / `sudo apt install smartmontools`
## Commit messages
We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/). Every commit subject line starts with a type:
| Type | When |
|------|------|
| `feat:` | New user-visible feature |
| `fix:` | Bug fix |
| `docs:` | Documentation only |
| `ci:` | CI config, Forgejo Actions, runner setup |
| `build:` | Packaging, `pyproject.toml`, dependency changes |
| `refactor:` | Code restructuring with no behavior change |
| `test:` | Adding or fixing tests |
| `chore:` | Everything else (e.g. `.gitignore`, version bumps) |
Examples:
```
feat: add S5 domain picker to installer wizard
fix: handle empty lsblk output in drives.parse_size_gb
docs: document NS delegation flow for managed gateway
ci: add ruff format check to Forgejo Actions workflow
```
Keep the subject line under 72 characters. Use the body to explain *why* — the code already says *what*.
## Code style
- **Python:** ruff handles lint + format. Config in `pyproject.toml`. Run `ruff check . && ruff format .` before committing.
- **Markdown:** wrap at a sensible width (no hard line-length rule). Every external link you add to a doc must resolve (the markdown-link-check CI job will catch it if it doesn't).
- **No comments that explain *what*** — the code says that. Only comment the *why* when it's non-obvious.
## PR / push workflow
While the team is two people, pushing to `main` is fine for small changes. For anything larger than ~50 lines or that touches architecture, open a PR and get the other person to look at it.
## Tests
Tests live in `tests/`. Pure functions get unit tests; anything that shells out to `lsblk` / `smartctl` is out of scope (those need hands-on testing on real hardware).
```bash
pytest # all tests
pytest tests/test_drives.py -v
```
## Releases
See [RELEASING.md](RELEASING.md).
## License
AGPL-3.0 (see `LICENSE`). By contributing you agree your contributions are licensed the same way.

73
RELEASING.md Normal file
View file

@ -0,0 +1,73 @@
# Releasing
Homebase uses calendar versioning: **`YY.N-stage`** — e.g. `26.0-alpha` is 2026, release 0, alpha stage. No `v` prefix.
- `YY` — last two digits of the current year
- `N` — incrementing release number within the year, starting at 0 (next one in 2026 is `26.1-alpha`, then `26.2-alpha`…)
- `-alpha` — drop it when the installer boots end-to-end and wipe-and-reinstall is safe
When the year rolls over, the next release becomes `27.0-alpha` regardless of how many `26.x` releases shipped.
## Cadence
Tag per meaningful milestone, not on a calendar. A milestone is: ISO boots, a wizard screen works end-to-end, managed gateway serves its first real domain, etc. If a week goes by with no tag, that's fine — no tag is better than a noisy one.
## Release steps
1. **Move `[Unreleased]` in `CHANGELOG.md` to a new version heading.**
```markdown
## [Unreleased]
## [26.1-alpha] - 2026-05-20
### Added
- ...
```
Add a `[26.1-alpha]` link definition at the bottom:
```markdown
[26.1-alpha]: https://forgejo.sourcegate.online/daniel/homebase/releases/tag/26.1-alpha
```
Update the `[Unreleased]` compare link to point at the new tag.
2. **Commit the changelog.**
```bash
git add CHANGELOG.md
git commit -m "chore: release 26.1-alpha"
```
3. **Tag the commit.**
```bash
git tag -a 26.1-alpha -m "Release 26.1-alpha"
```
4. **Push the tag and main.**
```bash
git push origin main
git push origin 26.1-alpha
```
5. **Create a Forgejo Release** at `https://forgejo.sourcegate.online/daniel/homebase/releases/new`:
- Tag: `26.1-alpha` (already exists)
- Title: `26.1-alpha`
- Body: paste the changelog section for this version
- Tick **Pre-release** for anything still `-alpha` or `-beta`
6. **Verify CI passed on the tag.** The Forgejo Actions run against the tagged commit should be green before you announce the release anywhere.
## First-time: find the current version
```bash
git describe --tags --abbrev=0
```
If the project is fresh and `git describe` fails, the next release is `26.0-alpha`.
## If the tag is wrong
Don't move published tags. Delete the release + tag, fix the problem, bump to the next number.
```bash
git tag -d 26.1-alpha
git push origin :refs/tags/26.1-alpha
# ... fix ...
git tag -a 26.2-alpha ...
```

113
docs/runner-setup.md Normal file
View file

@ -0,0 +1,113 @@
# Forgejo Runner Setup
How to stand up a `forgejo-runner` so the CI workflow in `.forgejo/workflows/ci.yml` actually executes on every push.
The runner is a long-running daemon that polls the Forgejo instance for queued jobs and runs them in Docker containers.
## Choosing a host
| Option | Good for | Trade-off |
|--------|----------|-----------|
| **Dedicated VPS** | Production-ish CI that runs even when you're offline | Costs a few €/month; one more machine to maintain |
| **Home server / NAS** | Free; plenty of capacity | CI blocked if home network / power drops |
| **Local dev machine** | Quick to set up, fast runs | CI only works while the machine is on |
Recommendation for now: **home server or a cheap VPS**. Don't use a laptop that suspends.
## Install
Pick either the binary or the Docker container path. Docker is easier to upgrade.
### Path A: Docker Compose (recommended)
On the chosen host, create `~/forgejo-runner/compose.yml`:
```yaml
services:
runner:
image: code.forgejo.org/forgejo/runner:6
container_name: forgejo-runner
restart: unless-stopped
environment:
- CONFIG_FILE=/data/config.yml
volumes:
- ./data:/data
- /var/run/docker.sock:/var/run/docker.sock
depends_on:
- docker-in-docker
command: /bin/sh -c "sleep 5; forgejo-runner daemon"
docker-in-docker:
image: docker:dind
container_name: forgejo-runner-dind
restart: unless-stopped
privileged: true
environment:
- DOCKER_TLS_CERTDIR=
command: dockerd -H tcp://0.0.0.0:2375 --tls=false
```
### Path B: Binary
Download the latest release from https://code.forgejo.org/forgejo/runner/releases and drop it somewhere in `$PATH`:
```bash
wget https://code.forgejo.org/forgejo/runner/releases/download/v6.0.0/forgejo-runner-6.0.0-linux-amd64
chmod +x forgejo-runner-6.0.0-linux-amd64
sudo mv forgejo-runner-6.0.0-linux-amd64 /usr/local/bin/forgejo-runner
```
## Register
1. In the Forgejo web UI: go to **Site Administration → Actions → Runners → Create new Runner**. Copy the registration token. (For a repo-scoped runner instead, use **Repo Settings → Actions → Runners**.)
2. Register from the runner host:
```bash
forgejo-runner register \
--instance https://forgejo.sourcegate.online \
--token <TOKEN> \
--name homebase-runner-1 \
--labels docker,ubuntu-latest,self-hosted \
--no-interactive
```
This writes `.runner` (registration file) and `config.yml` into the current directory.
3. Start the daemon (Docker: `docker compose up -d`; binary: `forgejo-runner daemon`).
4. Verify the runner shows up as **Idle** in Forgejo's admin Runners page.
## First CI run
Push any commit; the Actions tab on the repo should show the workflow running. If nothing happens:
- Confirm the runner is online (Forgejo admin → Actions → Runners).
- Check the workflow has labels that match the runner (`runs-on: ubuntu-latest` needs a runner registered with that label).
- Check the runner logs: `docker logs forgejo-runner` or the systemd journal.
## Systemd unit (for the binary path)
```ini
[Unit]
Description=Forgejo Actions Runner
After=docker.service
Requires=docker.service
[Service]
ExecStart=/usr/local/bin/forgejo-runner daemon
WorkingDirectory=/var/lib/forgejo-runner
User=forgejo-runner
Restart=on-failure
[Install]
WantedBy=multi-user.target
```
Save as `/etc/systemd/system/forgejo-runner.service`, then `sudo systemctl enable --now forgejo-runner`.
## Security notes
- The runner mounts `/var/run/docker.sock` which gives it root-equivalent access to the host. Run it on a machine you trust and nothing sensitive.
- Registration tokens are one-shot; a stolen token can't re-register after the runner is live.
- Prefer repo-scoped runners over instance-wide if you're sharing the runner with other repos you don't control.