4.0 KiB
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_sqliteandmbstringextensions - Composer
On Fedora:
sudo dnf install php-cli php-pdo php-mbstring composer
Setup
composer install
cp .env.example .env # optional; sane defaults are used without it
composer migrate # creates storage/database.sqlite and its tables
Running
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.
| 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
{ "status": "ok" }
POST /api/auth/register
Request:
{ "email": "ada@example.com", "password": "correct horse battery staple" }
201 Created:
{
"user": { "id": 1, "email": "ada@example.com", "created_at": "2026-09-03T12:00:00Z" },
"token": "<jwt>",
"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:
{ "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 <jwt>.
200 OK:
{ "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:
{ "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
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
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.