restructure handbook to flat-page spec
Replace the four-section dir layout with the revised flat-page spec: - Three-page nav: Libraries, Standards, Deploy. - libraries.md: live client-side fetch of the rethink-public org from the Gitea API, denylist-filtered, sorted table linking each repo, no version pins, graceful fallback on fetch/CORS failure. - standards.md: house coding standards. - deploy.md: deploy guide for rethink-net (services uid 1337, uid-agnostic Docker, paths/mounts, bind-mount permissions, read-only secrets). - index.md landing card grid updated for the three sections. - gitignore Playwright MCP artifacts. Verified: mkdocs build --strict clean; libraries fallback renders live. Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
parent
bad61bea2d
commit
d3c85acd1e
3
.gitignore
vendored
3
.gitignore
vendored
@ -9,3 +9,6 @@ __pycache__/
|
||||
*.py[cod]
|
||||
.venv/
|
||||
venv/
|
||||
|
||||
# Playwright MCP run artifacts
|
||||
.playwright-mcp/
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
# Conventions
|
||||
|
||||
Coding, library, and infrastructure conventions that keep projects consistent.
|
||||
|
||||
!!! note "Work in progress"
|
||||
Individual convention pages will be added under this section and wired into
|
||||
the nav.
|
||||
|
||||
## Topics to document
|
||||
|
||||
- **Python style** — flake8 clean (max line 120), type hints on public
|
||||
functions, lowercase-start docstrings with no trailing period.
|
||||
- **Library layout** — `src/` layout, hatchling, Python ≥ 3.10, underscores in
|
||||
names, `aio`-prefix only for libs that define async surfaces.
|
||||
- **Logging** — emit-only in libraries (`logging.getLogger(__name__)`); handler,
|
||||
level, and format configured only at the application entry point.
|
||||
- **Files** — trailing newline, no trailing whitespace, LF line endings.
|
||||
- **Config** — config-free modules (inject dependencies), single source of
|
||||
truth, no duplicated logic or constants.
|
||||
98
docs/deploy.md
Normal file
98
docs/deploy.md
Normal file
@ -0,0 +1,98 @@
|
||||
# Deployment Guide
|
||||
|
||||
> Ready for your project to see the light? You may be eligible for deployment on
|
||||
> **rethink-net** — our fleet of Ubuntu 26.x servers, ready to host whatever
|
||||
> you've built.
|
||||
|
||||
**Eligible:** APIs, websites, applets, bots, monitors.
|
||||
|
||||
The whole network runs on a few simple, consistent rules. Get your container to
|
||||
follow them and deploying is mostly handing us a `compose.yaml`.
|
||||
|
||||
## Docker — the services account
|
||||
|
||||
Every service runs containerized as the shared **`services`** account:
|
||||
**uid/gid 1337**, fixed fleet-wide. Build your image to be **uid-agnostic** so it
|
||||
runs cleanly as that account:
|
||||
|
||||
- `user: "1337:1337"` in compose.
|
||||
- `chmod -R a+rwX /app` in the Dockerfile (covers non-mounted dirs — see the
|
||||
bind-mount note below).
|
||||
- `HOME=/tmp`.
|
||||
- **No** in-container `user`/`useradd` — don't bake a user into the image.
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.12-slim
|
||||
ENV HOME=/tmp
|
||||
WORKDIR /app
|
||||
# git in the build if you pip-install from git
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY . .
|
||||
RUN pip install --no-cache-dir . \
|
||||
&& chmod -R a+rwX /app
|
||||
CMD ["python", "-m", "yourapp"]
|
||||
```
|
||||
|
||||
```yaml
|
||||
services:
|
||||
yourapp:
|
||||
build: .
|
||||
user: "1337:1337"
|
||||
environment:
|
||||
HOME: /tmp
|
||||
volumes:
|
||||
- /srv/configs/<project>:/app/config:ro # host-managed, read-only
|
||||
- /srv/<dev>/<project>:/app/logs # live + rolled logs
|
||||
- yourapp-data:/app/data # named volume — the rest
|
||||
|
||||
volumes:
|
||||
yourapp-data:
|
||||
```
|
||||
|
||||
## Paths and mounts
|
||||
|
||||
- **Configs** → `/srv/configs/<project>/` — bind mount, host-managed.
|
||||
- **Logs** → `/srv/<dev>/<project>/` — bind mount; live and rolled, scraped for
|
||||
monitoring.
|
||||
- **Everything else** (caches, browser profiles, scratch) → **named volumes**.
|
||||
Docker manages ownership, so there are no host permissions to fiddle with.
|
||||
|
||||
## Permissions — the bind-mount footgun
|
||||
|
||||
`docker compose up` does **not** create bind-mount directories as you. If a
|
||||
bind-mount source is missing, the Docker daemon (**root**) creates it **as
|
||||
root** — and your container (**1337**) then can't write it. Logs fall back to
|
||||
console-only, caches re-download every run.
|
||||
|
||||
So:
|
||||
|
||||
- **Bind-mount sources (configs, logs) must EXIST and be 1337-owned _before_
|
||||
`up`.** This is handled at provisioning, not a per-deploy chown hook.
|
||||
- **Named volumes avoid this entirely** — use them for anything that doesn't need
|
||||
host visibility.
|
||||
- The Dockerfile `chmod -R a+rwX /app` only covers **non-mounted** dirs. A bind
|
||||
mount overrides the image directory with the host directory, so for mounted
|
||||
paths the **host-side ownership wins**.
|
||||
|
||||
## What your compose / Dockerfile needs
|
||||
|
||||
- `user: "1337:1337"`
|
||||
- bind mounts for **configs + logs**
|
||||
- named volumes for **the rest**
|
||||
- secrets bind-mounted **`:ro`**
|
||||
- `HOME=/tmp`
|
||||
- `chmod -R a+rwX /app`
|
||||
- `git` in the build if you `pip install` from git
|
||||
|
||||
## Secrets
|
||||
|
||||
We do **not** commit secrets (usually, lol). The rule:
|
||||
|
||||
- Secrets stay **gitignored**.
|
||||
- They're placed on the host at `/srv/configs/<project>/`.
|
||||
- They're bind-mounted **read-only** at runtime.
|
||||
- **Never** baked into the image — add them to `.dockerignore` so `COPY . .`
|
||||
can't grab them.
|
||||
|
||||
Rotating a secret = edit the host file and restart. No rebuild.
|
||||
@ -1,22 +0,0 @@
|
||||
# Deploy
|
||||
|
||||
Guides for getting a service from a repo to running behind the reverse proxy.
|
||||
|
||||
!!! note "Work in progress"
|
||||
The services-container deploy guide will live here. Until it's added, this
|
||||
page is a placeholder.
|
||||
|
||||
## Planned guides
|
||||
|
||||
- **Services container standard** — the baseline image, `uid 1337`, volume and
|
||||
log layout, healthchecks.
|
||||
- **Compose pattern** — how a service's `compose.yaml` wires into the shared
|
||||
proxy network.
|
||||
- **Reverse proxy** — exposing a service at a subdomain (sanitized).
|
||||
|
||||
## Conventions
|
||||
|
||||
- Containers run as the services uid (`1337`) per our container standard.
|
||||
- Logs land under `/srv/logs/...` mirroring the app's deploy path.
|
||||
- No real hostnames, internal IPs, or exact topology in these public pages —
|
||||
use placeholders and describe the pattern.
|
||||
@ -1,46 +1,35 @@
|
||||
# Rethink Studios Handbook
|
||||
|
||||
The shared reference for how we build, deploy, and operate. Generic patterns and
|
||||
conventions live here — sanitized for public consumption. Real infrastructure
|
||||
specifics (hostnames, internal IPs, secrets, exact topology) stay in our private
|
||||
runbooks.
|
||||
The public reference for building and shipping with Rethink Studios: our shared
|
||||
libraries, our coding standards, and how to deploy a project on our network.
|
||||
|
||||
This is a public site — it documents generic patterns and conventions. Real
|
||||
infrastructure specifics (hostnames, internal IPs, exact topology, secrets) stay
|
||||
out of it; examples use placeholders like `<dev>`, `<project>`, and `/srv/...`.
|
||||
|
||||
## Sections
|
||||
|
||||
<div class="grid cards" markdown>
|
||||
|
||||
- :material-rocket-launch: __[Deploy](deploy/index.md)__
|
||||
- :material-package-variant: __[Libraries](libraries.md)__
|
||||
|
||||
---
|
||||
|
||||
How services get from a repo to running behind the proxy — container
|
||||
standards, compose patterns, and step-by-step deploy guides.
|
||||
The live list of the `rethink-public` library suite, pulled straight from
|
||||
Gitea — each entry links to the repo, where the README and tags live.
|
||||
|
||||
- :material-ruler-square: __[Conventions](conventions/index.md)__
|
||||
- :material-ruler-square: __[Standards](standards.md)__
|
||||
|
||||
---
|
||||
|
||||
Coding, library, and infrastructure conventions. Naming, layout, logging,
|
||||
and the rules that keep things consistent across projects.
|
||||
House coding standards — file hygiene, docstrings, type hints, linting, and
|
||||
how we handle errors.
|
||||
|
||||
- :material-package-variant: __[Libraries](libraries/index.md)__
|
||||
- :material-rocket-launch: __[Deploy](deploy.md)__
|
||||
|
||||
---
|
||||
|
||||
Usage docs for the shared `rethink-public` library suite — what each lib
|
||||
does and how to wire it into a project.
|
||||
|
||||
- :material-tools: __[Runbooks](runbooks/index.md)__
|
||||
|
||||
---
|
||||
|
||||
Operational how-tos for recurring tasks — sanitized for public reference.
|
||||
How to get a project running on **rethink-net** — containers, paths and
|
||||
mounts, permissions, and secrets.
|
||||
|
||||
</div>
|
||||
|
||||
## Conventions for this handbook
|
||||
|
||||
- One topic per page, grouped by section directory.
|
||||
- Public means sanitized: use placeholders (`<host>`, `<dev>`, `/srv/...`) and
|
||||
describe the pattern, not our literal infrastructure.
|
||||
- Code blocks are tagged with their language and kept copy-pasteable.
|
||||
|
||||
94
docs/libraries.md
Normal file
94
docs/libraries.md
Normal file
@ -0,0 +1,94 @@
|
||||
# Libraries
|
||||
|
||||
The shared `rethink-public` library suite. Before hand-rolling common
|
||||
functionality — retry/backoff, logging setup, HTTP sessions, proxies, webhooks,
|
||||
IMAP/mail, datastore/KV, crypto, `discord.py` helpers, timing/paths/masking
|
||||
utilities — check here first and prefer an existing lib.
|
||||
|
||||
This list is pulled live from Gitea, so a new library in the org shows up on the
|
||||
next page load — nothing here is rebuilt or version-pinned. Each entry links to
|
||||
the repo, where the README and tags live.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
<lib> @ git+https://git.rethinkstudios.io/rethink-public/<lib>.git@<tag>
|
||||
```
|
||||
|
||||
<div id="lib-list" markdown="0">
|
||||
<p class="lib-status">Loading libraries from Gitea…</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var API = "https://git.rethinkstudios.io/api/v1/orgs/rethink-public/repos?limit=50";
|
||||
var REPO_BASE = "https://git.rethinkstudios.io/rethink-public";
|
||||
var FALLBACK =
|
||||
'Could not load the live list. View the libraries directly at ' +
|
||||
'<a href="' + REPO_BASE + '">git.rethinkstudios.io/rethink-public</a>.';
|
||||
|
||||
// Non-library repos to exclude from the render.
|
||||
var DENYLIST = ["handbook", ".profile", ".profile-private"];
|
||||
|
||||
function isLibrary(repo) {
|
||||
if (!repo || !repo.name) return false;
|
||||
if (repo.name.charAt(0) === ".") return false; // any dot-repo
|
||||
return DENYLIST.indexOf(repo.name) === -1;
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s == null ? "" : s)
|
||||
.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
||||
.replace(/"/g, """);
|
||||
}
|
||||
|
||||
function render(repos) {
|
||||
var libs = repos.filter(isLibrary).sort(function (a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
var el = document.getElementById("lib-list");
|
||||
if (!libs.length) {
|
||||
el.innerHTML = '<p class="lib-status">No libraries found. Browse the org at ' +
|
||||
'<a href="' + REPO_BASE + '">git.rethinkstudios.io/rethink-public</a>.</p>';
|
||||
return;
|
||||
}
|
||||
var rows = libs.map(function (r) {
|
||||
var url = r.html_url || (REPO_BASE + "/" + r.name);
|
||||
var desc = r.description ? escapeHtml(r.description) : "<em>No description.</em>";
|
||||
return '<tr><td><a href="' + escapeHtml(url) + '"><code>' +
|
||||
escapeHtml(r.name) + '</code></a></td><td>' + desc + '</td></tr>';
|
||||
}).join("");
|
||||
el.innerHTML =
|
||||
'<table><thead><tr><th>Library</th><th>What it does</th></tr></thead>' +
|
||||
'<tbody>' + rows + '</tbody></table>';
|
||||
}
|
||||
|
||||
function fail() {
|
||||
document.getElementById("lib-list").innerHTML =
|
||||
'<p class="lib-status">' + FALLBACK + '</p>';
|
||||
}
|
||||
|
||||
try {
|
||||
fetch(API, { headers: { "Accept": "application/json" } })
|
||||
.then(function (resp) {
|
||||
if (!resp.ok) throw new Error("HTTP " + resp.status);
|
||||
return resp.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
if (!Array.isArray(data)) throw new Error("unexpected response");
|
||||
render(data);
|
||||
})
|
||||
.catch(fail);
|
||||
} catch (e) {
|
||||
fail();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
!!! info "If the live list is empty or stale"
|
||||
The fetch runs in your browser against the Gitea API and needs the org repos
|
||||
to be readable unauthenticated (they are — it's a public org) and CORS to
|
||||
allow the docs domain. If the list won't load, browse the org directly at
|
||||
[git.rethinkstudios.io/rethink-public](https://git.rethinkstudios.io/rethink-public).
|
||||
The fallback for a disabled live fetch is a webhook rebuild — a push to any
|
||||
`rethink-public` repo triggers a site rebuild.
|
||||
@ -1,23 +0,0 @@
|
||||
# Libraries
|
||||
|
||||
Usage docs for the shared `rethink-public` library suite. Before hand-rolling
|
||||
common functionality, check the suite first and prefer an existing lib.
|
||||
|
||||
!!! note "Work in progress"
|
||||
A page per library will be added here. Browse the `rethink-public` org for
|
||||
the live list — each repo's tagline says what it does.
|
||||
|
||||
## Install pattern
|
||||
|
||||
```
|
||||
<lib> @ git+https://git.rethinkstudios.io/rethink-public/<lib>.git@<tag>
|
||||
```
|
||||
|
||||
## Common capabilities covered by the suite
|
||||
|
||||
Retry/backoff, logging setup, HTTP sessions, proxies, webhooks, IMAP/mail,
|
||||
Mongo/KV/datastore, crypto/envelope, `discord.py` helpers, and timing/paths/
|
||||
masking utilities.
|
||||
|
||||
If a capability isn't in the suite, build it in-project — and flag whether it's
|
||||
generic enough to become a new shared lib.
|
||||
@ -1,17 +0,0 @@
|
||||
# Runbooks
|
||||
|
||||
Operational how-tos for recurring tasks — sanitized for public reference.
|
||||
|
||||
!!! note "Work in progress"
|
||||
Individual runbooks will be added under this section and wired into the nav.
|
||||
|
||||
## Sanitization reminder
|
||||
|
||||
Runbooks often touch real infrastructure. Before a runbook goes public:
|
||||
|
||||
- Replace real hostnames, internal IPs, and exact topology with placeholders
|
||||
(`<host>`, `<dev>`, `/srv/...`).
|
||||
- Strip secrets and credentials entirely — reference where they live, never the
|
||||
values.
|
||||
- Keep the procedure and the reasoning; drop the specifics that identify our
|
||||
boxes.
|
||||
42
docs/standards.md
Normal file
42
docs/standards.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Coding Standards
|
||||
|
||||
The house standards every Rethink Studios project follows. They keep our code
|
||||
consistent, readable, and predictable across the whole suite.
|
||||
|
||||
## File hygiene
|
||||
|
||||
- Files end with a **single trailing newline** (LF / Unix line endings).
|
||||
- **No trailing whitespace** on any line.
|
||||
|
||||
## Indentation
|
||||
|
||||
- **4 spaces** by default.
|
||||
- Respect language norms: TS/JS use **2 spaces**, Go uses **tabs**.
|
||||
- When editing an existing file, follow that file's existing indentation.
|
||||
|
||||
## Docstrings and comments
|
||||
|
||||
- Public functions get a **docstring**. Style: **lowercase-start, no trailing
|
||||
period**.
|
||||
- Keep inline comments minimal — prefer docstrings. Use an inline comment only
|
||||
where the code is genuinely complex.
|
||||
- Each module/file states its scope and purpose via a **module docstring**
|
||||
(header string) — **not** a license or copyright header.
|
||||
|
||||
## READMEs
|
||||
|
||||
Every library and project has a defined **README** covering:
|
||||
|
||||
- the install line,
|
||||
- what it does,
|
||||
- a usage example.
|
||||
|
||||
## Linting and types
|
||||
|
||||
- **flake8 clean**, max line length **120**.
|
||||
- **Type hints** on public functions.
|
||||
|
||||
## Error handling
|
||||
|
||||
- **Fail loud** — never swallow exceptions.
|
||||
- Catch the **specific** exception, and **log** it.
|
||||
15
mkdocs.yml
15
mkdocs.yml
@ -1,5 +1,5 @@
|
||||
site_name: Rethink Studios Handbook
|
||||
site_description: Deploy guides, infra and container standards, conventions, library usage, and runbooks.
|
||||
site_description: Libraries, coding standards, and how to deploy on our network.
|
||||
site_url: https://docs.rethinkstudios.io/
|
||||
copyright: Rethink Studios
|
||||
|
||||
@ -24,9 +24,7 @@ theme:
|
||||
features:
|
||||
- navigation.instant
|
||||
- navigation.tracking
|
||||
- navigation.sections
|
||||
- navigation.top
|
||||
- navigation.indexes
|
||||
- toc.follow
|
||||
- search.suggest
|
||||
- search.highlight
|
||||
@ -59,11 +57,6 @@ plugins:
|
||||
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Deploy:
|
||||
- deploy/index.md
|
||||
- Conventions:
|
||||
- conventions/index.md
|
||||
- Libraries:
|
||||
- libraries/index.md
|
||||
- Runbooks:
|
||||
- runbooks/index.md
|
||||
- Libraries: libraries.md
|
||||
- Standards: standards.md
|
||||
- Deploy: deploy.md
|
||||
|
||||
Loading…
Reference in New Issue
Block a user