# PHP Todo List A small todo-list application: a REST API written in PHP (Slim 4) backed by an SQLite file, plus a single-page frontend (added in a later stage). ## Status | Stage | Scope | State | |-------|-------|-------| | 1 | Auth API — register, login, `GET /me` | ✅ done | | 2 | Todo CRUD API | planned | | 3 | Single-page frontend | planned | ## Requirements - PHP 8.1+ with the `pdo_sqlite` and `mbstring` extensions - [Composer](https://getcomposer.org/) On Fedora: ```bash sudo dnf install php-cli php-pdo php-mbstring composer ``` ## Setup ```bash composer install cp .env.example .env # optional; sane defaults are used without it composer migrate # creates storage/database.sqlite and its tables ``` ## Running ```bash composer serve # http://localhost:8080 (php -S localhost:8080 -t public) ``` Any web server can serve the app as long as the document root is `public/` and unknown paths fall through to `public/index.php`. ## Configuration All settings are optional environment variables (read from `.env` or the real environment). See [.env.example](.env.example). | Variable | Default | Purpose | |----------|---------|---------| | `APP_DEBUG` | `false` | Include exception details in error responses | | `DATABASE_PATH` | `storage/database.sqlite` | SQLite file location | | `JWT_SECRET` | auto-generated into `storage/secret.key` | Token signing key | | `JWT_TTL` | `86400` | Token lifetime in seconds | ## API Base path: `/api`. All request and response bodies are JSON; send `Content-Type: application/json`. ### `GET /api/health` ```json { "status": "ok" } ``` ### `POST /api/auth/register` Request: ```json { "email": "ada@example.com", "password": "correct horse battery staple" } ``` `201 Created`: ```json { "user": { "id": 1, "email": "ada@example.com", "created_at": "2026-09-03T12:00:00Z" }, "token": "", "expires_at": "2026-09-04T12:00:00+00:00" } ``` Errors: `422` invalid input, `409` email already registered. Validation: `email` must be a valid address (≤ 255 chars); `password` must be 8–72 characters. ### `POST /api/auth/login` Request: ```json { "email": "ada@example.com", "password": "correct horse battery staple" } ``` `200 OK`: same shape as register. `401` on bad credentials (the message does not say whether it was the email or the password that was wrong). ### `GET /api/me` Requires `Authorization: Bearer `. `200 OK`: ```json { "user": { "id": 1, "email": "ada@example.com", "created_at": "2026-09-03T12:00:00Z" } } ``` `401` if the header is missing, malformed, or the token is invalid/expired. ### Error shape Every error response looks like: ```json { "error": { "message": "The submitted data was invalid.", "details": { "email": ["Email must be a valid address."] } } } ``` `details` is present only when relevant (e.g. validation). ## Try it ```bash BASE=http://localhost:8080 curl -s -X POST $BASE/api/auth/register \ -H 'Content-Type: application/json' \ -d '{"email":"ada@example.com","password":"password123"}' TOKEN=$(curl -s -X POST $BASE/api/auth/login \ -H 'Content-Type: application/json' \ -d '{"email":"ada@example.com","password":"password123"}' | grep -o '"token":"[^"]*"' | cut -d'"' -f4) curl -s $BASE/api/me -H "Authorization: Bearer $TOKEN" ``` ## Tests ```bash composer install # installs phpunit (require-dev) vendor/bin/phpunit ``` ## Layout ``` public/index.php Front controller src/bootstrap.php App wiring and route definitions src/Support/Config.php Environment-driven configuration src/Support/Database.php PDO/SQLite connection src/Auth/JwtService.php Issue/verify JWTs src/Auth/AuthMiddleware.php Bearer-token authentication src/Http/JsonErrorHandler.php Uniform JSON error envelope src/Http/Controllers/ Request handlers src/Repository/ Database access migrations/*.sql Schema, applied by bin/migrate.php ``` ## Provenance This project was generated with [Claude Code](https://claude.com/claude-code).