NowHere: Distributed Geospatial & Real-Time Microservices
High-Concurrency Location-Based Discovery Engine Built with NestJS, NATS JetStream & React Native
Executive Overview
NowHere is an enterprise-grade, distributed geolocation discovery platform engineered to answer a core real-time question: “What is happening right around me right now?”
Unlike traditional social platforms that push algorithmic feeds stored in centralized relational databases, NowHere enables hyper-local, ephemeral discovery. Users capture and view nearby “Snaps” categorized as Lost & Found, Hidden Gems, Local Promotions, or Live Events.
Key Architectural Requirements:
- High Concurrency & Low Latency: Real-time geofenced notifications broadcast to active clients within 100km radii with sub-100ms delivery.
- Zero-Bottleneck Media Ingestion: Camera feeds producing 5MB raw images must not choke API gateway bandwidth or saturate Node.js event loops.
- Decoupled Distributed Services: Discrete microservices communicating via microsecond-level RPCs with guaranteed at-least-once asynchronous event delivery.
- Multi-Cloud Vendor Portability: Clean separation of secrets management and blob storage across AWS, GCP, and local containerized environments via the Strategy Pattern.
High-Level System Context & Topology
NowHere segregates client ingress, API gateway routing, internal event messaging, and dedicated polyglot database persistence into cleanly isolated boundaries:
Figure 1: High-level architectural topology showing client ingress, API gateway routing, NATS message bus, domain microservices cluster, and polyglot database persistence.
The 5 Core Microservices
The backend is architected as an Nx Monorepo containing five decoupled applications:
Figure 2: Microservices class and interaction architecture displaying controllers, data layers, and NATS subject patterns.
1. API Gateway (apps/gateway)
Acts as the single point of entry on port 3005, shielding internal microservices from the public internet.
- Centralized Authentication Guard (
GatewayAuthGuard): Validates incoming Bearer JWT tokens, injects user payloads into request scopes, and prevents unauthorized requests from touching the internal NATS bus. - Envelope Standardization (
DataResponseInterceptor): Wraps all successful responses in a unified{ success: true, data: T }envelope. - Error Normalization (
HttpExceptionFilter): Converts exceptions into RFC 9457 Problem Details schemas with explicittype,title,status,detail, andinstanceproperties.
2. Authentication Service (apps/authentication)
Owns credential storage and token lifecycle management.
- Storage: Dedicated MySQL database using TypeORM.
- Security: Argon2 hashing for credentials, stateless RS256 JWT access tokens, and rolling refresh tokens.
- NATS Patterns: Listens to
auth.login,auth.signup,auth.refresh,auth.validate_token, andauth.me.
3. Users Service (apps/users)
Manages user profiles, social relationships, and discovery radius configurations.
- Storage: Independent MySQL schema (
users,settings,snaps_seen). - NATS Patterns: Responds to
users.get_by_id,users.update_profile,users.set_photo, andusers.get_settings. - Cross-Service Communication: Queries the
storagemicroservice over NATS request-reply to retrieve temporary signed download URLs for user avatars.
4. Snaps Service (apps/snaps)
The core geospatial discovery engine.
- Storage: MongoDB utilizing a native
2dspherespatial index onlocation.coordinates([longitude, latitude]). - Real-Time Gateway: An integrated Socket.IO server tracking live client coordinates in memory for real-time localized event dispatching.
- NATS Patterns: Handles
snaps.create,snaps.get_nearby, andsnaps.get_by_id.
5. Storage Service (apps/storage)
An isolated microservice responsible for media management and cloud abstraction.
- Cloud Strategy Pattern: Supports AWS S3, Cloudflare R2, MinIO, and Google Cloud Storage (GCS).
- Presigned URL Pipeline: Generates temporary cryptographic PUT/GET URLs so that binary media bypasses internal server memory completely.
- Redis Caching: Download URLs are cached in Redis with strict TTLs (
CACHE_TTL = 86340s) to avoid redundant signature computations.
Detailed Data Flows & Sequence Workflows
1. Direct-to-S3 Presigned Media Ingestion Pipeline
Handling 5MB camera image uploads synchronously through an API gateway saturates Node.js network sockets and increases memory footprint. NowHere solves this by decoupling upload authorization from binary transfer:
Figure 3: Sequence workflow demonstrating direct-to-S3 presigned upload bypass and lightweight metadata persistence.
2. Real-Time Proximity Broadcast & Vectorized Haversine Engine
When a snap is created, it must be pushed immediately to active users nearby without polling:
Figure 4: Sequence diagram detailing spatial proximity filtering using the Haversine distance formula.
The Haversine Mathematical Implementation (SnapsGateway):
getDistanceInMeters(lat1: number, lon1: number, lat2: number, lon2: number): number {
const toRadians = (deg: number) => deg * (Math.PI / 180);
const R = 6371e3; // Earth radius in meters
const dLat = toRadians(lat2 - lat1);
const dLon = toRadians(lon2 - lon1);
const a =
Math.sin(dLat / 2) ** 2 +
Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) * Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c; // Distance in meters
}
Inter-Service Communication: NATS Request-Reply vs. JetStream
NowHere divides communication into two distinct message delivery guarantees:
Figure 5: Comparison between synchronous NATS request-reply RPCs and asynchronous durable JetStream event streams.
1. Synchronous NATS Request-Reply
- Used when the API Gateway requires immediate data to answer an HTTP request (e.g., authenticating credentials or retrieving user settings).
- Latency is under 1ms on local container bridges, significantly faster than HTTP/1.1 REST calls between services.
2. Asynchronous NATS JetStream (At-Least-Once Delivery)
- Used for decoupled side-effects where the client should not wait (e.g., notifying subscribers, processing analytics, updating user streaks).
- If a downstream worker crashes, JetStream’s durable consumer maintains message offsets and retries upon worker restart.
Multi-Cloud Portability: Strategy Pattern
To prevent vendor lock-in across commercial cloud ecosystems, secrets retrieval and blob storage are abstracted behind TypeScript strategy interfaces.
Figure 6: Strategy Pattern class structure enabling multi-cloud portability across AWS, GCP, and local environments.
By specifying SECRETS_PROVIDER=gcp or STORAGE_PROVIDER=aws, the NestJS dependency injection container dynamically binds the corresponding concrete implementation at runtime with zero changes to business logic.
Frontend Integration & State Architecture (React Native / Expo 53)
The mobile client is built on React Native (Expo 53) utilizing a multi-layered offline-first data flow:
Figure 7: Frontend architecture diagram showing UI screens, TanStack React Query, Zustand, and MMKV C++ storage.
Technical Highlights of Frontend Implementation:
- Fast Storage via MMKV: Uses the C++ MMKV engine instead of
AsyncStorage, executing key-value transactions 30x faster and eliminating frame drops when caching dense geospatial arrays. - Resilient Auth Hydration: JWT access tokens and refresh tokens are stored in hardware-encrypted
Expo SecureStore. On cold boot,useAuthSessionseamlessly validates the session against/auth/mewithout flickering unauthenticated screens. - Offline Coordinate Smoothing: Real-time user position changes are debounced before transmission over WebSocket, conserving battery life while maintaining accurate proximity calculation.
Architectural Decision Records (ADRs)
| Decision | Chosen Solution | Alternatives Evaluated | Engineering Rationale |
|---|---|---|---|
| Inter-Service Broker | NATS Request-Reply + JetStream | RabbitMQ, gRPC, HTTP REST | Microsecond RPC latency, native pub/sub, zero connection pooling overhead, and built-in durable message replay. |
| Geospatial Engine | MongoDB 2dsphere Indexing | PostgreSQL + PostGIS | Flexible JSON document schema for dynamic tagging, combined with native millisecond $nearSphere queries. |
| Media Pipeline | Direct Presigned S3 Bypass | Multipart Stream through Gateway | Eliminates API gateway memory leaks, reduces server bandwidth costs to near-zero, and leverages S3 multi-part acceleration. |
| Error Handling Contract | RFC 9457 Problem Details | Ad-hoc error strings | Uniform machine-readable error format (type, status, detail, errors[]) shared across all services and mobile clients. |
| Cache Layer | Redis (Distributed Cache) | Node.js In-Memory Map | Shares signed media URL cache across scaled service replicas, preventing redundant signature generations. |
Local Development & Container Verification
# 1. Clone the monorepo
git clone https://github.com/AliSaleemHasan/NowHere.git
cd NowHere/backend
# 2. Spin up full microservices stack via Docker Compose
# (NATS, MySQL Auth, MySQL Users, MongoDB Snaps, MinIO S3, Redis Cache)
docker compose -f docker-compose.dev.yml up -d
# 3. Verify health checks across all services:
# - API Gateway: http://localhost:3005/health
# - Snaps Service: http://localhost:3002/health
# - Users Service: http://localhost:3001/health
# - Auth Service: http://localhost:3000/health
# - Storage Service: http://localhost:3004/health
# 4. Execute unit & integration test suites via Nx
pnpm nx run-many --target=test --all