rdev/internal/db/migrations/005_rate_limiting.sql
jordan 72d16929ca feat: Implement hexagonal architecture with services, webhooks, queue, and telemetry
Major refactoring to hexagonal (ports & adapters) architecture:

- Add service layer (apikey_service, project_service) for business logic
- Add webhook system with dispatcher and delivery tracking
- Add command queue with priority-based processing
- Add rate limiting with sliding window algorithm
- Add audit logging for command execution
- Add OpenTelemetry integration (traces, metrics, spans)
- Add circuit breaker for fault tolerance
- Add cached repository wrapper for performance
- Add comprehensive validation package
- Add Kubernetes client integration for pod management
- Add database migrations (allowed_ips, audit_log, rate_limiting, queue, webhooks)
- Add network policy and PodDisruptionBudget for k8s
- Remove legacy executor and projects/registry packages
- Untrack secrets.yaml (now managed via envault)
- Add coverage.out to .gitignore
- Add e2e test infrastructure with docker-compose
- Add comprehensive documentation (API, architecture, operations, plans)
- Add golangci-lint config and pre-commit hook

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:57:46 -07:00

32 lines
1.6 KiB
SQL

-- Add rate limiting columns to api_keys table
ALTER TABLE api_keys
ADD COLUMN IF NOT EXISTS rate_limit_per_minute INT DEFAULT 60,
ADD COLUMN IF NOT EXISTS rate_limit_per_hour INT DEFAULT 1000;
-- Create rate_limit_state table to track per-key usage windows
CREATE TABLE IF NOT EXISTS rate_limit_state (
id SERIAL PRIMARY KEY,
api_key_id UUID NOT NULL REFERENCES api_keys(id) ON DELETE CASCADE,
window_start TIMESTAMPTZ NOT NULL,
window_type VARCHAR(10) NOT NULL, -- 'minute' or 'hour'
request_count INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (api_key_id, window_start, window_type)
);
-- Index for efficient lookups by api_key_id and window
CREATE INDEX IF NOT EXISTS idx_rate_limit_state_lookup
ON rate_limit_state(api_key_id, window_type, window_start DESC);
-- Index for cleanup of old entries
CREATE INDEX IF NOT EXISTS idx_rate_limit_state_cleanup
ON rate_limit_state(window_start);
COMMENT ON TABLE rate_limit_state IS 'Tracks rate limit usage per API key per time window';
COMMENT ON COLUMN rate_limit_state.window_start IS 'Start of the time window (truncated to minute or hour)';
COMMENT ON COLUMN rate_limit_state.window_type IS 'Type of window: minute or hour';
COMMENT ON COLUMN rate_limit_state.request_count IS 'Number of requests in this window';
COMMENT ON COLUMN api_keys.rate_limit_per_minute IS 'Maximum requests allowed per minute (default: 60)';
COMMENT ON COLUMN api_keys.rate_limit_per_hour IS 'Maximum requests allowed per hour (default: 1000)';