Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
179 changes: 179 additions & 0 deletions .cursor/plans/microservices_infrastructure_setup_c72c57a3.plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
---
name: Microservices Infrastructure Setup
overview: Set up microservices infrastructure (API Gateway, shared patterns, single shared database, inter-service communication) before extracting the Activity Service as the next microservice.
todos:
- id: api-gateway
content: Create API Gateway (Spring Cloud Gateway) with JWT validation, routing, rate limiting, CORS
status: completed
- id: shared-lib
content: Create shared library or copy shared DTOs/utils to services
status: completed
- id: shared-db
content: Use single shared MySQL database for monolith and all services
status: completed
- id: inter-service-comm
content: Set up Feign clients + Resilience4j for inter-service communication
status: completed
- id: redis-pubsub
content: Implement Redis Pub/Sub for cross-service async events
status: completed
- id: extract-activity
content: Extract Activity Service (entities, repos, services, controllers, DTOs)
status: completed
- id: gateway-routes
content: Update gateway routes for activity-service
status: completed
- id: health-logging
content: Add health checks, structured logging, and distributed tracing across services
status: completed
- id: extract-chat
content: Extract Chat Service (chat entities, REST + optional WebSocket, Feign to monolith/activity)
status: completed
- id: monolith-cleanup
content: Remove activity/chat domain from monolith, use Feign clients and spawn-common DTOs
status: completed
isProject: false
---

# Microservices Infrastructure & Next Service Extraction Plan

## Current State

- Auth service extracted at `services/auth-service/` (port 8081)
- Main monolith at `src/main/java/` with modular package structure
- Both share the same MySQL database
- No API Gateway, no inter-service communication, no Docker
- Deploying on Railway

## Phase 1: Infrastructure Foundation (Weeks 1-3)

### 1A. API Gateway (Spring Cloud Gateway)

Create `gateway/api-gateway/` as a new Spring Boot application:

