{"id":42753772,"url":"https://github.com/thomas-0816/php_frameworkless","last_synced_at":"2026-01-29T20:02:21.490Z","repository":{"id":225288258,"uuid":"764294928","full_name":"thomas-0816/php_frameworkless","owner":"thomas-0816","description":"Example Micro Service REST API with PHP, frameworkless","archived":false,"fork":false,"pushed_at":"2025-03-29T10:17:58.000Z","size":1737,"stargazers_count":1,"open_issues_count":2,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-26T07:32:10.960Z","etag":null,"topics":["clickhouse","docker","frameworkless","javascript","jwt","microservices","mysql","openapi","php","php8","phpstan","phpunit","psalm","rector","redis","rest-api"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":false,"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/thomas-0816.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-02-27T20:28:39.000Z","updated_at":"2025-03-29T10:16:24.000Z","dependencies_parsed_at":"2024-07-08T12:45:16.420Z","dependency_job_id":"91296445-62ef-4dd7-b712-239d8a6aa6ab","html_url":"https://github.com/thomas-0816/php_frameworkless","commit_stats":{"total_commits":78,"total_committers":4,"mean_commits":19.5,"dds":0.2948717948717948,"last_synced_commit":"9d596e7c98a806812b6ada087483a800a72ef14a"},"previous_names":["thbley/php_frameworkless","thomas-0816/php_frameworkless"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thomas-0816/php_frameworkless","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-0816%2Fphp_frameworkless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-0816%2Fphp_frameworkless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-0816%2Fphp_frameworkless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-0816%2Fphp_frameworkless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thomas-0816","download_url":"https://codeload.github.com/thomas-0816/php_frameworkless/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomas-0816%2Fphp_frameworkless/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28883985,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-29T19:55:09.949Z","status":"ssl_error","status_checked_at":"2026-01-29T19:55:08.490Z","response_time":59,"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":["clickhouse","docker","frameworkless","javascript","jwt","microservices","mysql","openapi","php","php8","phpstan","phpunit","psalm","rector","redis","rest-api"],"created_at":"2026-01-29T20:02:18.187Z","updated_at":"2026-01-29T20:02:21.482Z","avatar_url":"https://github.com/thomas-0816.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"PHP Frameworkless Micro Service Example\n----------------------------------------\n\n[![Actions Build Status](https://github.com/thomasbley/example_tasks_php/workflows/build/badge.svg?branch=master)](https://github.com/thomasbley/example_tasks_php/actions)\n\nExample micro service to provide a REST API to manage customer tasks.\n\nThe backend is written in PHP without a standard framework, stores data in MySQL/MariaDB,\nuses ClickHouse for analytics and Redis as event stream.\n\nThe frontend is written as an SPA in Typed JavaScript using ES Modules and Alpine.js.\n\n#### Setup\n\n    # clone repository\n    git clone --depth=1 git@github.com:thbley/php_frameworkless.git\n    cd php_frameworkless\n\n    # build container\n    docker compose -f docker-compose-tasks-be.yml -f docker-compose-tasks-fe.yml build --pull --no-cache --parallel\n\n    # setup composer\n    mkdir -m 0777 tasks_be/src/vendor tasks_be/tests/vendor\n    chmod 0666 tasks_be/composer.json tasks_be/composer.lock tasks_be/tests/composer.json tasks_be/tests/composer.lock\n    docker compose -f docker-compose-tasks-be.yml run -u $(id -u) --rm composer\n    docker compose -f docker-compose-tasks-be.yml run -u $(id -u) --rm composer_tests\n\n    # setup npm\n    mkdir -m 0777 tasks_fe/src/node_modules tasks_fe/tests/node_modules\n    chmod 0666 tasks_fe/src/package.json tasks_fe/src/package-lock.json tasks_fe/tests/package.json tasks_fe/tests/package-lock.json\n    docker compose -f docker-compose-tasks-fe.yml run -u $(id -u) --rm npm\n    docker compose -f docker-compose-tasks-fe.yml run -u $(id -u) --rm npm_tests\n\n    # start containers\n    docker compose up\n    docker compose up -d\n\n    # setup database\n    docker compose -f docker-compose-tasks-be.yml run --rm cli update_database.php\n\n#### Static code analyzers (backend)\n\n    docker compose -f docker-compose-tasks-be.yml run --rm psalm\n    docker compose -f docker-compose-tasks-be.yml run --rm psalm_taint\n    docker compose -f docker-compose-tasks-be.yml run --rm phpstan\n    docker compose -f docker-compose-tasks-be.yml run --rm rector\n    docker compose -f docker-compose-tasks-be.yml run --rm phpmd\n    docker compose -f docker-compose-tasks-be.yml run --rm phpcsfixer\n\n#### Static code analyzers and builders (frontend)\n\n    docker compose -f docker-compose-tasks-fe.yml run --rm biome\n    docker compose -f docker-compose-tasks-fe.yml run --rm stylelint\n    docker compose -f docker-compose-tasks-fe.yml run --rm tsclint\n    docker compose -f docker-compose-tasks-fe.yml run --rm htmlvalidate\n    docker compose -f docker-compose-tasks-fe.yml run -u $(id -u) --rm esbuild\n\n#### Tests (backend)\n\n    docker compose -f docker-compose-tasks-be.yml run --rm phpunit\n    docker compose -f docker-compose-tasks-be.yml run --rm phpunit_feature\n\n#### Tests (frontend)\n\n    docker compose -f docker-compose-tasks-fe.yml run -u $(id -u) --rm vitest\n    docker compose -f docker-compose-tasks-e2e.yml run --rm playwright\n    docker compose -f docker-compose-tasks-e2e.yml run -u $(id -u) --rm lighthouse\n\n#### Security scanning\n\n    docker images | grep example_tasks | awk '{print $1}' | xargs -n1 trivy image --scanners vuln\n    trivy fs --scanners vuln,config,secret,license --license-full --skip-dirs \"tasks_be/tests/vendor/\" ./\n\n    docker images | grep example_tasks | awk '{print $1}' | xargs -n1 docker scout cves --locations\n    docker scout cves fs://.\n\n#### Convert API blueprint to OpenAPI-JSON, OpenAPI-PHP and HTML\n\n    chmod 0666 tasks_be/docs/api_openapi.json tasks_be/tests/data/api_openapi.php tasks_be/docs/api.html.gz\n    docker compose -f docker-compose-tasks-be.yml run -u $(id -u) --rm apib2openapi\n    docker compose -f docker-compose-tasks-be.yml run -u $(id -u) --rm apib2php\n    docker compose -f docker-compose-tasks-be.yml run -u $(id -u) --rm apib2html\n\n#### URLs\n\n    http://127.0.0.1:8080/tasks/ (Frontend SPA)\n    http://127.0.0.1:8080/v1/tasks (API endpoint)\n\n    http://127.0.0.1:8080/docs/ (OpenAPI and HTML documentation)\n    http://127.0.0.1:8080/coverage/ (code coverage)\n    http://127.0.0.1:8025/ (Mailpit, catches all outgoing emails)\n\n#### Command line tests\n\n    export BASE=http://127.0.0.1:8080\n\n    export TOKEN=$(curl -s -X POST -d '{\"email\":\"foo@bar.baz\",\"password\":\"insecure\"}' \"${BASE}/v1/customers/login\" | jq -r '.token')\n    echo $TOKEN\n\n    curl -i -X POST -d '{\"title\":\"test\",\"duedate\":\"2020-05-22\"}' -H \"Authorization: ${TOKEN}\" \"${BASE}/v1/tasks\"\n    curl -i -X GET -H \"Authorization: ${TOKEN}\" \"${BASE}/v1/tasks\"\n    curl -i -X PUT -d '{\"title\":\"test\",\"duedate\":\"2020-05-22\",\"completed\":true}' -H \"Authorization: ${TOKEN}\" \\\n        \"${BASE}/v1/tasks/1\"\n    curl -i -X GET -H \"Authorization: ${TOKEN}\" \"${BASE}/v1/tasks?completed=1\"\n    curl -i -X GET -H \"Authorization: ${TOKEN}\" \"${BASE}/v1/tasks/1\"\n    curl -i -X DELETE -H \"Authorization: ${TOKEN}\" \"${BASE}/v1/tasks/1\"\n\n    # import task queue into redis stream\n    docker compose -f docker-compose-tasks-be.yml run --rm cli task_queue.php\n\n    # import redis stream into clickhouse\n    docker compose -f docker-compose-tasks-be.yml run --rm cli task_stream.php\n\n    # generate bearer token for customer id \"42\" with email \"foo.bar@example.com\"\n    docker compose -f docker-compose-tasks-be.yml run --rm cli generate_token.php \\\n        42 foo.bar@example.com\n\n#### [architecture.md](https://github.com/thbley/php_frameworkless/blob/master/architecture.md)\n\n#### [development.md](https://github.com/thbley/php_frameworkless/blob/master/development.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomas-0816%2Fphp_frameworkless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthomas-0816%2Fphp_frameworkless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomas-0816%2Fphp_frameworkless/lists"}