Vienext
2026solo fullstack dev & devops engineer
A distributed social SaaS platform engineered around strict service boundaries, zero-trust cryptographic tokens, and asynchronous event streams.
Java · Spring Boot · Spring Cloud Gateway · TypeScript · PostgreSQL · RabbitMQ · Docker · WebSocket
01 — Overview
VieNext is a modern social SaaS platform engineered with a distributed microservices architecture. It combines high-throughput feed delivery, real-time WebSocket communication, and multi-tenant authentication into a cohesive, modular system.
Role & Scope
As the fullstack and backend architecture engineer, I designed and implemented the entire backend microservices cluster, the cryptographic security contracts between services, the asynchronous event pipelines, and the Next.js 15 frontend application.
Project Thesis
Distributed systems only succeed when service boundaries are enforced by strict cryptographic contracts rather than implicit network trust. VieNext demonstrates how to achieve low-latency throughput and high security without operational bloat.
02 — Problem
Building a modern social and interactive platform presents conflicting architectural demands:
- Tight coupling in monolithic models: Combining identity, feed generation, and real-time messaging into a single codebase creates deployment bottlenecks and prevents targeted scaling.
- Microservice trust vulnerabilities: In distributed systems, downstream services often blindly trust identity headers (
X-User-*) passed from API gateways, leaving the system vulnerable to header spoofing or unauthorized service-to-service (S2S) calls. - Latency vs. Security trade-offs: Validating tokens synchronously on every internal service hop introduces cascading latency and single-point-of-failure risks around the central auth service.
- Asynchronous consistency during onboarding: User registration workflows that synchronously invoke profile provisioning and notification triggers are prone to partial failures and slow response times.
03 — Architecture
The platform is structured into four primary layers: Edge Gateway, Domain Microservices, Event Broker, and Persistence.
┌─────────────────────────────────────────────────────────────┐
│ Client Application │
│ Next.js 15 · React 19 · TypeScript │
└──────────────────────────────┬──────────────────────────────┘
│ HTTPS / WSS
▼
┌─────────────────────────────────────────────────────────────┐
│ API Gateway (Edge) │
│ Spring Cloud Gateway · JWT Verification (Nimbus) │
│ Header Stripping · Signed Internal Token Minting │
└──────┬──────────────┬──────────────┬──────────────┬─────────┘
│ │ │ │
│ (S2S Token) │ (S2S Token) │ (STOMP/WS) │ (S2S Token)
▼ ▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ Auth │ │ Profile │ │ Chat │ │ Post │
│ Service │ │ Service │ │ Service │ │ Service │
└─────┬─────┘ └─────▲─────┘ └───────────┘ └─────┬─────┘
│ │ │
│ (Publish) │ (Consume) │
└────► ┌───────┴──────┐ │
│ RabbitMQ │ │
│ Event Broker │ │
└──────────────┘ │
┌────────────────────────────────────────────┴────────┐
│ Neon PostgreSQL Database │
│ Per-Service Isolated Schemas │
└─────────────────────────────────────────────────────┘Architectural Boundaries
- Edge Layer:
api-gatewayacts as the single public entry point. It handles SSL termination, CORS, rate limiting, and authenticates incoming client JWTs before minting signed internal tokens. - Identity Domain (
auth-service): Manages user credentials, challenge-based email verification, and database-backed refresh token sessions. - Social & Profile Domains (
profile-service,post-service): Handle user relationships, posts, comments, and feed aggregation with independent schema lifecycles. - Real-Time Domain (
chat-service): Manages bidirectional messaging over WebSocket (STOMP protocol). - Media Domain (
media-service): Handles image uploads, transformations, and optimizations directly via Cloudinary. - Shared Core (
common-core): A shared Java library enforcing uniform API responses, global exception handlers, and internal token cryptographic verification.
04 — Engineering
Authentication & Zero-Trust Security
- Gateway Verification: The API Gateway validates incoming client JWTs using Nimbus JOSE and strips any client-supplied
X-User-*orX-Internal-*headers to prevent header injection. - Signed Internal Tokens: For downstream communication, the Gateway mints a short-lived HMAC-SHA256 token containing verified claims (
userId,username,roles,issuer). Downstream services verify this token usingcommon-corebefore trusting user identity. - Session Management & Token Families: Implemented database-backed refresh token sessions (
AuthSession) with token family tracking. If a revoked or consumed refresh token is replayed, the entire token family is immediately invalidated to neutralize compromised sessions. - Account State Machine: Accounts transition through explicit states (
PENDING_VERIFICATION→ACTIVE). Unverified users cannot execute interactive social actions.
Data & Persistence
- Per-Service Schema Isolation: Each microservice maintains its own dedicated database schema within PostgreSQL, preventing cross-domain database coupling and foreign key entanglements.
- Automated Schema Evolution: Database schema migrations are version-controlled and applied at startup using Flyway.
Messaging & Event-Driven Communication
- Decoupled User Provisioning: When a user completes email verification,
auth-servicepublishes auser.verifiedevent to RabbitMQ.profile-serviceconsumes this event asynchronously to provision the user's profile without delaying the HTTP response. - Dead-Letter Queues & Retries: AMQP exchanges are configured with retry backoffs and dead-letter queues to guarantee at-least-once processing for critical background jobs.
Infrastructure & Deployment
- Multi-Stage Containerization: Docker builds are separated into a Maven compilation stage and a minimal Alpine JRE 21 runtime stage, reducing image sizes by over 60%.
- Network Isolation: Docker Compose orchestrates services inside an isolated internal bridge network (
vienext-net), exposing only the API Gateway to host ports.
05 — Challenges
1. Eliminating Header Spoofing Without Synchronous Auth Bottlenecks
In many microservice architectures, backend services either trust gateway headers blindly or call the auth service over HTTP on every request to introspect the token. The former is insecure; the latter introduces a severe latency bottleneck.
- Solution: Implemented an internal signing mechanism. The Gateway verifies the client JWT once, strips all untrusted headers, and mints an ephemeral HMAC-SHA256 signed internal token. Downstream services verify the signature locally in microsecond time using shared keys in
common-core.
2. Session Revocation in a Distributed Stateless Setup
Pure stateless JWTs cannot be revoked without maintaining a centralized distributed blocklist (e.g. Redis) that introduces additional operational complexity.
- Solution: Split identity into short-lived access tokens (15 minutes) and database-backed refresh token sessions with hash-only persistence. Refresh requests validate session validity, rotate the token, and detect token reuse attacks.
3. Service-to-Service Authorization Boundaries
Certain backend endpoints (such as batch profile fetching or media cleanup) should only be accessible by specific internal services, never by clients or other arbitrary services.
- Solution: Added caller identity claims to the internal token. The verifier in
common-coreenforces that endpoints likePOST /api/v1/profiles/batchreject requests unless the internal token explicitly identifies the caller aspost-service.
06 — Decisions
Decision: Gateway-Minted Internal Tokens vs. Mutual TLS (mTLS)
- Context: Need to guarantee authenticity of identity claims between Gateway and internal services.
- Alternative: Full service mesh with mTLS (e.g. Istio / Linkerd).
- Decision: Implemented lightweight HMAC-SHA256 signed tokens in
common-core. - Rationale: For a single-cluster deployment, mTLS adds significant infrastructure complexity, CPU overhead, and certificate management burden. Signed internal tokens provided identical security guarantees against spoofing with zero operational friction.
Decision: Event-Driven Provisioning vs. Synchronous REST Calls
- Context: Onboarding requires user creation in
auth-serviceand profile initialization inprofile-service. - Alternative:
auth-servicemakes a synchronous HTTP POST toprofile-service. - Decision: Publish
user.verifiedevent through RabbitMQ. - Rationale: Decouples service availability. If
profile-serviceis temporarily redeploying or under heavy load, the registration flow succeeds immediately and the profile is provisioned as soon as the service consumes the queue.
Decision: Elimination of the Backend-for-Frontend (BFF) Layer
- Context: The initial architecture considered a dedicated Node.js BFF layer between the Next.js frontend and the Java backend.
- Alternative: Maintain a separate Node.js BFF for request aggregation.
- Decision: Removed the BFF layer, routing the Next.js frontend directly through Spring Cloud Gateway.
- Rationale: Modern Next.js 15 Server Components already handle server-side data aggregation efficiently. A separate BFF added an unnecessary network hop and duplicated route definitions.
07 — Result
- Production-Ready Cluster: Built 5 Spring Boot microservices, Spring Cloud Gateway, and a Next.js 15 App Router frontend.
- Zero-Trust Security Verification: Passed exhaustive automated regression suites covering token tampering, expired tokens, wrong issuers, header injection, and direct backend access attempts.
- Optimized Footprint: Alpine JRE 21 multi-stage images reduced deployment footprint, enabling the entire stack (services + PostgreSQL + RabbitMQ) to run efficiently on a single VPS.
- Clean Domain Separation: Each domain (Auth, Profile, Post, Chat, Media) operates independently with dedicated persistence schemas and event contracts.
08 — Learnings
- Simplicity in security contracts: Security is most effective when it is enforced at the framework level through interceptors rather than left to individual controller logic. Centralizing token signing and verification in
common-coreprevented subtle authorization holes across services. - The true cost of distributed systems: Microservices offer great modularity, but every boundary requires careful consideration of latency, failure modes, and data consistency. Where synchronous calls can fail, asynchronous events provide resilience.
- App Router as an architectural simplifier: Using Next.js Server Components allowed server-side composition without needing an intermediate BFF service, keeping the infrastructure lean.