Laravel/PHP is **not obsolete**—Laravel 13 is current, actively maintained, and still a perfectly reasonable choice. Laravel releases annually, with bug fixes for 18 months and security fixes for two years. ([Laravel][1]) For your application, though—database, MQTT-connected devices, live status, APIs, and likely a web dashboard—I would lean toward a **TypeScript stack using NestJS**. ## My recommendation ```text Web UI: React + Next.js Backend API: NestJS + TypeScript Database: PostgreSQL Database ORM: Prisma MQTT broker: Mosquitto initially; EMQX if you outgrow it MQTT processor: Separate NestJS worker process Live browser UI: WebSockets or Server-Sent Events Deployment: Docker Compose initially Reverse proxy: Caddy, Traefik, or nginx ``` NestJS is particularly suitable because it supports conventional HTTP APIs, WebSockets, background services, and MQTT transport within one consistent framework. A Nest application can also operate as a “hybrid application,” listening for HTTP requests and messages from another transport. ([NestJS Documentation][2]) ### Suggested architecture ```text ┌────────────────────┐ │ React / Next.js UI │ └─────────┬──────────┘ │ HTTPS / WebSocket ┌─────────▼──────────┐ │ NestJS API │ │ Auth, users, maps, │ │ devices, tickets │ └─────────┬──────────┘ │ ┌──────▼──────┐ │ PostgreSQL │ └─────────────┘ MagLink / Receivers │ │ MQTT over TLS ▼ ┌──────────────────┐ ┌─────────────────────┐ │ MQTT Broker │──────▶│ MQTT Worker │ │ Mosquitto / EMQX │ │ validate, store, │ └──────────────────┘ │ acknowledge, alert │ └──────────┬──────────┘ │ PostgreSQL / API ``` I would **not** have the web API itself be the MQTT broker. Keep these separate: * The broker handles connections, sessions, subscriptions, retained messages, QoS, and TLS. * Your worker subscribes to device topics, validates messages, writes database records, and publishes acknowledgments. * Your API handles users, configuration, history, maps, device management, and commands. * The browser receives live updates through WebSockets or Server-Sent Events—not directly from the device MQTT namespace. This separation means restarting or deploying the web application does not disconnect every field device. ## Why NestJS is a good fit NestJS feels somewhat like Laravel: | Laravel concept | NestJS equivalent | | ----------------- | --------------------------- | | Controllers | Controllers | | Middleware | Middleware | | Service container | Dependency injection | | Artisan commands | CLI commands/scripts | | Eloquent models | Prisma models | | Queued jobs | Worker processes/queues | | Events/listeners | Events and message handlers | | Laravel Echo | WebSocket gateways | Because everything is TypeScript, you can share types between the browser, API, and MQTT message definitions. That is particularly useful for your MagLink JSON payloads: ```typescript export interface LocateRecord { messageId: string; deviceSerial: string; timestamp: string; latitude: number; longitude: number; altitudeM?: number; fixType: "NONE" | "GPS" | "DGPS" | "RTK_FLOAT" | "RTK_FIXED"; depthCm?: number; frequencyHz?: number; gain?: number; signalStrength?: number; tiltDeg?: number; ticketNumber?: string; } ``` You can then validate the runtime payload with Zod or NestJS validation before inserting it into PostgreSQL. ## Don’t begin with microservices I would start with one repository and three deployable processes: ```text apps/ web/ Next.js frontend api/ NestJS HTTP/WebSocket API mqtt-worker/ NestJS MQTT subscriber packages/ database/ Prisma schema and client contracts/ Shared DTOs and MQTT schemas common/ Shared utilities ``` They can all use the same PostgreSQL database at first. This gives you clear boundaries without introducing Kubernetes, Kafka, service discovery, distributed tracing, or multiple databases prematurely. Run them locally with Docker Compose: ```yaml services: postgres: image: postgres:17 environment: POSTGRES_DB: maglink POSTGRES_USER: maglink POSTGRES_PASSWORD: development volumes: - postgres-data:/var/lib/postgresql/data mosquitto: image: eclipse-mosquitto:2 ports: - "1883:1883" - "8883:8883" volumes: - ./infrastructure/mosquitto:/mosquitto/config api: build: . command: npm run start:api depends_on: - postgres mqtt-worker: build: . command: npm run start:mqtt-worker depends_on: - postgres - mosquitto web: build: . command: npm run start:web depends_on: - api volumes: postgres-data: ``` ## MQTT design I’d use For your devices, use topics such as: ```text devices/{serial}/telemetry devices/{serial}/locates devices/{serial}/status devices/{serial}/commands devices/{serial}/commands/ack ``` Every important device message should contain: ```json { "messageId": "01JZ...", "schemaVersion": 1, "deviceSerial": "ML-001234", "timestamp": "2026-07-11T21:50:00Z", "payload": {} } ``` The server should enforce a unique database constraint on `messageId`. That gives you idempotency: if MQTT QoS causes redelivery, the message is not stored twice. For important records: 1. Device publishes with QoS 1. 2. Worker validates and stores the record. 3. Database transaction commits. 4. Worker publishes an application-level acknowledgment containing the original `messageId`. 5. Device retains the local record until it receives that acknowledgment. MQTT QoS confirms broker delivery; your application acknowledgment confirms that your system actually accepted and persisted the record. ## Authentication Use two separate security systems: **Web users** * Secure HTTP-only session cookies * OIDC/OAuth later if customers need Microsoft or Google login * Organization-based access control in the database **Devices** * TLS from the beginning * Ideally one client certificate per device * Broker ACLs that restrict each device to its own topic hierarchy * Never embed a common fleet-wide MQTT password in every unit ## Other good options ### ASP.NET Core This would also be an excellent choice for you, especially since you already work with .NET MAUI. ASP.NET Core supports long-running hosted services, and MQTTnet provides both MQTT client and broker functionality with MQTT 5 support. ([Dotnet][3]) A good .NET version would be: ```text ASP.NET Core Web API Entity Framework Core PostgreSQL MQTTnet client React or Blazor frontend ``` I would choose this over NestJS when: * You prefer C# over JavaScript/TypeScript. * The server will contain substantial business logic. * You expect close integration with your MAUI application. * Long-term static typing and compiler enforcement matter more than frontend/backend language sharing. Honestly, **ASP.NET Core may be the strongest fit for your background**. NestJS is the more fashionable web stack, but ASP.NET Core is modern, mature, fast, strongly typed, and exceptionally well supported. ### Modern Laravel Staying with Laravel would be the fastest path if you already know it well: ```text Laravel 13 PostgreSQL React or Vue starter kit Laravel queues Separate PHP MQTT worker Mosquitto ``` Laravel 13 has first-party modern frontend integration and remains actively supported. ([Laravel][1]) The downside is that persistent MQTT consumers and highly concurrent real-time connections are somewhat less natural in traditional PHP deployment models than in Node.js or .NET. ### FastAPI/Python FastAPI is excellent for data processing, GIS, ML, and quick APIs, but I would not select it merely because Python is popular. Its built-in background tasks are intended to run after HTTP responses, rather than serve as a complete durable job-processing architecture. ([FastAPI][4]) It makes sense if significant Python-specific processing will occur. ## My final choice for your project Given your embedded devices, MQTT requirements, .NET MAUI exposure, and expectation that this may become a serious customer-facing platform: ```text Backend: ASP.NET Core Database: PostgreSQL + Entity Framework Core MQTT: Mosquitto + MQTTnet worker service Frontend: React + TypeScript Realtime: SignalR Local setup: Docker Compose Hosting: A single Linux VM initially ``` I would build it as a **modular monolith**, with the MQTT ingestion worker as a separate process. That gives you modern tooling and reliable long-running MQTT handling without adding unnecessary infrastructure. NestJS would be my second choice, particularly if you want TypeScript across the entire web stack. [1]: https://laravel.com/docs/13.x/releases?utm_source=chatgpt.com "Release Notes | Laravel 13.x - The clean stack for Artisans ..." [2]: https://docs.nestjs.com/microservices/basics?utm_source=chatgpt.com "Microservices | NestJS - A progressive Node.js framework" [3]: https://dotnet.github.io/MQTTnet/?utm_source=chatgpt.com "MQTTnet" [4]: https://fastapi.tiangolo.com/tutorial/background-tasks/?utm_source=chatgpt.com "Background Tasks"