# CLAUDE.md Obsidian: Projects/health This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. **Design Standards**: See `services/_docs/design.md` for naming conventions, code patterns, and data formats. **Input Validation**: See `services/_docs/input-validation.md` for validation layers, sanitization, and security considerations. ## Build and Deployment Commands ### Using Makefile (recommended) ```bash cd /home/josie/development/josiedot/health/services make test # Run all tests make check # Type check (fast) make build # Build release binaries make clean # Clean build artifacts ``` ### API Service (Crystal) ```bash cd /home/josie/development/josiedot/health/services/core # Local build crystal build src/main.cr --release --static -o simple-logs-api # OpenShift build oc start-build simple-logs-api --from-dir=. --follow # Deploy oc rollout restart deployment/logs-api oc rollout status deployment/logs-api ``` ### Discord Bot (Crystal) ```bash cd /home/josie/development/josiedot/health/services/discord-bot # Local build crystal build src/annotate_bot.cr --release --static -o annotate # OpenShift build oc start-build discord-bot --from-dir=. --follow # Deploy oc rollout restart deployment/discord-bot oc rollout status deployment/discord-bot ``` ### Web Frontend (Crystal) ```bash cd /home/josie/development/josiedot/health/services/web # Local build shards install crystal build src/main.cr --release --static -o josie-health-web # OpenShift build oc start-build josie-health-web --from-dir=. --follow # Deploy oc rollout restart deployment/josie-health-web oc rollout status deployment/josie-health-web ``` ### OpenShift Operations ```bash # Check build configs oc get buildconfigs # Check deployments oc get deployments # Check pods oc get pods | grep -E "(logs-api|discord-bot|josie-health-web)" # View logs oc logs deployment/logs-api --tail=20 oc logs deployment/discord-bot --tail=20 oc logs deployment/josie-health-web --tail=20 ``` ## Architecture Overview This is a health logging system with services deployed on OpenShift: ### 1. API Service (`services/core/`) - **Language**: Crystal with Kemal web framework - **Purpose**: RESTful API for substance logging, metrics, and drug information - **Architecture**: Modular handler-based design with Redis data backend - **Build Config**: `simple-logs-api` → deployment: `logs-api` - **Key Components**: - `src/router.cr`: Main request router with Basic Auth and Bearer token auth - `src/handlers/`: Separate handlers for logs, metrics, substances, interactions, aliases, reminders, auth, timezone - `src/redis_client.cr`: Redis client for data persistence - `src/rate_limiter.cr`: Leaky bucket rate limiting - `static/swagger-ui.html`: Swagger UI for API docs - **Dependencies**: - `josie-health-lut`: Substance normalization library with embedded JSON data (git@github.com:josiedot/health-lut.git) - `josie-health-utils`: Shared utilities (timestamp, dosage, timezone parsing, logging) ### 2. Discord Bot (`services/discord-bot/`) - **Language**: Crystal with discordcr library - **Purpose**: Discord bot for logging substance doses and querying data - **Build Config**: `discord-bot` → deployment: `discord-bot` - **Architecture**: Uses shared bot-core library, all data access through API (no direct Redis) - **Key Components**: - `src/annotate_bot.cr`: Main bot with command routing - `src/handlers/`: Discord-specific handlers (wrapped, github, roastme) - `src/api_client.cr`: HTTP client for API communication - `src/dto.cr`: Type-safe data transfer objects for API responses - `src/response_formatter.cr`: Discord message formatting - `src/webhook_server.cr`: Receives callbacks from API (reminders, wrapped) - **Dependencies**: - `josie-health-bot-core`: Shared bot framework with command handlers - `josie-health-utils`: Shared utilities (timestamp, dosage, timezone parsing, logging) ### 3. Shared Bot Framework (`josie-health-bot-core/`) - **Purpose**: Reusable command routing and handlers for Discord and IRC bots - **Key Components**: - `command_router.cr`: Route commands to handlers - `command_parser.cr`: Parse command input - `alias_parser.cr`: User alias expansion - `api_client.cr`: Shared API communication - `dto.cr`: Data transfer objects - `handlers/`: Reusable handlers (dose, query, substance, alias, reminder, timezone, vitals, lab) ### 4. Shared Utilities (`josie-health-utils/`) - **Purpose**: Common parsing and utility code shared between services - **Modules**: - `Timestamp`: Parse HHMM ago format, RFC3339 timestamps, display formatting - `Dosage`: Parse dosages with units, math expressions (47.5mg/2), extract from text - `Timezone`: Resolve aliases (EST->America/New_York), parse offsets, validate IANA - `Result`: Result type for error handling - `Log`: Structured logging with levels (debug/info/warn/error), controlled by DEBUG env var ### 5. Lookup Tables Library (`josie-health-lut/`) - **Purpose**: Substance normalization and embedded data - **Modules**: - `DrugLUT`: Main substance database with aliases and dosing info - `CaffeineLUT`: Caffeine sources (brands, content per serving) - `AlcoholLUT`: Alcohol sources - `CannabisLUT`: Cannabis strains - `MedsLUT`: Medications database - `VitalsTracker`: Valid ranges for vital signs ### 6. IRC Bot (`services/irc-bot/`) - **Language**: Crystal - **Purpose**: Interactive IRC bot with same commands as Discord bot - **Architecture**: Uses shared bot-core library - **Key Components**: - `src/irc_bot.cr`: IRC client with command routing ### 7. CLI (`services/cli/`) - **Language**: Crystal - **Purpose**: Local command-line REPL for logging doses and querying data offline or online - **Key Components**: - `src/cli.cr`: REPL loop with readline, history, command routing - `src/config.cr`: SQLite-backed configuration (API key, user ID, endpoint) - `src/offline_cache.cr`: SQLite queue for doses logged while offline - `src/sync_manager.cr`: Sync cached doses to API when connectivity returns - `src/response_formatter.cr`: Terminal-formatted output with ANSI colors - **Dependencies**: - `josie-health-bot-core`: Shared command routing and handlers - `sqlite3`: Local config and offline cache storage - `readline`: Interactive line editing and tab completion ### 8. Web Frontend (`services/web/`) - **Language**: Crystal with Kemal web framework - **Purpose**: Web UI for josie.health with server-side rendering - **Build Config**: `josie-health-web` → deployment: `josie-health-web` - **Port**: 3002 - **Key Components**: - `src/main.cr`: Entry point, Redis session setup - `src/router.cr`: Route definitions - `src/session_manager.cr`: Redis-backed sessions (7-day TTL) - `src/handlers/`: Auth, doses, keys, account, substance handlers - `src/middleware/`: Session and CSRF middleware - `src/views/`: ECR templates - `static/`: CSS and assets - **Features**: - Discord OAuth and IRC NickServ authentication - Dose logging, editing, deletion, and history - Account linking with data migration - Embedded Grafana dashboards - Substance info and interaction checker (public) - API key management - **Dependencies**: - `josie-health-utils`: Shared utilities ### 9. Wrapped Service (`services/wrapped/`) - **Language**: Ruby with Sinatra - **Purpose**: Generate "Spotify Wrapped" style statistics and visualizations - **Key Components**: - `app.rb`: Sinatra application - `lib/helpers/`: Statistics calculation, video/graph generation ### 10. Grafana Dashboards (provisioned via Helm chart) - **Purpose**: Visualization dashboards for health metrics - **Dashboard definitions**: Provisioned through `services/chart/templates/` ### 11. Communication Flow ```mermaid flowchart LR IRC[IRC Bot] <--> API[API Service] DC[Discord Bot] <--> API CLI[CLI] <--> API WEB[Web Frontend] <--> API API --> Redis[(Redis)] WEB --> Redis Redis --> Grafana[Grafana] ``` Note: Bot and API have bidirectional communication - API pushes reminder webhooks to bot when due. Web frontend uses Redis for sessions. ## Command Structures ### Discord Bot Commands The bot uses `;` prefix with commands like: - `;id [route]` - Log dose - `;id ; ` - Log multiple doses at once - `;td [route]` - Log dose at specific time - `;tally ` - Usage statistics - `;howhighami` - Recent consecutive doses analysis - `;lastdose [n]` - Show recent doses - `;info ` - Drug information - `;combo ` - Check interaction ### API Endpoints - `POST /v1/logs/substances` - Log new dose (normalizes caffeine/alcohol sources) - `GET /v1/substances/{name}/info` - Drug information - `GET /v1/interactions/{substance1}/{substance2}` - Check interaction - `GET /v1/metrics/users/{user_id}/{endpoint}` - User-specific metrics - `POST/GET/DELETE /v1/aliases` - User command aliases - `POST/GET/DELETE /v1/reminders` - User reminders (webhook-based delivery) - `GET/PUT /v1/users/{user_id}/timezone` - User timezone settings - `GET /health` - Service health check ## Data Models ### Dose Entry Format (Redis) Doses are stored in Redis as CSV-formatted strings with the format: ``` timestamp,user,substance,amount,route,annotation 2025-09-12T23:26:05Z,imnotjosie,4-mmc,85mg,insufflated, ``` ### API Response Format ```json { "data": { /* main response data */ }, "meta": { /* metadata about request */ } } ``` ## Environment Configuration ### API Service - `REDIS_HOST` - Redis host (logs-api-redis) - `REDIS_PORT` - Redis port (6379) - `API_USERNAME`, `API_PASSWORD` - Basic Auth credentials - `RATE_LIMIT_ENABLED` - Enable rate limiting (default: true, set to "false" to disable) - `RATE_LIMIT_BUCKET` - Max requests per bucket (default: 60) - `RATE_LIMIT_REFILL` - Tokens added per second (default: 10) ### Discord Bot - `DISCORD_TOKEN` - Discord bot token - `API_URL` - API service endpoint (http://logs-api:3001) - `API_USERNAME`, `API_PASSWORD` - API authentication - `WEBHOOK_URL` - Callback URL for API webhooks (http://discord-bot:8080/webhook/reminder) - `DEBUG` - Enable debug logging (optional) ### Web Frontend - `PORT` - Server port (3002) - `API_URL` - API service endpoint (http://logs-api:3001) - `API_USERNAME`, `API_PASSWORD` - API authentication - `REDIS_HOST`, `REDIS_PORT` - Redis connection for sessions - `SESSION_SECRET` - 64-byte hex string for session encryption - `GRAFANA_URL` - Base URL for Grafana embeds (https://josie.health) - `DISCORD_CLIENT_ID`, `DISCORD_CLIENT_SECRET` - Discord OAuth credentials - `DISCORD_REDIRECT_URI` - OAuth callback URL - `KEMAL_ENV` - Environment (production/development) ## Deployment Architecture Services are deployed on OpenShift with: - Container images built via OpenShift BuildConfigs - Secrets managed via OpenShift Secrets - Service-to-service communication via internal DNS - Static Crystal binaries in Alpine containers ## Development Patterns ### Adding New Bot Commands 1. Add command case in `annotate_bot.cr` handle_command method 2. Create handler method in appropriate handler class 3. Add API endpoint if needed in API service 4. Update help documentation in query_handler.cr ### Adding New API Endpoints 1. Add route in `router.cr` 2. Create handler method in appropriate handler class 3. Follow existing JSON response format with data/meta structure 4. Add Basic Auth bypass if endpoint should be public ### Crystal Dependencies Both services use Crystal 1.9.2 with shard.yml for dependency management. Run `shards install` after dependency changes. ## Testing Tests are run from the `services/` directory using the Makefile: ```bash cd services make test # Run all tests make test-utils # Run josie-health-utils tests only make test-bot # Run discord-bot tests only make test-api # Run API tests only make test-cli # Run CLI tests only make check # Type check only (fast, no codegen) ``` Test coverage: - `josie-health-utils/spec/`: Timestamp, Dosage, Timezone, Recurrence, Result parsing - `discord-bot/spec/`: DTO parsing, alias parsing, handler integration - `core/spec/`: Rate limiter, CSV parser, Redis client, range parser - `cli/spec/`: Config, offline cache, sync manager, response formatter, REPL ## Logging Services use `JosieHealth::Utils::Log` for structured logging: ```crystal Log = JosieHealth::Utils::Log Log.debug("context", "message") # Only shown when DEBUG env var is set Log.info("context", "message") Log.error("context", "message") ``` ## Notes - All substance data (drugs, combos, caffeine, alcohol, meds) is embedded in the `josie-health-lut` shard - Data sources should be documented in the LUT library