{"id":31097387,"url":"https://github.com/mjanez/metadata-quality-react","last_synced_at":"2026-06-14T21:31:15.795Z","repository":{"id":317728365,"uuid":"1060214541","full_name":"mjanez/metadata-quality-react","owner":"mjanez","description":"Web app for evaluating the quality of RDF metadata based on the EDP's MQA methodology. It supports DCAT-AP, DCAT-AP-ES and NTI-RISP (Spanish DCAT). Built with React and TypeScript. It is easily deployable to GitHub Pages.","archived":false,"fork":false,"pushed_at":"2026-05-12T08:33:36.000Z","size":5724,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-12T09:35:25.666Z","etag":null,"topics":["dcat-ap","dcat-ap-es","docker","docker-compose","metadata","metadata-quality","mqa","nti-risp","open-data","rdf","rdf-streaming-parser","react","shacl","shacl-engine","ttl"],"latest_commit_sha":null,"homepage":"https://metadata-quality.mjanez.dev/","language":"TypeScript","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/mjanez.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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-19T14:51:48.000Z","updated_at":"2026-02-09T12:13:00.000Z","dependencies_parsed_at":null,"dependency_job_id":"7deaf853-f2bc-46b8-930e-6a5448b331bb","html_url":"https://github.com/mjanez/metadata-quality-react","commit_stats":null,"previous_names":["mjanez/metadata-quality-react"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mjanez/metadata-quality-react","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjanez%2Fmetadata-quality-react","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjanez%2Fmetadata-quality-react/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjanez%2Fmetadata-quality-react/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjanez%2Fmetadata-quality-react/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mjanez","download_url":"https://codeload.github.com/mjanez/metadata-quality-react/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mjanez%2Fmetadata-quality-react/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34339192,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"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":["dcat-ap","dcat-ap-es","docker","docker-compose","metadata","metadata-quality","mqa","nti-risp","open-data","rdf","rdf-streaming-parser","react","shacl","shacl-engine","ttl"],"created_at":"2025-09-16T19:46:53.526Z","updated_at":"2026-06-14T21:31:15.756Z","avatar_url":"https://github.com/mjanez.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Metadata Quality Assessment Tool - WebApp\n\n\u003e [!TIP]\n\u003e **Live Demo**: [https://metadata-quality.mjanez.dev/](https://metadata-quality.mjanez.dev/)\n\nA modern web application for evaluating RDF metadata quality based on FAIR+C principles, built with [React](https://es.react.dev/) + [TypeScript](https://www.typescriptlang.org/docs/).\n\n## Features\n\u003e [!TIP]\n\u003e **For Docker Compose deployment with backend support see**: [Docker](#docker-full-stack---self-hosted)\n\n- **Complete [MQA](https://data.europa.eu/mqa/methodology) evaluation** with real metrics for [DCAT-AP](https://semiceu.github.io/DCAT-AP/), [DCAT-AP-ES](https://datosgobes.github.io/DCAT-AP-ES/) and [NTI-RISP](https://datosgobes.github.io/NTI-RISP/)\n- **Data Quality Analysis** [ISO/IEC 25012](https://iso25000.com/index.php/en/iso-25000-standards/iso-25012)-based assessment for `CSV`/`JSON` distributions (*Only backend enabled*)\n- **Multi-format support** `RDF/XML`, `Turtle`, `JSON-LD`, `N-Triples`, `GeoJSON` with auto-detection\n- **Remote URL processing** to validate online datasets (*Full option only if backend enabled*)\n- **SPARQL endpoint integration** with predefined queries for data portals\n- **Dashboard** for monitoring and managing metadata quality results.\n- **Interactive visualization** with [FAIR+C](https://www.go-fair.org/fair-principles/) radar charts and detailed tables\n- **Controlled [vocabularies](/public/data/)** integrated (formats, licenses, access rights, etc.) from [data.europa.eu](https://gitlab.com/dataeuropa/vocabularies)\n- **Responsive interface** with [Bootstrap 5](https://getbootstrap.com/docs/5.0/) and modern components\n- **Full TypeScript** for safe and maintainable development\n\n![IMG 1](./docs/img/validation-1.png)\n![IMG 2](./docs/img/validation-2.png)\n![IMG 3](./docs/img/validation-3.png)\n![IMG 4](./docs/img/dashboard-1.png)\n\n## Table of Contents\n\n- [Tech Stack](#-tech-stack)\n- [Quick Start](#-quick-start)\n- [Configuration](#-configuration)\n  - [MQA Profiles](#mqa-profiles)\n  - [Quality Metrics](#quality-metrics)\n  - [SPARQL Configuration](#sparql-configuration)\n- [Development](#-development)\n- [Deployment](#-deployment)\n  - [Docker](#docker-full-stack---self-hosted)\n  - [GitHub Pages](#github-pages-frontend-only)\n- [Backend API](#backend-api)\n- [Architecture](#-architecture)\n- [Internationalization](#-internationalization)\n- [Theming](#-theming)\n- [Troubleshooting](#-troubleshooting)\n\n## Tech Stack\n\n| Technology | Version | Purpose |\n|------------|---------|---------|\n| [**React**](https://github.com/facebook/react) | 19.1.10 | UI framework with modern hooks |\n| [**TypeScript**](https://github.com/microsoft/TypeScript) | 4.9.5 | Static typing and safe development |\n| [**N3.js**](https://github.com/rdfjs/N3.js) | 1.26.0 | RDF parsing and manipulation |\n| [**rdfxml-streaming-parser**](https://github.com/rdfjs/rdfxml-streaming-parser.js) | 3.1.0 | RDF/XML → Turtle conversion |\n| [**shacl-engine**](https://github.com/rdf-ext/shacl-engine) | 1.0.2 | A fast RDF/JS SHACL engine includes SHACL SPARQL-based Constraints |\n| [**Bootstrap**](https://github.com/twbs/bootstrap) | 5.3.7 | Responsive CSS framework |\n| [**Chart.js**](https://github.com/chartjs/Chart.js) | 4.5.0 | Radar charts visualization |\n| [**react-i18next**](https://github.com/i18next/react-i18next) | Latest | Internationalization support |\n| [**gh-pages**](https://github.com/tschaub/gh-pages) | 6.3.0 | Automated GitHub Pages deployment |\n\n## Quick Start\n\n### Quick deployment (Docker Compose)\n\n**Prerequisites**: [Docker and Docker Compose](https://docs.docker.com/get-started/get-docker/) installed\n\n```bash\n# Clone repository\ngit clone https://github.com/mjanez/metadata-quality-react.git\ncd metadata-quality-react\n\n# Start with pre-built image from GHCR\ndocker compose up -d\n\n# Or build locally\nIMAGE_TAG=local docker compose up -d --build\n```\n\n\u003e [!TIP]\n\u003e Application will be available at: **https://localhost:443** (HTTP auto-redirects to HTTPS)\n\u003e - Frontend: https://localhost:443\n\u003e - Backend API: https://localhost:443/api/health\n\n### Development Setup\n\n**Prerequisites**: Node.js \u003e= 16.x, npm \u003e= 8.x\n\n```bash\n# Quick start (both frontend and backend)\n./dev-start.sh\n\n# Or manually:\n# Install dependencies\nnpm install\n\n# Start development server (frontend only)\nnpm start\n\n# Optional: Start backend server (in separate terminal)\ncd backend\nnpm i \u0026\u0026 npm start\n```\n\n\u003e [!TIP]\n\u003e Development servers:\n\u003e - Frontend: **http://localhost:3000**\n\u003e - Backend API: **http://localhost:3001/api/health**\n\n## Configuration\n\nThe application is configured through the `src/config/mqa-config.json` file, which centralizes all settings for profiles, metrics, and SPARQL endpoints. This configuration file follows a structured approach to support multiple metadata standards and quality assessment methodologies.\n\n### MQA Profiles\n\nProfiles define the metadata standards (DCAT-AP, DCAT-AP-ES, NTI-RISP) with their specific versions and validation rules.\n\n#### Profile Structure\n\n```json\n{\n  \"profiles\": {\n    \"profile_id\": {\n      \"versions\": {\n        \"version_number\": {\n          \"name\": \"Display Name\",\n          \"maxScore\": 405,\n          \"icon\": \"img/icons/icon.svg\",\n          \"url\": \"https://profile-documentation-url\",\n          \"sampleUrl\": \"https://sample-data-url\",\n          \"shaclFiles\": [\n            \"https://shacl-validation-file-1.ttl\",\n            \"https://shacl-validation-file-2.ttl\"\n          ],\n          \"dimensions\": {\n            \"findability\": { \"maxScore\": 100 },\n            \"accessibility\": { \"maxScore\": 100 },\n            \"interoperability\": { \"maxScore\": 110 },\n            \"reusability\": { \"maxScore\": 75 },\n            \"contextuality\": { \"maxScore\": 20 }\n          }\n        }\n      },\n      \"defaultVersion\": \"version_number\"\n    }\n  }\n}\n```\n\n#### Adding a New Profile\n\n1. **Create the profile structure** in `mqa-config.json`:\n```json\n\"my_custom_profile\": {\n  \"versions\": {\n    \"1.0.0\": {\n      \"name\": \"My Custom Profile 1.0.0\",\n      \"maxScore\": 400,\n      \"icon\": \"img/icons/custom.svg\",\n      \"url\": \"https://my-profile-docs.com\",\n      \"sampleUrl\": \"https://my-sample-data.ttl\",\n      \"shaclFiles\": [\n        \"https://my-shacl-validation.ttl\"\n      ],\n      \"dimensions\": {\n        \"findability\": { \"maxScore\": 100 },\n        \"accessibility\": { \"maxScore\": 100 },\n        \"interoperability\": { \"maxScore\": 100 },\n        \"reusability\": { \"maxScore\": 75 },\n        \"contextuality\": { \"maxScore\": 25 }\n      }\n    }\n  },\n  \"defaultVersion\": \"1.0.0\"\n}\n```\n\n2. **Add corresponding metrics** in the `profile_metrics` section\n3. **Add icon file** to `public/img/icons/`\n4. **Update translations** in `public/locales/en/translation.json` and `public/locales/es/translation.json`\n\n### Quality Metrics\n\nMetrics define how quality is measured for each FAIR+C dimension. Each metric has an ID, weight, and associated RDF property.\n\n#### Metric Structure\n\n```json\n{\n  \"profile_metrics\": {\n    \"profile_id\": {\n      \"dimension_name\": [\n        {\n          \"id\": \"metric_identifier\",\n          \"weight\": 30,\n          \"property\": \"rdf:property\"\n        }\n      ]\n    }\n  }\n}\n```\n\n#### Adding New Metrics\n\n1. **Define the metric** in the appropriate profile and dimension:\n```json\n\"findability\": [\n  {\n    \"id\": \"my_custom_metric\",\n    \"weight\": 25,\n    \"property\": \"my:customProperty\"\n  }\n]\n```\n\n2. **Add metric labels** to translation files:\n```json\n{\n  \"metrics\": {\n    \"specific\": {\n      \"my_custom_metric\": \"My Custom Metric\"\n    }\n  }\n}\n```\n\n3. **Implement evaluation logic** in `src/services/MQAService.ts` if needed\n\n#### FAIR+C Dimensions\n\n| Dimension | Code | Description | Typical Metrics |\n|-----------|------|-------------|----------------|\n| **Findability** | `findability` | How easily the dataset can be found | Keywords, themes, spatial/temporal coverage |\n| **Accessibility** | `accessibility` | How accessible the data is | Access URLs, download URLs, status checks |\n| **Interoperability** | `interoperability` | Technical interoperability | Formats, media types, standards compliance |\n| **Reusability** | `reusability` | How easily the data can be reused | Licenses, access rights, contact information |\n| **Contextuality** | `contextuality` | Contextual information provided | Size, dates, rights information |\n\n### SPARQL Configuration\n\nThe SPARQL configuration enables integration with data portals and endpoints for automated data retrieval and validation.\n\n#### SPARQL Structure\n\n```json\n{\n  \"sparql_config\": {\n    \"default_endpoint\": \"https://sparql-endpoint-url\",\n    \"queries\": {\n      \"profile_id\": [\n        {\n          \"id\": \"query_identifier\",\n          \"name\": \"Human-readable name\",\n          \"description\": \"Query description\",\n          \"query\": \"SPARQL query string with {parameter} placeholders\",\n          \"parameters\": [\n            {\n              \"name\": \"parameter_name\",\n              \"label\": \"Parameter Label\",\n              \"type\": \"text\",\n              \"required\": true,\n              \"placeholder\": \"Enter value...\",\n              \"description\": \"Parameter description\"\n            }\n          ]\n        }\n      ]\n    }\n  }\n}\n```\n\n#### Adding SPARQL Queries\n\n1. **Define the query** for a specific profile:\n```json\n\"my_profile\": [\n  {\n    \"id\": \"my_custom_query\",\n    \"name\": \"Custom Data Query\",\n    \"description\": \"Retrieves custom dataset information\",\n    \"query\": \"PREFIX dcat: \u003chttp://www.w3.org/ns/dcat#\u003e\\nCONSTRUCT {\\n  ?dataset a dcat:Dataset ;\\n    dct:title ?title .\\n}\\nWHERE {\\n  ?dataset a dcat:Dataset ;\\n    dct:publisher ?publisher ;\\n    dct:title ?title .\\n  FILTER (regex(str(?publisher), \\\"{org_id}\\\", \\\"i\\\"))\\n}\\nLIMIT {limit}\",\n    \"parameters\": [\n      {\n        \"name\": \"org_id\",\n        \"label\": \"Organization ID\",\n        \"type\": \"text\",\n        \"required\": true,\n        \"placeholder\": \"e.g., ministry-of-health\",\n        \"description\": \"Identifier of the organization\"\n      },\n      {\n        \"name\": \"limit\",\n        \"label\": \"Result Limit\",\n        \"type\": \"number\",\n        \"required\": false,\n        \"placeholder\": \"50\",\n        \"description\": \"Maximum number of results\"\n      }\n    ]\n  }\n]\n```\n\n2. **Parameter Types Available**:\n   - `text`: Text input\n   - `number`: Numeric input\n   - `select`: Dropdown (requires `options` array)\n   - `textarea`: Multi-line text\n\n3. **Query Features**:\n   - **Parameter substitution**: Use `{parameter_name}` in queries\n   - **CONSTRUCT queries**: Preferred for generating valid RDF\n   - **Endpoint testing**: Use debug queries to test connectivity\n\n#### Debug Queries\n\nSpecial debug queries help test endpoint connectivity:\n\n```json\n\"debug\": [\n  {\n    \"id\": \"test_endpoint\",\n    \"name\": \"Test Endpoint\",\n    \"description\": \"Verify endpoint connectivity\",\n    \"query\": \"SELECT * WHERE { ?s ?p ?o } LIMIT 10\",\n    \"parameters\": []\n  }\n]\n```\n\n### Configuration Best Practices\n\n1. **Profile Naming**: Use consistent IDs (`dcat_ap`, `dcat_ap_es`, `dcat_ap_es_hvd` `nti_risp`, `dcat_ap_es_legacy`)\n2. **Version Management**: Support multiple versions per profile\n3. **Metric Weights**: Ensure weights sum to reasonable totals per dimension\n4. **SPARQL Queries**: Use CONSTRUCT queries for better RDF generation\n5. **Parameter Validation**: Provide clear descriptions and examples\n6. **Icon Management**: Store icons in `public/img/icons/` as SVG\n7. **Translation Keys**: Keep metric IDs consistent across profiles\n\n## Development\n\n| Script | Command | Description |\n|--------|---------|-------------|\n| **Development (Full)** | `./dev-start.sh` | Start both frontend and backend servers |\n| **Development (Frontend)** | `npm start` | Local server with hot reload (frontend only) |\n| **Cleanup** | `./dev-cleanup.sh` | Stop all development servers and clean ports |\n| **Build** | `npm run build` | Optimized production build |\n| **Deploy** | `npm run deploy` | Automatic deploy to GitHub Pages |\n| **Test** | `npm test` | Run tests (if any) |\n\n### File Structure\n\n```\nreact-app/\n├── public/\n│   ├── data/                    # JSONL vocabularies\n│   │   ├── access_rights.jsonl\n│   │   ├── file_types.jsonl\n│   │   ├── licenses.jsonl\n│   │   └── ...\n│   ├── locales/                 # i18n translations\n│   │   ├── en/translation.json  # English translations + metrics labels\n│   │   └── es/translation.json  # Spanish translations + metrics labels\n│   └── img/icons/               # Profile icons\n├── src/\n│   ├── components/              # React components\n│   │   ├── ValidationForm.tsx   # Input form + SPARQL integration\n│   │   ├── ValidationResults.tsx # Results and charts\n│   │   ├── QualityChart.tsx     # FAIR+C radar chart\n│   │   └── ...\n│   ├── services/                # Business logic\n│   │   ├── MQAService.ts        # Main MQA engine + metric evaluation\n│   │   ├── SPARQLService.ts     # SPARQL endpoint integration\n│   │   └── RDFService.ts        # RDF processing\n│   ├── config/                  # Configuration\n│   │   └── mqa-config.json      # **Central configuration file**\n│   ├── types/                   # TypeScript types\n│   └── i18n/                    # Internationalization setup\n└── package.json\n```\n\n## Deployment\nThis application can be deployed on multiple platforms with different configurations.\n\n\u003e [!IMPORTANT]\n\u003e **Automatic Configuration for Docker Deployments**\n\u003e \n\u003e When using Docker Compose, the container **automatically enables backend features** on startup:\n\u003e - Detects if `backend_server.enabled` or `data_quality.enabled` are `false`\n\u003e - Automatically updates configuration to `true` for Docker deployment\n\u003e - Creates backup of original config as `mqa-config.json.bak`\n\u003e - No manual configuration needed! 🎉\n\u003e \n\u003e **Manual Configuration** (only if deploying to platforms without backend):\n\u003e \n\u003e | Platform | `backend_server.enabled` | `data_quality.enabled` | Auto-configured? |\n\u003e |----------|-------------------------|------------------------|------------------|\n\u003e | **Docker Compose** | `true` | `true` | ✅ **Yes** (automatic) |\n\u003e | **GitHub Pages** | `false` | `false` | ❌ No (manual) |\n\u003e | **Local Development** | `true` | `true` | ✅ Yes (via dev-start.sh) |\n\u003e \n\u003e For GitHub Pages deployment:\n\u003e ```bash\n\u003e # Disable backend features\n\u003e sed -i 's/\"enabled\": true/\"enabled\": false/g' src/config/mqa-config.json\n\u003e npm run deploy\n\u003e ```\n\n\n### Supported Platforms\n\n| Platform | Frontend | Backend | Auto HTTPS | Free Tier | CI/CD | Backend Config | Data Quality | Best For |\n|----------|----------|---------|------------|-----------|-------|---------------|----------------|----------|\n| **Docker** | ✅ | ✅ (Express) | ⚙️ | - | ⚙️ | `enabled: true` | ✅ Full analysis | Self-hosted (Full control) |\n| **GitHub Pages** | ✅ | ❌ | ✅ | ✅ | ✅ | `enabled: false` | ❌ Limited | Demo/Docs (No backend) |\n\n---\n\n### Docker (Full Stack - Self Hosted)\n\n**Features**: Full control, both frontend and backend, custom domain support\n\n\u003e [!NOTE]  \n\u003e **Docker Configuration**: For Docker deployment, backend features should be **enabled** in `mqa-config.json`:\n\u003e ```json\n\u003e {\n\u003e   \"backend_server\": {\n\u003e     \"enabled\": true,\n\u003e     \"url\": \"\"\n\u003e   },\n\u003e   \"data_quality\": {\n\u003e     \"enabled\": true,\n\u003e     \"require_backend\": true\n\u003e   }\n\u003e }\n\u003e ```\n\n#### Quick Start\n\n```bash\n# 1. Clone and configure\ngit clone https://github.com/mjanez/metadata-quality-react.git\ncd metadata-quality-react\ncp .env.example .env\n\n# 2. Start with pre-built image (recommended)\ndocker compose up -d\n\n# Or build locally\nIMAGE_TAG=local docker compose up -d --build\n\n# 3. Access application\n# Frontend: https://localhost:443\n# Backend API: https://localhost:443/api/health\n```\n\n\u003e [!NOTE]\n\u003e By default, uses the latest stable image from GHCR. Set `IMAGE_TAG=develop` for development version or `IMAGE_TAG=local` to build locally.\n\n#### Deployment Modes\n\n| Mode | Command | Use Case | Features |\n|------|---------|----------|----------|\n| **Production (GHCR)** | `docker compose up -d` | Self-hosted with pre-built image | Fast deployment, auto-updates, SSL, caching |\n| **Development (Local)** | `IMAGE_TAG=local docker compose up -d --build` | Local build and testing | Custom changes, SSL, caching, auto-restart |\n\n#### Container Services\n\n```yaml\nservices:\n  mqa-backend:       # Express.js Backend API\n    ports:\n      - \"3001:3001\"  # Backend API (not exposed by default)\n    \n  mqa-frontend:      # React Frontend Application\n    ports:\n      - \"3000:3000\"  # Frontend (not exposed by default)\n  \n  nginx:             # Nginx Reverse Proxy\n    ports:\n      - \"80:80\"      # HTTP (redirects to HTTPS)\n      - \"443:443\"    # HTTPS (main entry point)\n```\n\n**Service Architecture:**\n- **mqa-backend**: Node.js API for data validation, quality assessment, and SHACL validation\n- **mqa-frontend**: Static React app served with `serve`\n- **nginx**: Reverse proxy that routes requests to frontend and `/api` to backend\n\n**Default Access:**\n- All traffic goes through Nginx (https://localhost)\n- Backend and frontend ports are internal to Docker network\n- For direct service access during debugging, expose ports in docker-compose.yml\n\n#### Configuration\n\n**Environment Variables** (`.env` file):\n```env\n# Image Configuration\nIMAGE_TAG=latest\n\n# Port Configuration\nFRONTEND_PORT=3000\nBACKEND_PORT=3001\n\n# Service Hosts (Docker internal networking)\nBACKEND_HOST=mqa-backend\nFRONTEND_HOST=mqa-frontend\n\n# Nginx Configuration\nNGINX_HTTP_PORT=80\nNGINX_HTTPS_PORT=443\n\n# Application\nPUBLIC_URL=/\nREACT_APP_BACKEND_URL=/api\nNODE_ENV=production\n\n# Security Configuration\nNODE_TLS_REJECT_UNAUTHORIZED=1\nALLOWED_DOMAINS=\n```\n\n**Custom Configuration**:\n```yaml\nservices:\n  mqa-frontend:\n    volumes:\n      # Mount custom MQA config\n      - ./mqa-config.json:/app/build/config/mqa-config.json:ro\n      # Mount custom vocabularies\n      - ./public/data:/app/build/data:ro\n  \n  mqa-backend:\n    environment:\n      # Security: Whitelist allowed domains for SSRF protection\n      - ALLOWED_DOMAINS=datos.gob.es,semiceu.github.io\n      # Disable SSL verification (development only!)\n      - NODE_TLS_REJECT_UNAUTHORIZED=0\n```\n\n#### Management Commands\n\n```bash\n# View logs for all services\ndocker compose logs -f\n\n# View specific service logs\ndocker compose logs -f mqa-backend\ndocker compose logs -f mqa-frontend\ndocker compose logs -f nginx\n\n# Restart services\ndocker compose restart\n\n# Stop and remove\ndocker compose down\n\n# Update and rebuild\ndocker compose up -d --build\n\n# Health check (via nginx)\ncurl -k https://localhost/health\ncurl -k https://localhost/api/health\n\n# Direct service health check (within containers)\ndocker exec mqa-frontend curl http://localhost:3000/\ndocker exec mqa-backend curl http://localhost:3001/api/health\n\n# Using Makefile (recommended)\nmake logs-backend    # View backend logs\nmake logs-frontend   # View frontend logs\nmake logs-nginx      # View nginx logs\nmake health          # Check all services health\nmake shell-backend   # Open shell in backend container\n```\n\n#### GitHub Container Registry (GHCR)\n\nPre-built Docker images are automatically published to GitHub Container Registry on every push and pull request.\n\n**Available Images:**\n- **Backend**: `ghcr.io/mjanez/metadata-quality-react-backend`\n- **Frontend**: `ghcr.io/mjanez/metadata-quality-react-frontend`\n\n**Quick Deploy:**\n```bash\n# Pull latest stable versions\ndocker pull ghcr.io/mjanez/metadata-quality-react-backend:latest\ndocker pull ghcr.io/mjanez/metadata-quality-react-frontend:latest\n\n# Or use docker-compose (recommended)\ncat \u003e docker-compose.yml \u003c\u003c EOF\nservices:\n  mqa-backend:\n    image: ghcr.io/mjanez/metadata-quality-react-backend:latest\n    environment:\n      - NODE_ENV=production\n      - PORT=3001\n    restart: unless-stopped\n    networks:\n      - mqa-network\n\n  mqa-frontend:\n    image: ghcr.io/mjanez/metadata-quality-react-frontend:latest\n    environment:\n      - NODE_ENV=production\n    restart: unless-stopped\n    networks:\n      - mqa-network\n    depends_on:\n      - mqa-backend\n\n  nginx:\n    image: nginx:alpine\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - ./nginx.conf:/etc/nginx/nginx.conf:ro\n    depends_on:\n      - mqa-frontend\n      - mqa-backend\n    restart: unless-stopped\n    networks:\n      - mqa-network\n\nnetworks:\n  mqa-network:\n    driver: bridge\nEOF\n\ndocker compose up -d\n```\n\n**Available Tags:**\n- `latest` - Latest stable version (main branch)\n- `develop` - Development version (develop branch)\n- `pr-\u003cnumber\u003e` - Pull request specific images\n- `v1.2.3` - Semantic versioning tags\n\n**Multi-Architecture Support**: Images built for `linux/amd64` and `linux/arm64` (Apple Silicon/ARM servers)\n\n**See**: [GHCR Documentation](.github/GHCR.md) for complete details on image tags, security scanning, and usage.\n\n---\n\n#### Production Deployment with SSL\n\n1. **Generate SSL certificates** (automatic self-signed for development):\n```bash\n# Generate self-signed certificate (local development)\nmake ssl-generate\n# or\n./docker/nginx/generate-ssl.sh\n\n# For production: replace with valid certificates\n# See docker/README.md#ssl-configuration\n```\n\n2. **Start with nginx profile**:\n```bash\n# HTTP automatically redirects to HTTPS\ndocker compose up -d\n# or\nmake up-prod\n```\n\n3. **Access via HTTPS**:\n```\nhttps://localhost (development - will show browser warning)\nhttps://your-domain.com (production with valid certificate)\n```\n\n\u003e [!NOTE]\n\u003e **Self-signed certificates**: Browsers will show a security warning. This is normal for local development.\n\u003e **Production**: Replace certificates in `docker/nginx/ssl/` with valid ones from Let's Encrypt or a CA.\n\n#### Alternative: Full Stack Deployment\n\nFor complete deployment with API backend (Python FastAPI):\n```bash\ngit clone https://github.com/mjanez/metadata-quality-stack\ncd metadata-quality-stack\ndocker compose up -d\n```\n\nIncludes:\n- React frontend (this project)\n- Python FastAPI backend\n- Streamlit dashboard\n- Nginx reverse proxy\n- Volume persistence\n\n#### Troubleshooting\n\n| Issue | Solution |\n|-------|----------|\n| Port in use | Change `FRONTEND_PORT` or `BACKEND_PORT` in `.env` |\n| Build fails | `docker compose build --no-cache` |\n| Network issues | `docker compose down \u0026\u0026 docker network prune` |\n| Permission errors | `sudo chown -R $USER:$USER .` |\n\n---\n\n### GitHub Pages (Frontend Only)\n\n**Features**: Simple static hosting, free for public repos, no backend support\n\n\u003e [!IMPORTANT]  \n\u003e **GitHub Pages Configuration**: For GitHub Pages deployment, you **MUST** disable backend features in `mqa-config.json`:\n\u003e ```json\n\u003e {\n\u003e   \"backend_server\": {\n\u003e     \"enabled\": false\n\u003e   },\n\u003e   \"data_quality\": {\n\u003e     \"enabled\": false\n\u003e   }\n\u003e }\n\u003e ```\n\u003e \n\u003e **Why**: GitHub Pages only serves static files and cannot run backend services. Leaving these enabled will cause:\n\u003e - Failed API requests and console errors\n\u003e - Non-functional data quality analysis features  \n\u003e - Degraded user experience with loading states that never complete\n\n#### Prerequisites\n- Repository must be public\n- GitHub Pages must be enabled in repository settings\n\n#### Automatic Deployment\n```bash\n# Deploy to GitHub Pages\nnpm run deploy\n```\n\nThis command:\n1. Builds the application with correct `PUBLIC_URL`\n2. Deploys to `gh-pages` branch\n3. Makes it available at: `https://{username}.github.io/{repo-name}/`\n\n#### Manual Deployment\n```bash\n# 1. Build with correct base path\nnpm run build\n\n# 2. Deploy using gh-pages\nnpx gh-pages -d build\n```\n\n---\n\n### Local Development with Backend\n\nFor complete local development including backend:\n\n#### Option 1: Automatic Setup (Recommended)\n```bash\n# Install dependencies and start both servers\n./dev-start.sh\n\n# If ports are occupied, clean up first:\n./dev-cleanup.sh \u0026\u0026 ./dev-start.sh\n```\n\n#### Option 2: Manual Setup\n```bash\n# Terminal 1: Start backend server\ncd backend\nnpm install\nnpm start\n# Backend running on http://localhost:3001\n\n# Terminal 2: Start React app\nnpm install\nnpm start\n# Frontend running on http://localhost:3000\n```\n\n**Environment Setup:**\n\nThe `.env.local` file is automatically configured for local development:\n```env\n# Local development configuration (already configured)\nBROWSER=none\nPORT=3000\nBACKEND_PORT=3001\nREACT_APP_BACKEND_URL=http://localhost:3001/api\nREACT_APP_ENV=development\n```\n\n**Custom Configuration:**\n\nTo modify ports or settings, edit `.env.local`:\n```env\n# Change frontend port\nPORT=3005\n\n# Change backend port\nBACKEND_PORT=3002\nREACT_APP_BACKEND_URL=http://localhost:3002/api\n```\n\n**Development Script Features:**\n\nThe `./dev-start.sh` script automatically:\n- Checks Node.js and npm installation\n- Installs dependencies if missing\n- Loads environment variables from `.env.local`\n- Starts backend server on configured port (default: 3001)\n- Starts frontend development server on configured port (default: 3000)\n- Verifies backend health check\n- Handles graceful shutdown on Ctrl+C\n\n**Backend Configuration:**\n\nThe backend (`backend/server.js`) provides:\n- CORS proxy for accessing external RDF data\n- URL validation to check accessibility\n- Data download with SSL certificate handling\n- Health check endpoint\n- Batch URL validation for performance\n\n**API Endpoints:**\n```bash\nGET  /api/health                    # Health check\nPOST /api/validate-url              # Single URL validation\nPOST /api/validate-urls-batch       # Batch URL validation (performance)\nPOST /api/download-data             # Download and proxy data\n```\n\n**Port Configuration:**\n\n| Service | Default Port | Environment Variable | Configuration File |\n|---------|--------------|---------------------|-------------------|\n| Frontend | 3000 | `PORT` | `.env.local` |\n| Backend | 3001 | `BACKEND_PORT` | `.env.local` |\n\n---\n\n## Backend API\n\nThe backend provides a REST API for programmatic access to quality assessment and SHACL validation. Full documentation available in [backend/API.md](backend/API.md).\n\n### Endpoints\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| GET | `/api/v1/profiles` | List available validation profiles |\n| POST | `/api/v1/quality` | Quality assessment (JSON, JSON-LD, DQV) |\n| POST | `/api/v1/shacl` | SHACL validation (JSON, Turtle, CSV) |\n| POST | `/api/v1/validate` | Combined quality + SHACL validation |\n| POST | `/api/v1/syntax` | RDF syntax validation |\n\n### Quick Examples\n\n```bash\n# Quality assessment\ncurl -X POST http://localhost:3001/api/v1/quality \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.org/catalog.ttl\", \"profile\": \"dcat_ap_es\"}'\n\n# SHACL validation with Turtle output\ncurl -X POST http://localhost:3001/api/v1/shacl \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.org/catalog.ttl\", \"outputFormat\": \"turtle\"}'\n\n# DQV format (W3C Data Quality Vocabulary)\ncurl -X POST http://localhost:3001/api/v1/quality \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"url\": \"https://example.org/catalog.ttl\", \"outputFormat\": \"dqv\"}'\n```\n\n### Dashboard Integration\n\nThe JSON output from the API can be loaded directly into the Dashboard. The frontend auto-detects the API format and converts it:\n\n1. Call `/api/v1/validate` and save the response\n2. Go to Dashboard \u003e Upload Data\n3. Upload the JSON file - both metrics and SHACL data load automatically\n\n---\n\n## Architecture\n\n### Component Overview\n```mermaid\nflowchart TB\n  subgraph Client [\"Browser\"]\n    App[\"React App\\n(Frontend)\"]\n  end\n\n  subgraph Nginx [\"Nginx Reverse Proxy\"]\n    RP[\"/:443\\n(HTTPS)\"]\n  end\n\n  subgraph Frontend [\"Frontend Container\"]\n    VF[\"ValidationForm\"]\n    VR[\"ValidationResults\"]\n    MQA[\"MQAService\"]\n    RDF[\"RDFService\"]\n  end\n\n  subgraph Backend [\"Backend Container\"]\n    API[\"Express API\\n:3001\"]\n    VAL[\"URL Validation\"]\n    PROXY[\"Data Download\"]\n    QAPI[\"Quality API v1\"]\n  end\n\n  Client --\u003e Nginx\n  Nginx --\u003e|/| Frontend\n  Nginx --\u003e|/api| Backend\n  Frontend --\u003e|API Calls| Backend\n  Backend --\u003e|External RDF| Internet((Internet))\n```\n\n**Service Architecture:**\n- **Frontend**: Static React app with quality assessment logic\n- **Backend**: Node.js API for data fetching, validation, and SHACL\n- **Nginx**: Routes traffic between services, handles SSL/TLS\n\n### Data Flow\n\n1. **Configuration Loading**: `mqa-config.json` → Services\n2. **User Input**: Form data → ValidationForm\n3. **SPARQL Integration**: Queries → SPARQLService → RDF data\n4. **RDF Processing**: Raw data → RDFService → Parsed triples\n5. **Quality Assessment**: Triples → MQAService → Metrics scores\n6. **Visualization**: Scores → Chart components → User interface\n\n### Supported Profiles\n\n- **DCAT-AP 2.1.1**: 405 maximum points\n- **DCAT-AP 3.0.0**: 405 maximum points  \n- **DCAT-AP-ES 1.0.0**: 405 maximum points\n- **NTI-RISP 2013**: 305 maximum points\n\n### FAIR+C Quality Model\n| Dimension | Description |\n|-----------|-------------|\n| **F** - Findability | Ease of finding the dataset |\n| **A** - Accessibility | Data accessibility |\n| **I** - Interoperability | Technical interoperability |\n| **R** - Reusability | Ease of reuse |\n| **C** - Contextuality | Contextual information |\n\n## Internationalization\n\n### Languages Supported\n- **English** (default)\n- **Spanish** (Español)\n\n### Adding New Languages\n1. Create translation file in `public/locales/{lang}/translation.json`\n2. Add language option to `LanguageSelector` component\n3. Update i18n configuration in `src/i18n/index.ts`\n\n### Translation Structure\n\nTranslation files in `public/locales/{lang}/translation.json` include both UI labels and metric definitions:\n\n```json\n{\n  \"common\": {\n    \"title\": \"Metadata Quality Assessment\",\n    \"loading\": \"Loading...\",\n    \"validate\": \"Validate\"\n  },\n  \"dimensions\": {\n    \"findability\": \"Findability\",\n    \"accessibility\": \"Accessibility\",\n    \"interoperability\": \"Interoperability\", \n    \"reusability\": \"Reusability\",\n    \"contextuality\": \"Contextuality\"\n  },\n  \"metrics\": {\n    \"labels\": {\n      \"name\": \"Métrica\",\n      \"score\": \"Puntuación\",\n      ...\n    },\n    \"specific\": {\n      \"dcat_keyword\": \"Palabras clave\",\n      \"dcat_theme\": \"Temas/Categorías\",\n      \"dct_spatial\": \"Cobertura espacial\",\n      \"dct_temporal\": \"Cobertura temporal\",\n      \"dcat_access_url_status\": \"Disponibilidad de la URL de acceso\"\n      ...\n    }\n  }\n}\n```\n\nThe `metrics.specific` section contains all quality metric translations and is integrated with the MQA evaluation system.\n\n## Theming\n### Customizing Styles\nEdit these files:\n- `src/App.css` - Main application styles\n- `src/components/*.css` - Component-specific styles\n- Bootstrap variables can be overridden in CSS\n\n### Theme Variables\n```css\n:root {\n  --bs-primary: #0d6efd;\n  --mqa-chart-bg: #ffffff;\n  --mqa-text-color: #212529;\n}\n\n[data-bs-theme=\"dark\"] {\n  --mqa-chart-bg: #212529;\n  --mqa-text-color: #ffffff;\n}\n```\n\n### Vocabulary Data\n\nControlled vocabularies are stored in `public/data/` as JSONL files for efficient loading:\n\n| File | Purpose | Usage |\n|------|---------|-------|\n| `access_rights.jsonl` | Access rights vocabulary | License validation |\n| `file_types.jsonl` | File format types | Format classification |\n| `licenses.jsonl` | License definitions | License compliance |\n| `machine_readable.jsonl` | Machine-readable formats | Interoperability metrics |\n| `media_types.jsonl` | MIME media types | Format validation |\n| `non_proprietary.jsonl` | Non-proprietary formats | Openness assessment |\n\n#### Updating Vocabularies\n\n```bash\n# Convert CSV vocabularies to JSONL format\npython3 scripts/vocabs_csv2jsonl.py\n```\n\n## Troubleshooting\n\n### Build Errors\n```bash\n# Clear cache\nrm -rf node_modules/.cache\nnpm run build\n```\n\n### Type Errors\n```bash\n# Check types without build\nnpx tsc --noEmit\n```\n\n### Deploy Issues\n```bash\n# Check gh-pages branch\ngit checkout gh-pages\ngit log --oneline -5\n\n# Force redeploy\nnpm run deploy -- --force\n```\n\n### i18n Issues\n```bash\n# Check translation files\ncat public/locales/en/translation.json\ncat public/locales/es/translation.json\n```\n\n### Configuration Issues\n\n```bash\n# Validate mqa-config.json syntax\nnpm run build 2\u003e\u00261 | grep -i \"config\\|json\"\n\n# Check for missing metric labels\ngrep -r \"metrics.specific\" public/locales/\n```\n\n### Deployment Configuration Issues\n\n**Backend Server Configuration Errors:**\n```bash\n# Check current backend_server configuration\ngrep -A 10 '\"backend_server\"' src/config/mqa-config.json\n\n# Common fixes:\n# For GitHub Pages: Set \"enabled\": false\n# For Docker: Set \"enabled\": true, \"url\": \"\"\n# For local dev: Set \"enabled\": true, \"url\": \"http://localhost:3001/api\"\n```\n\n**Data Quality Configuration Errors:**\n```bash\n# Check current data_quality configuration  \ngrep -A 5 '\"data_quality\"' src/config/mqa-config.json\n\n# GitHub Pages: Must be \"enabled\": false (no backend support)\n# Docker/Local: Can be \"enabled\": true (backend available)\n```\n\n**Configuration by Deployment Type:**\n| Deployment | backend_server.enabled | data_quality.enabled | Reason |\n|------------|----------------------|---------------------|--------|\n| GitHub Pages | `false` | `false` | No backend services available |\n| Docker | `true` | `true` | Full backend support with Express API |\n| Local Dev | `true` | `true` | Backend runs on localhost:3001 |\n| Static Hosting | `false` | `false` | Similar to GitHub Pages |\n\n### Development Issues\n\n```bash\n# Port already in use error\n./dev-cleanup.sh  # Clean up occupied ports\n./dev-start.sh    # Restart development servers\n\n# Backend connection issues\ncurl http://localhost:3001/api/health  # Check backend health\ncat .env.local                         # Verify configuration\n\n# Frontend can't reach backend\n# Check that REACT_APP_BACKEND_URL matches actual backend port\ngrep REACT_APP_BACKEND_URL .env.local\n```\n\n### Performance Issues\n\n```bash\n# Analyze bundle size\nnpm run build \u0026\u0026 npx webpack-bundle-analyzer build/static/js/*.js\n\n# Check for memory leaks in development\nnpm start -- --profile\n```\n\n## Contributing\n\n### Adding New Features\n\n1. **New Profile Support**:\n   - Update `mqa-config.json` with profile definition\n   - Add SHACL validation files\n   - Create profile icon in `public/img/icons/`\n   - Add translations for profile name and metrics\n\n2. **New Quality Metrics**:\n   - Define metric in `profile_metrics` section\n   - Implement evaluation logic in `MQAService.ts`\n   - Add metric labels to translation files\n   - Update documentation\n\n3. **SPARQL Queries**:\n   - Add queries to `sparql_config.queries`\n   - Test with debug queries first\n   - Document parameter usage\n   - Provide sample data URLs\n\n### Code Standards\n\n- **TypeScript**: Strict mode enabled, no `any` types\n- **React**: Functional components with hooks\n- **CSS**: Bootstrap 5 + custom CSS variables\n- **i18n**: All user-facing text must be translatable\n- **Testing**: Add tests for new services and components\n\n## License\n\nThis project is licensed under the MIT License. See the [LICENSE](../LICENSE) file for details.\n\n---\n\n**Built with ❤️ for the Open Data community**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjanez%2Fmetadata-quality-react","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmjanez%2Fmetadata-quality-react","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmjanez%2Fmetadata-quality-react/lists"}