Architecture Decision Records¶
This page documents the key architectural decisions made during the development of Imbi v2. We use Architecture Decision Records (ADRs) as described by Michael Nygard to capture important architectural choices and their rationale.
What is an ADR?¶
An Architecture Decision Record (ADR) is a document that captures an important architectural decision made along with its context and consequences. Each ADR describes:
- Context: The issue or requirement that prompted the decision
- Decision: The change or approach being proposed or adopted
- Status: Whether the decision is proposed, accepted, deprecated, or superseded
- Consequences: The positive and negative outcomes of the decision
ADR Index¶
Core Architecture¶
ADR 0001: Record Architecture Decisions¶
Date: 2025-12-30 | Status: Accepted
Establishes the practice of using Architecture Decision Records to document architectural decisions on this project, following Michael Nygard's format.
Key Points:
- Lightweight ADR process adopted
- ADRs stored in version control alongside code
- Provides historical context for architectural choices
ADR 0002: Authentication and Authorization Architecture¶
Date: 2025-12-30 | Status: Accepted
Comprehensive design for Imbi's authentication and authorization system, including OAuth2/OIDC integration, JWT tokens, API keys, and permission management.
Key Decisions:
- Graph database (originally Neo4j, since migrated to Apache AGE on PostgreSQL — see ADR 0006/0007) for user and permission data (natural fit for permission inheritance)
- ClickHouse for audit logs (time-series optimized with automatic TTL)
- JWT tokens with revocation list (stateless with security)
- Argon2id for password hashing (modern, memory-hard algorithm)
- Hybrid RBAC + resource-level permissions (flexible and powerful)
- FastAPI dependency injection for authorization (not middleware)
- Dual authentication for services (JWTs and API keys)
Authentication Methods:
- Local username/password
- OAuth2 (GitHub, Google, Generic OIDC)
- JWT tokens for API access
- API keys for service-to-service communication
ADR 0003: Email Sending Architecture¶
Date: 2026-01-01 | Status: Accepted
Design for transactional email system supporting password reset, welcome emails, email verification, and security alerts.
Key Decisions:
- Direct SMTP using Python's
smtplib(no vendor lock-in) - Templates stored in source code (version control, code review)
- FastAPI BackgroundTasks for async delivery (simple, no infrastructure)
- Exponential backoff retry with dead letter queue
- Mailpit for development testing (web UI, SMTP server in Docker)
- ClickHouse for email audit logs (1-year retention)
- Jinja2 with dual HTML/text templates (accessibility)
- Table-based layout with inline CSS (email client compatibility)
Email Types:
- Password reset
- Welcome messages
- Email verification
- Security notifications
ADR 0004: Phase 5 Authentication Enhancements¶
Date: 2026-01-01 | Status: Accepted
Seven security and usability enhancements to the authentication system, addressing gaps identified after Phase 4 completion.
Key Enhancements:
- Token Revocation: Implement actual logout (complete Phase 2 TODO)
- OAuth Token Encryption: Encrypt provider tokens using Fernet
- Rate Limiting: Using slowapi library to prevent brute force
- API Keys: Full-featured API keys with scopes and usage tracking
- Session Management: Enforce max concurrent sessions setting
- MFA/2FA: TOTP-based multi-factor authentication with backup codes
- Token Rotation: Rotate refresh tokens on every use (security best practice)
Security Improvements:
- OAuth tokens encrypted at rest (Fernet symmetric encryption)
- Token revocation on logout (immediate invalidation)
- Rate limiting on auth endpoints (5/min login, 10/min refresh, etc.)
- MFA support with TOTP and backup codes
- Refresh token rotation (detects token theft)
- Session limits (prevent session hijacking)
API Keys:
- Format:
ik_<16chars>_<32chars>for easy identification - Scoped permissions (least privilege)
- Usage tracking in ClickHouse
- Rotation support
- Expiration enforcement
ADR 0005: File Upload Storage Architecture¶
Date: 2026-02-06 | Status: Accepted
Design for general-purpose file upload system backed by S3-compatible storage, supporting icons, avatars, and documents for all Node-based entities.
Key Decisions:
- S3-compatible object storage with aioboto3 for async operations
- LocalStack for development (full AWS API emulation)
- Apache AGE (PostgreSQL) for upload metadata (consistent with all other entities)
- Presigned URL redirects (307) for efficient file serving
- Pillow for thumbnail generation, filetype for magic-byte validation
- WEBP thumbnails at 256x256 max, maintaining aspect ratio
Upload Features:
- Content type validation with magic-byte verification
- Configurable size limits (default 50 MB)
- Automatic thumbnail generation for raster images
- Permission-based access control (upload:create, upload:read, upload:delete)
ADR 0006: Project Identity and Multi-Type Support¶
Date: 2026-02-13 | Status: Accepted
Replaces single-type, slug-keyed project identity with a Nano-ID primary key and many-to-many project type relationships, enabling stable URLs and natural blueprint composition.
Key Decisions:
- Nano-ID (21-char URL-safe) as the canonical project identifier
- Many
Project -[:TYPE]-> ProjectTyperelationships (was: single) - Blueprint aggregation across all of a project's types, merged by priority
- API paths shift from
/projects/{type_slug}/{slug}to/projects/{id}
ADR 0007: Relationship Blueprints¶
Date: 2026-02-20 | Status: Proposed
Extends the blueprint system to relationships (edges), so admins can add custom properties to [:DEPLOYED_IN] and other edges without code changes.
Key Decisions:
kind: 'node' | 'relationship'discriminator onBlueprint- Relationship blueprints declare
(source, edge, target)triple - Edge properties become data-driven, mirroring the node-blueprint model
Plugin Platform¶
ADR 0008: Plugin System Architecture¶
Date: 2026-04-27 | Status: Accepted
Establishes Imbi as a SaaS IDP with a stable, versioned plugin model. Plugins are standalone Python packages discovered via entry points; capabilities are stored as Plugin graph nodes linked to a shared ThirdPartyService.
Key Decisions:
imbi.pluginsentry-point group; manifests areClassVars on handler classesThirdPartyService+ServiceApplication+Plugintriplet in the graph- One service record can back multiple capabilities (
aws-ssm,aws-cloudwatch-logs,aws-iam-ic) - Project-type and per-project
USES_PLUGINedges with explicit overrides - Plugin types grow incrementally (
configuration,logs, thenidentity,deployment)
ADR 0009: Database-Driven OAuth Provider Configuration¶
Date: 2026-04-30 | Status: Accepted
Moves OAuth provider configuration (Google, GitHub, OIDC) from IMBI_AUTH_OAUTH_* environment variables into the graph database, manageable via the admin UI.
Key Decisions:
- New
OAuthProvidernode with Fernet-encryptedclient_secret_encrypted - 30-second TTL cache keyed by slug, invalidated on writes
- New admin endpoints gated by
oauth-providers:read|writepermissions - Per-provider env vars deleted;
oauth_auto_link_by_email/oauth_auto_create_usersremain
ADR 0010: Identity Plugin Architecture¶
Date: 2026-05-05 | Status: Accepted
Adds a third plugin type — identity — for backends where caller identity matters (AWS IAM IC, GitHub, generic OIDC). Other plugin types declare identity_plugin_id; the API materializes per-user credentials at call time.
Key Decisions:
identityplugin type alongsideconfigurationandlogs- Per-user
IdentityConnectionnode with Fernet-encrypted tokens, scoped to(User, Plugin) - Identity plugins can double as login providers (
used_as_login: bool) - First-party identity entry points in
imbi-plugin-aws,imbi-plugin-github,imbi-plugin-oidc
ADR 0011: Graph-Based Project Scoring¶
Date: 2026-04-15 | Status: Accepted
Replaces v1's fact-based scoring with a blueprint-aware, graph-driven scoring policy model. Attribute policies ship first; event policies are deferred until the integration ingestion path is settled.
Key Decisions:
ScoringPolicynode withvalue_score_maporrange_score_map- Effective-attribute-set + optional
TARGETS → ProjectTypefor policy selection - Materialized
Project.score, history in ClickHouse (score_history+score_latestMV) - Valkey Streams queue with per-project debounce for async recomputation
- CH-before-AGE write ordering for durable history
ADR 0012: Plugin Manifest Third-Party Service Template¶
Date: 2026-05-05 | Status: Accepted
Plugin manifests declare a third_party_service template and an embedded icon asset; install-time auto-provisions the ThirdPartyService, dedupes capabilities from the same package, and stops re-entering vendor boilerplate.
Key Decisions:
PluginManifest.third_party_serviceandPluginIcon(viaimportlib.resources)- One service record per template ID; multi-entry-point packages dedup
- Manifests carry no secrets;
ServiceApplicationis still operator-supplied - Re-install preserves operator edits; opt-in "managed by manifest" mode
ADR 0013: Deployment Plugin Type¶
Date: 2026-05-08 | Status: Accepted
Adds a fourth plugin type — deployment — so the release-train UI can trigger workflows, draft AI release notes, and record deployments end-to-end against any plugin-supported backend.
Key Decisions:
deploymentplugin type with a small protocol (list refs/commits, trigger, tag/release)- Separate
github-deploymententry point alongside thegithubidentity plugin workflow_dispatchwith{environment, ref}inputs as the v1 trigger- Deploys run as the human via
identity_plugin_id - Anthropic client in
imbi-commonfor server-side release-note drafting
ADR 0014: Generic Plugin-Entity CRUD Abstraction¶
Date: 2026-05-06 | Status: Accepted
Replaces hand-coded per-plugin entity routers (e.g., aws_accounts.py) with a generic CRUD surface driven by vertex_labels / edge_labels declared in plugin manifests.
Key Decisions:
- Generic
/admin/plugins/{slug}/entities/{label}routes mounted once - Edge endpoints for plugin-declared
(source, edge, target)triples - Manifest-driven admin UI consuming JSON Schemas
- Existing AWS-specific code is migrated, not preserved in parallel (alpha, no URL compatibility owed)
ADR Format¶
Our ADRs follow this structure:
# [Number]. [Title]
Date: YYYY-MM-DD
## Status
[Proposed | Accepted | Deprecated | Superseded]
## Context
[Description of the issue or requirement]
## Decision
[The change or approach being adopted]
## Consequences
[Positive and negative outcomes]
## References
[Links to relevant documentation]
Creating New ADRs¶
When making significant architectural decisions:
- Create a new ADR file in
docs/adr/ - Use sequential numbering: Check existing ADRs and use the next number
- Follow the format: Use the template structure above
- Be thorough: Include context, alternatives considered, and trade-offs
- Update this index: Add a summary entry linking to your new ADR
- Submit for review: ADRs should go through the same PR process as code
ADR Guidelines¶
- Be specific: Vague ADRs aren't helpful. Include concrete examples.
- Explain trade-offs: Every decision has pros and cons. Document both.
- Consider alternatives: Show what other options were considered and why they were rejected.
- Update status: If a decision is superseded, update the status and link to the new ADR.
- Link to code: Reference the files or modules that implement the decision.
- Keep context: Future developers need to understand why decisions were made.
Related Documentation¶
- Configuration Guide: Environment variables and settings
- GitHub Repository: Source code and issues
References¶
- Documenting Architecture Decisions - Michael Nygard
- ADR Tools - Lightweight ADR toolset by Nat Pryce
- ADR GitHub Organization - Community resources and examples