From a365fd5f34b1810c099fcaa00a129ef3c60cad12 Mon Sep 17 00:00:00 2001 From: Sasiiiiiiiiiiiiii Date: Sat, 28 Feb 2026 02:34:22 +0100 Subject: [PATCH 1/7] feat: Add README.md --- README.md | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3176cd3..e66208b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,73 @@ # Chronodash -TODO: Add project README. +## Project Flow & Structure Info + +Chronodash is an Elixir/Phoenix application designed to provide web-based functionality and business logic handling. +The project follows a clear separation of concerns: + +1. **Configuration** – All environment-specific and runtime settings are under `config/`. +2. **Codebase** – Core Elixir modules live in `lib/`, split between backend logic (`chronodash`) and web interface (`chronodash_web`). +3. **Privileged Resources** – `priv/` holds static assets, database migrations, seeds, and translation files. +4. **Dockerization** – All container setup is located in `docker/` for easy deployment. +5. **Tests** – Test files are isolated under `test/` to validate modules and controllers (not detailed here). + +--- + +## Project Structure + +``` +. +├── AGENTS.md # Documentation or definition of system agents +├── Makefile # Make script to automate project tasks +├── README.md # Main project documentation +├── config # Application configuration files +│ ├── config.exs # General project configuration +│ ├── dev.exs # Development-specific configuration +│ ├── prod.exs # Production-specific configuration +│ ├── runtime.exs # Runtime-loaded configuration +│ └── test.exs # Test environment configuration +├── docker # Docker containerization files +│ ├── Dockerfile +│ ├── docker-compose.tel.yml +│ └── docker-compose.yml +├── lib # Main Elixir source code +│ ├── chronodash # Core business logic modules +│ │ ├── application.ex +│ │ ├── mailer.ex +│ │ └── repo.ex +│ ├── chronodash.ex # Main project entry point +│ ├── chronodash_web # Web (Phoenix) layer of the project +│ │ ├── controllers # Web controllers handling routes and requests +│ │ │ ├── error_json.ex +│ │ │ └── health_controller.ex +│ │ ├── endpoint.ex +│ │ ├── gettext.ex +│ │ ├── router.ex +│ │ └── telemetry.ex +│ └── chronodash_web.ex # Web module entry point +├── mix.exs # Mix configuration file (Elixir build tool) +├── mix.lock # Dependency lockfile +├── priv # Private application resources +│ ├── gettext # Translation files +│ │ ├── en +│ │ │ └── LC_MESSAGES +│ │ │ └── errors.po +│ │ └── errors.pot # Translation template file +│ ├── repo # Database-related files +│ │ ├── migrations +│ │ └── seeds.exs +│ ├── specs # Specification files +│ │ └── cronodash +│ │ └── openapi.json +│ └── static # Static assets served by Phoenix +│ ├── favicon.ico +│ └── robots.txt +└── test # Project test files + ├── chronodash_web + │ └── controllers + │ └── error_json_test.exs + ├── support + │ ├── conn_case.ex + │ └── data_case.ex + └── test_helper.exs +``` From b726c8a9a183adc58fe30c7a9ebe3bcd5e6afeb6 Mon Sep 17 00:00:00 2001 From: Sasiiiiiiiiiiiiii Date: Sat, 28 Feb 2026 12:43:09 +0100 Subject: [PATCH 2/7] docs: add md files --- CONTRIBUTING.md | 247 ++++++ README.md | 137 +++ SECURITY.md | 96 +++ priv/specs/cronodash/meteosix_api_v5.json | 962 ++++++++++++++++++++++ 4 files changed, 1442 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 priv/specs/cronodash/meteosix_api_v5.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b331381 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,247 @@ +# Contributing to Chronodash + +Thank you for taking the time to contribute to Chronodash 🚀 +Please read this guide before opening a PR to keep the codebase clean and consistent. + +--- + +## Table of Contents + +- [Development Setup](#development-setup) +- [Project Structure](#project-structure) +- [Branching Strategy](#branching-strategy) +- [Commit Convention](#commit-convention) +- [Pull Requests](#pull-requests) +- [Code Style](#code-style) +- [Testing](#testing) +- [Reporting Bugs](#reporting-bugs) + +--- + +## Development Setup + +### Prerequisites + +Make sure you have the following installed: + +- **Elixir** `~> 1.15` +- **PostgreSQL** (or use the included Docker setup) +- **Node.js** `>= 18` (for the frontend) + +### Steps + +1. **Clone the repository** + + ```bash + git clone + cd chronodash + ``` + +2. **Install Elixir dependencies** + + ```bash + mix deps.get + ``` + +3. **Configure environment variables** + + ```bash + cp .env.example .env + # Edit .env with your local database credentials + ``` + +4. **Start PostgreSQL with Docker (optional)** + + ```bash + docker compose up -d + ``` + +5. **Create and migrate the database** + + ```bash + mix ecto.setup + ``` + +6. **Start the backend server** + + ```bash + mix phx.server + # API available at http://localhost:4000 + ``` + +7. **Start the frontend** + ```bash + npm install + npm run dev + # App available at http://localhost:5173 + ``` + +--- + +## Project Structure + +``` +chronodash/ +├── lib/ +│ ├── chronodash/ # Business logic (Ash resources, contexts) +│ │ └── accounts/ # User authentication context +│ └── chronodash_web/ # Phoenix web layer +│ ├── controllers/ # API controllers +│ └── router.ex # Route definitions +├── priv/ +│ └── repo/migrations/ # Ecto database migrations +├── config/ # Environment configuration +└── test/ # Tests +``` + +--- + +## Branching Strategy + +Always branch off from `main`. Use descriptive names with the following prefixes: + +| Prefix | Use case | +| ----------- | ------------------------------------------ | +| `feat/` | New feature | +| `fix/` | Bug fix | +| `docs/` | Documentation only | +| `refactor/` | Code restructuring without behavior change | +| `test/` | Adding or updating tests | +| `chore/` | Maintenance, dependencies, config | + +**Examples:** + +``` +feat/user-registration-endpoint +fix/cors-preflight-headers +docs/update-security-policy +chore/update-ash-dependency +``` + +--- + +## Commit Convention + +We follow [Conventional Commits](https://www.conventionalcommits.org/). + +### Format + +``` +(): + +[optional body] +``` + +### Types + +| Type | When to use | +| ---------- | ------------------------------- | +| `feat` | A new feature | +| `fix` | A bug fix | +| `docs` | Documentation changes | +| `refactor` | Refactoring without feature/fix | +| `test` | Adding or updating tests | +| `chore` | Maintenance, deps, tooling | +| `perf` | Performance improvements | + +### Examples + +```bash +feat(auth): add user registration endpoint +fix(router): handle missing CORS preflight options +docs(contributing): add project structure section +chore(deps): update ash_postgres to 2.1 +``` + +--- + +## Pull Requests + +Before submitting a PR, make sure all of the following pass: + +```bash +# 1. All tests pass +mix test + +# 2. Code is properly formatted +mix format + +# 3. No unused dependencies +mix deps.unlock --unused + +# 4. Full precommit check (runs all of the above) +mix precommit +``` + +### PR Checklist + +- [ ] Branch is up to date with `main` +- [ ] `mix precommit` passes without errors +- [ ] New functionality has tests +- [ ] No secrets or credentials committed +- [ ] PR description explains **what** changed and **why** + +### PR Description Template + +``` +## What does this PR do? +Brief description of the change. + +## Why? +Context or motivation. + +## How to test it? +Steps to verify the change works. + +## Related issues +Closes # (if applicable) +``` + +--- + +## Code Style + +This project uses `mix format` for automatic formatting. Run it before every commit. + +Additional guidelines: + +- Keep functions small and focused — one responsibility per function +- Use descriptive variable and function names in English +- Add `@doc` comments to public functions in contexts and modules +- Avoid hardcoding values — use environment variables or config files +- In the frontend, keep components in `PascalCase` and utilities in `camelCase` + +--- + +## Testing + +Run the full test suite with: + +```bash +mix test +``` + +When adding new features: + +- Add unit tests for context functions (`Chronodash.Accounts`, etc.) +- Add controller tests for new API endpoints +- Test both the happy path and error cases (invalid input, missing fields, duplicate email, etc.) + +--- + +## Reporting Bugs + +Found a bug? Please check if it's already reported in the [issues](../../issues) before opening a new one. + +For **security vulnerabilities**, do NOT open a public issue — see [SECURITY.md](./SECURITY.md) instead. + +When opening a bug report, include: + +- What you expected to happen +- What actually happened +- Steps to reproduce +- Elixir/Node version and OS + +--- + +_We appreciate every contribution, big or small. Thanks for helping make Chronodash better!_ 🙌 diff --git a/README.md b/README.md index e66208b..55b6a96 100644 --- a/README.md +++ b/README.md @@ -71,3 +71,140 @@ The project follows a clear separation of concerns: │ └── data_case.ex └── test_helper.exs ``` + +# Dependencies + +This document lists all dependencies used in Chronodash, their purpose, and relevant version information. + +--- + +## Core Stack + +| Technology | Version | Purpose | +| -------------------------------------------------- | ---------- | ----------------------------- | +| [Elixir](https://elixir-lang.org/) | `~> 1.15` | Primary programming language | +| [Phoenix Framework](https://phoenixframework.org/) | `~> 1.8.1` | Web framework and API layer | +| [PostgreSQL](https://www.postgresql.org/) | latest | Primary relational database | +| [Docker](https://www.docker.com/) | latest | Local development environment | + +--- + +## Backend Dependencies + +### Framework & Web + +| Package | Version | Purpose | +| ------------------------------------------------------ | ---------- | ----------------------------------------------- | +| [`phoenix`](https://hex.pm/packages/phoenix) | `~> 1.8.1` | Web framework — routing, controllers, endpoints | +| [`bandit`](https://hex.pm/packages/bandit) | `~> 1.5` | HTTP server (replaces Cowboy) | +| [`phoenix_ecto`](https://hex.pm/packages/phoenix_ecto) | `~> 4.5` | Phoenix and Ecto integration | +| [`gettext`](https://hex.pm/packages/gettext) | `~> 0.26` | Internationalization and translations | + +### Data Layer + +| Package | Version | Purpose | +| ------------------------------------------------------ | ---------- | ------------------------------------------------- | +| [`ecto_sql`](https://hex.pm/packages/ecto_sql) | `~> 3.13` | SQL query interface for Ecto | +| [`postgrex`](https://hex.pm/packages/postgrex) | `>= 0.0.0` | PostgreSQL driver for Elixir | +| [`ash`](https://hex.pm/packages/ash) | `~> 3.0` | Resource-based framework for domain modeling | +| [`ash_postgres`](https://hex.pm/packages/ash_postgres) | `~> 2.0` | AshPostgres adapter — manages migrations and repo | +| [`ash_phoenix`](https://hex.pm/packages/ash_phoenix) | `~> 2.0` | Integration between Ash and Phoenix | + +### API & Documentation + +| Package | Version | Purpose | +| -------------------------------------------------------- | --------- | -------------------------------------------------------- | +| [`open_api_spex`](https://hex.pm/packages/open_api_spex) | `~> 3.16` | OpenAPI 3.0 spec generation and validation | +| [`jason`](https://hex.pm/packages/jason) | `~> 1.2` | Fast JSON encoding/decoding | +| [`cors_plug`](https://hex.pm/packages/cors_plug) | `~> 3.0` | CORS headers for cross-origin requests from the frontend | + +### HTTP & Networking + +| Package | Version | Purpose | +| ---------------------------------------------------- | ---------- | --------------------------------- | +| [`req`](https://hex.pm/packages/req) | `~> 0.5` | HTTP client for outgoing requests | +| [`dns_cluster`](https://hex.pm/packages/dns_cluster) | `~> 0.2.0` | DNS-based node clustering | + +### Observability + +| Package | Version | Purpose | +| -------------------------------------------------------------------------- | ---------- | -------------------------------------- | +| [`telemetry_metrics`](https://hex.pm/packages/telemetry_metrics) | `~> 1.0` | Metrics definitions and aggregation | +| [`telemetry_poller`](https://hex.pm/packages/telemetry_poller) | `~> 1.0` | Periodic VM and application metrics | +| [`phoenix_live_dashboard`](https://hex.pm/packages/phoenix_live_dashboard) | `~> 0.8.3` | Real-time metrics dashboard (dev/prod) | + +### Email + +| Package | Version | Purpose | +| ------------------------------------------ | --------- | ------------------------------ | +| [`swoosh`](https://hex.pm/packages/swoosh) | `~> 1.16` | Email composition and delivery | + +### Tooling & DX + +| Package | Version | Purpose | +| -------------------------------------------- | -------- | ------------------------------------------------------ | +| [`igniter`](https://hex.pm/packages/igniter) | `~> 0.3` | Code generation and project automation | +| [`credo`](https://hex.pm/packages/credo) | `~> 1.7` | Static code analysis and style enforcement (test only) | + +--- + +## Frontend Dependencies + +The frontend is a **React + TypeScript** application. Dependencies are managed via `npm`. + +| Package | Purpose | +| ------------ | --------------------------------- | +| `react` | UI library | +| `react-dom` | DOM rendering for React | +| `typescript` | Static typing for JavaScript | +| `vite` | Development server and build tool | + +> Run `npm install` to install all frontend dependencies. +> Full list available in `package.json`. + +--- + +## Development & Infrastructure + +| Tool | Purpose | +| ----------------------- | ------------------------------------------------ | +| Docker & Docker Compose | Runs PostgreSQL locally without a manual install | +| `.env` / `.env.example` | Environment variable management | + +--- + +## Updating Dependencies + +### Elixir + +```bash +# Check for outdated packages +mix hex.outdated + +# Update a specific package +mix deps.update + +# Update all packages +mix deps.update --all + +# Check for known vulnerabilities +mix hex.audit +``` + +### Frontend + +```bash +# Check for outdated packages +npm outdated + +# Update all packages +npm update +``` + +--- + +## Notes + +- **Ash Framework**: This project uses Ash (`~> 3.0`) as the primary domain layer. Migrations are managed by `AshPostgres` rather than plain Ecto — always use `mix ash_postgres.generate_migrations` when changing resources. +- **Bandit vs Cowboy**: This project uses `bandit` as the HTTP server. Do not add `plug_cowboy` as a dependency. +- **CORS**: Cross-origin requests from the React frontend (`localhost:5173`) are handled by `cors_plug` in the `:api` pipeline. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..95477bf --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,96 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | --------- | +| main | ✅ | +| older | ❌ | + +--- + +## Reporting a Vulnerability + +If you discover a security vulnerability in Chronodash, please **do NOT open a public issue**. Public disclosure before a fix is available puts all users at risk. + +Instead, report it through one of these two channels: + +- **GitHub Private Advisory** → [Open a security advisory](https://github.com/saulzascarballal/chronodash/security/advisories/new) +- **Email** → [saulzascarballal@gmail.com](mailto:saulzascarballal@gmail.com) + +Please include as much detail as possible: + +- Clear description of the vulnerability +- Steps to reproduce it +- Affected component (auth, API, database, etc.) +- Potential impact +- Suggested fix if you have one + +We will acknowledge receipt **within 48 hours** and aim to release a patch **within 7 days** for critical issues. + +--- + +## Security Scope + +The following areas are actively monitored and considered in scope: + +### 🔐 Authentication & Users + +- Unauthorized access to user accounts +- Password hashing weaknesses +- Session or token hijacking +- Brute force vulnerabilities on login endpoints + +### 🔑 API Keys & Tokens + +- Exposure of API keys or secrets in logs, responses, or source code +- Insufficient token expiration or revocation +- Tokens with overly broad permissions + +### 🗄️ Database + +- SQL injection or query manipulation +- Unauthorized access to user data +- Data leakage through API responses +- Insecure database configuration + +--- + +## Out of Scope + +The following are **not** considered security vulnerabilities for this project: + +- Issues in unsupported/older versions +- Bugs that require physical access to the server +- Social engineering attacks +- Denial of service (DoS) via excessive requests without proof of exploitability + +--- + +## Disclosure Policy + +We follow a **responsible disclosure** process: + +1. You report the vulnerability privately +2. We confirm and investigate within 48 hours +3. We develop and test a fix +4. We release the fix and credit you (if desired) +5. Public disclosure happens after the fix is deployed + +We genuinely appreciate the work of security researchers and will always credit contributors who report valid vulnerabilities responsibly. + +--- + +## Security Best Practices for Contributors + +If you are contributing to Chronodash, please follow these guidelines: + +- Never commit secrets, API keys, or credentials to the repository +- Use environment variables for all sensitive configuration (see `.env.example`) +- Validate and sanitize all user inputs +- Do not log sensitive data (passwords, tokens, personal data) +- Keep dependencies up to date — run `mix hex.audit` regularly + +--- + +_Last updated: February 2026_ diff --git a/priv/specs/cronodash/meteosix_api_v5.json b/priv/specs/cronodash/meteosix_api_v5.json new file mode 100644 index 0000000..c8af776 --- /dev/null +++ b/priv/specs/cronodash/meteosix_api_v5.json @@ -0,0 +1,962 @@ +{ + "api": { + "name": "MeteoSIX API", + "version": "v5", + "description": "Servizo web gratuito para acceso a información meteorolóxica e oceanográfica de MeteoGalicia.", + "base_url": "https://servizos.meteogalicia.gal/apiv5", + "methods": [ + "GET", + "POST" + ], + "authentication": { + "type": "api_key", + "parameter": "API_KEY", + "required": true, + "note": "Clave de uso privado, única por usuario. Non é necesario solicitar nova KEY para usuarios de v4." + }, + "general": { + "coordinate_system": "WGS84 (EPSG:4326)", + "coordinate_format": "longitude,latitude", + "date_format": "yyyy-MM-ddTHH:mm:ssZZ", + "date_format_input": "yyyy-MM-ddTHH:mm:ss", + "decimal_separator": ".", + "default_timezone": "Europe/Madrid", + "supported_languages": [ + "gl", + "es", + "en" + ], + "default_language": "en", + "max_locations_per_request": 20, + "response_formats": [ + "application/json", + "gml3", + "kml", + "text/html" + ], + "exception_formats": [ + "application/json", + "application/xml" + ], + "default_response_format": "application/json", + "default_exception_format": "application/json" + } + }, + "models": { + "WRF": { + "name": "Weather Research Forecast", + "type": "atmospheric", + "grids": { + "1km": { + "resolution": "1km", + "execution_start": "00:00 UTC", + "execution_end_approx": "07:30 UTC", + "first_forecast_hour": "01:00 UTC", + "forecast_horizon": "96h" + }, + "04km": { + "resolution": "4km", + "execution_start": [ + "00:00 UTC", + "12:00 UTC" + ], + "execution_end_approx": [ + "05:00 UTC", + "17:00 UTC" + ], + "first_forecast_hour": [ + "01:00 UTC", + "13:00 UTC" + ], + "forecast_horizon": [ + "96h", + "84h" + ] + }, + "12km": { + "resolution": "12km", + "execution_start": [ + "00:00 UTC", + "12:00 UTC" + ], + "execution_end_approx": [ + "05:00 UTC", + "17:00 UTC" + ], + "first_forecast_hour": [ + "01:00 UTC", + "13:00 UTC" + ], + "forecast_horizon": [ + "96h", + "84h" + ] + }, + "36km": { + "resolution": "36km", + "execution_start": [ + "00:00 UTC", + "12:00 UTC" + ], + "execution_end_approx": [ + "05:00 UTC", + "17:00 UTC" + ], + "first_forecast_hour": [ + "01:00 UTC", + "13:00 UTC" + ], + "forecast_horizon": [ + "96h", + "84h" + ] + } + } + }, + "WW3": { + "name": "Wave Watch III", + "type": "wave", + "grids": { + "Galicia": { + "resolution": "0.05°", + "execution_start": [ + "00:00 UTC", + "12:00 UTC" + ], + "execution_end_approx": [ + "05:00 UTC", + "17:00 UTC" + ], + "first_forecast_hour": [ + "12:00 UTC", + "00:00 UTC" + ], + "forecast_horizon": [ + "109h", + "97h" + ] + }, + "Iberica": { + "resolution": "0.25°", + "execution_start": [ + "00:00 UTC", + "12:00 UTC" + ], + "execution_end_approx": [ + "05:00 UTC", + "17:00 UTC" + ], + "first_forecast_hour": [ + "12:00 UTC", + "00:00 UTC" + ], + "forecast_horizon": [ + "109h", + "97h" + ] + }, + "AtlanticoNorte": { + "resolution": "0.5°", + "execution_start": [ + "00:00 UTC", + "12:00 UTC" + ], + "execution_end_approx": [ + "05:00 UTC", + "17:00 UTC" + ], + "first_forecast_hour": [ + "12:00 UTC", + "00:00 UTC" + ], + "forecast_horizon": [ + "109h", + "97h" + ] + } + } + }, + "ROMS": { + "name": "Regional Ocean Modeling System", + "type": "ocean", + "note_v5": "CORRECCIÓN v5: NO especificar grids para ROMS. El parámetro grids=Galicia devuelve error 316. Dejar que la API elija la mejor malla automáticamente.", + "grids_note": "No usar el parámetro grids con ROMS. Omitirlo y la API selecciona la malla óptima." + }, + "MOHID": { + "name": "MOHID", + "type": "ocean_coastal", + "grids": { + "Artabro": { + "resolution": "0.003°", + "execution_start": "00:00 UTC", + "execution_end_approx": "12:30 UTC", + "first_forecast_hour": "00:00 UTC", + "forecast_horizon": "49h" + }, + "Arousa": { + "resolution": "0.003°", + "execution_start": "00:00 UTC", + "execution_end_approx": "12:30 UTC", + "first_forecast_hour": "00:00 UTC", + "forecast_horizon": "49h" + }, + "Vigo": { + "resolution": "0.003°", + "execution_start": "00:00 UTC", + "execution_end_approx": "12:30 UTC", + "first_forecast_hour": "00:00 UTC", + "forecast_horizon": "49h" + } + }, + "note_v5": "ADVERTENCIA: MOHID puede devolver error 000 (fallo interno del servidor) de forma intermitente. Si ocurre, reintentar más tarde o usar ROMS como alternativa." + }, + "USWAN": { + "name": "Unstructured SWAN (Simulating Waves Nearshore)", + "type": "wave_nearshore", + "grids": { + "Galicia": { + "resolution": "Variable (malla no estructurada)", + "execution_start": "00:00 UTC", + "execution_end_approx": "06:30 UTC", + "first_forecast_hour": "00:00 UTC", + "forecast_horizon": "97h" + } + }, + "note_v5": "CORRECCIÓN v5: el modelo se llama USWAN, no SWAN. Usar models=USWAN en las peticiones." + } + }, + "endpoints": { + "/findPlaces": { + "description": "Busca lugares polo seu nome.", + "methods": [ + "GET", + "POST" + ], + "parameters": { + "API_KEY": { + "required": true, + "type": "string", + "description": "Clave da API" + }, + "location": { + "required": true, + "type": "string", + "description": "Cadea de texto para buscar (ex: 'oure', 'coru')" + }, + "types": { + "required": false, + "type": "string", + "description": "Tipos de lugar separados por comas", + "allowed_values": [ + "locality", + "beach" + ] + }, + "lang": { + "required": false, + "type": "string", + "default": "en", + "allowed_values": [ + "gl", + "es", + "en" + ] + }, + "format": { + "required": false, + "type": "string", + "default": "application/json", + "allowed_values": [ + "application/json", + "gml3", + "kml" + ] + }, + "exceptionsFormat": { + "required": false, + "type": "string", + "default": "application/json", + "allowed_values": [ + "application/json", + "application/xml" + ] + } + }, + "response": { + "type": "FeatureCollection", + "max_results": 1000, + "feature_attributes": [ + "id", + "name", + "municipality", + "province", + "type", + "geometry" + ] + }, + "place_types": { + "locality": "Entidades de poboación (Galicia)", + "beach": "Praias (Galicia)" + }, + "examples": [ + "https://servizos.meteogalicia.gal/apiv5/findPlaces?location=oure&API_KEY=***", + "https://servizos.meteogalicia.gal/apiv5/findPlaces?location=lanza&types=beach&API_KEY=***" + ] + }, + "/getNumericForecastInfo": { + "description": "Devolve información de predición numérica meteorolóxica e oceanográfica.", + "methods": [ + "GET", + "POST" + ], + "temporal_range": { + "max_days_per_request": 7, + "default_days": 7, + "min_date": "día actual", + "note": "Tense en conta a hora exacta nos parámetros startTime/endTime" + }, + "parameters": { + "API_KEY": { + "required": true, + "type": "string" + }, + "coords": { + "required": "one_of_coords_or_locationIds", + "type": "string", + "format": "lon1,lat1;lon2,lat2", + "max_points": 20, + "description": "Lista de pares lonxitude,latitude separados por punto e coma" + }, + "locationIds": { + "required": "one_of_coords_or_locationIds", + "type": "string", + "format": "id1,id2,id3", + "max_locations": 20, + "description": "IDs de lugares obtidos de /findPlaces" + }, + "startTime": { + "required": false, + "type": "string", + "format": "yyyy-MM-ddTHH:mm:ss", + "default": "instante actual" + }, + "endTime": { + "required": false, + "type": "string", + "format": "yyyy-MM-ddTHH:mm:ss", + "default": "máximo dispoñible (7 días)" + }, + "variables": { + "required": false, + "type": "string", + "default": "sky_state,temperature,wind,precipitation_amount", + "description": "Lista de variables separadas por comas" + }, + "models": { + "required": false, + "type": "string", + "description": "Lista de modelos separados por comas. Debe ter o mesmo número de elementos que variables. Cadea baleira = mellor dispoñible.", + "allowed_values": [ + "WRF", + "WW3", + "SWAN", + "ROMS", + "MOHID" + ] + }, + "grids": { + "required": false, + "type": "string", + "description": "Lista de mallas separadas por comas. Debe ter o mesmo número de elementos que variables." + }, + "units": { + "required": false, + "type": "string", + "description": "Lista de unidades separadas por comas. Debe ter o mesmo número de elementos que variables." + }, + "autoAdjustPosition": { + "required": false, + "type": "boolean", + "default": true, + "description": "Axuste automático de posición en puntos próximos á costa para predicións máis fiables." + }, + "lang": { + "required": false, + "type": "string", + "default": "en", + "allowed_values": [ + "gl", + "es", + "en" + ] + }, + "tz": { + "required": false, + "type": "string", + "default": "Europe/Madrid" + }, + "CRS": { + "required": false, + "type": "string", + "default": "EPSG:4326", + "allowed_values": [ + "EPSG:4326" + ] + }, + "format": { + "required": false, + "type": "string", + "default": "application/json", + "allowed_values": [ + "application/json", + "gml3", + "kml", + "text/html" + ] + }, + "exceptionsFormat": { + "required": false, + "type": "string", + "default": "application/json" + } + }, + "variables": { + "sky_state": { + "description": "Estado do ceo", + "models": [ + "WRF" + ], + "units": null, + "has_icon": true, + "possible_values": [ + "SUNNY", + "HIGH_CLOUDS", + "PARTLY_CLOUDY", + "OVERCAST", + "CLOUDY", + "FOG", + "SHOWERS", + "OVERCAST_AND_SHOWERS", + "INTERMITENT_SNOW", + "DRIZZLE", + "RAIN", + "SNOW", + "STORMS", + "MIST", + "FOG_BANK", + "MID_CLOUDS", + "WEAK_RAIN", + "WEAK_SHOWERS", + "STORM_THEN_CLOUDY", + "MELTED_SNOW", + "RAIN_HAIL" + ] + }, + "temperature": { + "description": "Temperatura", + "models": [ + "WRF" + ], + "value_type": "integer", + "units": [ + "degC", + "degK", + "degF" + ], + "default_unit": "degC", + "has_icon": false + }, + "precipitation_amount": { + "description": "Precipitación acumulada durante a hora anterior", + "models": [ + "WRF" + ], + "value_type": "real (2 decimais)", + "units": [ + "lm2" + ], + "default_unit": "lm2", + "has_icon": false + }, + "wind": { + "description": "Vento (módulo e dirección)", + "models": [ + "WRF" + ], + "value_type": "real (2 decimais)", + "units": [ + "kmh_deg", + "ms_deg", + "mph_deg", + "kt_deg" + ], + "default_unit": "kmh_deg", + "has_icon": true, + "note": "Devolve moduleValue e directionValue por separado" + }, + "relative_humidity": { + "description": "Humidade relativa", + "models": [ + "WRF" + ], + "value_type": "real (2 decimais)", + "units": [ + "perc" + ], + "default_unit": "perc", + "has_icon": false + }, + "cloud_area_fraction": { + "description": "Cobertura de nubes", + "models": [ + "WRF" + ], + "value_type": "real (2 decimais)", + "units": [ + "perc" + ], + "default_unit": "perc", + "has_icon": false + }, + "air_pressure_at_sea_level": { + "description": "Presión ao nivel do mar", + "models": [ + "WRF" + ], + "value_type": "integer", + "units": [ + "hpa", + "pa", + "atm" + ], + "default_unit": "hpa", + "has_icon": false + }, + "snow_level": { + "description": "Cota de neve", + "models": [ + "WRF" + ], + "value_type": "integer", + "units": [ + "m", + "ft" + ], + "default_unit": "m", + "has_icon": false + }, + "sea_water_temperature": { + "description": "Temperatura da auga", + "models": [ + "ROMS", + "MOHID" + ], + "value_type": "integer", + "units": [ + "degC", + "degK", + "degF" + ], + "default_unit": "degC", + "has_icon": false + }, + "significative_wave_height": { + "description": "Altura significativa de onda", + "models": [ + "WW3", + "USWAN" + ], + "value_type": "real (2 decimais)", + "units": [ + "m", + "ft" + ], + "default_unit": "m", + "has_icon": false + }, + "mean_wave_direction": { + "description": "Dirección do mar", + "models": [ + "WW3", + "USWAN" + ], + "value_type": "real (2 decimais)", + "units": [ + "deg" + ], + "default_unit": "deg", + "has_icon": true + }, + "relative_peak_period": { + "description": "Período de onda", + "models": [ + "WW3", + "USWAN" + ], + "value_type": "integer", + "units": [ + "s" + ], + "default_unit": "s", + "has_icon": false + }, + "sea_water_salinity": { + "description": "Salinidade da auga", + "models": [ + "ROMS", + "MOHID" + ], + "value_type": "real (2 decimais)", + "units": [ + "psu" + ], + "default_unit": "psu", + "has_icon": false + } + }, + "units_reference": { + "degC": "Graos Celsius (ºC)", + "degK": "Graos Kelvin (ºK)", + "degF": "Graos Fahrenheit (ºF)", + "kmh_deg": "Quilómetros por hora (km/h) – graos (º)", + "ms_deg": "Metros por segundo (m/s) – graos (º)", + "mph_deg": "Millas por hora (mph) – graos (º)", + "kt_deg": "Nós (kt) – graos (º)", + "m": "Metros (m)", + "ft": "Pés (ft)", + "lm2": "Litros por metro cadrado (l/m²)", + "perc": "Porcentaxe (%)", + "hpa": "Hectopascais (hPa)", + "pa": "Pascais (Pa)", + "atm": "Atmosferas (atm)", + "s": "Segundos (s)", + "deg": "Graos (º)", + "psu": "Unidades prácticas de salinidade (psu)" + }, + "examples": [ + "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?coords=-8.350573861318628,43.3697102138535&API_KEY=***", + "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?coords=-8.350573861318628,43.3697102138535&format=text/html&API_KEY=***", + "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?locationIds=42917&variables=temperature,temperature,sky_state&models=WRF,WRF,WRF&grids=04km,12km,36km&format=gml3&API_KEY=***" + ] + }, + "/getTidesInfo": { + "description": "Devolve información de mareas para puntos da costa galega.", + "methods": [ + "GET", + "POST" + ], + "temporal_range": { + "max_days_per_request": 30, + "max_future_days": 60, + "default_days": 5, + "note": "Só se ten en conta o día (non a hora) nos parámetros startTime/endTime" + }, + "parameters": { + "API_KEY": { + "required": true, + "type": "string" + }, + "coords": { + "required": "one_of_coords_or_locationIds", + "type": "string", + "format": "lon,lat;lon,lat" + }, + "locationIds": { + "required": "one_of_coords_or_locationIds", + "type": "string" + }, + "startTime": { + "required": false, + "type": "string", + "format": "yyyy-MM-ddTHH:mm:ss", + "note": "Só se usa a parte de data" + }, + "endTime": { + "required": false, + "type": "string", + "format": "yyyy-MM-ddTHH:mm:ss", + "note": "Só se usa a parte de data" + }, + "lang": { + "required": false, + "type": "string", + "default": "en" + }, + "tz": { + "required": false, + "type": "string", + "default": "Europe/Madrid" + }, + "format": { + "required": false, + "type": "string", + "default": "application/json" + }, + "exceptionsFormat": { + "required": false, + "type": "string", + "default": "application/json" + } + }, + "ports": [ + { + "id": 1, + "name": "A Coruña", + "is_reference_port": true + }, + { + "id": 3, + "name": "Vigo", + "is_reference_port": true + }, + { + "id": 4, + "name": "Vilagarcía", + "is_reference_port": true + }, + { + "id": 6, + "name": "Ría de Foz", + "is_reference_port": false + }, + { + "id": 7, + "name": "Corcubión", + "is_reference_port": false + }, + { + "id": 8, + "name": "Ría de Camariñas", + "is_reference_port": false + }, + { + "id": 9, + "name": "Ría de Corme", + "is_reference_port": false + }, + { + "id": 10, + "name": "A Guarda", + "is_reference_port": true + }, + { + "id": 11, + "name": "Ribeira", + "is_reference_port": false + }, + { + "id": 12, + "name": "Muros", + "is_reference_port": false + }, + { + "id": 13, + "name": "Pontevedra", + "is_reference_port": false + }, + { + "id": 14, + "name": "Ferrol Porto exterior", + "is_reference_port": true + }, + { + "id": 15, + "name": "Marín", + "is_reference_port": true + }, + { + "id": 16, + "name": "Ferrol", + "is_reference_port": true + }, + { + "id": 2, + "name": "Xixón", + "is_reference_port": true + } + ], + "response_data": { + "variable_name": "tides", + "units": "m", + "summary": { + "description": "Preamares e baixamares do día", + "fields": { + "id": "Identificador do dato (consecutivo desde 1)", + "state": "Estado: 'High tides' (preamar) ou 'Low tides' (baixamar)", + "timeInstant": "Hora da preamar/baixamar", + "height": "Altura en metros" + } + }, + "values": { + "description": "Altura de marea cada 30 minutos (do porto de referencia)", + "fields": { + "timeInstant": "Instante temporal", + "height": "Altura en metros" + } + } + }, + "examples": [ + "https://servizos.meteogalicia.gal/apiv5/getTidesInfo?coords=-8.637,43.45&API_KEY=***" + ] + }, + "/getSolarInfo": { + "description": "Devolve información sobre horas de saída e posta de sol para calquera punto do planeta.", + "methods": [ + "GET", + "POST" + ], + "temporal_range": { + "max_days_per_request": 365, + "max_future_days": 365, + "default_days": 5, + "note": "Só se ten en conta o día (non a hora) nos parámetros startTime/endTime" + }, + "parameters": { + "API_KEY": { + "required": true, + "type": "string" + }, + "coords": { + "required": "one_of_coords_or_locationIds", + "type": "string" + }, + "locationIds": { + "required": "one_of_coords_or_locationIds", + "type": "string" + }, + "startTime": { + "required": false, + "type": "string", + "format": "yyyy-MM-ddTHH:mm:ss", + "note": "Só se usa a parte de data" + }, + "endTime": { + "required": false, + "type": "string", + "format": "yyyy-MM-ddTHH:mm:ss", + "note": "Só se usa a parte de data" + }, + "lang": { + "required": false, + "type": "string", + "default": "en" + }, + "tz": { + "required": false, + "type": "string", + "default": "Europe/Madrid" + }, + "format": { + "required": false, + "type": "string", + "default": "application/json" + }, + "exceptionsFormat": { + "required": false, + "type": "string", + "default": "application/json" + } + }, + "response_data": { + "variable_name": "solar", + "fields": { + "sunrise": "Hora de saída do sol", + "midday": "Hora do mediodía (punto máis alto)", + "sunset": "Hora de posta do sol", + "duration": "Horas totais de luz (formato Xh Xm, ex: '9h 12m')" + }, + "note": "Non inclúe subelemento geometry xa que se usa o punto exacto solicitado" + }, + "examples": [ + "https://servizos.meteogalicia.gal/apiv5/getSolarInfo?coords=-8.350573861318628,43.3697102138535&API_KEY=***", + "https://servizos.meteogalicia.gal/apiv5/getSolarInfo?coords=-8.350573861318628,43.3697102138535&format=text/html&startTime=2014-03-07T00:00:00&endTime=2014-03-09T00:00:00&API_KEY=***" + ] + } + }, + "exceptions": { + "common": { + "000": "Erro interno da aplicación ou dalgún servidor de datos", + "001": "Non se obtivo a resposta dentro do tempo máximo", + "002": "Algún parámetro non existe ou está mal escrito", + "003": "Algún parámetro está duplicado", + "004": "Algún parámetro está baleiro", + "005": "Non se atopa o parámetro API_KEY", + "006": "A API_KEY non é válida", + "007": "O idioma indicado non existe ou non está soportado", + "008": "O parámetro format indica un formato non soportado", + "009": "O parámetro exceptionsFormat indica un formato non soportado", + "010": "O sistema de coordenadas non está soportado ou é inválido", + "011": "O estilo indicado non está soportado ou é inválido" + }, + "findPlaces": { + "100": "Non se especificou o valor do parámetro location", + "101": "O formato do parámetro types é inválido", + "102": "O parámetro types contén algún valor inválido" + }, + "getNumericForecastInfo_getTidesInfo_getSolarInfo": { + "200": "Non se especificou nin locationIds nin coords", + "201": "Especificáronse locationIds e coords ao mesmo tempo", + "202": "Indicáronse máis puntos dos permitidos (máximo 20)", + "203": "Algún valor do parámetro coords está baleiro", + "204": "Algún valor do parámetro locationIds está baleiro", + "205": "O formato do parámetro coords é inválido", + "206": "Algún valor de coords é inválido ou está mal escrito", + "207": "O formato do parámetro locationIds é inválido", + "208": "Algún valor de locationIds é inválido ou está mal escrito", + "209": "O formato dalgunha data é inválido (debe ser yyyy-MM-ddTHH:mm:ss)", + "210": "O formato do parámetro tz é inválido", + "211": "Non se atopou ningún lugar co identificador indicado", + "212": "O instante inicial é posterior ao instante final", + "213": "O instante inicial é anterior ao día actual", + "214": "O instante final é anterior ao día actual", + "215": "O intervalo de tempo especificado é demasiado grande", + "216": "Non hai datos para o intervalo temporal indicado", + "217": "O punto indicado cae fóra dos límites xeográficos para os que hai datos" + }, + "getNumericForecastInfo": { + "300": "O valor do parámetro variables non é válido", + "301": "O valor do parámetro models non é válido", + "302": "O valor do parámetro grids non é válido", + "303": "O valor do parámetro units non é válido", + "304": "O valor do parámetro autoAdjustPosition non é válido", + "305": "O valor das unidades para a variable wind non é válido", + "306": "O número de variables non é igual ao número de modelos", + "307": "O número de variables non é igual ao número de mallas", + "308": "O número de variables non é igual ao número de unidades", + "309": "Algunha das variables indicadas non existe", + "310": "Algún dos modelos indicados non existe", + "311": "Algunha das mallas indicadas non existe", + "312": "Algunha das unidades indicadas non existe", + "313": "Hai variables repetidas sen indicar modelos/mallas distintas", + "314": "Indicáronse valores para grids sen indicar o modelo correspondente", + "315": "Un dos modelos indicados non é aplicable para esa variable", + "316": "Unha das mallas indicadas non é aplicable para esa variable", + "317": "Unha das unidades indicadas non é aplicable para esa variable", + "318": "O parámetro endTime indica un instante anterior á hora actual; debe incluírse startTime", + "319": "O intervalo de tempo especificado é demasiado pequeno" + }, + "getTidesInfo": { + "400": "A información sobre os portos non está dispoñible" + } + }, + "v5_changes_from_v4": { + "incompatibilities": [ + { + "model": "WRF", + "description": "As mallas artabro1km, riasbaixas1km e norteportugal1km foron eliminadas e substituídas pola malla unificada '1km'. Actualizar peticións que usen eses valores de grid." + }, + { + "model": "SWAN", + "description": "O modelo SWAN con mallas Ártabro e Rías Baixas foi substituído polo modelo USWAN coa malla Galicia, con mellor resolución e cobertura de todo o litoral galego." + } + ], + "uswan_example": "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?coords=-8.393145,43.4372239&models=USWAN&variables=significative_wave_height&grids=Galicia&lang=gl&format=text/html&API_KEY=****", + "confirmed_by_tests": { + "SWAN_eliminated": "Confirmado: models=SWAN devuelve error 310. Usar USWAN.", + "ROMS_grid_Galicia_invalid": "Confirmado: grids=Galicia con ROMS devuelve error 316. Omitir grids.", + "WRF_artabro1km_eliminated": "Confirmado: grids=artabro1km devuelve error 311. Usar grids=1km.", + "HTML_KML_GML_formats_valid": "Confirmado: format=text/html, kml, gml3 funcionan correctamente (devuelven HTML/XML, no JSON).", + "WRF_36km_timeout": "Advertencia: malla 36km puede hacer timeout (>20s) por volumen de datos. Normal." + } + } +} From 1fd2ab6c8799d09a9f41f71dd8ac06ec13649dcc Mon Sep 17 00:00:00 2001 From: Sasiiiiiiiiiiiiii Date: Sat, 28 Feb 2026 12:56:20 +0100 Subject: [PATCH 3/7] fix: remove file and add vscode --- .gitignore | 3 + priv/specs/cronodash/meteosix_api_v5.json | 962 ---------------------- 2 files changed, 3 insertions(+), 962 deletions(-) delete mode 100644 priv/specs/cronodash/meteosix_api_v5.json diff --git a/.gitignore b/.gitignore index 8d53365..f134411 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,6 @@ chronodash-*.tar # Env files .env + +# VsCode files +.vscode/ diff --git a/priv/specs/cronodash/meteosix_api_v5.json b/priv/specs/cronodash/meteosix_api_v5.json deleted file mode 100644 index c8af776..0000000 --- a/priv/specs/cronodash/meteosix_api_v5.json +++ /dev/null @@ -1,962 +0,0 @@ -{ - "api": { - "name": "MeteoSIX API", - "version": "v5", - "description": "Servizo web gratuito para acceso a información meteorolóxica e oceanográfica de MeteoGalicia.", - "base_url": "https://servizos.meteogalicia.gal/apiv5", - "methods": [ - "GET", - "POST" - ], - "authentication": { - "type": "api_key", - "parameter": "API_KEY", - "required": true, - "note": "Clave de uso privado, única por usuario. Non é necesario solicitar nova KEY para usuarios de v4." - }, - "general": { - "coordinate_system": "WGS84 (EPSG:4326)", - "coordinate_format": "longitude,latitude", - "date_format": "yyyy-MM-ddTHH:mm:ssZZ", - "date_format_input": "yyyy-MM-ddTHH:mm:ss", - "decimal_separator": ".", - "default_timezone": "Europe/Madrid", - "supported_languages": [ - "gl", - "es", - "en" - ], - "default_language": "en", - "max_locations_per_request": 20, - "response_formats": [ - "application/json", - "gml3", - "kml", - "text/html" - ], - "exception_formats": [ - "application/json", - "application/xml" - ], - "default_response_format": "application/json", - "default_exception_format": "application/json" - } - }, - "models": { - "WRF": { - "name": "Weather Research Forecast", - "type": "atmospheric", - "grids": { - "1km": { - "resolution": "1km", - "execution_start": "00:00 UTC", - "execution_end_approx": "07:30 UTC", - "first_forecast_hour": "01:00 UTC", - "forecast_horizon": "96h" - }, - "04km": { - "resolution": "4km", - "execution_start": [ - "00:00 UTC", - "12:00 UTC" - ], - "execution_end_approx": [ - "05:00 UTC", - "17:00 UTC" - ], - "first_forecast_hour": [ - "01:00 UTC", - "13:00 UTC" - ], - "forecast_horizon": [ - "96h", - "84h" - ] - }, - "12km": { - "resolution": "12km", - "execution_start": [ - "00:00 UTC", - "12:00 UTC" - ], - "execution_end_approx": [ - "05:00 UTC", - "17:00 UTC" - ], - "first_forecast_hour": [ - "01:00 UTC", - "13:00 UTC" - ], - "forecast_horizon": [ - "96h", - "84h" - ] - }, - "36km": { - "resolution": "36km", - "execution_start": [ - "00:00 UTC", - "12:00 UTC" - ], - "execution_end_approx": [ - "05:00 UTC", - "17:00 UTC" - ], - "first_forecast_hour": [ - "01:00 UTC", - "13:00 UTC" - ], - "forecast_horizon": [ - "96h", - "84h" - ] - } - } - }, - "WW3": { - "name": "Wave Watch III", - "type": "wave", - "grids": { - "Galicia": { - "resolution": "0.05°", - "execution_start": [ - "00:00 UTC", - "12:00 UTC" - ], - "execution_end_approx": [ - "05:00 UTC", - "17:00 UTC" - ], - "first_forecast_hour": [ - "12:00 UTC", - "00:00 UTC" - ], - "forecast_horizon": [ - "109h", - "97h" - ] - }, - "Iberica": { - "resolution": "0.25°", - "execution_start": [ - "00:00 UTC", - "12:00 UTC" - ], - "execution_end_approx": [ - "05:00 UTC", - "17:00 UTC" - ], - "first_forecast_hour": [ - "12:00 UTC", - "00:00 UTC" - ], - "forecast_horizon": [ - "109h", - "97h" - ] - }, - "AtlanticoNorte": { - "resolution": "0.5°", - "execution_start": [ - "00:00 UTC", - "12:00 UTC" - ], - "execution_end_approx": [ - "05:00 UTC", - "17:00 UTC" - ], - "first_forecast_hour": [ - "12:00 UTC", - "00:00 UTC" - ], - "forecast_horizon": [ - "109h", - "97h" - ] - } - } - }, - "ROMS": { - "name": "Regional Ocean Modeling System", - "type": "ocean", - "note_v5": "CORRECCIÓN v5: NO especificar grids para ROMS. El parámetro grids=Galicia devuelve error 316. Dejar que la API elija la mejor malla automáticamente.", - "grids_note": "No usar el parámetro grids con ROMS. Omitirlo y la API selecciona la malla óptima." - }, - "MOHID": { - "name": "MOHID", - "type": "ocean_coastal", - "grids": { - "Artabro": { - "resolution": "0.003°", - "execution_start": "00:00 UTC", - "execution_end_approx": "12:30 UTC", - "first_forecast_hour": "00:00 UTC", - "forecast_horizon": "49h" - }, - "Arousa": { - "resolution": "0.003°", - "execution_start": "00:00 UTC", - "execution_end_approx": "12:30 UTC", - "first_forecast_hour": "00:00 UTC", - "forecast_horizon": "49h" - }, - "Vigo": { - "resolution": "0.003°", - "execution_start": "00:00 UTC", - "execution_end_approx": "12:30 UTC", - "first_forecast_hour": "00:00 UTC", - "forecast_horizon": "49h" - } - }, - "note_v5": "ADVERTENCIA: MOHID puede devolver error 000 (fallo interno del servidor) de forma intermitente. Si ocurre, reintentar más tarde o usar ROMS como alternativa." - }, - "USWAN": { - "name": "Unstructured SWAN (Simulating Waves Nearshore)", - "type": "wave_nearshore", - "grids": { - "Galicia": { - "resolution": "Variable (malla no estructurada)", - "execution_start": "00:00 UTC", - "execution_end_approx": "06:30 UTC", - "first_forecast_hour": "00:00 UTC", - "forecast_horizon": "97h" - } - }, - "note_v5": "CORRECCIÓN v5: el modelo se llama USWAN, no SWAN. Usar models=USWAN en las peticiones." - } - }, - "endpoints": { - "/findPlaces": { - "description": "Busca lugares polo seu nome.", - "methods": [ - "GET", - "POST" - ], - "parameters": { - "API_KEY": { - "required": true, - "type": "string", - "description": "Clave da API" - }, - "location": { - "required": true, - "type": "string", - "description": "Cadea de texto para buscar (ex: 'oure', 'coru')" - }, - "types": { - "required": false, - "type": "string", - "description": "Tipos de lugar separados por comas", - "allowed_values": [ - "locality", - "beach" - ] - }, - "lang": { - "required": false, - "type": "string", - "default": "en", - "allowed_values": [ - "gl", - "es", - "en" - ] - }, - "format": { - "required": false, - "type": "string", - "default": "application/json", - "allowed_values": [ - "application/json", - "gml3", - "kml" - ] - }, - "exceptionsFormat": { - "required": false, - "type": "string", - "default": "application/json", - "allowed_values": [ - "application/json", - "application/xml" - ] - } - }, - "response": { - "type": "FeatureCollection", - "max_results": 1000, - "feature_attributes": [ - "id", - "name", - "municipality", - "province", - "type", - "geometry" - ] - }, - "place_types": { - "locality": "Entidades de poboación (Galicia)", - "beach": "Praias (Galicia)" - }, - "examples": [ - "https://servizos.meteogalicia.gal/apiv5/findPlaces?location=oure&API_KEY=***", - "https://servizos.meteogalicia.gal/apiv5/findPlaces?location=lanza&types=beach&API_KEY=***" - ] - }, - "/getNumericForecastInfo": { - "description": "Devolve información de predición numérica meteorolóxica e oceanográfica.", - "methods": [ - "GET", - "POST" - ], - "temporal_range": { - "max_days_per_request": 7, - "default_days": 7, - "min_date": "día actual", - "note": "Tense en conta a hora exacta nos parámetros startTime/endTime" - }, - "parameters": { - "API_KEY": { - "required": true, - "type": "string" - }, - "coords": { - "required": "one_of_coords_or_locationIds", - "type": "string", - "format": "lon1,lat1;lon2,lat2", - "max_points": 20, - "description": "Lista de pares lonxitude,latitude separados por punto e coma" - }, - "locationIds": { - "required": "one_of_coords_or_locationIds", - "type": "string", - "format": "id1,id2,id3", - "max_locations": 20, - "description": "IDs de lugares obtidos de /findPlaces" - }, - "startTime": { - "required": false, - "type": "string", - "format": "yyyy-MM-ddTHH:mm:ss", - "default": "instante actual" - }, - "endTime": { - "required": false, - "type": "string", - "format": "yyyy-MM-ddTHH:mm:ss", - "default": "máximo dispoñible (7 días)" - }, - "variables": { - "required": false, - "type": "string", - "default": "sky_state,temperature,wind,precipitation_amount", - "description": "Lista de variables separadas por comas" - }, - "models": { - "required": false, - "type": "string", - "description": "Lista de modelos separados por comas. Debe ter o mesmo número de elementos que variables. Cadea baleira = mellor dispoñible.", - "allowed_values": [ - "WRF", - "WW3", - "SWAN", - "ROMS", - "MOHID" - ] - }, - "grids": { - "required": false, - "type": "string", - "description": "Lista de mallas separadas por comas. Debe ter o mesmo número de elementos que variables." - }, - "units": { - "required": false, - "type": "string", - "description": "Lista de unidades separadas por comas. Debe ter o mesmo número de elementos que variables." - }, - "autoAdjustPosition": { - "required": false, - "type": "boolean", - "default": true, - "description": "Axuste automático de posición en puntos próximos á costa para predicións máis fiables." - }, - "lang": { - "required": false, - "type": "string", - "default": "en", - "allowed_values": [ - "gl", - "es", - "en" - ] - }, - "tz": { - "required": false, - "type": "string", - "default": "Europe/Madrid" - }, - "CRS": { - "required": false, - "type": "string", - "default": "EPSG:4326", - "allowed_values": [ - "EPSG:4326" - ] - }, - "format": { - "required": false, - "type": "string", - "default": "application/json", - "allowed_values": [ - "application/json", - "gml3", - "kml", - "text/html" - ] - }, - "exceptionsFormat": { - "required": false, - "type": "string", - "default": "application/json" - } - }, - "variables": { - "sky_state": { - "description": "Estado do ceo", - "models": [ - "WRF" - ], - "units": null, - "has_icon": true, - "possible_values": [ - "SUNNY", - "HIGH_CLOUDS", - "PARTLY_CLOUDY", - "OVERCAST", - "CLOUDY", - "FOG", - "SHOWERS", - "OVERCAST_AND_SHOWERS", - "INTERMITENT_SNOW", - "DRIZZLE", - "RAIN", - "SNOW", - "STORMS", - "MIST", - "FOG_BANK", - "MID_CLOUDS", - "WEAK_RAIN", - "WEAK_SHOWERS", - "STORM_THEN_CLOUDY", - "MELTED_SNOW", - "RAIN_HAIL" - ] - }, - "temperature": { - "description": "Temperatura", - "models": [ - "WRF" - ], - "value_type": "integer", - "units": [ - "degC", - "degK", - "degF" - ], - "default_unit": "degC", - "has_icon": false - }, - "precipitation_amount": { - "description": "Precipitación acumulada durante a hora anterior", - "models": [ - "WRF" - ], - "value_type": "real (2 decimais)", - "units": [ - "lm2" - ], - "default_unit": "lm2", - "has_icon": false - }, - "wind": { - "description": "Vento (módulo e dirección)", - "models": [ - "WRF" - ], - "value_type": "real (2 decimais)", - "units": [ - "kmh_deg", - "ms_deg", - "mph_deg", - "kt_deg" - ], - "default_unit": "kmh_deg", - "has_icon": true, - "note": "Devolve moduleValue e directionValue por separado" - }, - "relative_humidity": { - "description": "Humidade relativa", - "models": [ - "WRF" - ], - "value_type": "real (2 decimais)", - "units": [ - "perc" - ], - "default_unit": "perc", - "has_icon": false - }, - "cloud_area_fraction": { - "description": "Cobertura de nubes", - "models": [ - "WRF" - ], - "value_type": "real (2 decimais)", - "units": [ - "perc" - ], - "default_unit": "perc", - "has_icon": false - }, - "air_pressure_at_sea_level": { - "description": "Presión ao nivel do mar", - "models": [ - "WRF" - ], - "value_type": "integer", - "units": [ - "hpa", - "pa", - "atm" - ], - "default_unit": "hpa", - "has_icon": false - }, - "snow_level": { - "description": "Cota de neve", - "models": [ - "WRF" - ], - "value_type": "integer", - "units": [ - "m", - "ft" - ], - "default_unit": "m", - "has_icon": false - }, - "sea_water_temperature": { - "description": "Temperatura da auga", - "models": [ - "ROMS", - "MOHID" - ], - "value_type": "integer", - "units": [ - "degC", - "degK", - "degF" - ], - "default_unit": "degC", - "has_icon": false - }, - "significative_wave_height": { - "description": "Altura significativa de onda", - "models": [ - "WW3", - "USWAN" - ], - "value_type": "real (2 decimais)", - "units": [ - "m", - "ft" - ], - "default_unit": "m", - "has_icon": false - }, - "mean_wave_direction": { - "description": "Dirección do mar", - "models": [ - "WW3", - "USWAN" - ], - "value_type": "real (2 decimais)", - "units": [ - "deg" - ], - "default_unit": "deg", - "has_icon": true - }, - "relative_peak_period": { - "description": "Período de onda", - "models": [ - "WW3", - "USWAN" - ], - "value_type": "integer", - "units": [ - "s" - ], - "default_unit": "s", - "has_icon": false - }, - "sea_water_salinity": { - "description": "Salinidade da auga", - "models": [ - "ROMS", - "MOHID" - ], - "value_type": "real (2 decimais)", - "units": [ - "psu" - ], - "default_unit": "psu", - "has_icon": false - } - }, - "units_reference": { - "degC": "Graos Celsius (ºC)", - "degK": "Graos Kelvin (ºK)", - "degF": "Graos Fahrenheit (ºF)", - "kmh_deg": "Quilómetros por hora (km/h) – graos (º)", - "ms_deg": "Metros por segundo (m/s) – graos (º)", - "mph_deg": "Millas por hora (mph) – graos (º)", - "kt_deg": "Nós (kt) – graos (º)", - "m": "Metros (m)", - "ft": "Pés (ft)", - "lm2": "Litros por metro cadrado (l/m²)", - "perc": "Porcentaxe (%)", - "hpa": "Hectopascais (hPa)", - "pa": "Pascais (Pa)", - "atm": "Atmosferas (atm)", - "s": "Segundos (s)", - "deg": "Graos (º)", - "psu": "Unidades prácticas de salinidade (psu)" - }, - "examples": [ - "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?coords=-8.350573861318628,43.3697102138535&API_KEY=***", - "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?coords=-8.350573861318628,43.3697102138535&format=text/html&API_KEY=***", - "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?locationIds=42917&variables=temperature,temperature,sky_state&models=WRF,WRF,WRF&grids=04km,12km,36km&format=gml3&API_KEY=***" - ] - }, - "/getTidesInfo": { - "description": "Devolve información de mareas para puntos da costa galega.", - "methods": [ - "GET", - "POST" - ], - "temporal_range": { - "max_days_per_request": 30, - "max_future_days": 60, - "default_days": 5, - "note": "Só se ten en conta o día (non a hora) nos parámetros startTime/endTime" - }, - "parameters": { - "API_KEY": { - "required": true, - "type": "string" - }, - "coords": { - "required": "one_of_coords_or_locationIds", - "type": "string", - "format": "lon,lat;lon,lat" - }, - "locationIds": { - "required": "one_of_coords_or_locationIds", - "type": "string" - }, - "startTime": { - "required": false, - "type": "string", - "format": "yyyy-MM-ddTHH:mm:ss", - "note": "Só se usa a parte de data" - }, - "endTime": { - "required": false, - "type": "string", - "format": "yyyy-MM-ddTHH:mm:ss", - "note": "Só se usa a parte de data" - }, - "lang": { - "required": false, - "type": "string", - "default": "en" - }, - "tz": { - "required": false, - "type": "string", - "default": "Europe/Madrid" - }, - "format": { - "required": false, - "type": "string", - "default": "application/json" - }, - "exceptionsFormat": { - "required": false, - "type": "string", - "default": "application/json" - } - }, - "ports": [ - { - "id": 1, - "name": "A Coruña", - "is_reference_port": true - }, - { - "id": 3, - "name": "Vigo", - "is_reference_port": true - }, - { - "id": 4, - "name": "Vilagarcía", - "is_reference_port": true - }, - { - "id": 6, - "name": "Ría de Foz", - "is_reference_port": false - }, - { - "id": 7, - "name": "Corcubión", - "is_reference_port": false - }, - { - "id": 8, - "name": "Ría de Camariñas", - "is_reference_port": false - }, - { - "id": 9, - "name": "Ría de Corme", - "is_reference_port": false - }, - { - "id": 10, - "name": "A Guarda", - "is_reference_port": true - }, - { - "id": 11, - "name": "Ribeira", - "is_reference_port": false - }, - { - "id": 12, - "name": "Muros", - "is_reference_port": false - }, - { - "id": 13, - "name": "Pontevedra", - "is_reference_port": false - }, - { - "id": 14, - "name": "Ferrol Porto exterior", - "is_reference_port": true - }, - { - "id": 15, - "name": "Marín", - "is_reference_port": true - }, - { - "id": 16, - "name": "Ferrol", - "is_reference_port": true - }, - { - "id": 2, - "name": "Xixón", - "is_reference_port": true - } - ], - "response_data": { - "variable_name": "tides", - "units": "m", - "summary": { - "description": "Preamares e baixamares do día", - "fields": { - "id": "Identificador do dato (consecutivo desde 1)", - "state": "Estado: 'High tides' (preamar) ou 'Low tides' (baixamar)", - "timeInstant": "Hora da preamar/baixamar", - "height": "Altura en metros" - } - }, - "values": { - "description": "Altura de marea cada 30 minutos (do porto de referencia)", - "fields": { - "timeInstant": "Instante temporal", - "height": "Altura en metros" - } - } - }, - "examples": [ - "https://servizos.meteogalicia.gal/apiv5/getTidesInfo?coords=-8.637,43.45&API_KEY=***" - ] - }, - "/getSolarInfo": { - "description": "Devolve información sobre horas de saída e posta de sol para calquera punto do planeta.", - "methods": [ - "GET", - "POST" - ], - "temporal_range": { - "max_days_per_request": 365, - "max_future_days": 365, - "default_days": 5, - "note": "Só se ten en conta o día (non a hora) nos parámetros startTime/endTime" - }, - "parameters": { - "API_KEY": { - "required": true, - "type": "string" - }, - "coords": { - "required": "one_of_coords_or_locationIds", - "type": "string" - }, - "locationIds": { - "required": "one_of_coords_or_locationIds", - "type": "string" - }, - "startTime": { - "required": false, - "type": "string", - "format": "yyyy-MM-ddTHH:mm:ss", - "note": "Só se usa a parte de data" - }, - "endTime": { - "required": false, - "type": "string", - "format": "yyyy-MM-ddTHH:mm:ss", - "note": "Só se usa a parte de data" - }, - "lang": { - "required": false, - "type": "string", - "default": "en" - }, - "tz": { - "required": false, - "type": "string", - "default": "Europe/Madrid" - }, - "format": { - "required": false, - "type": "string", - "default": "application/json" - }, - "exceptionsFormat": { - "required": false, - "type": "string", - "default": "application/json" - } - }, - "response_data": { - "variable_name": "solar", - "fields": { - "sunrise": "Hora de saída do sol", - "midday": "Hora do mediodía (punto máis alto)", - "sunset": "Hora de posta do sol", - "duration": "Horas totais de luz (formato Xh Xm, ex: '9h 12m')" - }, - "note": "Non inclúe subelemento geometry xa que se usa o punto exacto solicitado" - }, - "examples": [ - "https://servizos.meteogalicia.gal/apiv5/getSolarInfo?coords=-8.350573861318628,43.3697102138535&API_KEY=***", - "https://servizos.meteogalicia.gal/apiv5/getSolarInfo?coords=-8.350573861318628,43.3697102138535&format=text/html&startTime=2014-03-07T00:00:00&endTime=2014-03-09T00:00:00&API_KEY=***" - ] - } - }, - "exceptions": { - "common": { - "000": "Erro interno da aplicación ou dalgún servidor de datos", - "001": "Non se obtivo a resposta dentro do tempo máximo", - "002": "Algún parámetro non existe ou está mal escrito", - "003": "Algún parámetro está duplicado", - "004": "Algún parámetro está baleiro", - "005": "Non se atopa o parámetro API_KEY", - "006": "A API_KEY non é válida", - "007": "O idioma indicado non existe ou non está soportado", - "008": "O parámetro format indica un formato non soportado", - "009": "O parámetro exceptionsFormat indica un formato non soportado", - "010": "O sistema de coordenadas non está soportado ou é inválido", - "011": "O estilo indicado non está soportado ou é inválido" - }, - "findPlaces": { - "100": "Non se especificou o valor do parámetro location", - "101": "O formato do parámetro types é inválido", - "102": "O parámetro types contén algún valor inválido" - }, - "getNumericForecastInfo_getTidesInfo_getSolarInfo": { - "200": "Non se especificou nin locationIds nin coords", - "201": "Especificáronse locationIds e coords ao mesmo tempo", - "202": "Indicáronse máis puntos dos permitidos (máximo 20)", - "203": "Algún valor do parámetro coords está baleiro", - "204": "Algún valor do parámetro locationIds está baleiro", - "205": "O formato do parámetro coords é inválido", - "206": "Algún valor de coords é inválido ou está mal escrito", - "207": "O formato do parámetro locationIds é inválido", - "208": "Algún valor de locationIds é inválido ou está mal escrito", - "209": "O formato dalgunha data é inválido (debe ser yyyy-MM-ddTHH:mm:ss)", - "210": "O formato do parámetro tz é inválido", - "211": "Non se atopou ningún lugar co identificador indicado", - "212": "O instante inicial é posterior ao instante final", - "213": "O instante inicial é anterior ao día actual", - "214": "O instante final é anterior ao día actual", - "215": "O intervalo de tempo especificado é demasiado grande", - "216": "Non hai datos para o intervalo temporal indicado", - "217": "O punto indicado cae fóra dos límites xeográficos para os que hai datos" - }, - "getNumericForecastInfo": { - "300": "O valor do parámetro variables non é válido", - "301": "O valor do parámetro models non é válido", - "302": "O valor do parámetro grids non é válido", - "303": "O valor do parámetro units non é válido", - "304": "O valor do parámetro autoAdjustPosition non é válido", - "305": "O valor das unidades para a variable wind non é válido", - "306": "O número de variables non é igual ao número de modelos", - "307": "O número de variables non é igual ao número de mallas", - "308": "O número de variables non é igual ao número de unidades", - "309": "Algunha das variables indicadas non existe", - "310": "Algún dos modelos indicados non existe", - "311": "Algunha das mallas indicadas non existe", - "312": "Algunha das unidades indicadas non existe", - "313": "Hai variables repetidas sen indicar modelos/mallas distintas", - "314": "Indicáronse valores para grids sen indicar o modelo correspondente", - "315": "Un dos modelos indicados non é aplicable para esa variable", - "316": "Unha das mallas indicadas non é aplicable para esa variable", - "317": "Unha das unidades indicadas non é aplicable para esa variable", - "318": "O parámetro endTime indica un instante anterior á hora actual; debe incluírse startTime", - "319": "O intervalo de tempo especificado é demasiado pequeno" - }, - "getTidesInfo": { - "400": "A información sobre os portos non está dispoñible" - } - }, - "v5_changes_from_v4": { - "incompatibilities": [ - { - "model": "WRF", - "description": "As mallas artabro1km, riasbaixas1km e norteportugal1km foron eliminadas e substituídas pola malla unificada '1km'. Actualizar peticións que usen eses valores de grid." - }, - { - "model": "SWAN", - "description": "O modelo SWAN con mallas Ártabro e Rías Baixas foi substituído polo modelo USWAN coa malla Galicia, con mellor resolución e cobertura de todo o litoral galego." - } - ], - "uswan_example": "https://servizos.meteogalicia.gal/apiv5/getNumericForecastInfo?coords=-8.393145,43.4372239&models=USWAN&variables=significative_wave_height&grids=Galicia&lang=gl&format=text/html&API_KEY=****", - "confirmed_by_tests": { - "SWAN_eliminated": "Confirmado: models=SWAN devuelve error 310. Usar USWAN.", - "ROMS_grid_Galicia_invalid": "Confirmado: grids=Galicia con ROMS devuelve error 316. Omitir grids.", - "WRF_artabro1km_eliminated": "Confirmado: grids=artabro1km devuelve error 311. Usar grids=1km.", - "HTML_KML_GML_formats_valid": "Confirmado: format=text/html, kml, gml3 funcionan correctamente (devuelven HTML/XML, no JSON).", - "WRF_36km_timeout": "Advertencia: malla 36km puede hacer timeout (>20s) por volumen de datos. Normal." - } - } -} From f00cf1c83c08f6ad212969daa9900e9152f30e0a Mon Sep 17 00:00:00 2001 From: Sasiiiiiiiiiiiiii <146834593+Sasiiiiiiiiiiiiii@users.noreply.github.com> Date: Sat, 28 Feb 2026 13:00:54 +0100 Subject: [PATCH 4/7] fix. CONTRIBUTING.md --- CONTRIBUTING.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b331381..e92907c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,8 +26,6 @@ Make sure you have the following installed: - **Elixir** `~> 1.15` - **PostgreSQL** (or use the included Docker setup) -- **Node.js** `>= 18` (for the frontend) - ### Steps 1. **Clone the repository** @@ -69,13 +67,6 @@ Make sure you have the following installed: # API available at http://localhost:4000 ``` -7. **Start the frontend** - ```bash - npm install - npm run dev - # App available at http://localhost:5173 - ``` - --- ## Project Structure From a4d1dd1b5768d320bdd53cbe51cd0e48e658fa35 Mon Sep 17 00:00:00 2001 From: Sasiiiiiiiiiiiiii <146834593+Sasiiiiiiiiiiiiii@users.noreply.github.com> Date: Sat, 28 Feb 2026 13:03:20 +0100 Subject: [PATCH 5/7] fix: SECURITY.md --- SECURITY.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 95477bf..b0ebf16 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -34,20 +34,20 @@ We will acknowledge receipt **within 48 hours** and aim to release a patch **wit The following areas are actively monitored and considered in scope: -### 🔐 Authentication & Users +### Authentication & Users - Unauthorized access to user accounts - Password hashing weaknesses - Session or token hijacking - Brute force vulnerabilities on login endpoints -### 🔑 API Keys & Tokens +### API Keys & Tokens - Exposure of API keys or secrets in logs, responses, or source code - Insufficient token expiration or revocation - Tokens with overly broad permissions -### 🗄️ Database +### Database - SQL injection or query manipulation - Unauthorized access to user data From c5446d2c0eeda24464929ce3209ee00dafc7a8d5 Mon Sep 17 00:00:00 2001 From: Sasiiiiiiiiiiiiii <146834593+Sasiiiiiiiiiiiiii@users.noreply.github.com> Date: Sat, 28 Feb 2026 13:30:58 +0100 Subject: [PATCH 6/7] fix: README.md --- README.md | 112 +++++++++++++++++++++--------------------------------- 1 file changed, 43 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index 55b6a96..61ac3fa 100644 --- a/README.md +++ b/README.md @@ -80,12 +80,12 @@ This document lists all dependencies used in Chronodash, their purpose, and rele ## Core Stack -| Technology | Version | Purpose | -| -------------------------------------------------- | ---------- | ----------------------------- | -| [Elixir](https://elixir-lang.org/) | `~> 1.15` | Primary programming language | -| [Phoenix Framework](https://phoenixframework.org/) | `~> 1.8.1` | Web framework and API layer | -| [PostgreSQL](https://www.postgresql.org/) | latest | Primary relational database | -| [Docker](https://www.docker.com/) | latest | Local development environment | +| Technology | Version | Purpose | +|------------|---------|---------| +| [Elixir](https://elixir-lang.org/) | `~> 1.15` | Primary programming language | +| [Phoenix Framework](https://phoenixframework.org/) | `~> 1.8.1` | Web framework and API layer | +| [PostgreSQL](https://www.postgresql.org/) | latest | Primary relational database | +| [Docker](https://www.docker.com/) | latest | Local development environment | --- @@ -93,83 +93,67 @@ This document lists all dependencies used in Chronodash, their purpose, and rele ### Framework & Web -| Package | Version | Purpose | -| ------------------------------------------------------ | ---------- | ----------------------------------------------- | -| [`phoenix`](https://hex.pm/packages/phoenix) | `~> 1.8.1` | Web framework — routing, controllers, endpoints | -| [`bandit`](https://hex.pm/packages/bandit) | `~> 1.5` | HTTP server (replaces Cowboy) | -| [`phoenix_ecto`](https://hex.pm/packages/phoenix_ecto) | `~> 4.5` | Phoenix and Ecto integration | -| [`gettext`](https://hex.pm/packages/gettext) | `~> 0.26` | Internationalization and translations | +| Package | Version | Purpose | License | +|---------|---------|---------|---------| +| [`phoenix`](https://hex.pm/packages/phoenix) | `~> 1.8.1` | Web framework — routing, controllers, endpoints | MIT | +| [`bandit`](https://hex.pm/packages/bandit) | `~> 1.5` | HTTP server (replaces Cowboy) | MIT | +| [`phoenix_ecto`](https://hex.pm/packages/phoenix_ecto) | `~> 4.5` | Phoenix and Ecto integration | MIT | +| [`gettext`](https://hex.pm/packages/gettext) | `~> 0.26` | Internationalization and translations | MIT | ### Data Layer -| Package | Version | Purpose | -| ------------------------------------------------------ | ---------- | ------------------------------------------------- | -| [`ecto_sql`](https://hex.pm/packages/ecto_sql) | `~> 3.13` | SQL query interface for Ecto | -| [`postgrex`](https://hex.pm/packages/postgrex) | `>= 0.0.0` | PostgreSQL driver for Elixir | -| [`ash`](https://hex.pm/packages/ash) | `~> 3.0` | Resource-based framework for domain modeling | -| [`ash_postgres`](https://hex.pm/packages/ash_postgres) | `~> 2.0` | AshPostgres adapter — manages migrations and repo | -| [`ash_phoenix`](https://hex.pm/packages/ash_phoenix) | `~> 2.0` | Integration between Ash and Phoenix | +| Package | Version | Purpose | License | +|---------|---------|---------|---------| +| [`ecto_sql`](https://hex.pm/packages/ecto_sql) | `~> 3.13` | SQL query interface for Ecto | Apache 2.0 | +| [`postgrex`](https://hex.pm/packages/postgrex) | `>= 0.0.0` | PostgreSQL driver for Elixir | Apache 2.0 | +| [`ash`](https://hex.pm/packages/ash) | `~> 3.0` | Resource-based framework for domain modeling | MIT | +| [`ash_postgres`](https://hex.pm/packages/ash_postgres) | `~> 2.0` | AshPostgres adapter — manages migrations and repo | MIT | +| [`ash_phoenix`](https://hex.pm/packages/ash_phoenix) | `~> 2.0` | Integration between Ash and Phoenix | MIT | ### API & Documentation -| Package | Version | Purpose | -| -------------------------------------------------------- | --------- | -------------------------------------------------------- | -| [`open_api_spex`](https://hex.pm/packages/open_api_spex) | `~> 3.16` | OpenAPI 3.0 spec generation and validation | -| [`jason`](https://hex.pm/packages/jason) | `~> 1.2` | Fast JSON encoding/decoding | -| [`cors_plug`](https://hex.pm/packages/cors_plug) | `~> 3.0` | CORS headers for cross-origin requests from the frontend | +| Package | Version | Purpose | License | +|---------|---------|---------|---------| +| [`open_api_spex`](https://hex.pm/packages/open_api_spex) | `~> 3.16` | OpenAPI 3.0 spec generation and validation | MIT | +| [`jason`](https://hex.pm/packages/jason) | `~> 1.2` | Fast JSON encoding/decoding | Apache 2.0 | +| [`cors_plug`](https://hex.pm/packages/cors_plug) | `~> 3.0` | CORS headers for cross-origin requests from the frontend | MIT | ### HTTP & Networking -| Package | Version | Purpose | -| ---------------------------------------------------- | ---------- | --------------------------------- | -| [`req`](https://hex.pm/packages/req) | `~> 0.5` | HTTP client for outgoing requests | -| [`dns_cluster`](https://hex.pm/packages/dns_cluster) | `~> 0.2.0` | DNS-based node clustering | +| Package | Version | Purpose | License | +|---------|---------|---------|---------| +| [`req`](https://hex.pm/packages/req) | `~> 0.5` | HTTP client for outgoing requests | Apache 2.0 | +| [`dns_cluster`](https://hex.pm/packages/dns_cluster) | `~> 0.2.0` | DNS-based node clustering | Apache 2.0 | ### Observability -| Package | Version | Purpose | -| -------------------------------------------------------------------------- | ---------- | -------------------------------------- | -| [`telemetry_metrics`](https://hex.pm/packages/telemetry_metrics) | `~> 1.0` | Metrics definitions and aggregation | -| [`telemetry_poller`](https://hex.pm/packages/telemetry_poller) | `~> 1.0` | Periodic VM and application metrics | -| [`phoenix_live_dashboard`](https://hex.pm/packages/phoenix_live_dashboard) | `~> 0.8.3` | Real-time metrics dashboard (dev/prod) | +| Package | Version | Purpose | License | +|---------|---------|---------|---------| +| [`telemetry_metrics`](https://hex.pm/packages/telemetry_metrics) | `~> 1.0` | Metrics definitions and aggregation | Apache 2.0 | +| [`telemetry_poller`](https://hex.pm/packages/telemetry_poller) | `~> 1.0` | Periodic VM and application metrics | Apache 2.0 | +| [`phoenix_live_dashboard`](https://hex.pm/packages/phoenix_live_dashboard) | `~> 0.8.3` | Real-time metrics dashboard (dev/prod) | MIT | ### Email -| Package | Version | Purpose | -| ------------------------------------------ | --------- | ------------------------------ | -| [`swoosh`](https://hex.pm/packages/swoosh) | `~> 1.16` | Email composition and delivery | +| Package | Version | Purpose | License | +|---------|---------|---------|---------| +| [`swoosh`](https://hex.pm/packages/swoosh) | `~> 1.16` | Email composition and delivery | MIT | ### Tooling & DX -| Package | Version | Purpose | -| -------------------------------------------- | -------- | ------------------------------------------------------ | -| [`igniter`](https://hex.pm/packages/igniter) | `~> 0.3` | Code generation and project automation | -| [`credo`](https://hex.pm/packages/credo) | `~> 1.7` | Static code analysis and style enforcement (test only) | - ---- - -## Frontend Dependencies - -The frontend is a **React + TypeScript** application. Dependencies are managed via `npm`. - -| Package | Purpose | -| ------------ | --------------------------------- | -| `react` | UI library | -| `react-dom` | DOM rendering for React | -| `typescript` | Static typing for JavaScript | -| `vite` | Development server and build tool | - -> Run `npm install` to install all frontend dependencies. -> Full list available in `package.json`. +| Package | Version | Purpose | License | +|---------|---------|---------|---------| +| [`igniter`](https://hex.pm/packages/igniter) | `~> 0.3` | Code generation and project automation | MIT | +| [`credo`](https://hex.pm/packages/credo) | `~> 1.7` | Static code analysis and style enforcement (test only) | MIT | --- ## Development & Infrastructure -| Tool | Purpose | -| ----------------------- | ------------------------------------------------ | +| Tool | Purpose | +|------|---------| | Docker & Docker Compose | Runs PostgreSQL locally without a manual install | -| `.env` / `.env.example` | Environment variable management | +| `.env` / `.env.example` | Environment variable management | --- @@ -191,16 +175,6 @@ mix deps.update --all mix hex.audit ``` -### Frontend - -```bash -# Check for outdated packages -npm outdated - -# Update all packages -npm update -``` - --- ## Notes From c158c2480f4e2cdeefc1591ef0f0c8527491628c Mon Sep 17 00:00:00 2001 From: Sasiiiiiiiiiiiiii <146834593+Sasiiiiiiiiiiiiii@users.noreply.github.com> Date: Sat, 28 Feb 2026 13:48:00 +0100 Subject: [PATCH 7/7] fix: README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 61ac3fa..ead61e3 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,6 @@ This document lists all dependencies used in Chronodash, their purpose, and rele |---------|---------|---------|---------| | [`open_api_spex`](https://hex.pm/packages/open_api_spex) | `~> 3.16` | OpenAPI 3.0 spec generation and validation | MIT | | [`jason`](https://hex.pm/packages/jason) | `~> 1.2` | Fast JSON encoding/decoding | Apache 2.0 | -| [`cors_plug`](https://hex.pm/packages/cors_plug) | `~> 3.0` | CORS headers for cross-origin requests from the frontend | MIT | ### HTTP & Networking @@ -181,4 +180,3 @@ mix hex.audit - **Ash Framework**: This project uses Ash (`~> 3.0`) as the primary domain layer. Migrations are managed by `AshPostgres` rather than plain Ecto — always use `mix ash_postgres.generate_migrations` when changing resources. - **Bandit vs Cowboy**: This project uses `bandit` as the HTTP server. Do not add `plug_cowboy` as a dependency. -- **CORS**: Cross-origin requests from the React frontend (`localhost:5173`) are handled by `cors_plug` in the `:api` pipeline.