Skip to Content
⚠️Active Development Notice: TimeTiles is under active development. Information may be placeholder content or not up-to-date.
DevelopmentArchitectureResource Protection

Resource Protection

TimeTiles combines quotas for resource allocation with rate limits for request frequency. They protect different boundaries; not every operation needs both.

Two-Layer Protection

AspectQuotasRate limits
PurposeLimit resource consumption and daily usageLimit bursts and sustained request frequency
ScopeAuthenticated userIdentifier chosen by the caller, such as user ID or IP
StoragePostgreSQLIn-memory Map or PostgreSQL
WindowsUTC calendar days or current resource totalsFixed-duration windows starting with the first request
ExamplesDaily uploads, total events, active schedulesUpload burst, hourly API requests

Why Both Exist

A user can stay within a daily upload quota while sending requests too quickly. Conversely, requests spread across the day can avoid a burst limit while exhausting storage or processing capacity. Rate limits constrain request frequency; quotas constrain the associated resource use.

These application checks do not replace network-level denial-of-service protection.

Execution Flow

Where both protections apply, reject excessive request frequency before performing quota-controlled work:

Request → Rate-limit check → Quota check/reservation → Process request

Custom routes opt into rate limiting through apiRoute(). Quota enforcement belongs at the operation that consumes the resource, including collection hooks and background import processing. Use QuotaService.checkAndIncrementUsage() when usage must be reserved atomically; a separate check followed by an increment can race with concurrent requests.

Rate-limit and quota errors handled by the shared API error handler return HTTP 429. Background jobs have their own failure and review handling; they do not return HTTP responses.

When Each Triggers

Limits are cumulative: passing a burst window does not bypass an hourly or daily window. For example, the default Regular upload limits allow one request per five seconds but only five per hour. Uploading every six seconds therefore reaches the hourly rate limit before the ten-upload daily quota.

See Usage Limits for the complete defaults rather than treating this example as a separate configuration source.

Trust Level Scaling

Trust levels provide default quotas and upload/API rate limits. Per-user quota overrides take precedence over quota defaults.

The Unlimited (5) level removes many quotas, but still has a file-size quota and rate limits. Fixed technical ceilings, including the import wizard’s 50 MB preview limit, remain independent of trust level.

Daily Resets

Daily quota windows use midnight UTC. The quota-reset maintenance task resets daily counters, and quota accounting also resets stale daily counters on access so enforcement does not depend on the task running at exactly midnight. Non-daily resource totals, such as events and active schedules, are not cleared by this reset.

Rate-limit windows are fixed, not sliding: the first request starts a window, subsequent requests retain its expiry, and the first request after expiry starts a new window. Expiry is checked during requests; cleanup removes expired entries but is not needed to unlock an expired window.

Storage Differences

Set RATE_LIMIT_BACKEND to select rate-limit storage:

  • memory (default): process-local counters, lost on restart. Suitable for local development and single-process deployments.
  • pg: shared PostgreSQL counters updated by an atomic UPSERT. Use this for multiple workers or replicas so each process does not grant its own independent allowance.

In production, the service rejects memory when WEB_CONCURRENCY or CLUSTER_WORKERS indicates more than one worker. This check cannot discover independently deployed replicas; their configuration must still select pg.

Quotas always use PostgreSQL, regardless of the rate-limit backend.

Implementation

  • lib/services/quota-service.ts: effective quotas, usage accounting and atomic reservations.
  • lib/services/rate-limit-service.ts: identifiers, multiple rate-limit windows and trust-level limits.
  • lib/services/rate-limit/{memory-store,pg-store}.ts: counter storage and expiry.
  • lib/jobs/handlers/quota-reset-job/: daily quota maintenance.
  • lib/jobs/handlers/rate-limit-cleanup-job.ts: expired PostgreSQL rate-limit counter cleanup.

The memory backend cleans expired entries within the running process. The rate-limit-cleanup maintenance task handles PostgreSQL entries. The separate cache-cleanup task manages application caches, not quota or rate-limit resets.

Last updated on