simple-web-app

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit 90486b5dd24369cd615a0505e916662ae4f4162d
parent 0cd96c2e93ae77a6642c362847dd98dde150907f
Author: Silas Brack <silasbrack@gmail.com>
Date:   Sun,  7 Jun 2026 22:47:45 +0200

docs: update README with current stack, principles, and structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

Diffstat:
MREADME.md | 132++++++++++++++++++++++++++++++++++++++++++-------------------------------------
1 file changed, 71 insertions(+), 61 deletions(-)

diff --git a/README.md b/README.md @@ -1,93 +1,103 @@ # Simple Web App -A news aggregation web application built with Rust, Axum, Askama, and SQLite. +A link aggregator (HN clone) built with Rust, Axum, Askama, and Trailbase. + +Live at [simple.fnarglebeast.com](https://simple.fnarglebeast.com). ## Tech Stack -- **Axum** - Web framework -- **Askama** - Type-safe HTML templating -- **SQLx** - Async SQL toolkit with compile-time checked queries -- **HTMX** - Frontend interactivity without JavaScript frameworks -- **PicoCSS** - Minimal CSS framework +- **Axum** — Web framework +- **Askama** — Type-safe HTML templating +- **Trailbase** — Auth, record APIs, and SQLite storage +- **HTMX** — Voting without full page reloads +- **FTS5** — Full-text search via a WASM guest component + +## Principles + +1. **Explicit over clever** — Code reads top-to-bottom. A new reader should understand what a function does without chasing through layers of indirection. -## Development Guidelines +2. **Pure functions** — Isolate decision logic from I/O. Functions like `time_ago`, `hot_score`, `extract_domain`, and `parse_tags` take data and return data with no side effects. -Configuration should be performed via environment variables following the [12-factor app](https://12factor.net/) principles. +3. **Linear flow** — Handlers read as sequential steps: authenticate, fetch data, build view, respond. No callbacks or deep nesting. -## Developer Setup +4. **Minimize shared state** — `AppState` holds only the trailbase URL and an HTTP client. Everything else is passed explicitly. -### With Nix (recommended) +5. **Minimize indirection** — No traits, no dependency injection, no "in case we swap implementations later." Direct function calls throughout. -1. Copy the example environment file: - ```bash - cp .env.example .env - ``` +## Development + +```bash +nix develop +cargo run # start server +cargo watch -x run # auto-reload +``` -2. Enter the development shell: - ```bash - nix develop - ``` +Trailbase runs separately: -3. Run the server: - ```bash - cargo run - ``` +```bash +trail run +``` -4. For auto-reload during development: - ```bash - cargo watch -x run - ``` +## Type Generation -### Without Nix +Types are auto-generated from the Trailbase schema: -1. Install Rust via [rustup](https://rustup.rs/) +```bash +./scripts/generate-types.sh +``` -2. Copy the example environment file: - ```bash - cp .env.example .env - ``` +Requires `trail` and `quicktype` (both in the dev shell). -3. Run the server: - ```bash - cargo run - ``` +## Seeding -4. Go to [localhost:8000](http://localhost:8000/) to see the page. +```bash +TOKEN=$(trail user mint-token <email>) ./scripts/seed.sh +``` -## Building for Production +## Building ```bash -nix build +nix build # app binary +nix build .#trailbase # trailbase binary ``` -Or without Nix: +The WASM search guest must be built separately: ```bash -cargo build --release +cd guests/rust +cargo build --target wasm32-wasip2 --release +cp target/wasm32-wasip2/release/search_guest.wasm ../../traildepot/wasm/ ``` ## Project Structure ``` simple-web-app/ -├── Cargo.toml # Rust dependencies -├── flake.nix # Nix flake configuration -├── traildepot/ # TrailBase data directory (migrations, config, data) -├── static/ # Static assets (CSS) -├── templates/ # Askama HTML templates -└── src/ - ├── main.rs # Entry point - ├── config.rs # Environment configuration - ├── state.rs # Application state (DB pool) - ├── error.rs # Error types - ├── routes.rs # Route definitions - ├── extractors.rs # Custom Axum extractors - ├── templates.rs # Askama template structs - ├── handlers/ # Route handlers - │ ├── home.rs - │ ├── search.rs - │ └── settings.rs - └── db/ # Database layer - ├── models.rs - └── queries.rs +├── src/ +│ ├── main.rs # Entry point +│ ├── config.rs # Environment configuration +│ ├── state.rs # AppState (trailbase URL, HTTP client) +│ ├── error.rs # Error types +│ ├── routes.rs # Route definitions + static file serving +│ ├── templates.rs # Askama template structs +│ ├── trailbase.rs # Trailbase API client functions +│ ├── trailbase_types.rs # Auto-generated types (quicktype) +│ ├── db/mod.rs # View models (StoryWithMeta, CommentWithMeta) +│ └── handlers/ # Route handlers +│ ├── auth.rs # Login, register, verification +│ ├── feed.rs # Hot/new/top feeds +│ ├── story.rs # Story detail, submit, edit +│ ├── comment.rs # Comments, replies +│ ├── vote.rs # HTMX voting endpoints +│ ├── search.rs # FTS5 search (via WASM guest) +│ ├── user.rs # User profiles +│ └── tag.rs # Tag pages +├── templates/ # Askama HTML templates +├── static/ # CSS, htmx.min.js, preload.min.js +├── guests/rust/ # WASM guest for FTS5 search +├── traildepot/ # Trailbase config, migrations, WASM components +├── schemas/ # JSON schemas for type generation +├── scripts/ # seed.sh, generate-types.sh +├── trailbase.nix # Nix derivation for trailbase binary +└── flake.nix # Nix flake (build, dev shell, checks) ```