diff options
| author | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-21 20:08:09 +0300 |
|---|---|---|
| committer | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-21 20:08:09 +0300 |
| commit | 0ef072f64456f9e6a0105bd123987d66434a2254 (patch) | |
| tree | 1884be3cbe75d829f0627180aec49272f009e6e4 | |
| parent | 83f3d9ce90b190dac02abd8f227ce5bfac4a2c82 (diff) | |
ci: Update readme, ci and add cursor rules
| -rw-r--r-- | .cursorrules | 174 | ||||
| -rw-r--r-- | .woodpecker/lint.yml | 4 | ||||
| -rw-r--r-- | .woodpecker/rust-test.yml | 2 | ||||
| -rw-r--r-- | README.md | 77 |
4 files changed, 254 insertions, 3 deletions
diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..4438139 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,174 @@ +# Rust Rules + +## π§± Project Architecture + +### **Modular Design** + +* Organize code into **crates** and **modules**: + + * Use a **workspace** for multi-crate projects (`Cargo.toml` + `Cargo.lock` at root). + * Split concerns into crates: e.g., `core`, `network`, `storage`, `cli`, `web`, `domain`, `infra`. +* Avoid monoliths β design for composability. + +### **Layered Architecture** + +Separate by **responsibility**, not technology: + +* **Domain layer** β business logic, domain models, pure logic, no dependencies. +* **Application layer** β use-cases, orchestrators, service interfaces. +* **Infrastructure layer** β database, HTTP clients, FS, external APIs. +* **Presentation layer** β CLI, gRPC, REST API, etc. + +Use traits to **abstract interfaces** between layers. + +--- + +## π¦ Crate and Module Hygiene + +### **Use Visibility Thoughtfully** + +* Keep as much private (`pub(crate)` or private) as possible. +* Use `mod.rs` sparingly β prefer flat `mod_x.rs` and `mod x;` where possible. +* Keep `lib.rs` or `main.rs` minimal β just wiring and top-level declarations. + +### **Predeclare your modules** + +Explicitly declare modules in parent files, avoiding implicit module discovery: + +```rust +mod domain; +mod services; +``` + +--- + +## π§ Code Design and Idioms + +### **Prefer Composition Over Inheritance** + +* Favor structs + traits over enums for extensibility. +* Use `impl Trait` for abstraction and `dyn Trait` for dynamic dispatch when needed. + +### **Minimize Unnecessary Abstractions** + +* Don't abstract over one implementation β wait for the second one. +* Donβt use traits where a simple function will do. + +### **Idiomatic Error Handling** + +* Use `Result<T, E>`, `?`, and `thiserror` or `anyhow` (depending on layer). +* Business logic: custom error enums (`thiserror`). +* App layer or CLI: use `anyhow::Result` for bubble-up and crash-on-error. + +### **Zero-cost abstractions** + +* Use generics, lifetimes, borrowing, and ownership where appropriate. +* Minimize heap allocations, unnecessary `.clone()`s. + +## π οΈ Tooling and Dev Experience + +### **Use Clippy, Rustfmt, and IDEs** + +* `clippy`: catch non-idiomatic code. +* `rustfmt`: consistent formatting. +* `cargo-expand`: inspect macro-generated code. + +### **Use `cargo features` for Flexibility** + +* Feature-gate optional deps and functionalities: + +```toml +[features] +default = ["serde"] +cli = ["clap"] +``` + +## π§ͺ Testing & Quality + +### **Test by Layer** + +* Unit tests for pure logic. +* Integration tests (`tests/`) for subsystems and public interfaces. +* End-to-end/system tests where applicable. + +Use `mockall` or `double` for mocking when interface testing is needed. + +### **Property-based test* Study open-source Rust projects like `ripgrep`, `tokio`, `tower`, `axum`, or `zellij`. +ing** + +* Use `proptest` for verifying correctness over ranges of inputs. + +## π Performance and Safety + +### **Measure Before Optimizing** + +* Use `cargo bench`, `criterion`, `perf`, or `flamegraph` for real profiling. +* Don't optimize until there's a clear need. + +### **Minimize Unsafe Code** + +* Keep `unsafe` blocks minimal, justified, and well-documented. +* Use crates like `bytemuck`, `zeroize`, or `unsafe-libyaml` only when needed. + +## π Dependency Hygiene + +### **Minimal and Audited Dependencies** + +* Prefer well-maintained, minimal, audited crates. +* Avoid depending on "kitchen sink" crates unless unavoidable. +* Regularly check for security updates via `cargo audit`. + +## π§Ύ Documentation & Maintainability + +### **Document Public APIs and Crates** + +* Use `//!` and `///` comments. +* Auto-generate docs with `cargo doc --open`. + +### **Conventional Naming** + +* Stick to Rust conventions: `snake_case` for functions and variables, `PascalCase` for types. + +## βοΈ Async, Concurrency, and IO + +### **Choose Your Runtime Wisely** + +* `tokio`: for production-grade, multi-core async workloads. +* `async-std`: if you prefer a more "standard" style. +* Use `tracing` instead of `log` for structured async-aware logging. + +### **Limit Shared Mutable State** + +* Prefer ownership and message passing (`tokio::sync::mpsc`, `crossbeam`, `flume`) over `Arc<Mutex<T>>`. +* Avoid global mutable state unless itβs guarded and justified. + +### **Reproducible Builds** + +* Pin versions where critical. +* Use lockfiles even in libraries (`[package] publish = false` in internal crates). + +## π Example Folder Structure + +```text +my-app/ +βββ Cargo.toml +βββ Cargo.lock +βββ crates/ +β βββ core/ +β βββ api/ +β βββ domain/ +β βββ storage/ +βββ bin/ +β βββ cli.rs +βββ tests/ +β βββ integration.rs +βββ docs/ +β βββ architecture.md +``` + +## π§ Final Advice + +* Think in **lifetimes**, **ownership**, and **borrowing**. +* Design for **testability** and **composability**. +* Don't fight the compiler β **embrace it as your co-architect**. +* Be conservative with third-party crates β **audit and isolate** them if needed. diff --git a/.woodpecker/lint.yml b/.woodpecker/lint.yml index a32ae83..e3c45d6 100644 --- a/.woodpecker/lint.yml +++ b/.woodpecker/lint.yml @@ -27,7 +27,7 @@ steps: - pull_request - name: rust-fmt - image: rust:1.76 + image: rust:1.88 commands: - cargo fmt --all -- --check when: @@ -35,7 +35,7 @@ steps: - pull_request - name: rust-clippy - image: rust:1.76 + image: rust:1.88 commands: - cargo clippy --all-targets --all-features -- -D warnings when: diff --git a/.woodpecker/rust-test.yml b/.woodpecker/rust-test.yml index ba9d16a..e25f00d 100644 --- a/.woodpecker/rust-test.yml +++ b/.woodpecker/rust-test.yml @@ -2,7 +2,7 @@ when: event: pull_request steps: - name: test - image: rust:1.76 + image: rust:1.88 commands: - cargo test --all when: @@ -3,6 +3,7 @@ Silmataivas is a weather monitoring service that sends personalized alerts based on user-defined thresholds and notification preferences. This is the Rust version, providing a RESTful API for managing users, locations, weather thresholds, and notification settings. ## Features + - Weather monitoring using OpenWeatherMap API - Custom weather thresholds per user - Flexible notifications: NTFY (push) and SMTP (email) @@ -10,6 +11,7 @@ Silmataivas is a weather monitoring service that sends personalized alerts based - RESTful API for all resources ## Project Structure + - **src/main.rs**: All application logic and API endpoints (no lib.rs, not a library) - **src/**: Modules for users, locations, notifications, weather thresholds, etc. - **migrations/**: SQL migrations for SQLite @@ -18,10 +20,12 @@ Silmataivas is a weather monitoring service that sends personalized alerts based ## Quick Start ### Prerequisites + - Rust (see [rustup.rs](https://rustup.rs/)) - SQLite (default, or set `DATABASE_URL` for PostgreSQL) ### Running Locally + ```bash # Clone the repository git clone https://codeberg.org/silmataivas/silmataivas.git @@ -35,12 +39,14 @@ Silmataivas is a weather monitoring service that sends personalized alerts based The server will listen on port 4000 by default. You can set the `DATABASE_URL` environment variable to change the database location. ### Using Docker + ```bash docker build -t silmataivas . docker run -p 4000:4000 -e DATABASE_URL=sqlite:///data/silmataivas.db silmataivas ``` ## API Usage + All API endpoints (except `/health`) require authentication using a Bearer token: ``` @@ -50,17 +56,88 @@ Authorization: Bearer <user_id> See the source code for endpoint details. (OpenAPI docs are not yet auto-generated in this Rust version.) ## Migration Note + This project was previously implemented in Elixir/Phoenix. All Elixir/Phoenix code, references, and setup instructions have been removed. The project is now a Rust binary only (no library, no Elixir code). ## Development + - Format: `cargo fmt` - Lint: `cargo clippy` - Test: `cargo test` ## Contributing + - Use conventional commits for PRs - See the code for module structure and API details --- For any issues or questions, please open an issue on Codeberg. + +## TODO + +### β
Project Completion Checklist for Weather Monitoring App + +#### π§± Architecture & Code Quality + +- [ ] Centralized error handling (e.g., `thiserror`, `anyhow`, `IntoResponse`) +- [ ] Organize code into service/domain/modules to improve separation of concerns +- [ ] Add rate limiting/backoff for OpenWeather API usage +- [ ] Write unit tests for core logic (e.g., user CRUD, weather checks) +- [ ] Add integration tests for full API endpoints +- [ ] Benchmark endpoint latency and cold-start performance + +#### π Security + +- [ ] Ensure proper SQL injection protection (`sqlx` should cover this, but verify inputs) +- [ ] Review CORS and CSRF protection for web endpoints +- [ ] Validate and sanitize all environment variables at startup +- [ ] Secure storage for SMTP/Ntfy credentials (env vars or secret store) + +#### π Observability & Monitoring + +- [ ] Add `/healthz` and `/metrics` endpoints (e.g., Prometheus) +- [ ] Use structured logging (`tracing` spans for request lifecycle) +- [ ] Consider log rotation or persistent log storage +- [ ] Alerting or notifications if cron job fails + +#### βοΈ CLI & Deployment + +- [ ] Build CLI for DB/settings management (with help output and scripting support) +- [ ] Implement DB backup or export functionality (even for SQLite) +- [ ] Enable SQLite WAL mode and regular vacuuming +- [ ] Add install/setup instructions to CLI or README + +#### π§βπ» Web Interface (MVP) + +- [ ] Add a minimal web UI (htmx, Yew, or static + API) +- [ ] Ensure UI is responsive/mobile friendly +- [ ] Add form to configure thresholds, ntfy/smtp, location, etc. +- [ ] Web UI: Add table or list of current weather rules + +#### βοΈ Weather & Notifications Logic + +- [ ] Only send notification on threshold **crossing**, not on every cron run +- [ ] Allow multiple thresholds per user (e.g., temp < 0Β°C and wind > 30km/h) +- [ ] Store basic history of weather checks (for debugging/trends) +- [ ] Abstract weather provider to allow future plug-ins (e.g., Tomorrow.io, Meteomatics) + +#### π§ͺ Testing & QA + +- [ ] Add CI test for API correctness (user + notification config CRUD) +- [ ] Add e2e test for full flow: create user β set threshold β trigger alert +- [ ] Add test for OpenAPI schema consistency + +#### π¦ Open Source Readiness + +- [ ] Add detailed README with setup, architecture overview, and usage +- [ ] Add LICENSE file +- [ ] Add `CONTRIBUTING.md` with basic guide +- [ ] Add `.env.example` with defaults +- [ ] Add changelog or release notes for future versions + +#### π Final Steps + +- [ ] Deploy to production server +- [ ] Verify Docker Compose deployment with CLI and web UI +- [ ] Publish initial release/tag on Codeberg |
