{"id":34534360,"url":"https://github.com/sgort/aow-query-portal","last_synced_at":"2026-05-27T00:33:11.943Z","repository":{"id":326551693,"uuid":"1106064642","full_name":"sgort/aow-query-portal","owner":"sgort","description":null,"archived":false,"fork":false,"pushed_at":"2025-11-28T16:12:15.000Z","size":69,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-27T00:33:01.674Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sgort.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-11-28T15:15:38.000Z","updated_at":"2025-11-28T16:12:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sgort/aow-query-portal","commit_stats":null,"previous_names":["sgort/aow-query-portal"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sgort/aow-query-portal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgort%2Faow-query-portal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgort%2Faow-query-portal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgort%2Faow-query-portal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgort%2Faow-query-portal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sgort","download_url":"https://codeload.github.com/sgort/aow-query-portal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sgort%2Faow-query-portal/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33545458,"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":"ssl_error","status_checked_at":"2026-05-26T15:22:15.568Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-24T05:57:42.886Z","updated_at":"2026-05-27T00:33:11.937Z","avatar_url":"https://github.com/sgort.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TriplyDB SPARQL Query Portal\n\nA modern, static web application for providing public access to SPARQL queries and linked data from TriplyDB instances. Built with vanilla JavaScript and Vite, designed for Azure Static Web Apps deployment.\n\n## Features\n\n- ✅ **Pre-defined SPARQL Queries** - Execute curated queries with one click\n- ✅ **Multi-format Downloads** - Export results in RDF/XML, Turtle, JSON-LD, and JSON\n- ✅ **Responsive Design** - Works on desktop, tablet, and mobile\n- ✅ **Organization Branding** - Customizable colors, logos, and metadata\n- ✅ **Zero Authentication** - Public access with fair use policy\n- ✅ **Static Deployment** - Secure, fast, and scalable on Azure\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│  Static Web App (Azure)                                 │\n│  ┌──────────────────────────────────────────┐           │\n│  │  HTML/CSS/JS                             │           │\n│  │  - Query Interface                       │           │\n│  │  - Results Renderer                      │           │\n│  │  - Download Manager                      │           │\n│  └────────────┬─────────────────────────────┘           │\n└───────────────┼─────────────────────────────────────────┘\n                │\n                │ SPARQL over HTTP\n                ▼\n┌─────────────────────────────────────────────────────────┐\n│  TriplyDB Instance                                      │\n│  https://open-regels.triply.cc                          │\n│  ┌──────────────────────────────────────────┐           │\n│  │  RDF Dataset                             │           │\n│  │  - Metadata (TTL)                        │           │\n│  │  - Distribution URLs                     │           │\n│  │  - SPARQL Endpoint                       │           │\n│  └──────────────────────────────────────────┘           │\n└─────────────────────────────────────────────────────────┘\n```\n\n## Project Structure\n\n```\ntriply-static-webapp/\n├── index.html              # Main HTML template\n├── style.css               # Application styles\n├── main.js                 # Application entry point\n├── config.json             # Organization \u0026 query configuration\n├── modules/\n│   ├── sparql-client.js    # SPARQL query execution\n│   ├── download-manager.js # Multi-format downloads\n│   └── results-renderer.js # Results display\n├── assets/\n│   └── logo.png           # Organization logo\n├── .github/\n│   └── workflows/\n│       └── azure-static-web-apps.yml  # CI/CD pipeline\n├── package.json\n├── vite.config.js\n└── staticwebapp.config.json\n```\n\n## Setup\n\n### Prerequisites\n\n- Node.js 18+ and npm\n- Azure subscription (connected to GitHub)\n- Access to Azure DNS zone for custom domains\n- TriplyDB instance with datasets\n\n### 1. Clone and Install\n\n```bash\ngit clone \u003cyour-repo-url\u003e\ncd triply-static-webapp\nnpm install\n```\n\n### 2. Configure Your Organization\n\nEdit `config.json`:\n\n```json\n{\n  \"organization\": {\n    \"name\": \"Your Organization Name\",\n    \"shortName\": \"your-org\",\n    \"description\": \"Public access to linked data\",\n    \"logo\": \"./assets/logo.png\",\n    \"primaryColor\": \"#003DA5\"\n  },\n  \"triplydb\": {\n    \"endpoint\": \"https://your-instance.triply.cc/account/dataset/sparql\",\n    \"account\": \"account-name\",\n    \"dataset\": \"dataset-name\"\n  },\n  \"queries\": [\n    {\n      \"id\": \"your-query-id\",\n      \"name\": \"Query Name\",\n      \"description\": \"Query description\",\n      \"category\": \"Category\",\n      \"sparql\": \"SELECT * WHERE { ?s ?p ?o } LIMIT 10\"\n    }\n  ]\n}\n```\n\n### 3. Add Your Logo\n\nPlace your organization logo at `assets/logo.png` (recommended size: 128x64px or similar aspect ratio).\n\n### 4. Test Locally\n\n```bash\nnpm run dev\n```\n\nVisit `http://localhost:3000` to test the application.\n\n## Deployment to Azure\n\n### Option 1: Azure Portal (First-time Setup)\n\n1. **Create Static Web App**\n   - Go to Azure Portal → Create Resource → Static Web App\n   - Choose your GitHub repository\n   - Build preset: Custom\n   - App location: `/`\n   - Output location: `dist`\n\n2. **Configure Custom Domain**\n   - In Azure Portal → Your Static Web App → Custom domains\n   - Add custom domain (e.g., `aow.open-regels.nl`)\n   - Get the validation TXT record\n\n3. **Update DNS**\n   - In your DNS zone, add:\n     ```\n     A record: @ → \u003cAzure Static Web Apps IP\u003e\n     TXT record: @ → \u003cvalidation token\u003e\n     ```\n\n4. **Get Deployment Token**\n   - In Azure Portal → Your Static Web App → Manage deployment token\n   - Copy the token\n\n5. **Add GitHub Secret**\n   - In GitHub → Your repository → Settings → Secrets\n   - Add `AZURE_STATIC_WEB_APPS_API_TOKEN` with your deployment token\n\n### Option 2: Azure CLI (Automated)\n\n```bash\n# Login to Azure\naz login\n\n# Create resource group (if needed)\naz group create \\\n  --name rg-open-regels-static-apps \\\n  --location westeurope\n\n# Create static web app\naz staticwebapp create \\\n  --name aow-query-portal \\\n  --resource-group rg-open-regels-static-apps \\\n  --source https://github.com/your-username/your-repo \\\n  --location westeurope \\\n  --branch main \\\n  --app-location \"/\" \\\n  --output-location \"dist\" \\\n  --login-with-github\n\n# Add custom domain\naz staticwebapp hostname set \\\n  --name aow-query-portal \\\n  --resource-group rg-open-regels-static-apps \\\n  --hostname aow.open-regels.nl\n```\n\n### DNS Configuration\n\nFor each organization site, add an A record:\n\n```\naow.open-regels.nl      A    \u003cAzure Static Web App IP\u003e\ngemeente-x.open-regels.nl A  \u003cAzure Static Web App IP\u003e\n```\n\n## Multi-Organization Deployment\n\n### Strategy 1: Separate Repositories (Recommended)\n\nEach organization gets its own repository and Azure Static Web App:\n\n```\n├── aow-query-portal/          (separate repo)\n│   └── config.json            (AOW-specific config)\n├── gemeente-x-portal/         (separate repo)\n│   └── config.json            (Gemeente X config)\n└── gemeente-y-portal/         (separate repo)\n    └── config.json            (Gemeente Y config)\n```\n\nBenefits:\n- Independent deployments\n- Organization-specific customizations\n- Separate Azure billing\n- Isolated Git histories\n\n### Strategy 2: Monorepo with Multiple Configs\n\nSingle repository with organization-specific folders:\n\n```\ntriply-portals/\n├── organizations/\n│   ├── aow/\n│   │   ├── config.json\n│   │   └── assets/\n│   ├── gemeente-x/\n│   │   ├── config.json\n│   │   └── assets/\n│   └── gemeente-y/\n│       ├── config.json\n│       └── assets/\n├── src/                       (shared codebase)\n└── .github/workflows/\n    ├── deploy-aow.yml\n    ├── deploy-gemeente-x.yml\n    └── deploy-gemeente-y.yml\n```\n\n## Configuration Reference\n\n### Query Configuration\n\nEach query in `config.json` requires:\n\n```json\n{\n  \"id\": \"unique-id\",              // Used for filenames\n  \"name\": \"Display Name\",         // Shown in dropdown\n  \"description\": \"Description\",   // Help text\n  \"category\": \"Category Name\",    // For grouping\n  \"sparql\": \"SELECT...\"          // SPARQL query string\n}\n```\n\n### Export Format Configuration\n\nDefault formats are included, but you can customize:\n\n```json\n{\n  \"id\": \"turtle\",\n  \"name\": \"Turtle\",\n  \"extension\": \"ttl\",\n  \"mediaType\": \"text/turtle\",\n  \"accept\": \"text/turtle\"\n}\n```\n\n## SPARQL Query Examples\n\n### Distribution URLs (from your DMN-STORAGE.md)\n\n```sparql\nPREFIX dcat: \u003chttp://www.w3.org/ns/dcat#\u003e\nPREFIX dct: \u003chttp://purl.org/dc/terms/\u003e\nPREFIX ex: \u003chttps://open-regels.triply.cc/stevenport/aow-leeftijd-service/id/\u003e\n\nSELECT ?distributionTitle ?format ?mediaType ?accessURL ?downloadURL\nWHERE {\n  ex:aow_leeftijd_regels dcat:distribution ?distribution .\n  ?distribution dct:title ?distributionTitle ;\n                dct:format ?format ;\n                dcat:mediaType ?mediaType ;\n                dcat:accessURL ?accessURL ;\n                dcat:downloadURL ?downloadURL .\n  FILTER(LANG(?distributionTitle) = \"nl\")\n}\n```\n\n### Full Export (CONSTRUCT)\n\n```sparql\nCONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o }\n```\n\n## Customization\n\n### Branding\n\n- **Colors**: Update `primaryColor` in `config.json` or modify CSS variables in `style.css`\n- **Logo**: Replace `assets/logo.png`\n- **Typography**: Modify font-family in `style.css`\n\n### Adding New Queries\n\n1. Add query to `config.json`:\n   ```json\n   {\n     \"id\": \"new-query\",\n     \"name\": \"New Query Name\",\n     \"description\": \"What this query does\",\n     \"category\": \"Category\",\n     \"sparql\": \"SELECT...\"\n   }\n   ```\n\n2. Commit and push - automatic deployment via GitHub Actions\n\n### Security Headers\n\nConfigured in `staticwebapp.config.json`:\n- CORS enabled for SPARQL endpoints\n- Content Security Policy\n- X-Frame-Options\n- Referrer Policy\n\n## Monitoring \u0026 Maintenance\n\n### Azure Monitoring\n\n- Application Insights automatically enabled\n- Monitor in Azure Portal → Your Static Web App → Monitoring\n\n### GitHub Actions\n\n- View deployment status: Repository → Actions\n- Failed deployments trigger email notifications\n\n### Health Checks\n\nTest SPARQL endpoint connectivity:\n\n```bash\ncurl -H \"Accept: application/sparql-results+json\" \\\n  \"https://open-regels.triply.cc/stevenport/aow-leeftijd-service/sparql?query=SELECT%20*%20WHERE%20%7B%20%3Fs%20%3Fp%20%3Fo%20%7D%20LIMIT%201\"\n```\n\n## Troubleshooting\n\n### Query Returns No Results\n\n1. Test query in TriplyDB web interface\n2. Check for typos in prefixes and URIs\n3. Verify dataset has data: `SELECT * WHERE { ?s ?p ?o } LIMIT 1`\n\n### Download Fails\n\n1. Verify query type matches format (CONSTRUCT for RDF, SELECT for JSON)\n2. Check browser console for CORS errors\n3. Test endpoint directly with curl\n\n### Deployment Fails\n\n1. Check GitHub Actions logs\n2. Verify `AZURE_STATIC_WEB_APPS_API_TOKEN` secret is set\n3. Ensure `npm run build` succeeds locally\n\n## License\n\nMIT License - See LICENSE file\n\n## Support\n\nFor issues with:\n- **TriplyDB**: https://triply.cc/support\n- **Azure Static Web Apps**: https://learn.microsoft.com/azure/static-web-apps\n- **This template**: Open an issue in the repository\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgort%2Faow-query-portal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsgort%2Faow-query-portal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsgort%2Faow-query-portal/lists"}