{"id":31235497,"url":"https://github.com/rurfy/urlx","last_synced_at":"2026-05-02T18:33:09.730Z","repository":{"id":313981025,"uuid":"1053457204","full_name":"rurfy/urlx","owner":"rurfy","description":"Laravel 12 URL shortener with click tracking, QR codes, stats, tests, and CI/CD","archived":false,"fork":false,"pushed_at":"2025-09-09T19:24:28.000Z","size":92,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-09T23:16:14.366Z","etag":null,"topics":["ci-cd","laravel","php","postgresql","qr-code","rest-api","sqlite","unit-testing","url-shortener","web-app"],"latest_commit_sha":null,"homepage":"","language":"Blade","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/rurfy.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-09-09T13:28:49.000Z","updated_at":"2025-09-09T19:24:33.000Z","dependencies_parsed_at":"2025-09-09T23:18:15.502Z","dependency_job_id":"47e48de6-1079-4108-a92b-35fb6b9225fd","html_url":"https://github.com/rurfy/urlx","commit_stats":null,"previous_names":["rurfy/urlx"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/rurfy/urlx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rurfy%2Furlx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rurfy%2Furlx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rurfy%2Furlx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rurfy%2Furlx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rurfy","download_url":"https://codeload.github.com/rurfy/urlx/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rurfy%2Furlx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279001643,"owners_count":26083146,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"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":["ci-cd","laravel","php","postgresql","qr-code","rest-api","sqlite","unit-testing","url-shortener","web-app"],"created_at":"2025-09-22T14:32:44.826Z","updated_at":"2025-10-09T15:20:16.277Z","avatar_url":"https://github.com/rurfy.png","language":"Blade","funding_links":[],"categories":[],"sub_categories":[],"readme":"![CI](https://github.com/rurfy/urlx/actions/workflows/ci.yml/badge.svg)\n\n# URLX – Minimaler URL-Shortener (Laravel)\n\nKleines Showcase-Projekt mit **Laravel 12**, **OOP**, **Validation**, **DB-Migrationen**, **Weiterleitung \u0026 Tracking** und **QR-Code**.  \nZiel: Kompaktes Repo, das moderne PHP- und Web-Skills zeigt (Routing, Controller, Models, Tests, CI).\n\n## Features\n- POST `/api/links` → Shortlink erstellen (Validation, optional `slug`, optional `expires_at`)\n- GET `/{slug}` → Weiterleitung mit Klick-Tracking (Events)\n- GET `/api/qr/{slug}` → QR-Code (PNG)\n- GET `/api/links` → Links paginiert listen\n- GET `/api/links/{slug}/stats` → Klicks je Tag (30 Tage)\n\n---\n\n## Schnellstart (Windows + SQLite, ohne Docker)\n\nVoraussetzungen: PHP 8.3+ (mit `fileinfo`, `mbstring`, `zip`, `gd`), Composer, Node (optional).\n\n```powershell\n# 1) Abhängigkeiten\ncomposer install\n\n# 2) .env + App Key\nCopy-Item .env.example .env\nphp artisan key:generate\n\n# 3) SQLite-DB anlegen und .env auf SQLite stellen\nNew-Item -ItemType Directory -Force -Path .\\database | Out-Null\nNew-Item -ItemType File -Force -Path .\\database\\database.sqlite | Out-Null\n\n# .env patchen\n(Get-Content .env) `\n -replace 'DB_CONNECTION=mysql','DB_CONNECTION=sqlite' `\n -replace 'DB_HOST=.*','' `\n -replace 'DB_PORT=.*','' `\n -replace 'DB_DATABASE=.*','DB_DATABASE=database/database.sqlite' `\n -replace 'DB_USERNAME=.*','' `\n -replace 'DB_PASSWORD=.*','' |\n Set-Content .env\n\n# 4) Migrationen\nphp artisan migrate\n\n# 5) Start\nphp artisan serve\n```\n\n---\n\n## API Beispiele (PowerShell)\n\n**Link erstellen**\n```powershell\nInvoke-RestMethod -Method Post `\n  -Uri http://127.0.0.1:8000/api/links `\n  -ContentType application/json `\n  -Body (@{ target_url = \"https://example.com\" } | ConvertTo-Json)\n```\n\nOptional mit Slug/Expiry:\n```powershell\nInvoke-RestMethod -Method Post `\n  -Uri http://127.0.0.1:8000/api/links `\n  -ContentType application/json `\n  -Body (@{ target_url=\"https://example.com\"; slug=\"meinSlug\"; expires_at=\"2030-01-01\" } | ConvertTo-Json)\n```\n\n**Weiterleiten**  \nIm Browser: `http://127.0.0.1:8000/\u003cslug\u003e`\n\n**QR-Code**  \nIm Browser: `http://127.0.0.1:8000/api/qr/\u003cslug\u003e`\n\n**Links paginiert**\n```\nGET http://127.0.0.1:8000/api/links\n```\n\n**Stats je Tag**\n```\nGET http://127.0.0.1:8000/api/links/\u003cslug\u003e/stats\n```\n\n---\n\n## Wie es funktioniert (kurz \u0026 einfach)\n\n- **Route** verbindet URL → **Controller**-Methode.  \n- **Request-Validation** prüft Eingaben.  \n- **Model (Eloquent)** schreibt/liest Daten in Tabellen, die die **Migrationen** anlegen.  \n- Weiterleitung zählt Klicks + legt Event ab, QR liefert PNG aus.\n\n---\n\n## Tests (PHPUnit, SQLite In-Memory)\n\n`phpunit.xml` enthält:\n```xml\n\u003cphp\u003e\n  \u003cserver name=\"APP_ENV\" value=\"testing\"/\u003e\n  \u003cserver name=\"DB_CONNECTION\" value=\"sqlite\"/\u003e\n  \u003cserver name=\"DB_DATABASE\" value=\":memory:\"/\u003e\n\u003c/php\u003e\n```\n\nTests ausführen:\n```powershell\nphp artisan test\n```\n\n---\n\n## CI (GitHub Actions)\n\n- Läuft auf Ubuntu mit PHP 8.3\n- Nutzt SQLite (Datei wird erstellt)\n- Installiert Composer-Pakete, migriert, führt Tests aus\n\nSiehe `.github/workflows/ci.yml`.\n\n---\n\n## Auf verteilte DB wechseln (YugabyteDB / Postgres)\n\n- **YugabyteDB (YSQL)** spricht Postgres-Protokoll → einfach `.env` anpassen:\n```\nDB_CONNECTION=pgsql\nDB_HOST=\u003cyb-host\u003e\nDB_PORT=5433\nDB_DATABASE=urlx\nDB_USERNAME=\u003cuser\u003e\nDB_PASSWORD=\u003cpw\u003e\n```\n- Keine Codeänderung nötig. Die write-lastigen `click_events` profitieren von Sharding/Replikation.\n\n---\n\n## Sicherheit \u0026 Privacy\n\n- `ip_hash` statt Roh-IP (hash + Salt, z. B. `APP_KEY` oder eigener `IP_SALT`)\n- `expires_at` respektiert: abgelaufene Links → HTTP 410\n- `throttle:60,1` schützt API vor Abuse\n\n---\n\n## Roadmap (kurz)\n- Admin-UI (Blade) mit Tabelle \u0026 Charts\n- API Keys (Personal Access Tokens)\n- Queue-Job für Event-Write (Batch) + Redis\n- CSV/JSON-Export\n\n---\n\n## Tech-Stack\n- PHP 8.3/8.4, Laravel 12\n- SQLite lokal / Postgres / YugabyteDB\n- PHPUnit für Tests\n- GitHub Actions CI\n- simple-qrcode (PNG) / bacon-qr-code (SVG möglich)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frurfy%2Furlx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frurfy%2Furlx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frurfy%2Furlx/lists"}