# Route Spec

## Route ID
`hubs-get`

## Endpoint
`GET /api/v1/hubs/{hubId}`

## Human Description
Returns hub profile details, member counts, active user count, and viewer status/role.

## Authentication
- Required: `yes`

## Responses
### Success: `200 OK`
```json
{
  "success": true,
  "message": "Hub loaded",
  "data": {
    "id": "hub_1",
    "name": "Cairo Startups",
    "description": "Founders and builders",
    "profilePhotoUrl": "https://cdn.example.com/hub/1/profile.jpg",
    "customLink": "cairo-startups",
    "memberCount": 12400,
    "activeUsers24h": 1390,
    "viewerStatus": "member",
    "viewerRole": "member"
  }
}
```

### Error: `401 Unauthorized`
When returned:
- Missing or invalid access token.

Body:
```json
{"success": false, "error": {"code": "UNAUTHORIZED", "message": "Authentication required.", "details": {}}}
```

### Error: `404 Not Found`
When returned:
- Hub does not exist.

Body:
```json
{"success": false, "error": {"code": "HUB_NOT_FOUND", "message": "Hub does not exist.", "details": {}}}
```

## Data & Caching Dependencies
- **Spanner Tables:** `hubs, hub_member_counters (Read)`
- **Redis Cache:** `None`
- **GCS Storage:** `None`
- **Edge Cache (CDN):** `Yes (short TTL)`

## Side Effects
- None (read-only endpoint).

## Privacy Notes
- `viewerStatus` may be `invited` or `pending_admin_approval` for dark hubs.
- Dark/pending users can see safe hub preview fields but cannot access hub feed, chat, voting, or private member phone numbers until membership is active.
