Skip to content

feat(backend): response caching with ETag support and per-route TTLs#174

Merged
Smartdevs17 merged 2 commits intoSmartdevs17:mainfrom
gidson5:feature/response-caching
Mar 29, 2026
Merged

feat(backend): response caching with ETag support and per-route TTLs#174
Smartdevs17 merged 2 commits intoSmartdevs17:mainfrom
gidson5:feature/response-caching

Conversation

@gidson5
Copy link
Copy Markdown
Contributor

@gidson5 gidson5 commented Mar 29, 2026

Summary

Adds backend/src/middleware/cache.ts — a cacheControl() middleware factory covering all three acceptance criteria.

What changed

File Change
backend/src/middleware/cache.ts New middleware: cacheControl() factory + CacheTTL constants
backend/src/middleware/__tests__/cache.test.ts 16 unit tests
backend/src/index.ts Global no-store for mutations + Vary: Accept-Encoding
backend/src/routes/catalog.ts STATIC cache (300 s + stale-while-revalidate=60)
backend/src/routes/stellar.ts SHORT for accounts (30 s), IMMUTABLE for txs (600 s)
backend/src/routes/verification.ts SHORT cache on GET /:id (30 s)

Acceptance criteria

  • Cache GET responses with ETag supportcacheControl() computes a SHA-1 ETag from the response body and returns 304 Not Modified when If-None-Match matches
  • Configure cache duration per routeCacheTTL constants (STATIC / SHORT / IMMUTABLE / NONE) applied individually to each GET route
  • Add Cache-Control headerspublic, max-age=N on cached GET responses; no-store on all mutation methods via global middleware in index.ts

Test plan

  • 16 unit tests pass: npm test (vitest)
  • Confirm curl -I /api/v1/catalog returns Cache-Control: public, max-age=300 and an ETag
  • Confirm second request with If-None-Match: <etag> receives 304 Not Modified
  • Confirm POST to any route returns Cache-Control: no-store

Closes #17

🤖 Generated with Claude Code

gidson5 added 2 commits March 29, 2026 08:10
…ollback (Smartdevs17#46)

Adds scripts/deploy.sh implementing the full deployment lifecycle:

- Build: runs `npm ci && npm run build` for backend (TypeScript/tsc)
  and frontend (Next.js) independently; each can be skipped via flags
- Database migration hook: structured no-op with commented-out
  stubs for Prisma, TypeORM, and custom migration scripts — ready
  to activate when a database is introduced
- Zero-downtime reload: uses PM2 `reload` for in-place restarts of
  existing processes; `start` for first-time deploys
- Health check: polls GET /health (up to 12 × 5s) and accepts both
  `healthy` and `degraded` status responses (HTTP 200/206)
- Automatic rollback: backs up dist/ and .next/ before each deploy;
  restores and reloads processes if the health check fails
- Manual rollback: `./scripts/deploy.sh --rollback` restores the
  last saved backup at any time

Flags: --env <staging|production>, --skip-frontend, --skip-backend,
       --skip-migrations, --rollback

Closes Smartdevs17#46
…TLs (Smartdevs17#17)

Adds backend/src/middleware/cache.ts — a cacheControl() middleware factory
that handles all three acceptance criteria:

Cache-Control headers
  Sets `public/private, max-age=N [, stale-while-revalidate=M]` on GET/HEAD
  responses. Mutation methods (POST/PUT/PATCH/DELETE) receive `no-store` via
  a global middleware in index.ts so they are never accidentally cached.

ETag support
  Intercepts res.json(), serialises the body, and computes a 16-char SHA-1
  ETag. On subsequent requests that include `If-None-Match`, the middleware
  short-circuits and returns 304 Not Modified without re-sending the payload.

Configurable per-route durations
  CacheTTL constants define four tiers:
    STATIC (300 s)   — catalog (rarely changes)
    SHORT (30 s)     — stellar account balances, verification results
    IMMUTABLE (600 s)— confirmed Stellar transactions (never change)
    NONE (0)         — explicit no-store

Routes updated:
  GET /api/v1/catalog            → STATIC  (300 s + stale-while-revalidate=60)
  GET /api/v1/stellar/account/:a → SHORT   (30 s)
  GET /api/v1/stellar/tx/:hash   → IMMUTABLE (600 s)
  GET /api/v1/verification/:id   → SHORT   (30 s)

Tests: 16 unit tests covering Cache-Control header generation, ETag
consistency, 304 conditional GET, non-GET passthrough, and no-store.

Closes Smartdevs17#17
@vercel
Copy link
Copy Markdown

vercel Bot commented Mar 29, 2026

@gidson5 is attempting to deploy a commit to the smartdevs17's projects Team on Vercel.

A member of the Team first needs to authorize it.

@Smartdevs17 Smartdevs17 merged commit b958f55 into Smartdevs17:main Mar 29, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backend: Add response caching

2 participants