Skip to content

Repository files navigation

TinyURL

TinyURL banner

A URL shortening API. The product is an API, not an application with a user interface — every operation (registration, key management, link CRUD, statistics) is reachable over HTTP.

The project is at an early stage: the development environment, the Symfony skeleton and the quality tooling are in place. The domain is not implemented yet.

Requirements

Docker and Docker Compose. Nothing else — PHP, Composer and the databases all run in containers.

Getting started

make init            # create .env from .env.example
make up              # nginx, php, postgres, postgres-analytics, redis, rabbitmq, mailpit
make db-test-create  # test databases for both connections

Application: http://localhost:8000. Mailpit inbox: http://localhost:8025. RabbitMQ management UI: http://localhost:15672.

Workers and cron live behind a separate compose profile, so the HTTP stack can be started without them:

make workers-up

Run make help for the full list of targets.

Environment

Service Host port Notes
nginx 8000 public listener
nginx internal listener on 8081, deliberately not published
postgres 5432 default database: accounts, links, moderation
postgres-analytics 5433 analytics database: clicks and rollups
redis 6379 cache, click buffer, rate limiting
rabbitmq 5672 / 15672 business events
mailpit 8025 captures outgoing mail

Internal endpoints (/health/status, /metrics, /fpm-status) are served by the listener on port 8081, which is not mapped to the host. On the public listener they return 404. Reach them with make metrics, make health-status and make fpm-status.

Stack

PHP 8.5, Symfony 8.1, PostgreSQL 17 (two databases, two entity managers), Redis 7, RabbitMQ, nginx + PHP-FPM. Tests: PHPUnit 12. Analysis: PHPStan at level max, PHP-CS-Fixer, Deptrac.

Architecture

DDD + CQRS. The code is split into bounded contexts under src/, each with four layers:

src/
  Shared/          kernel shared between contexts
  Identity/        accounts, authentication, plans and quotas
  UrlShortening/   creating and managing links
  Redirection/     serving redirects (hot path)
  Analytics/       click counting and reporting
  Safety/          abuse protection

The boundaries — both between layers and between contexts — are enforced by Deptrac through deptrac-layers.yaml and deptrac-contexts.yaml, not merely documented.

Quality

make cs        # PHP-CS-Fixer
make stan      # PHPStan at level max
make deptrac   # layer and bounded context boundaries
make test      # every test suite
make check     # all four in sequence

Test suites: tests/Unit (no I/O), tests/Integration (real Postgres and Redis, each test wrapped in a transaction that is rolled back), tests/Functional (end to end through the HTTP kernel).

Migrations

Two independent sets, because there are two databases:

make migrate            # default database
make migrate-analytics  # analytics database
make migrate-status     # status of both

Migrations never run automatically when a container starts — that is a separate deployment step.

About

No description or website provided.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages