Skip to content

cryptobulldev/Lead-API

Repository files navigation

Backend API (Lumen) — MySQL Edition

A minimal, production-friendly backend that accepts unique leads, stores them in MySQL, and asynchronously notifies a local mock endpoint via an Outbox + Worker pattern. Includes API-key auth, JSON logs (PII-masked, request-ID propagation, daily rotation), and a test suite.

Highlights

  • Leads API (create/read) with validation and duplicate protection
  • Outbox Pattern: non-blocking notifications + worker retries (1s → 2s → 4s; max 3)
  • Local Mock /mock/notify with toggleable outcomes (off|always|random)
  • Security: protect endpoints with X-API-KEY
  • Logs: JSON lines, daily folders, PII masking, request-ID propagation
  • Feature flags from env (FEATURE_ASYNC_NOTIFY, FEATURE_CIRCUIT_BREAKER)
  • Circuit breaker (simple, cache-backed) around notify sending
  • Tests: unit + feature (composer test)
  • CLI: scripts to send sample leads; curl/Postman included

Project Structure

.
├─ app/
│  ├─ Console/
│  │  ├─ Commands/
│  │  │  ├─ ProcessOutbox.php            # worker (watch mode + graceful stop-file)
│  │  │  └─ StopOutbox.php               # stop worker process
│  │  └─ Kernel.php
│  ├─ Events/
│  ├─ Exceptions/
│  │  ├─ Handler.php
│  │  └─ CircuitOpenException.php
│  ├─ Helpers/
│  │  ├─ Flags.php                        # env feature flag helper
│  │  └─ SimpleCircuitBreaker.php         # tiny cache-backed circuit breaker
│  ├─ Http/
│  │  ├─ Controllers/
│  │  │  ├─ LeadController.php            # /leads endpoints
│  │  │  ├─ MockController.php            # /mock/notify
│  │  │  └─ HealthController.php          # /health
│  │  └─ Middleware/
│  │     ├─ ApiKeyMiddleware.php          # X-API-KEY guard
│  │     ├─ RequestIdMiddleware.php       # request ID propagation
│  │     └─ AccessLogMiddleware.php       # JSON access logs + PII masking
│  ├─ Jobs/
│  │  └─ NotifyLeadJob.php                # calls /mock/notify (with circuit breaker)
│  ├─ Listeners/
│  ├─ Models/
│  │  ├─ Lead.php
│  │  └─ OutboxJob.php
│  ├─ Providers/
│  │  ├─ AppServiceProvider.php
│  │  ├─ AuthServiceProvider.php
│  │  └─ EventServiceProvider.php
│  ├─ Repositories/
│  │  ├─ LeadDispatcher.php               # DB create/show for leads
│  │  └─ OutboxDispatcher.php             # enqueue + fetch due outbox jobs
│  └─ Services/
│     ├─ HealthService.php								# getting health
│     ├─ LeadService.php									# Lead store/show
│     ├─ MockService.php                  # mock notify
│     └─ OutboxService.php                # retries, backoff, logging
├─ bootstrap/
│  ├─ app.php
├─ config/
│  └─ jwt.php
├─ database/
│  ├─ factories/
│  ├─ migrations/                         # leads + outbox_jobs
│  └─ seeders/                            # leads seeder
├─ logs/                                  # rotated JSON logs (app.log)
│  └─ YYYY-MM-DD/
│     └─ app.log		
├─ public/
│  ├─ index.php
│  └─ .htaccess                           # optional (Apache)
├─ resources/
├─ routes/
│  └─ web.php                             # /health, /leads, /mock/notify
├─ scripts/
│  ├─ send_leads.php                      # PHP CLI sender
│  ├─ send_leads.ps1                      # PowerShell sender
│  └─ send_leads.sh                       # Bash sender
├─ storage/
├─ tests/
│  ├─ Feature/
│  │  ├─ FakeNotifyLeadJob.php
│  │  ├─ HealthTest.php
│  │  └─ LeadApiTest.php
│  └─ Unit/
│     └─ OutboxServiceTest.php
├─ .env.example
├─ .env                                   # not committed
├─ composer.json
├─ Lead_API.postman_collection.json       # postman collection exported
├─ phpunit.xml
└─ README.md

Requirements (Xampp 8.1.25)

  • PHP 8.1+ with pdo_mysql, mbstring, json, curl
  • MySQL 8.x (or MariaDB ≥10.4)
  • Compose

Setup

  • Create databases and user

    • Create a new database named MyDB in MySQL.
    • Configure a dedicated user account with appropriate permissions for this database. (For initial testing, the default MySQL user root with no password can be used, but it is strongly recommended to create a separate user with a secure password for production environments.)
  • Run Command

# Install
composer install
# Environment
cp .env.example .env
# Migrate
php artisan migrate
# Run the server (Lumen has no artisan serve)
php -S 127.0.0.1:8000 -t public
# Health check
curl http://127.0.0.1:8000/health

Authentication

  • All endpoints except /health and /mock/notify require:
X-API-KEY: <your .env API_KEY>
  • For traceability, you can pass a request id:
X-Request-Id: <any-unique-id>

Outbox Worker (retries, graceful stop)

  • POST /leads enqueues an outbox_jobs row and returns immediately.
  • The worker processes due jobs, calling /mock/notify.
  • Retries with backoff 1s → 2s → 4s - max 3 attempts - failed jobs kept with last_error.

Run once:

php artisan outbox:process

Run continuously with graceful stop:

php artisan outbox:process --watch --sleep=2
# in another terminal:
php artisan outbox:stop

CLI — Send Sample Leads

  • Bash scripts/send_leads.sh
chmod +x scripts/send_leads.sh
API_KEY=apikeysupersecret0925 HOST=http://127.0.0.1:8000 ./scripts/send_leads.sh 3
  • PowerShell scripts/send_leads.ps1
$env:HOST="http://127.0.0.1:8000"
$env:API_KEY="apikeysupersecret0925"
.\scripts\send_leads.ps1 -Count 3
  • PHP CLI
php scripts/send_leads.php 3
# or set envs:
HOST=http://127.0.0.1:8000 API_KEY=apikeysupersecret0925 php scripts/send_leads.php 3
  • Or Singl curl
curl -X POST http://127.0.0.1:8000/leads \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "X-API-KEY: apikeysupersecret0925" \
  -H "X-Request-Id: demo-abc-123" \
  -d '{"email":"user+'$(date +%s)'@example.com","first_name":"John","last_name":"Doe","phone":"+12025550123","utm_source":"curl"}'

Logging

  • JSON logs written to: logs/YYYY-MM-DD/app.log
  • Each line includes: timestamp, level, request_id, route, status, message
  • Access logs mask email/phone
  • Request ID flows HTTP → outbox payload (_rid) → worker → mock (searchable across logs)

Feature Flags & Circuit Breaker

  • FEATURE_ASYNC_NOTIFY=off → disables enqueue (synchronous no-op)

  • FEATURE_CIRCUIT_BREAKER=on → enables simple breaker around notify

    • Opens after CB_FAIL_THRESHOLD consecutive failures
    • Stays open CB_OPEN_SECONDS seconds, then allows a trial
    • Success resets; failure re-opens

To simulate failures:

MOCK_NOTIFY_FAIL_MODE=always

Then flip back to off to see recovery.

Tests

Run all tests:

composer test

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published