# Oculus

Value Monitoring • Single Binary • Zero Dependencies

[![Crates.io](https://img.shields.io/crates/v/oculus.svg)](https://crates.io/crates/oculus)
[![Documentation](https://docs.rs/oculus/badge.svg)](https://docs.rs/oculus)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Oculus is an out-of-the-box value monitoring software designed for individuals and small teams. Written in Rust, single binary, zero external dependencies.

> - ⚠️ **Status**: v0.1.3 - Under active development
> - 🛑 **Scope Note**: v0.1.x is single-user; no user/account/role management.

## Features

- 🚀 **Zero Dependencies** - Single binary, runs anywhere
- 📊 **Unified Value Monitoring** - Crypto, stocks, prediction markets, network metrics in one place
- 🌐 **No-Build Web UI** - HTMX-powered dashboard, no JavaScript build step
- 🔔 **Rule Engine** - Calculate derived values, trigger alerts with YAML configs and raw SQL
- 📬 **Multi-Channel Notifications** - Log, Email, Telegram, Discord, Slack, Webhook
- 🎯 **Actions** - HTTP POST triggers for automation

> 📖 See [PRD](docs/PRD.md) for detailed functional requirements.

## Supported Value Types

| Category               | Examples                                 | Description                             |
| ---------------------- | ---------------------------------------- | --------------------------------------- |
| **Cryptocurrency**     | BTC, ETH                                 | Asset prices from exchanges             |
| **Stock Market**       | TSLA, GOOGL, SPY, QQQ                    | Stock and index prices                  |
| **Prediction Markets** | Polymarket                               | Event contract prices and odds          |
| **Market Indicators**  | Fear Index, S&P Multiples, Altcoin Index | Sentiment and valuation metrics         |
| **Network Metrics**    | HTTP, TCP, Ping                          | Response time, status codes, latency    |
| **Custom Values**      | RESTful API                              | Any numeric value via generic collector |

## Architecture

```text
Collectors  →  MPSC Channel  →  SQLite/PostgreSQL →  Rule Engine  →  Notifications/Actions
    │                              │              │                    │
    ├─ Crypto Prices               └─ Single      ├─ Simple Rules      ├─ Log
    ├─ Stock Prices                    Writer        (YAML/TOML)       ├─ Email
    ├─ Prediction Markets                         ├─ Complex Rules     ├─ Telegram
    ├─ Market Indicators                             (Raw SQL)         ├─ Discord
    ├─ Network Probes (HTTP/TCP/Ping)                                  ├─ Slack
    └─ Generic API Collector                                           ├─ Webhook
                                                                       └─ HTTP POST Action
```

> 📖 See [PRD](docs/PRD.md) for detailed logical architecture and component overview.

## Tech Stack

| Layer         | Technology   | Purpose                        |
| ------------- | ------------ | ------------------------------ |
| Language      | Rust 2024    | Memory safety, zero GC pause   |
| Async Runtime | Tokio        | High-concurrency I/O           |
| Web Framework | Axum         | Lightweight, Tokio-native      |
| Database      | SQLite       | Embedded database, single file |
| Frontend      | HTMX         | AJAX via HTML attributes       |
| Templating    | Askama       | Type-safe, compiled templates  |
| Styling       | Tailwind CSS | Bundled, offline-first         |

## Quick Start

### Prerequisites

- Rust toolchain (Edition 2024)
- Optional: Tailwind CSS CLI for style customization

### Build & Run

```bash
# Clone the repository
git clone https://github.com/telepair/oculus.git
cd oculus

# Build full distribution (CSS + release binary)
make release

# Run with default config
./target/release/oculus

# Run with custom options
./target/release/oculus --config configs/config.yaml --server-port 9090
```

> 📖 See [Getting Started](docs/getting-started.md) for detailed configuration options.

### Development

```bash
# Full CI pipeline: format → lint → check → test → build
make all

# Individual commands
make fmt        # Format code
make lint       # Run clippy + markdownlint
make test       # Run tests
make doc-open   # Build and view documentation
```

## Configuration

Oculus uses a YAML configuration file for server, database, and collectors:

```yaml
# Example: configs/config.yaml
server:
  bind: 0.0.0.0
  port: 8080

database:
  driver: sqlite
  dsn: data/oculus.db
  channel_capacity: 10000

collectors:
  tcp:
    - name: google-dns
      host: 8.8.8.8
      port: 53
      enabled: true
      group: production
      interval: 5s
      timeout: 5s
      tags:
        env: production

  ping:
    - name: cloudflare-ping
      host: 1.1.1.1
      enabled: true
      group: production
      interval: 30s
      timeout: 3s

  http:
    - name: api-health
      url: https://api.example.com/health
      enabled: true
      group: production
      method: GET
      expected_status: 200
      interval: 30s
      timeout: 10s
      headers:
        Authorization: "Bearer ${API_TOKEN:-default}"
      success_conditions:
        status_codes: [200, 201]
        body_jsonpath: "$.status"
```

> 📖 See `configs/config.example.yaml` for complete configuration options.

## API Endpoints

| Endpoint             | Method | Description                 |
| -------------------- | ------ | --------------------------- |
| `/`                  | GET    | Dashboard homepage          |
| `/api/metrics`       | GET    | List metrics with filters   |
| `/api/metrics/stats` | GET    | Get aggregated metric stats |
| `/api/events`        | GET    | List events with filters    |
| `/api/collectors`    | GET    | List configured collectors  |
| `/api/query`         | POST   | Execute read-only SQL query |
| `/healthz`           | GET    | Health check (process up)   |
| `/readyz`            | GET    | Readiness check (DB ready)  |

## Project Structure

```text
oculus/
├── src/
│   ├── lib.rs           # Library: shared core functionality
│   └── main.rs          # Binary: runs complete system
├── templates/           # Askama templates (compiled into binary)
│   ├── dashboard.html
│   └── static/css/
├── configs/             # Configuration examples
├── docs/
│   ├── PRD.md           # Product Requirements Document
│   ├── getting-started.md # Build & Run Guide
│   ├── lib.md           # Library Integration Guide
│   └── schema.md        # Database Schema Reference
├── Cargo.toml           # Rust dependencies
├── Makefile             # Build automation
└── LICENSE              # MIT License
```

### Library vs Binary

| Target | Path          | Purpose                                                          |
| ------ | ------------- | ---------------------------------------------------------------- |
| `lib`  | `src/lib.rs`  | Exports reusable modules (collector, storage, rule engine, etc.) |
| `bin`  | `src/main.rs` | Entry point for running the complete Oculus system               |

**Use as a library:**

```rust
use oculus::{Collector, Storage, RuleEngine};
```

**Run as a binary:**

```bash
cargo run --bin oculus
```

## Performance Targets

| Metric        | Target  |
| ------------- | ------- |
| Startup Time  | < 100ms |
| Memory (Idle) | < 50MB  |
| Binary Size   | < 20MB  |

## TODO

> v0.1.3 milestone tasks based on [PRD](docs/PRD.md)

### Collector Layer

- [x] Core collector trait and MPSC channel pipeline
- [ ] Crypto Market: Asset price (BTC, ETH), Fear & Greed Index, MVRV
- [ ] Stock Market: Stock price, index data (SPY, QQQ)
- [ ] Prediction Market: Polymarket integration
- [x] Network Probe: TCP port probe
- [x] Network Probe: ICMP ping probe
- [x] Network Probe: HTTP RTT and status code checks
- [ ] Generic API Collector: RESTful API with JSON path extraction

### Storage Layer

- [x] SQLite for single-node support
- [ ] PostgreSQL for multi-node support
- [x] `metrics` table schema and migrations
- [x] `events` table for alerts/audit
- [x] `collectors` table for collector configuration
- [x] Data retention and cleanup policy (configurable window)

### Rule Engine

- [ ] Simple rules: YAML/TOML-based threshold alerts
- [ ] Complex rules: Raw SQL with scheduled execution
- [ ] Derived value calculation
- [ ] Event emitter for rule triggers

### Presentation Layer

- [x] Axum web server setup
- [x] HTMX dashboard homepage (`GET /`)
- [x] Real-time metrics partial (`GET /api/metrics`)
- [x] Real-time events partial (`GET /api/events`)
- [x] Metrics stats endpoint (`GET /api/metrics/stats`)
- [ ] Raw SQL query endpoint (`POST /api/query`)
- [x] Askama templates with Tailwind CSS (bundled)

### Notification Layer

- [x] Log output via `tracing` crate
- [ ] Email notifications (SMTP)
- [ ] Telegram bot integration
- [ ] Discord webhook support
- [ ] Slack webhook support
- [ ] Generic webhook support

### Action Layer

- [ ] HTTP POST action trigger

### Infrastructure

- [x] Configuration file parsing (YAML)
- [x] CLI argument handling
- [x] Health probes (`/healthz`, `/readyz`)
- [ ] Performance validation (startup < 100ms, memory < 50MB)

## Contributing

Contributions are welcome! Please read the PRD in `docs/PRD.md` for architectural context before submitting changes.

1. Fork the repository
2. Create your feature branch (`git checkout -b feat/amazing-feature`)
3. Commit your changes (`git commit -s -m 'feat: add amazing feature'`)
4. Push to the branch (`git push origin feat/amazing-feature`)
5. Open a Pull Request

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---

**Oculus** - _Monitor any value, miss nothing._
