Real-time location tracking SaaS platform designed for developers. Hosts a fast, protocol-agnostic backend and scalable infrastructure—built with Laravel, Swoole, Redis, and MariaDB.
Rectifies vendor lock-in by enabling clients to integrate via TCP, UDP, WebSocket, HTTP, or Redis Pub/Sub without relying on proprietary SDKs (dev.to, github.com).
- Core Features
- Architecture Overview
- Protocol Interfaces
- Geofencing & Webhooks
- Quickstart – Local Docker Setup
- Client Integration Guidelines
- Extending & Contributing
- Deployment & Scaling
- Security & Compliance
- License & Author
- Multi-protocol ingestion: Supports TCP, UDP, HTTP POST, WebSocket, and Redis Pub/Sub.
- Geofencing: Define zones—polygonal or circular—with events for entry/exit via webhooks or Redis (linkedin.com, dev.to).
- Scalable queuing: Uses Redis for ingestion buffers and Laravel queues for reliable processing.
- Designed for microservices: Clients can subscribe to a Redis channel and forward events to custom handlers .
- Dashboard: Provides UI to monitor active devices, zones, tokens, and events.
- Containerization: Built for Docker Compose and Kubernetes with environment-based services.
┌── Clients ──> [TCP/UDP/WebSocket/HTTP] ──┐
│ ↓
│ Swoole-based Protocol Servers
│ ↓
│ Redis ingestion queues
│ ↓
│ Laravel queue workers
│ ↓
│ MariaDB (event storage)
│ ↓
│ Dashboard / API / Webhooks
└──────────────────────────────────────────────┘
Devices connect over TCP/UDP on configured ports. Example packet format:
{
"device_id": "abc123",
"lat": 36.75,
"lng": 3.06,
"timestamp": 1710000000
}Laravel’s SwooleListener wraps these into jobs targeting Redis queues for asynchronous handling.
Clients initiate persistent WS connections:
const ws = new WebSocket("ws://host:port");
ws.onopen = () => {
ws.send(JSON.stringify({ device_id: "abc123", lat: 36.75, lng: 3.06 }));
};The server broadcasts DeviceLocationUpdated events channelled through Redis (dev.to).
HTTP API endpoints allow POST /api/track with similar JSON payloads for quick integrations and testing.
A backend listener—e.g., written in Python—subscribes to Pulsetracker channels:
def channel_callback(data):
redis.rpush("pulsetracker_database_queues:geopulse", job_json)This decouples real-time ingestion from event processing (dev.to).
Define geofence zones via dashboard or programmatically:
Http::withToken('API_KEY')
->post('https://www.pulsestracker.com/api/geofences', [
'name' => 'Warehouse Zone',
'app_id' => 12345,
'webhook_url' => 'https://yourapp.com/webhook/geofence',
'geometry' => json_encode([
'type' => 'Polygon',
'coordinates' => [[[1,1],[1,2],[2,2],[2,1],[1,1]]]
])
]);Pulsetracker emits events via POST to your webhook:
{
"event": "inside",
"point": { "type":"Point","coordinates":[1.5,1.5] },
"device_id": 42,
"geofence_id": 123,
"location_received_at": 1700000000,
"event_sent_at": 1700000005
}Secure webhook handling in Laravel:
class VerifyPulsetrackerSignature
{
public function handle(Request $req, Closure $next)
{
$sig = $req->header('p-signature');
$secret = config('pulsetracker.webhook_secret');
if (!hash_equals(hash_hmac('sha256', json_encode($req->all()), $secret), $sig)) {
return response()->json(['error' => 'Invalid signature'], 403);
}
return $next($req);
}
}Then register route:
Route::post('/webhook/geofence', [GeofenceWebhookController::class, 'handle'])
->middleware('verify.pulsetracker');Controller logs or dispatches the event internally (dev.to).
Prereqs: Docker, Docker Compose
git clone https://github.com/LAGGOUNE-Walid/pulsetracker.git
cd pulsetracker
cp .env.example .env
# Set REDIS_PASSWORD and PULSET_TRACKER_API_KEY
docker-compose up -d --build
docker-compose exec php php artisan migrate --seedAccess services:
- API / Dashboard:
http://localhost:8080 - TCP listener: port 9000 (default)
- WebSocket: port 1215
- Redis: default 6379 (auth via env)
Run queue workers:
docker-compose exec php php artisan queue:work --queue=geopulse,defaultConnect to real-time channels and push into Redis queue:
pusher = pysher.Pusher(key=APP_KEY, auth_endpoint=..., custom_host="pusher.pulsestracker.com")
def on_update(data):
redis.rpush("pulsetracker_database_queues:geopulse", job_payload)Queue names follow pulsetracker_database_queues:<queue> convention (dev.to).
class PulseLocationUpdatedJob implements ShouldQueue
{
public function handle($job, array $data)
{
DeviceLocation::create([
'device_id' => $data['device_id'],
'latitude' => $data['lat'],
'longitude' => $data['lng'],
'timestamp' => $data['timestamp']
]);
$job->delete();
}
}Dispatch this in queue:work for reliable persistence.
- Fork and PR: Follow Git flow with feature branches.
- Testing:
phpunitinside container. - New protocols: Add Swoole listener and box JSON to queue.
- Geofence enhancements: Support circles, dynamic membership via dashboard.
- Client SDKs: Add Node.js, Go, or mobile wrappers.
-
Docker Compose works for small to mid-scale use.
-
For higher scale:
- Deploy Swoole servers behind load balancers
- Use Redis cluster
- Configure Laravel queue workers with Horizon or Supervisor
-
Monitoring:
- Check
jobs:failed,redis:monitor, and Swoole metrics.
- Check
-
Security:
- TLS for HTTP/WS
- Enforce TLS between services
- Secure Redis with ACL or password
- TLS authentication on protocols
- Webhooks validated via HMAC headers
- Sensitive data in env (
.env) or secrets manager - Follow OWASP and PCI DSS practices as needed
MIT License – see LICENSE.
Developed and maintained by Walid Laggoune – Backend Engineer and Founder of PulseTracker. Based in Algiers, Algeria (dev.to, github.com, linkedin.com, dev.to, laggoune-walid.github.io).
- Python + Laravel real-time listener guide
- Laravel geofencing integration example (dev.to)
- Node.js Redis Pub/Sub backend use case (linkedin.com)