{"id":31057348,"url":"https://github.com/dpup/info.ersn.net","last_synced_at":"2025-09-15T06:58:56.771Z","repository":{"id":314676896,"uuid":"1056380738","full_name":"dpup/info.ersn.net","owner":"dpup","description":"A real-time API server providing road conditions and weather information for the Ebbett's Pass region.","archived":false,"fork":false,"pushed_at":"2025-09-14T01:26:21.000Z","size":24646,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-14T03:09:14.403Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","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/dpup.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-14T00:59:41.000Z","updated_at":"2025-09-14T01:26:25.000Z","dependencies_parsed_at":"2025-09-14T03:09:18.625Z","dependency_job_id":"e2af085b-b2a5-47c2-a06c-7b248df11c70","html_url":"https://github.com/dpup/info.ersn.net","commit_stats":null,"previous_names":["dpup/info.ersn.net"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dpup/info.ersn.net","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Finfo.ersn.net","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Finfo.ersn.net/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Finfo.ersn.net/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Finfo.ersn.net/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dpup","download_url":"https://codeload.github.com/dpup/info.ersn.net/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpup%2Finfo.ersn.net/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":275219533,"owners_count":25425889,"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-09-15T02:00:09.272Z","response_time":75,"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-09-15T06:58:51.075Z","updated_at":"2025-09-15T06:58:56.752Z","avatar_url":"https://github.com/dpup.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ERSN Info Server\n\nA real-time API server providing road conditions and weather information for the Ebbett's Pass region, combining data from Google Routes API, Caltrans feeds, and OpenWeatherMap.\n\n## Overview\n\nThe server dynamically builds routes between geographic points using the Google Routes API, retrieving real-time traffic data and estimated travel times. Polyline geometry from Google is used to cross-reference Caltrans feeds, with alerts filtered and classified as on-route or nearby based on spatial relevance. To improve usability, OpenAI is integrated to automatically convert technical Caltrans alerts into clear, human-readable summaries.\n\nWeather data is independently sourced from OpenWeatherMap for each configured location, providing current conditions and active alerts.\n\nThe architecture is modular and location-agnostic, allowing easy adaptation to other regions or road networks by updating configuration.\n\n**Live API available at: https://info.ersn.net**\n\n## Features\n\n- **Real-time Road Conditions**: Live traffic data, travel times, and congestion levels from Google Routes API\n- **Intelligent Road Alerts**: AI-enhanced alerts from Caltrans feeds including lane closures, CHP incidents, and construction\n- **Smart Alert Classification**: Route-aware filtering (ON_ROUTE/NEARBY/DISTANT) based on spatial analysis\n- **AI-Enhanced Descriptions**: Automatic OpenAI conversion of technical alerts into clear, human-readable summaries\n- **Weather Information**: Current conditions and alerts for multiple locations from OpenWeatherMap\n- **Stale-while-revalidate Caching**: Sub-100ms responses by serving cached data while refreshing in background\n- **REST API**: Clean HTTP endpoints with comprehensive JSON responses\n- **gRPC Support**: Native gRPC services with automatic HTTP gateway\n- **Configurable \u0026 Scalable**: Location-agnostic architecture with simple YAML configuration\n\n## API Endpoints\n\n### Roads API\n\n#### List All Roads\n```http\nGET /api/v1/roads\n```\n\n**Response Example:**\n```json\n{\n  \"roads\": [\n    {\n      \"id\": \"hwy4-angels-murphys\",\n      \"name\": \"Hwy 4\",\n      \"section\": \"Angels Camp to Murphys\",\n      \"status\": \"OPEN\",\n      \"durationMinutes\": 11,\n      \"distanceKm\": 13,\n      \"congestionLevel\": \"CLEAR\",\n      \"delayMinutes\": 0,\n      \"alerts\": [\n        {\n          \"type\": \"CONSTRUCTION\",\n          \"severity\": \"INFO\",\n          \"classification\": \"NEARBY\",\n          \"title\": \"Lane Closure Advisory\",\n          \"description\": \"Routine maintenance work on shoulder, no traffic impact expected.\",\n          \"condensedSummary\": \"Shoulder work, no delays\",\n          \"impact\": \"none\",\n        }\n      ]\n    }\n  ],\n  \"lastUpdated\": \"2025-09-11T01:52:05.646618Z\"\n}\n```\n\n#### Get Specific Road\n```http\nGET /api/v1/roads/{road_id}\n```\n\n**Response Example:**\n```json\n{\n  \"road\": {\n    \"id\": \"hwy4-murphys-arnold\",\n    \"name\": \"Hwy 4\",\n    \"section\": \"Murphys to Arnold\",\n    \"status\": \"OPEN\",\n    \"durationMinutes\": 15,\n    \"distanceKm\": 20,\n    \"congestionLevel\": \"CLEAR\",\n    \"delayMinutes\": 0,\n    \"alerts\": [\n      {\n        \"type\": \"INCIDENT\",\n        \"severity\": \"WARNING\",\n        \"classification\": \"ON_ROUTE\",\n        \"title\": \"CHP Incident 250911GG0206\",\n        \"description\": \"Multi-vehicle accident blocking right lane near mile marker 45. Expect 15-20 minute delays while emergency crews clear the scene.\",\n        \"condensedSummary\": \"Accident blocking right lane, 15-20 min delays\",\n        \"startTime\": \"2025-09-11T01:30:00Z\",\n        \"location\": {\n          \"latitude\": 38.2345,\n          \"longitude\": -120.1234\n        },\n        \"locationDescription\": \"Highway 4 near mile marker 45\",\n        \"impact\": \"moderate\",\n        \"timeReported\": \"2025-09-11T01:30:00Z\",\n        \"lastUpdated\": \"2025-09-11T01:45:00Z\",\n        \"metadata\": {\n          \"lanes_affected\": \"1 of 2\",\n          \"emergency_services\": \"CHP on scene\"\n        }\n      }\n    ]\n  },\n  \"lastUpdated\": \"2025-09-11T01:52:05.646618Z\"\n}\n```\n\n**Road Status Values:**\n- `OPEN` - Road is open to traffic\n- `CLOSED` - Road is closed\n- `RESTRICTED` - Limited access or restrictions\n- `MAINTENANCE` - Under maintenance\n\n**Congestion Levels:**\n- `CLEAR` - Free flowing traffic\n- `LIGHT` - Light traffic\n- `MODERATE` - Moderate traffic\n- `HEAVY` - Heavy traffic\n- `SEVERE` - Severe congestion\n\n### Road Alerts\n\nThe Roads API provides intelligent alerts that combine data from multiple sources and uses AI enhancement for better readability.\n\n**Alert Types:**\n- `CLOSURE` - Road closures and lane restrictions\n- `CONSTRUCTION` - Planned construction activities\n- `INCIDENT` - Traffic accidents and emergency situations\n- `WEATHER` - Weather-related road conditions\n\n**Alert Severity:**\n- `INFO` - Informational notices\n- `WARNING` - Moderate impact on travel\n- `CRITICAL` - Severe impact or safety concerns\n\n**Alert Classification:**\n- `ON_ROUTE` - Directly affects route path (\u003c 100m from route)\n- `NEARBY` - In surrounding area but not blocking route\n- `DISTANT` - Too far from route to be relevant\n\n**AI Enhancement Features:**\n- **Smart Descriptions**: Technical Caltrans alerts are automatically converted to human-readable summaries using OpenAI\n- **Impact Assessment**: AI evaluates impact levels: `none`, `light`, `moderate`, `severe`\n- **Duration Estimates**: AI provides duration estimates: `unknown`, `\u003c 1 hour`, `several hours`, `ongoing`\n- **Condensed Summaries**: Short format optimized for mobile displays\n- **Structured Metadata**: Additional contextual information like lanes affected, emergency services on scene\n\n**Data Sources:**\n- **Caltrans KML Feeds**: Lane closures, CHP incidents, and chain control status\n- **Google Routes API**: Real-time traffic conditions and route geometry for spatial matching\n- **OpenAI Enhancement**: Automatic conversion of technical alerts into clear, actionable information\n\n*Note: Chain control status is currently disabled until winter when actual chain requirement data becomes available in Caltrans feeds. All roads will show no chain requirements.*\n\n### Weather API\n\n#### List All Weather Locations\n```http\nGET /api/v1/weather\n```\n\n**Response Example:**\n```json\n{\n  \"weatherData\": [\n    {\n      \"locationId\": \"murphys\",\n      \"locationName\": \"Murphys, CA\",\n      \"weatherMain\": \"Clear\",\n      \"weatherDescription\": \"clear sky\",\n      \"weatherIcon\": \"01d\",\n      \"temperatureCelsius\": 22,\n      \"feelsLikeCelsius\": 21,\n      \"humidityPercent\": 45,\n      \"windSpeedKmh\": 8,\n      \"windDirectionDegrees\": 230,\n      \"visibilityKm\": 16,\n      \"alerts\": []\n    }\n  ],\n  \"lastUpdated\": \"2025-09-11T01:52:05.646618Z\"\n}\n```\n\n#### Get Weather Alerts\n```http\nGET /api/v1/weather/alerts\n```\n\n**Response Example:**\n```json\n{\n  \"alerts\": [\n    {\n      \"id\": \"alert-123\",\n      \"type\": \"WEATHER\",\n      \"severity\": \"WARNING\",\n      \"title\": \"Winter Weather Advisory\",\n      \"description\": \"Snow expected above 7000 feet\",\n      \"startTime\": \"2025-09-11T06:00:00Z\",\n      \"endTime\": \"2025-09-11T18:00:00Z\",\n      \"affectedAreas\": [\"Sierra Nevada Mountains\"]\n    }\n  ],\n  \"lastUpdated\": \"2025-09-11T01:52:05.646618Z\"\n}\n```\n\n## Quick Start\n\n### Prerequisites\n\n- Go 1.21+\n- Google Routes API key\n- OpenWeatherMap API key\n\n### Installation\n\n1. Clone the repository:\n   ```bash\n   git clone \u003crepository-url\u003e\n   cd info.ersn.net\n   ```\n\n2. Set up environment variables:\n   ```bash\n   export PF__GOOGLE_ROUTES__API_KEY=\"your-google-api-key\"\n   export PF__OPENWEATHER__API_KEY=\"your-openweather-api-key\"\n   export PF__OPENAI__API_KEY=\"your-openai-api-key\"  # Optional, for AI-enhanced alerts\n   ```\n\n3. Build and run:\n   ```bash\n   make build\n   make run\n   ```\n\n4. Test the API:\n   ```bash\n   # Test locally\n   curl http://localhost:8080/api/v1/roads\n   curl http://localhost:8080/api/v1/weather\n   \n   # Or test the live API\n   curl https://info.ersn.net/api/v1/roads\n   curl https://info.ersn.net/api/v1/weather\n   ```\n\n### Configuration\n\nThe server uses `prefab.yaml` for configuration with a **simplified structure** and supports environment variable overrides using the `PF__` prefix. Configuration has been streamlined with top-level client configs and consistent camelCase naming:\n\n```yaml\n# Client Configurations - Top Level\ngoogleRoutes:\n  # apiKey set via PF__GOOGLE_ROUTES__API_KEY\n\nopenai:\n  # apiKey set via PF__OPENAI__API_KEY  \n  model: \"gpt-4o-mini\"\n  timeout: \"30s\"\n  maxRetries: 3\n\nopenweather:\n  # apiKey set via PF__OPENWEATHER__API_KEY\n\n# Service Configurations\nroads:\n  refreshInterval: \"5m\"\n  staleThreshold: \"10m\"\n  monitoredRoads:\n    - name: \"Hwy 4\"\n      section: \"Angels Camp to Murphys\"\n      id: \"hwy4-angels-murphys\"\n      origin:\n        latitude: 38.067400\n        longitude: -120.540200\n      destination:\n        latitude: 38.139117\n        longitude: -120.456111\n\nweather:\n  refreshInterval: \"5m\"\n  staleThreshold: \"10m\"\n  locations:\n    - id: \"murphys\"\n      name: \"Murphys, CA\"\n      coordinates:\n        latitude: 38.139117\n        longitude: -120.456111\n```\n\n## Deployment\n\nThe project includes built-in support for AWS ECR and ECS deployment:\n\n### AWS ECR/ECS Deployment\n\nSet the required environment variables:\n```bash\nexport DOCKER_REGISTRY=your-account-id.dkr.ecr.region.amazonaws.com\nexport ECS_CLUSTER=your-cluster-name\nexport ECS_SERVICE=your-service-name\nexport ECS_TASK_DEFINITION=your-task-definition-name\n```\n\nDeploy to ECS:\n```bash\n# Build, push to ECR, and deploy to ECS in one command\nmake ecs-deploy\n\n# Or run individual steps:\nmake ecr-push    # Build and push Docker image to ECR\nmake ecs-deploy  # Update ECS service with latest image\n```\n\n**What happens during deployment:**\n1. Builds Docker image for linux/amd64 platform\n2. Authenticates and pushes to ECR\n3. Updates ECS task definition with new image\n4. Triggers ECS service deployment\n5. Waits for deployment to complete\n\n**Prerequisites:**\n- AWS CLI configured with appropriate permissions\n- Docker installed locally\n- `jq` installed for JSON processing (`brew install jq`)\n\n## Development\n\n### Build Commands\n\n```bash\n# Build all binaries\nmake build\n\n# Build specific components\nmake server    # Main API server\nmake tools     # CLI testing tools\n\n# Generate protobuf code\nmake proto\n\n# Clean build artifacts\nmake clean\n```\n\n### Running the Server\n\n```bash\n# Run in foreground\nmake run\n\n# Run in background for testing\nmake run-bg\n\n# Stop background server\nmake stop\n```\n\n### Testing\n\n```bash\n# Run all tests\nmake test\n\n# Run specific test suites\nmake test-contract      # gRPC contract tests\nmake test-integration   # External API integration tests\nmake test-unit         # Unit tests\n\n# Test individual API clients\nmake test-google       # Test Google Routes API\nmake test-caltrans     # Test Caltrans KML parsing\nmake test-weather      # Test OpenWeatherMap API\n```\n\n### Code Quality\n\n```bash\n# Run linting\nmake lint\n\n# Format code\nmake fmt\n\n# Run both linting and tests\nmake lint \u0026\u0026 make test\n```\n\n### Project Structure\n\n```\n/\n├── api/v1/                     # Protocol Buffer definitions\n│   ├── roads.proto            # gRPC service for road conditions\n│   ├── weather.proto          # gRPC service for weather data\n│   └── common.proto           # Shared proto definitions\n├── cmd/                       # CLI applications\n│   ├── server/                # Main API server\n│   ├── test-google/           # Google Routes API testing tool\n│   ├── test-caltrans/         # Caltrans data testing tool\n│   └── test-weather/          # Weather API testing tool\n├── internal/                  # Private application code\n│   ├── services/              # gRPC service implementations\n│   ├── clients/               # External API clients\n│   ├── cache/                 # In-memory caching with TTL\n│   └── config/                # Configuration management\n├── tests/                     # Test support\n│   └── testdata/              # Static fixture data\n├── prefab.yaml                # Server configuration\n├── Dockerfile                 # Sample docker file\n└── Makefile                   # Build automation\n```\n\n### Adding New Roads\n\n1. Update `prefab.yaml` with new road coordinates (note the simplified structure):\n   ```yaml\n   roads:\n     monitoredRoads:  # Note: camelCase naming\n       - name: \"Highway Name\"\n         section: \"Start to End\"\n         id: \"unique-road-id\"\n         origin:\n           latitude: 0.0\n           longitude: 0.0\n         destination:\n           latitude: 0.0\n           longitude: 0.0\n   ```\n\n2. Test with the Google Routes API tool:\n   ```bash\n  make test-google\n   ```\n\n3. Restart the server to pick up configuration changes:\n   ```bash\n   make stop \u0026\u0026 make run-bg\n   ```\n\n### API Rate Limits\n\n- **Google Routes API**: 3,000 queries per minute\n- **OpenWeatherMap API**: 60 calls per minute (free tier)\n- **Caltrans KML Feeds**: No official limits, but feeds are refreshed every 5-30 minutes\n\n### Architecture\n\nThe server uses a hybrid architecture:\n\n- **gRPC Services**: Core business logic implemented as gRPC services\n- **HTTP Gateway**: Automatic REST API generation from gRPC definitions\n- **External Clients**: Dedicated clients for each external API\n- **Caching Layer**: In-memory cache with TTL for performance\n- **Configuration**: Prefab framework for flexible configuration management\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature/amazing-feature`)\n3. Make your changes following the existing code style\n4. Run tests and linting (`make lint \u0026\u0026 make test`)\n5. Commit your changes (`git commit -m 'Add amazing feature'`)\n6. Push to the branch (`git push origin feature/amazing-feature`)\n7. Open a Pull Request\n\n## Support\n\nFor questions, issues, or feature requests, please open an issue on the GitHub repository.\n\n## License\n\nMIT License\n\nCopyright (c) 2025 Daniel Pupius\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpup%2Finfo.ersn.net","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdpup%2Finfo.ersn.net","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpup%2Finfo.ersn.net/lists"}