Files
sentryagent-idp/docs/devops/architecture.md
SentryAgent.ai Developer d94a8cedc0 docs: DevOps documentation — complete docs/devops/ set
Adds the full devops-documentation OpenSpec change implementation.
Separate from docs/developers/ — serves a different audience (operators,
not API consumers).

docs/devops/:
- README.md          — index and system overview
- architecture.md    — components, ports, data flow, Redis key patterns
- environment-variables.md — all 7 env vars (required + optional, formats, .env example)
- database.md        — 4-table schema, indexes, constraints, migration runner
- local-development.md — docker-compose setup, health checks, startup, Dockerfile gap noted
- security.md        — RSA key generation/rotation, CORS, bcrypt, secret storage guidance
- operations.md      — startup order, graceful shutdown, log reference, troubleshooting

QA gates: 48/48 tasks complete. All env vars verified against source.
All table names verified against migrations. All ports verified against
docker-compose.yml. All internal links resolve.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 14:28:55 +00:00

5.4 KiB

Architecture

Component Overview

                    ┌─────────────────────────────────────┐
                    │         AgentIdP Application         │
                    │           Node.js / Express          │
                    │              Port 3000               │
                    │                                      │
                    │  Auth MW → RateLimit MW → Routes     │
                    │       ↓                   ↓          │
                    │  Controllers → Services → Repos      │
                    └──────────────┬──────────────┬────────┘
                                   │              │
                    ┌──────────────▼──┐   ┌───────▼────────┐
                    │   PostgreSQL 14  │   │    Redis 7      │
                    │    Port 5432     │   │   Port 6379     │
                    │                  │   │                 │
                    │  agents          │   │  Token revoke   │
                    │  credentials     │   │  Rate limits    │
                    │  audit_events    │   │  Monthly counts │
                    │  token_revocati- │   │                 │
                    │  ons             │   │                 │
                    └──────────────────┘   └─────────────────┘

Components

AgentIdP Application

A stateless Express HTTP server. Every request is handled independently — no in-process shared state. This means it can be horizontally scaled (multiple instances) as long as all instances share the same PostgreSQL and Redis.

Internal layers:

Layer Responsibility
Routes Wire HTTP methods and paths to controllers
Auth middleware Validate Bearer JWT (RS256 + Redis revocation check)
Rate limit middleware Redis sliding-window counter per client_id
Controllers Parse and validate request, call service, return response
Services Business logic — no direct DB access
Repositories All SQL queries — no business logic
Utils JWT sign/verify, bcrypt, error types, async handler

PostgreSQL 14+

Primary durable data store. All agent identities, credentials, audit events, and token revocation records live here. See database.md for schema details.

The application connects via a connection pool (pg.Pool) initialised from DATABASE_URL. The pool is a singleton shared across all request handlers.

Redis 7+

Ephemeral store for three use cases:

Key pattern Purpose TTL
revoked:<jti> Token revocation list — checked on every authenticated request Until token's exp
rate:<client_id>:<window> Request count per client per 60-second window 60 seconds
monthly:<client_id>:<year>:<month> Token issuance count for free tier limit enforcement End of month

Redis is supplementary, not the source of truth. Token revocations are also written to the token_revocations PostgreSQL table for durability across Redis restarts. On Redis restart, the revocation list is cold — previously revoked tokens will pass auth until the PostgreSQL-backed warm-up is implemented (Phase 2).

Request Data Flow

HTTP Request
    │
    ▼
Express Router (matches path + method)
    │
    ▼
Auth Middleware
  - Extract Bearer token from Authorization header
  - Verify RS256 signature using JWT_PUBLIC_KEY
  - Check Redis for revocation (key: revoked:<jti>)
  - Attach decoded payload to req.user
    │
    ▼
Rate Limit Middleware
  - Key: rate:<client_id>:<60s-window>
  - Increment counter in Redis (INCR + EXPIRE)
  - Set X-RateLimit-* headers
  - Reject with 429 if count > 100
    │
    ▼
Controller
  - Validate request body / query params (Joi schemas)
  - Call service method
  - Return HTTP response
    │
    ▼
Service
  - Business logic and orchestration
  - Calls one or more repositories
  - Fires audit log writes (async, fire-and-forget)
    │
    ▼
Repository
  - Executes parameterised SQL queries
  - Maps DB rows to typed interfaces
  - Returns typed results to service
    │
    ▼
PostgreSQL / Redis

Service Map

Route prefix Service Repository
/api/v1/agents AgentService AgentRepository
/api/v1/agents/:id/credentials CredentialService CredentialRepository
/api/v1/token OAuth2Service TokenRepository, CredentialRepository, AgentRepository
/api/v1/audit AuditService AuditRepository

Ports

Service Internal port Exposed port (local dev)
AgentIdP app 3000 3000
PostgreSQL 5432 5432
Redis 6379 6379

Graceful Shutdown

The server listens for SIGTERM and SIGINT. On receipt:

  1. server.close() is called — stops accepting new connections
  2. In-flight requests complete
  3. process.exit(0) is called

The PostgreSQL pool and Redis client are not explicitly closed in the current shutdown path. This is safe for single-instance deployments; connection cleanup is handled by the OS.