Skip to content

PHP Laravel Todos

A REST API for managing todos, built with PHP/Laravel and PostgreSQL. Demonstrates deploying a database-backed PHP application on AppMecca with Eloquent ORM and Artisan migrations.

Overview

Repository git@gitlab.com:appmecca-sample-apps/php-laravel-todos.git
Tech Stack PHP 8.3 / Laravel 11 / Eloquent / Apache
Services api (port 8080)
Database Yes
Cache None
URL Pattern https://php-laravel-todos-api.{env}.appmecca.net

What This App Demonstrates

  • Deploying a database-backed PHP application on AppMecca
  • Eloquent ORM with Artisan migrations for schema management
  • Multi-stage Docker builds for Laravel (Composer + PHP Apache)
  • REST API with full CRUD operations against PostgreSQL
  • The database.enabled: true configuration pattern

appmecca.yaml

containers:
  - name: api
    dockerfile: Dockerfile
    context: .

deploy:
  - name: api
    container: api
    port: 8080
    health_check:
      path: /health

database:
  enabled: true

The only addition compared to Hello PHP is database.enabled: true. AppMecca provisions a PostgreSQL database on first deploy and injects DATABASE_URL, DB_HOST, DB_PORT, DB_NAME, DB_USER and DB_PASSWORD into every container of the app automatically.

Never hardcode the database name

The database and user names are opaque, generated identifiers of the form am_<hash>_db and am_<hash>_user — derived from the app and branch, so each branch gets its own isolated database. They are never php-laravel-todos_db. Always read DATABASE_URL (or the DB_* pair) rather than composing a name yourself.

Step-by-Step Deployment

1. Register the app

mecca register git@gitlab.com:appmecca-sample-apps/php-laravel-todos.git -e dev

2. Build the container

mecca build trigger -e dev -g git@gitlab.com:appmecca-sample-apps/php-laravel-todos.git
Expected output
Build started: build-xxxxxxxx
Cloning repository...
Building container: api
Pushing to the image registry: appmecca-dev-php-laravel-todos
Build complete. Duration: 55s

3. Deploy

mecca app deploy -e dev php-laravel-todos
Expected output
Deploying php-laravel-todos to dev...
Deployment queued: deploy-xxxxxxxx
Waiting for agents...
Container started: php-laravel-todos-api
Health check passed: /health -> 200 OK
Deployment complete.

Services:
  api: https://php-laravel-todos-api.dev.appmecca.net

4. Verify

mecca app show -e dev php-laravel-todos

Test the API:

# Health check
curl https://php-laravel-todos-api.dev.appmecca.net/health
{"status": "healthy"}
# Create a todo
curl -X POST https://php-laravel-todos-api.dev.appmecca.net/api/todos \
  -H "Content-Type: application/json" \
  -d '{"title": "Deploy more apps", "done": false}'

# List all todos
curl https://php-laravel-todos-api.dev.appmecca.net/api/todos

# Update a todo
curl -X PUT https://php-laravel-todos-api.dev.appmecca.net/api/todos/1 \
  -H "Content-Type: application/json" \
  -d '{"done": true}'

# Delete a todo
curl -X DELETE https://php-laravel-todos-api.dev.appmecca.net/api/todos/1

API Endpoints

Method Path Description
GET /health Health check
GET /api/todos List all todos
POST /api/todos Create a todo
PUT /api/todos/:id Update a todo
DELETE /api/todos/:id Delete a todo

Key Concepts

Eloquent ORM and Artisan migrations

Laravel uses Eloquent as its ORM and Artisan as its CLI tool. Database migrations are versioned PHP files in the database/migrations/ directory. The entrypoint script runs php artisan migrate --force on startup to apply any pending migrations. The --force flag is required in production because Laravel prompts for confirmation by default.

Multi-stage Docker builds for Laravel

The Dockerfile uses two stages. The first stage uses the official Composer image to install PHP dependencies (composer install --no-dev). The second stage uses PHP 8.3 with Apache, copying the vendor directory and application code from the build stage. This keeps Composer, development dependencies, and build tools out of the final image.

Any language, same workflow

AppMecca does not care what language your application is written in. As long as your container listens on the declared port and responds to health checks, the deployment workflow is identical.

What's Next?