|
| 1 | +# Copilot Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +RIPT (Reclaimer of Inactive Partitions and Topics) is a stateless Go daemon that monitors Apache Kafka topics to identify unused ones. It persists state in its own internal Kafka topic (`ript-state`) and exposes a REST API and web dashboard. |
| 6 | + |
| 7 | +## Build, Test, and Run |
| 8 | + |
| 9 | +```bash |
| 10 | +make build # Build binary to bin/ript |
| 11 | +make run # Build and run locally (requires .env or env vars) |
| 12 | +make test # go test -v ./... |
| 13 | +make clean # Remove build artifacts |
| 14 | +make deps # go mod download && go mod tidy |
| 15 | + |
| 16 | +# Docker |
| 17 | +make docker-up # Start Zookeeper + Kafka + RIPT |
| 18 | +make docker-down # Tear down stack |
| 19 | +make docker-logs # Tail RIPT logs |
| 20 | +``` |
| 21 | + |
| 22 | +**Single test:** |
| 23 | +```bash |
| 24 | +go test -v -run TestFunctionName ./internal/package_name |
| 25 | +``` |
| 26 | + |
| 27 | +**Integration tests** (requires Docker): |
| 28 | +```bash |
| 29 | +./test-integration.sh |
| 30 | +``` |
| 31 | + |
| 32 | +## Architecture |
| 33 | + |
| 34 | +``` |
| 35 | +cmd/ript/ Entry point — wires up all components, handles OS signals, graceful shutdown |
| 36 | +internal/config/ Loads and validates env vars with defaults (via godotenv) |
| 37 | +internal/models/ Domain types: TopicStatus, PartitionInfo, ClusterSnapshot, Duration |
| 38 | +internal/kafka/ Kafka client (topic metadata + offset fetching) and StateManager (snapshot persistence) |
| 39 | +internal/tracker/ TopicTracker — core scan loop, staleness logic, in-memory snapshot |
| 40 | +internal/api/ Gin HTTP server — routes and handlers read from TopicTracker snapshot |
| 41 | +internal/logging/ Custom leveled logger (DEBUG/INFO/WARN/ERROR/FATAL) |
| 42 | +web/templates/ dashboard.html — Bootstrap 5 frontend served by the API server |
| 43 | +``` |
| 44 | + |
| 45 | +**Data flow:** `main` → initialize config/logging → connect Kafka (with retry) → `StateManager.Load()` → start `TopicTracker` scan loop → start `api.Server` → serve traffic from in-memory snapshot. |
| 46 | + |
| 47 | +Each scan: fetch Kafka metadata + offsets → compute ages → update snapshot → persist to `ript-state` (log-compacted, one message per topic key). |
| 48 | + |
| 49 | +**Staleness thresholds (configurable):** |
| 50 | +- Partition "stale": no offset update in `RIPT_STALE_PARTITION_DAYS` days (default 7) |
| 51 | +- Topic "unused": all partitions stale for `RIPT_UNUSED_TOPIC_DAYS` days (default 30) |
| 52 | + |
| 53 | +## Key Conventions |
| 54 | + |
| 55 | +**Concurrency:** Snapshot access uses `sync.RWMutex` (read-heavy). Goroutines are coordinated with context cancellation and `sync.WaitGroup` for shutdown. |
| 56 | + |
| 57 | +**HTTP handlers (Gin):** All handlers are pointer receiver methods on `api.Server`. Return `503 ServiceUnavailable` if the tracker snapshot is not yet initialized. Use `gin.H` maps for all JSON responses. |
| 58 | + |
| 59 | +**Error handling:** Wrap errors with `fmt.Errorf("context: %w", err)`. Log warnings and degrade gracefully for non-fatal errors; use `logger.Fatal()` only for initialization failures. |
| 60 | + |
| 61 | +**State persistence:** `StateManager` writes one compacted Kafka message per topic (topic name as key). On restart, it reads back to EOF to restore the last snapshot. The app is stateless from infrastructure's perspective — Kafka is the durable store. |
| 62 | + |
| 63 | +**Configuration:** All config via environment variables with `RIPT_` prefix. `.env` file auto-loaded if present. See `.env.example` for all supported variables. Key vars: `RIPT_KAFKA_BROKERS`, `RIPT_SCAN_INTERVAL_MINUTES`, `RIPT_HTTP_PORT`, `RIPT_LOG_LEVEL`. |
| 64 | + |
| 65 | +**Models:** `Duration` is a custom type with `Days/Hours/Minutes/Seconds` fields and a `String()` method for human-readable output. Use `models.CalculateDuration(t time.Time)` to convert timestamps. |
| 66 | + |
| 67 | +## Local Development Setup |
| 68 | + |
| 69 | +```bash |
| 70 | +cp .env.example .env # Configure Kafka brokers and other settings |
| 71 | +make docker-up # Start Kafka stack (listens on localhost:9092) |
| 72 | +make run # Run RIPT against local Kafka |
| 73 | +``` |
| 74 | + |
| 75 | +The RIPT dashboard is available at `http://localhost:8080` once running. |
0 commit comments