BetterMan is a fast, modern web interface for Linux man pages (see SPEC.md).
/
├── frontend/ # React SPA
├── backend/ # FastAPI service (serves API + built SPA)
├── ingestion/ # Ingestion pipeline scripts
├── docker-compose.yml # Local Postgres + Redis
└── SPEC.md
v0.1.0shipped (tagv0.1.0).v0.1.1shipped (tagv0.1.1).v0.1.2shipped (tagv0.1.2).v0.2.0shipped (tagv0.2.0).v0.2.1shipped (tagv0.2.1).v0.3.0shipped (tagv0.3.0) (multi-distribution + SEO + performance).v0.4.0shipped (tagv0.4.0) (hardening + discoverability + observability).- Default branch:
main. Execution plan:PLAN.md.
- Auto-deploy:
.github/workflows/ci.ymldeploys after all jobs pass on pushes tomain. - Manual deploy:
.github/workflows/deploy.yml(workflowdeploy-railway, inputref). - Requires
RAILWAY_TOKENGitHub Actions secret (exported to Railway CLI asRAILWAY_API_TOKEN).
- Monthly ingest + promote:
.github/workflows/update-docs.yml(workflowupdate-dataset). - Requires
BETTERMAN_STAGING_DATABASE_URL+BETTERMAN_PROD_DATABASE_URLGitHub Actions secrets.
- Required PR checks for
main:dependency_review,frontend,backend,ingestion,api_types,e2e. - Code scanning:
.github/workflows/codeql.yml(CodeQL) +.github/workflows/scorecards.yml(OSSF Scorecards → SARIF). - Dependency updates:
.github/dependabot.yml(GitHub Actions, frontend npm, backend/ingestion uv, Dockerfile base images). - API contract:
frontend/src/api/openapi.gen.tsis generated from backend OpenAPI and enforced in CI.
Error tracking for both backend and frontend.
Environment variables:
SENTRY_DSN(backend): Sentry DSN for the FastAPI serviceVITE_SENTRY_DSN(frontend): Sentry DSN for the React app
Errors include page context (route + params) and component stack traces.
Production note: the SPA reads VITE_SENTRY_DSN at runtime from /config.js (served by the backend), so set it as a backend service env var (e.g., Railway variable).
Privacy-friendly analytics (no cookies, GDPR-compliant).
Environment variables:
VITE_PLAUSIBLE_DOMAIN(frontend): Domain configured in Plausible (e.g.,betterman.dev)
Analytics are disabled if the env var is not set.
Production note: the backend injects the Plausible script tag into index.html when VITE_PLAUSIBLE_DOMAIN is set.
For accurate IP-based rate limiting behind a reverse proxy:
Environment variables:
TRUSTED_PROXY_CIDRS(backend): Comma-separated list of trusted proxy CIDRs (e.g.,10.0.0.0/8,172.16.0.0/12)
When set, X-Forwarded-For is only trusted from connections originating within these CIDRs.
- Desktop man pages: sticky “Navigator” rail (TOC + Find) with scroll-spy.
- Man page: “Find in page” stays sticky by default; users can hide/show it.
- Mobile: TOC is available via the sticky header “TOC” button (drawer).
- Man sections support extended suffixes (e.g.
/man/openssl/1ssl,/section/3p).
pnpm db:up— start Postgres + Redis (Docker)pnpm db:down— stop services- Postgres exposed on
localhost:54320
- Postgres exposed on
pnpm backend:dev— FastAPI dev server (port 8000)pnpm backend:test— backend tests (pytest)pnpm backend:lint— ruff check + format check
pnpm frontend:dev— Vite dev serverpnpm frontend:build— production buildpnpm frontend:lint— eslintpnpm frontend:test— unit tests (Vitest)pnpm frontend:e2e— E2E tests (Playwright; expects backend running)
pnpm ingest:sample— ingest a small sample setpnpm ingest:run— ingest full datasetpnpm ingest:lint— ruff check + format checkpnpm ingest:test— ingestion tests (pytest)
- Read
CONTRIBUTING.md. - Be kind:
CODE_OF_CONDUCT.md. - Security issues:
SECURITY.md.
MIT — see LICENSE.