{"id":31582915,"url":"https://github.com/charlieroth/capsule","last_synced_at":"2025-10-05T23:20:31.467Z","repository":{"id":310784275,"uuid":"1040697854","full_name":"charlieroth/capsule","owner":"charlieroth","description":"Read later web service","archived":false,"fork":false,"pushed_at":"2025-08-29T06:32:59.000Z","size":233,"stargazers_count":0,"open_issues_count":26,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-22T13:02:28.463Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/charlieroth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-19T11:23:46.000Z","updated_at":"2025-08-29T06:33:03.000Z","dependencies_parsed_at":"2025-08-20T08:35:19.671Z","dependency_job_id":"60671630-a8e7-435d-9755-4753a4b3961a","html_url":"https://github.com/charlieroth/capsule","commit_stats":null,"previous_names":["charlieroth/capsule"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/charlieroth/capsule","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieroth%2Fcapsule","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieroth%2Fcapsule/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieroth%2Fcapsule/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieroth%2Fcapsule/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/charlieroth","download_url":"https://codeload.github.com/charlieroth/capsule/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charlieroth%2Fcapsule/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278532569,"owners_count":26002389,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-05T23:20:29.163Z","updated_at":"2025-10-05T23:20:31.463Z","avatar_url":"https://github.com/charlieroth.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# capsule\n\n[![CI](https://github.com/charlieroth/capsule/actions/workflows/ci.yml/badge.svg)](https://github.com/charlieroth/capsule/actions/workflows/ci.yml)\n\nA pragmatic \"read later\" service built in Rust to explore production-grade web service patterns:\n\n- Authentication\n- Background jobs\n- Full‑text search\n- Observability\n- Robust operations\n\n## Features (Planned / In Progress)\n\n- REST API with generated OpenAPI docs (axum + utoipa)\n- User authentication (argon2 password hashes + JWT)\n- Background fetch \u0026 extract pipeline (reqwest + scraper)\n- Full‑text search (tantivy)\n- Structured logging \u0026 tracing (tracing) + metrics (future Prometheus endpoint)\n- Database persistence (PostgreSQL via sqlx; async, compile‑time checked queries when `make prepare` is run)\n- Schema documentation / ERD via SchemaSpy (`make erd` -\u003e `./erd/index.html`)\n\n## Architecture Overview\n\nHigh-level flow:\n\n1. Client creates an item (URL + metadata)\n2. A background task fetches \u0026 normalizes HTML, stores text content\n3. Indexer updates tantivy with (title + site + tags + text)\n4. Search endpoint returns ranked results with snippets\n\n## Repository Layout\n\n```\nsrc/\n  bin/\n    api.rs        # HTTP server entrypoint\n    migrate.rs    # One-shot migration runner (used in Docker / local)\n  lib.rs          # (future) shared library code\nmigrations/       # sqlx migrations (*.up.sql / *.down.sql)\nMakefile          # Developer workflow commands\nDockerfile        # Multi-stage container build (api + migrate)\ndocker-compose.yml# Postgres + migrate + api + schemaspy services\nscripts/db-health.sh # Wait/health checks for Postgres\nerd/              # Generated SchemaSpy output (HTML + diagrams)\ndocs/PROJECT.md   # Vision, roadmap, non-functional goals\n```\n\n## Quick Start (Local Dev)\n\nPre-requisites:\n\n- Rust (see `rust-toolchain.toml`)\n- Docker (for Postgres + ERD generation)\n- Run `make install-tools`\n\nSteps:\n\n```bash\n# 1. Start Postgres\nmake db-up\n\n# 2. Run migrations\nmake db-migrate\n\n# 3. Launch the API (defaults to 0.0.0.0:8080 via Config)\nmake dev\n\n# 4. Hit the root endpoint\ncurl -s localhost:8080/\n```\n\nExpected response: `Hello from capsule!`\n\nTear down:\n\n```bash\nmake db-down\n```\n\nFull reset (drops volume):\n\n```bash\nmake db-reset\n```\n\n## Configuration\n\n`Config::from_env()` (see `config/mod.rs`) loads environment variables. Key variable:\n\n- `DATABASE_URL` (required for API \u0026 migrations) e.g. `postgres://capsule:capsule_password@localhost:5432/capsule_dev`\n\nAdditional configuration knobs (future): bind address, logging level, JWT secrets, rate limits.\n\n## Database \u0026 Migrations\n\nMigrations live in `migrations/` and are executed by either:\n\n- `make db-migrate` (sqlx-cli) OR\n- The `capsule-migrate` binary (used in `docker-compose.yml` as the `migrate` service)\n\nGenerate / update sqlx offline metadata (speeds up compile-time query checking):\n\n```bash\nmake prepare\n```\n\nCheck database health:\n\n```bash\nmake db-health    # exit 0 if healthy\nmake db-wait      # block until healthy (used in CI / scripts)\n```\n\nOpen a psql-like shell (requires `pgcli` installed):\n\n```bash\nmake pgcli\n```\n\n## Schema / ERD Docs\n\nGenerate ERD \u0026 HTML docs (writes into `./erd`):\n\n```bash\nmake erd\nopen erd/index.html  # macOS\n```\n\n## Docker / Compose\n\nBuild \u0026 run everything (Postgres + migrations + API):\n\n```bash\ndocker compose up --build api\n```\n\nServices:\n\n- `postgres` (port 5432)\n- `migrate` (runs once; executes migrations then exits)\n- `api` (exposes port 8080)\n- `schemaspy` (on-demand ERD generation: `make erd`)\n\nEnvironment is baked with `DATABASE_URL` pointing at the compose network host.\n\n## Makefile Cheat Sheet\n\n| Target       | Purpose                          |\n| ------------ | -------------------------------- |\n| `dev`        | Run API locally (debug)          |\n| `fmt`        | Format sources                   |\n| `lint`       | Clippy (deny warnings)           |\n| `test`       | Run tests                        |\n| `audit`      | Security audit (cargo-audit)     |\n| `deny`       | Dependency policy (cargo-deny)   |\n| `check`      | fmt + lint + test + audit + deny |\n| `db-up`      | Start Postgres via Docker        |\n| `db-down`    | Stop Postgres                    |\n| `db-migrate` | Apply migrations                 |\n| `db-reset`   | Drop volume \u0026 reinit DB          |\n| `db-health`  | Health probe (fast)              |\n| `db-wait`    | Wait until healthy               |\n| `db-logs`    | Tail Postgres logs               |\n| `prepare`    | sqlx offline metadata            |\n| `erd`        | Generate ERD docs                |\n\nInstall tooling once:\n\n```bash\nmake install-tools\n```\n\n## Testing Strategy (Planned)\n\n- Unit tests for parsing, auth, extraction\n- Integration tests exercising HTTP routes \u0026 DB side-effects\n- Property tests (URL normalization; idempotent job enqueue)\n- Fuzzing extractor inputs\n\nRun tests:\n\n```bash\nmake test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharlieroth%2Fcapsule","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcharlieroth%2Fcapsule","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharlieroth%2Fcapsule/lists"}