- **JWT validation** as a global filter -- the gateway validates tokens so downstream services don't each need to. It adds `X-User-Id` header to forwarded requests.
- **Route configuration** mapping `/api/v1/auth/`** to auth-service (port 8081), everything else to the monolith (port 8080) for now. As services are extracted, new routes get added.
- **Rate limiting** via Redis (reuse existing Bucket4j or use Spring Cloud Gateway's built-in Redis rate limiter).
- **CORS handling** centralized at the gateway level.
- **Health check** endpoint at `/actuator/health`.
- Gateway runs on port **8090** (or configurable).

Key files to create:

- `gateway/api-gateway/pom.xml` -- Spring Cloud Gateway + JWT dependencies
- `gateway/api-gateway/src/main/java/.../GatewayApplication.java`
- `gateway/api-gateway/src/main/java/.../filter/JwtAuthFilter.java`
- `gateway/api-gateway/src/main/resources/application.yml` -- route definitions

### 1B. Shared Library Pattern

Since services are independent Maven projects, create a lightweight shared module at `shared/spawn-common/`:

- **Common DTOs** for inter-service communication (e.g., `UserSummaryDTO` that services exchange)
- **JWT utilities** (token validation logic shared between gateway and services)
- **Common exception types**

Publish via `mvn install` locally, or as a GitHub Package for Railway builds. Each service adds it as a Maven dependency.

Alternatively, for maximum simplicity: just copy the ~5-10 shared classes into each service. Easier to start with, refactor to shared lib later.

### 1C. Single Shared Database

All backends (monolith and microservices) use **one MySQL database**:

- No new databases per service — monolith, auth-service, and future services (e.g. activity-service) all connect to the same MySQL instance/schema.
- Auth service and activity service use the same datasource URL as the monolith; each service only touches the tables it owns (e.g. auth: `email_verification`, `user_id_external_id_map`; activity: `activity`, `activity_type`, etc.).
- User data for login/registration can stay as direct DB access or REST to monolith, depending on preference; shared DB allows direct access if desired.
- Flyway migrations can live in the monolith (or a single migration module) so schema changes are applied once.

### 1D. Inter-Service Communication

Set up the pattern for services to call each other:

- **Synchronous (Feign/RestTemplate):** Auth service calls monolith to look up users. Activity service (later) calls monolith for user data.
- **Async events (Redis Pub/Sub):** Replace Spring `ApplicationEventPublisher` with Redis Pub/Sub for cross-service events (e.g., "user registered" event from auth -> monolith notification system). Start simple -- only add Redis Pub/Sub for events that actually need to cross service boundaries.
- **Circuit breakers (Resilience4j):** Wrap Feign clients so a downstream service outage doesn't cascade.

---

## Phase 2: Extract Activity Service (Weeks 4-8)

Once infrastructure is in place, extract the Activity domain:

### What moves to `services/activity-service/`:

- **Entities:** `Activity`, `ActivityType`, `ActivityUser`, `Location` (from [activity/internal/domain/](src/main/java/com/danielagapov/spawn/activity/internal/domain/))
- **Repositories:** Activity, ActivityType, ActivityUser, Location repositories
- **Services:** `ActivityService`, `ActivityTypeService`, `LocationService`, `CalendarService`, `ActivityParticipationService`
- **Controllers:** `ActivityController`, `ActivityTypeController`, `CalendarController`
- **DTOs:** All activity-related DTOs

### Cross-cutting concerns:

- Activity service needs **user data** (creator info, participant info) -- use Feign client to call monolith's `/api/v1/users/{id}` endpoint
- Activity service needs **friend data** (for invite validation) -- Feign client to monolith's social endpoints
- Activity creation triggers **notification events** -- publish to Redis Pub/Sub, monolith's notification module subscribes
- **Caching:** Activity service gets its own Redis namespace (`activity:`*)

### Database:

- **Shared database:** Activity service connects to the same MySQL as the monolith. Activity, ActivityType, ActivityUser, Location tables remain in that single schema; Flyway migrations (if used) stay in the monolith or a single place.

### Gateway update:

- Add route: `/api/v1/activities/`** and `/api/v1/activity-types/`** -> activity-service

---

## Phase 3: Polish & Prepare for Chat (Weeks 9-10)

- Add health checks to all services (Spring Boot Actuator)
- Set up structured logging (JSON format) across services
- Add distributed tracing headers (`X-Trace-Id` propagation)
- Document API contracts between services
- Monitor Railway metrics, tune resource allocation
- Evaluate: proceed to Chat Service extraction?

---

## Phase 4: Extract Chat Service (Next)

- **Scope:** Move chat domain from monolith to `services/chat-service/` (port 8083).
- **What moves:** Entities `ChatMessage`, `ChatMessageLikes`; repositories; `ChatMessageService`, `IChatMessageService`; `ChatMessageController`; DTOs (`CreateChatMessageDTO`, `FullActivityChatMessageDTO`, etc.).
- **Cross-cutting:** Chat service needs activity membership checks — Feign to activity-service or monolith. Monolith currently exposes `/api/v1/chat-messages/by-activity/{activityId}` for activity-service; after extraction, chat-service owns that API and activity-service calls chat-service via Feign.
- **Gateway:** Add route `/api/v1/chat-messages/`** → chat-service.
- **Optional:** WebSocket support for real-time messaging (see `docs/microservices/MICROSERVICES_IMPLEMENTATION_PLAN.md`).
- **Database:** Shared MySQL; chat tables remain in the same schema.

---

## Summary of Deliverables

- `gateway/api-gateway/` -- Spring Cloud Gateway with JWT validation, routing, rate limiting
- `shared/spawn-common/` -- shared DTOs (activity, chat, user) for Feign clients and inter-service contracts
- `services/auth-service/` -- uses shared database; Feign client for user lookup as needed
- `services/activity-service/` -- microservice for activity domain (shared database)
- `services/chat-service/` -- microservice for chat domain (shared database)
- Updated monolith: activity/chat domains removed; uses ActivityServiceClient, ChatServiceClient; DTOs from spawn-common
- Updated gateway routes
- Distributed tracing: `X-Trace-Id` propagation (gateway), MDC in monolith; see `docs/microservices/DISTRIBUTED_TRACING.md`

## Monolith Cleanup (Completed)

- Removed `src/main/java/.../activity/` package (controllers, services, repos, entities, DTOs)
- Removed activity mappers (ActivityMapper, ActivityTypeMapper, LocationMapper)
- Removed activity notification events (ActivityInviteNotificationEvent, etc.) — activity-service has its own
- Replaced IActivityService/IActivityTypeService usage with ActivityServiceClient (ReportContentService, CacheService, ShareLinkController, NewCommentEventSubscriber)
- Replaced ICalendarService with ActivityServiceClient and ActivityExpirationService with ActivityExpirationUtil
- ActivityTypeInitializer and ActivityTypeEventListener now call activity-service via Feign
- Added MinimalFriendDTO to spawn-common for ActivityTypeDTO

## Key Technical Decisions

- **Independent Maven projects** per service (no parent POM)
- **No Docker** for local dev -- develop against Railway
- **Spring Cloud Gateway** for API Gateway
- **Feign + Resilience4j** for synchronous inter-service calls
- **Redis Pub/Sub** for async cross-service events
- **Single shared MySQL database** for monolith and all services on Railway

29 changes: 29 additions & 0 deletions docs/microservices/DISTRIBUTED_TRACING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Distributed Tracing (X-Trace-Id)

Request tracing is implemented so logs across the gateway and backend services can be correlated by a single ID.

## How it works

1. **API Gateway** (`gateway/api-gateway`):
- **TraceIdFilter** runs first on every request.
- If the client sends an `X-Trace-Id` header, it is reused; otherwise a new UUID is generated.
- The chosen trace ID is added to the request forwarded to downstream services and echoed in the response (`X-Trace-Id`).

2. **Monolith** (`src/main/java`):
- **TraceIdMdcFilter** reads `X-Trace-Id` from the request (or generates one for direct calls) and puts it in SLF4J MDC under the key `traceId`.
- Logback is configured so log lines include `traceId=...`. This allows log aggregation tools to correlate all log entries for a given request.

3. **Other services** (auth-service, activity-service):
- When called via the gateway, they receive `X-Trace-Id` on the request.
- To include trace ID in their logs, add a similar filter that reads `X-Trace-Id` and puts it in MDC, and add `traceId=%X{traceId:-}` (or equivalent) to the log pattern.

## Client usage

Clients can send an `X-Trace-Id` header (e.g. a UUID they generate) when making requests. The same value will be returned in the response and used for all downstream calls, making it easy to correlate client-side logs with backend logs.

## Feign / outbound calls

When a service (e.g. activity-service) calls another service via Feign, the gateway is not in the path. To propagate the trace ID:

- Add a Feign `RequestInterceptor` that reads the current MDC `traceId` (or request attribute) and sets the `X-Trace-Id` header on the outgoing request.
- Ensure the receiving service has a filter that puts `X-Trace-Id` into MDC (as in the monolith).
2 changes: 2 additions & 0 deletions gateway/api-gateway/.mvn/maven.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Maven configuration options
# Add Maven command-line options here, one per line
19 changes: 19 additions & 0 deletions gateway/api-gateway/.mvn/wrapper/maven-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
wrapperVersion=3.3.2
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
Loading
Loading