Production-ready microservice for social interactions (Likes) across content types. Built with Rust, Axum, PostgreSQL, and Redis.
- API Layer: Axum web framework with REST endpoints
- Database: PostgreSQL 15+ with read replica support
- Cache: Redis for like counts (hot path), content validation, rate limiting
- Content Validation: Pluggable interface — add new content types via config only
User likes use token-based pagination (not offset) because:
- Consistency: Offset pagination can skip/duplicate items when data changes during pagination
- Performance:
WHERE (created_at, id) < (ts, id)uses the index efficiently; offset requires scanning N rows - Scale: Tokens don't degrade with large offsets
- Like counts: Redis, TTL 300s. Invalidated on write. Fallback to DB when Redis unavailable.
- Content validation: Redis, TTL 3600s. Reduces external API calls.
- Cache stampede: Single-flight pattern (simplified in initial implementation).
docker compose up --buildService: http://localhost:8080
# Health
curl -s http://localhost:8080/health/ready | jq .
# Like count (public)
curl -s http://localhost:8080/v1/likes/post/731b0395-4888-4822-b516-05b4b7bf2089/count | jq .
# Like (auth)
curl -X POST http://localhost:8080/v1/likes \
-H "Authorization: Bearer tok_user_1" \
-H "Content-Type: application/json" \
-d '{"content_type":"post","content_id":"731b0395-4888-4822-b516-05b4b7bf2089"}' | jq .| Method | Path | Auth | Description |
|---|---|---|---|
| POST | /v1/likes | Bearer | Like content |
| DELETE | /v1/likes/{type}/{id} | Bearer | Unlike |
| GET | /v1/likes/{type}/{id}/count | — | Like count (cached) |
| GET | /v1/likes/{type}/{id}/status | Bearer | User like status |
| GET | /v1/likes/user | Bearer | User's likes (page_token) |
| POST | /v1/likes/batch/counts | — | Batch like counts |
| POST | /v1/likes/batch/statuses | Bearer | Batch like statuses |
| GET | /v1/likes/top | — | Top liked (leaderboard) |
| GET | /v1/likes/stream | — | SSE like events |
| GET | /health/live | — | Liveness |
| GET | /health/ready | — | Readiness |
| GET | /metrics | — | Prometheus metrics |
| Variable | Required | Default |
|---|---|---|
| DATABASE_URL | Yes | — |
| READ_DATABASE_URL | No | DATABASE_URL |
| REDIS_URL | Yes | — |
| HTTP_PORT | No | 8080 |
| CONTENT_API_POST_URL | No | http://mock-post-api:8081 |
| CONTENT_API_BONUS_HUNTER_URL | No | http://mock-bonus-hunter-api:8082 |
| CONTENT_API_TOP_PICKS_URL | No | http://mock-top-picks-api:8083 |
| PROFILE_API_URL | No | http://mock-profile-api:8084 |
- Content API: GET /v1/{content_type}/{content_id} — returns 200 with items for valid UUIDs
- Profile API: GET /v1/auth/validate with Bearer token — returns user_id for tok_user_1..5
MIT