Rate Limiting#
| Scope | Limit | Window | Applies To |
|---|
| Global API | 100 req | 1 min | Per authenticated user |
| Auth (login/register) | 5 req | 1 min | Per IP |
| Code execution (run) | 10 req | 1 min | Per user |
| Code submission | 3 req | 1 min | Per user |
| Room joins | 5 req | 1 min | Per user |
| AI hints | 3 req | 5 min | Per user per room |
| AI messages | 20 req | 1 min | Per user per room |
Rate limit headers on every response:X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1709467260
429 responses include Retry-After header.CORS#
Allowed origins via CORS_ORIGINS env var. Default: http://localhost:5173,https://syncode.anggita.org.Versioning#
No URL versioning (internal API). Breaking changes use Accept-Version header with backward compat for one minor release.Request Size Limits#
Code submission body: 5 MB
Avatar upload metadata: 1 KB (actual upload goes to S3)
Observability#
Trace ID in X-Trace-Id response header (OpenTelemetry)
Structured logging (pino) with request ID correlation
Metrics: request count, latency histogram, error rate per endpoint
Data Retention#
| Data | Retention |
|---|
| Execution results & submissions | 24 hours (Redis TTL) |
| Audit logs | 1 year |
| Soft-deleted users | 30 days then anonymized |
| Match requests | 5 minutes |
| Code snapshots | Indefinite (with session) |
| Session recordings | 90 days (S3 lifecycle) |
| Refresh tokens | 7 days (Redis TTL) |
Conditional Requests#
| Endpoint | ETag | If-Match |
|---|
GET /problems/:id | Yes (weak, updatedAt) | - |
GET /users/me | Yes (weak, updatedAt) | - |
GET /sessions/:id/report | Yes (strong, immutable) | - |
PATCH /users/me | - | Yes (prevents lost updates) |
PATCH /problems/:id | - | Yes (prevents lost updates) |
Modified at 2026-03-12 05:26:10