Integration Matrix: family-hub + devarno.cloud Services
Generated: 2026-02-19
Status: TASKSET 2 Deliverable
Overview
This document is the source of truth for all external service integrations fromfamily-hub (casa.devarno.cloud) to surrounding devarno.cloud services. Every external call path maps to a documented contract.
Service Integration Matrix
| Service | Status | Protocol | Auth Model | Base URL Env Var | Contract Source |
|---|---|---|---|---|---|
| chat-service | Implemented | HTTP REST + WebSocket | Cookie forwarding / Query token | CHAT_SERVICE_URL, NEXT_PUBLIC_CHAT_WS_URL | proto-contracts/proto/devarno/events/v1/chat.proto |
| media-service | Implemented | HTTP REST (multipart) | Cookie forwarding | MEDIA_SERVICE_URL | proto-contracts/proto/devarno/content/v1/media.proto |
| auth-service | Scaffolding | HTTP REST | N/A (family-hub uses better-auth directly) | N/A | proto-contracts/proto/devarno/shared/v1/user.proto |
| api-gateway | Scaffolding | HTTP | JWT (planned) | N/A | N/A |
| audit-service | Scaffolding | Redis Streams (planned) | Internal | N/A | proto-contracts/proto/devarno/events/v1/audit.proto |
| config-service | Scaffolding | HTTP + Redis pub/sub (planned) | Cookie | N/A | N/A |
Detailed Endpoint Contracts
1. chat-service (Rust/Axum)
Base URLs:- REST:
${CHAT_SERVICE_URL}(default:http://localhost:8082) - WebSocket:
${NEXT_PUBLIC_CHAT_WS_URL}(default:ws://localhost:8082)
- HTTP endpoints: Cookie header forwarded verbatim
- WebSocket: Query parameter
?token=<better-auth.session_token> - Validation:
GET ${AUTH_SERVICE_URL}/api/auth/get-sessionwith Cookie header
Endpoints
| Method | Path | family-hub Caller | Request | Response | Errors |
|---|---|---|---|---|---|
| GET | /ws?token=<token> | use-chat-socket.ts | WebSocket upgrade | WS connection | 401 invalid token |
| GET | /api/v1/messages | /api/chat-service/messages/route.ts | ?channel=<id>&before=<ts>&limit=<n> | ChatMessage[] | 401, 400 |
| GET | /api/v1/presence | Not currently used | ?channel=<id> | PresenceUpdate[] | 401 |
WebSocket Message Contract (JSON)
Client → Server:Proto Contract Mapping
| Proto Message | chat-service JSON Field | family-hub Type |
|---|---|---|
ChatMessage.id | id | string |
ChatMessage.content | content | string |
ChatMessage.sender_id | sender (WS) / sender_id (REST) | string |
ChatMessage.channel_id | channel (WS) / channel_id (REST) | string |
ChatMessage.created_at | timestamp (WS) / created_at (REST) | string (ISO8601) |
ChatMessage interface in modules/chat/service.ts:13-21 and hooks/use-chat-socket.ts:11-19 instead of importing from proto-contracts/gen/ts/.
2. media-service (Go/Gin)
Base URL:${MEDIA_SERVICE_URL} (default: http://localhost:8081)
Authentication: Cookie header forwarded verbatim
Endpoints
| Method | Path | family-hub Caller | Request | Response | Errors |
|---|---|---|---|---|---|
| POST | /api/v1/upload | /api/media/upload/route.ts | multipart/form-data with file, optional type | UploadResponse | 401, 400, 413, 415 |
| GET | /api/v1/files/:id | Not proxied | - | MediaMetadata | 401, 404 |
| GET | /api/v1/files/:id/download | Direct URL in content | - | Binary file | 401, 404 |
| GET | /api/v1/files/:id/download?thumb=1 | Direct URL in content | - | Binary thumbnail | 401, 404 |
| DELETE | /api/v1/files/:id | Not proxied | - | 204 | 401, 403, 404 |
Upload Response Contract
Proto Contract Mapping
| Proto Message | media-service JSON Field | Notes |
|---|---|---|
UploadResponse.id | id | Match |
UploadResponse.url | url | Match |
UploadResponse.thumbnail_url | thumbnail_url | Match |
UploadResponse.sha256 | sha256 | Match |
UploadResponse.size_bytes | size_bytes | Proto is int64, JSON is number |
Restrictions
- Allowed content types:
image/jpeg,image/png,image/gif,image/webp,application/pdf,video/mp4,video/webm - Max file size: 10MB (configurable via
MAX_FILE_SIZE) - Max avatar size: 2MB (configurable via
MAX_AVATAR_SIZE) - Role
childcannot upload files
3. better-auth (Internal to family-hub)
family-hub does not call an external auth-service. Authentication is handled internally viabetter-auth library with the following configuration:
Session Validation Endpoint (exposed by better-auth):
chat-service→src/auth/client.rs:24-46media-service→internal/services/auth_client.go:27-55
- Domain:
.devarno.cloud - SameSite:
lax - Secure:
true(production)
Call Path Inventory
family-hub → chat-service
| family-hub Location | Target | Auth | Purpose |
|---|---|---|---|
src/hooks/use-chat-socket.ts:236-238 | ${CHAT_WS_URL}/ws?token=<token> | Query param (session token) | WebSocket realtime messages |
src/hooks/use-chat-socket.ts:139-141 | /api/chat-service/messages (internal) | Credentials | Load message history |
src/app/api/chat-service/messages/route.ts:37-44 | ${CHAT_SERVICE_URL}/api/v1/messages | Cookie forwarding | Proxy to chat-service |
family-hub → media-service
| family-hub Location | Target | Auth | Purpose |
|---|---|---|---|
src/app/api/media/upload/route.ts:24-30 | ${MEDIA_SERVICE_URL}/api/v1/upload | Cookie forwarding | Upload files |
family-hub Internal (Direct DB)
| family-hub Location | Data Source | Purpose |
|---|---|---|
src/modules/chat/service.ts | Drizzle → messages, users tables | Polling fallback message storage |
src/modules/chat/presence.ts | In-memory Map (BROKEN on Vercel) | Presence tracking |
src/app/api/chat/messages/route.ts | modules/chat/service.ts | Polling endpoint |
src/app/api/chat/send/route.ts | modules/chat/service.ts | Send message (polling fallback) |
src/app/api/chat/presence/route.ts | modules/chat/presence.ts | Presence heartbeat |
Gap Analysis
Critical Gaps
| Gap | Impact | Resolution |
|---|---|---|
| In-memory presence | Presence data not shared across Vercel instances | TASKSET 4: Move to Upstash Redis |
| Duplicate message storage | Messages stored in both family-hub DB and chat-service DB | Decide single source of truth |
| No proto-contracts usage | family-hub defines own types; drift risk | Import from proto-contracts/gen/ts/ |
| No request IDs | Cannot trace requests across services | Add X-Request-ID / traceparent header |
| No timeouts | Proxy routes have no explicit fetch timeout | Add 10s timeout to all outbound fetches |
| No retries | Single failure = user error | Add retry with exponential backoff for idempotent calls |
Architecture Gaps
| Gap | Description | Resolution |
|---|---|---|
| WS auth via raw session token | Session token passed in query param to chat-service | TASKSET 1 decision: Implement ephemeral tokens |
| No unified error envelope | Each route returns different error shapes | Standardize: { error: string, code?: string } |
| Polling without backoff | Fixed 3s interval regardless of errors | Add exponential backoff + jitter |
| Direct cookie parsing in JS | use-chat-socket.ts:79-83 parses document.cookie | Fetch token from server endpoint |
Environment Variables (Complete)
Required
| Variable | Service | Description |
|---|---|---|
DATABASE_URL | family-hub | Neon PostgreSQL connection string |
BETTER_AUTH_SECRET | family-hub | Auth encryption key (min 32 chars) |
BETTER_AUTH_URL | family-hub | Auth base URL (e.g., https://casa.devarno.cloud) |
RESEND_API_KEY | family-hub | Resend email service API key |
NEXT_PUBLIC_APP_URL | family-hub | Client-side app URL |
MEDIA_SERVICE_URL | family-hub | Media service backend URL |
CHAT_SERVICE_URL | family-hub | Chat service REST URL |
NEXT_PUBLIC_CHAT_WS_URL | family-hub | Chat service WebSocket URL |
New (Required for Production)
| Variable | Service | Description |
|---|---|---|
UPSTASH_REDIS_REST_URL | family-hub | Upstash Redis endpoint |
UPSTASH_REDIS_REST_TOKEN | family-hub | Upstash Redis auth token |
WS_TOKEN_SECRET | family-hub | Secret for signing ephemeral WS tokens |
External Service Dependencies
| Service | Required Env Vars |
|---|---|
| chat-service | DATABASE_URL, REDIS_URL, AUTH_SERVICE_URL, PORT |
| media-service | DATABASE_URL, AUTH_SERVICE_URL, PORT, STORAGE_PATH, BASE_URL |
AUTH_SERVICE_URL for chat-service and media-service should point to family-hub’s /api/auth/get-session endpoint (e.g., https://casa.devarno.cloud).
CORS / Origins Configuration
family-hub Trusted Origins
Fromsrc/lib/auth.ts:77-81:
Security Headers
Fromnext.config.ts:
X-Frame-Options: DENYContent-Security-Policy: connect-src 'self' wss: ws:(allows WebSocket)Strict-Transport-Security: max-age=31536000; includeSubDomains
WebSocket CORS
chat-service must allow WebSocket upgrades from:https://casa.devarno.cloudhttp://localhost:3000(development)
Proto Contract File Locations
| Domain | Proto File | Generated TypeScript |
|---|---|---|
| Chat | proto-contracts/proto/devarno/events/v1/chat.proto | proto-contracts/gen/ts/devarno/events/v1/chat_pb.ts |
| Media | proto-contracts/proto/devarno/content/v1/media.proto | proto-contracts/gen/ts/devarno/content/v1/media_pb.ts |
| User | proto-contracts/proto/devarno/shared/v1/user.proto | proto-contracts/gen/ts/devarno/shared/v1/user_pb.ts |
| Audit | proto-contracts/proto/devarno/events/v1/audit.proto | proto-contracts/gen/ts/devarno/events/v1/audit_pb.ts |
How to Regenerate
Failure Modes and Error Handling
chat-service Unavailable
| Scenario | Current Behavior | Correct Behavior |
|---|---|---|
| WS connection fails | Exponential backoff (1s, 2s, 4s), then polling | Acceptable |
| Polling 500 error | Silent failure, retry in 3s | Log, exponential backoff |
| Auth validation fails | WS upgrade rejected | Redirect to sign-in |
media-service Unavailable
| Scenario | Current Behavior | Correct Behavior |
|---|---|---|
| Upload fails | Generic “Failed to upload file” | Show service-specific error, suggest retry |
| Timeout | No timeout configured | 30s timeout for uploads, user feedback |
Database Unavailable
| Scenario | Current Behavior | Correct Behavior |
|---|---|---|
| Neon connection fails | 500 “Internal server error” | Graceful degradation message |
| Health check fails | Returns unhealthy status | Acceptable |
Verification Checklist
- Every external
fetch()in family-hub documented above - Every external
fetch()has explicit timeout - All required env vars listed
- All proto-contracts mapped to actual payloads
- Error envelopes consistent across routes
- Request ID propagation implemented
- Gaps identified have resolution tasks
Next Steps (TASKSET 3)
- Create unified service client layer (
src/lib/services/) - Import types from
proto-contracts/gen/ts/ - Add request ID generation and propagation
- Implement timeouts and retry logic
- Create ephemeral WS token endpoint
- Replace in-memory presence with Upstash Redis