A collaborative platform for managing Architecture Decision Records (ADRs) with multi-tenant support, role-based access control, and structured review workflows.
- Overview
- Features
- Architecture
- Getting Started
- API Documentation
- Database Schema
- Security & Authentication
- Decision Workflow
- Role-Based Access Control
- Development Guidelines
- Contributing
- License
ArchTrack is a comprehensive backend system for managing Architecture Decision Records (ADRs) in software development teams. It provides a structured approach to documenting, reviewing, and tracking architectural decisions throughout the software development lifecycle.
- Multi-Tenant Architecture: Isolated workspaces for organizations with team-based structures
- Structured Decision Management: Create, review, and track architectural decisions with context, consequences, and alternatives
- Collaborative Review Process: Assign reviewers, collect verdicts, and maintain decision audit trails
- Role-Based Permissions: Fine-grained access control across org admins, team admins, architects, and developers
- Project Organization: Group decisions by projects with tagging and filtering capabilities
-
🏢 Organization Management
- Multi-tenant isolation with organization-scoped queries
- Custom organization slugs and branding
- Organization-level settings and configurations
-
👥 Team Collaboration
- Team-based user organization within organizations
- Email invitation system with secure token-based registration
- Team admin capabilities for user management
-
📝 Decision Records
- Structured ADR format (Context, Decision, Consequences)
- Multiple decision options with voting capabilities
- Tag-based categorization and filtering
- Status-based workflow (Proposed → Under Review → Accepted/Rejected)
- Full audit trail for all decision changes
-
🔍 Review System
- Reviewer assignment by decision authors
- Structured review comments and verdicts
- One verdict per reviewer constraint
- Review status tracking and notifications
-
💬 Collaboration Features
- Decision comments and discussions
- Real-time voting on decision options
- Project-level organization
- Advanced filtering (by status, tags, projects)
- RESTful API with FastAPI framework
- JWT-based authentication with secure token management
- PostgreSQL database with SSL support
- Multi-tenant data isolation using organization-scoped queries
- CORS support for frontend integration
- Comprehensive validation with Pydantic schemas
| Component | Technology | Version |
|---|---|---|
| Framework | FastAPI | 0.136.3 |
| Language | Python | 3.9+ |
| Database | PostgreSQL | - |
| ORM | SQLAlchemy | 2.0.50 |
| Authentication | JWT (python-jose) | 3.5.0 |
| Password Hashing | Bcrypt (passlib) | 1.7.4 |
| Validation | Pydantic | 2.13.4 |
| Server | Uvicorn | 0.49.0 |
Backend/
├── app/
│ ├── db/
│ │ ├── database.py # Database connection & session management
│ │ └── __init__.py
│ ├── models/ # SQLAlchemy ORM models
│ │ ├── organizations.py # Organization entity
│ │ ├── teams.py # Team entity
│ │ ├── users.py # User entity with roles
│ │ ├── projects.py # Project entity
│ │ ├── decisions.py # Decision & reviewer assignment
│ │ ├── options.py # Decision options
│ │ ├── votes.py # Voting system
│ │ ├── comments.py # Decision comments
│ │ ├── reviewcomments.py # Review verdicts
│ │ ├── tags.py # Tagging system
│ │ ├── invites.py # Team invitation system
│ │ └── decisionaudits.py # Audit trail
│ ├── routers/ # API route handlers
│ │ ├── auth.py # Authentication & registration
│ │ ├── admin.py # Organization admin operations
│ │ ├── Organizations.py # Organization management
│ │ ├── Teams.py # Team management
│ │ ├── Invites.py # Invitation handling
│ │ ├── Projects.py # Project CRUD
│ │ ├── Decisions.py # Decision CRUD & workflow
│ │ ├── ReviewerAssignments.py # Review management
│ │ ├── Options.py # Decision options
│ │ ├── Votes.py # Voting endpoints
│ │ ├── Comments.py # Comment system
│ │ └── Tags.py # Tag management
│ ├── schemas/ # Pydantic validation schemas
│ │ ├── user.py
│ │ ├── organization.py
│ │ ├── team.py
│ │ ├── project.py
│ │ ├── decision.py
│ │ ├── invite.py
│ │ └── ...
│ ├── utils/ # Utility modules
│ │ ├── oauth2.py # JWT token handling
│ │ ├── hashing.py # Password hashing
│ │ ├── permissions.py # Authorization checks
│ │ ├── org_query.py # Organization-scoped queries
│ │ ├── context.py # Request context management
│ │ ├── workflow.py # Decision workflow logic
│ │ └── token_generator.py # Invitation token generation
│ ├── config.py # Application configuration
│ └── __init__.py
├── main.py # Application entry point
├── requirements.txt # Python dependencies
├── .env.example # Environment variables template
├── README.md # This file
└── CONTRIBUTING.md # Development guidelines
The system implements strict multi-tenant isolation using the OrgScopedQuery pattern:
# All route handlers must use organization-scoped queries
projects = sq.projects().all() # ✅ Correct
projects = db.query(Project).all() # ❌ ForbiddenThis ensures data isolation between organizations and prevents cross-tenant data leaks.
- Python 3.9+ installed on your system
- PostgreSQL database instance (with SSL support)
- pip package manager
- Git for version control
- Clone the repository
git clone <repository-url>
cd Backend- Create and activate virtual environment
# Windows
python -m venv venv
venv\Scripts\activate
# macOS/Linux
python3 -m venv venv
source venv/bin/activate- Install dependencies
pip install -r requirements.txt- Configure environment variables
Create a .env file in the root directory:
cp .env.example .envEdit .env with your configuration:
DATABASE_URL=postgresql://username:password@host:port/database
SECRET_KEY=your-secret-key-here-min-32-characters
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30- Initialize the database
The application will automatically create all required tables on startup using SQLAlchemy's Base.metadata.create_all().
- Run the application
uvicorn main:app --reload --host 0.0.0.0 --port 8000The API will be available at http://localhost:8000
Create your first organization and admin user:
POST /auth/bootstrap
{
"org_name": "Your Organization",
"org_slug": "your-org",
"admin_email": "admin@example.com",
"admin_password": "secure-password"
}Once the server is running, access the interactive API documentation:
- Swagger UI:
http://localhost:8000/docs - ReDoc:
http://localhost:8000/redoc
POST /auth/login- User login (returns JWT token)POST /auth/bootstrap- First-time organization setupPOST /auth/register- Register via team invitationGET /auth/invite-info- Get invitation detailsGET /auth/me- Get current user profile
GET /organizations/me- Get organization detailsPUT /organizations/me- Update organization (org admin only)
POST /teams- Create team (org admin only)GET /teams- List all teamsPUT /teams/{id}- Update teamDELETE /teams/{id}- Delete team
POST /invites/team/{team_id}- Create team invitationGET /invites/team/{team_id}/pending- List pending invitesDELETE /invites/{id}- Revoke invitation
POST /projects- Create projectGET /projects- List all projectsGET /projects/{id}- Get project detailsPUT /projects/{id}- Update projectDELETE /projects/{id}- Delete project
POST /decisions/project/{project_id}- Create decisionGET /decisions/project/{project_id}- List decisions (with filters)GET /decisions/{id}- Get decision detailsPUT /decisions/{id}- Update decisionPUT /decisions/{id}/status- Update decision status
POST /reviewers/decision/{id}- Assign reviewerDELETE /reviewers/decision/{id}/reviewer/{reviewer_id}- Remove reviewerPOST /reviewers/decision/{id}/verdict- Submit review verdictGET /reviewers/decision/{id}/reviews- Get all verdicts
POST /options/decision/{decision_id}- Add decision optionDELETE /options/{id}- Delete option
POST /votes- Cast vote on option- Additional voting endpoints...
POST /comments/decision/{decision_id}- Add commentDELETE /comments/{id}- Delete comment
GET /tags- List all tags
GET /admin/users- List all users with rolesPUT /admin/users/{id}/role- Change user roleDELETE /admin/users/{id}- Remove userGET /admin/projects- List all projectsPUT /admin/decisions/{id}/status/override- Override decision status
- Multi-tenant root entity
- Unique slug for URL-friendly identification
- Contains teams, users, and projects
- Group users within an organization
- Team-level permissions and invitations
- Many-to-many relationship with users
- Email-based authentication
- Role-based access (org_admin, team_admin, architect, developer)
- Belongs to one organization and optionally one team
- Logical grouping of decisions
- Owned by users within an organization
- Can be archived or deleted
- Core ADR entity with context, decision, and consequences
- Status-based workflow (StatusEnum)
- Many-to-many relationship with reviewers
- Belongs to a project and authored by a user
- Alternative solutions for a decision
- Supports voting by team members
- User votes on decision options
- One vote per user per decision
- Discussion threads on decisions
- Authored by users
- Formal review verdicts (approve/reject)
- One verdict per assigned reviewer per decision
- Categorization and filtering mechanism
- Many-to-many relationship with decisions
- Secure token-based team invitations
- Email-based with expiration
- Complete audit trail of all decision changes
- Tracks status changes and modifications
Organization (1) ──< (N) Teams
Organization (1) ──< (N) Users
Organization (1) ──< (N) Projects
Team (1) ──< (N) Users
Team (1) ──< (N) Invites
Project (1) ──< (N) Decisions
Decision (1) ──< (N) Options
Decision (1) ──< (N) Comments
Decision (1) ──< (N) Review Comments
Decision (1) ──< (N) Decision Audits
Decision (N) ──< (M) Tags
Decision (N) ──< (M) Users (as reviewers)
Option (1) ──< (N) Votes
User (1) ──< (N) Decisions (as author)
User (1) ──< (N) Projects (as owner)
User (1) ──< (N) Votes
User (1) ──< (N) Comments
🔗Click the diagram below to open the interactive DrawSQL version.
To evaluate API performance and concurrency handling, the backend was load-tested using Locust against a remote Supabase PostgreSQL database.
- Sustained Throughput: ~40 requests/second (RPS)
- Concurrent Load Tested: Up to 100 simulated users
- Observed Failure Rate: 0% at 30 concurrent users; failures at higher loads were caused by Supabase free-tier connection limits rather than application errors.
- Infrastructure Bottleneck: Encountered
EMAXCONNSESSIONwhen exceeding the database pool limit of 15 active sessions on Supabase. - Authentication Analysis: Identified that every protected route performs a database lookup through JWT-based user resolution (
get_current_user()), making database connections the primary scaling constraint under heavy load.
- Algorithm: HS256 (configurable)
- Token Expiration: 30 minutes (configurable)
- Password Hashing: Bcrypt with automatic salt generation
- User submits credentials via
/auth/login - Server validates credentials and generates JWT token
- Client includes token in
Authorization: Bearer <token>header - Server validates token on protected endpoints using
get_current_userdependency
- Secure token-based team invitations
- Tokens include org_id, team_id, inviter_id, and email
- Expiration checking on registration
- Prevents token reuse after successful registration
- All queries are organization-scoped using
OrgScopedQuery - Prevents cross-tenant data access
- Enforced at the database query level
Architect
---------
proposed → under_review
rejected → proposed
Reviewer
--------
under_review → accepted
under_review → rejected
Team Admin
----------
Can perform both Architect + Reviewer transitions
Org Admin
---------
Must use override endpoint for any status change
| Status | Description |
|---|---|
| proposed | Initial state when decision is created |
| under_review | Decision is being reviewed by assigned reviewers |
| accepted | Decision has been approved by reviewers |
| rejected | Decision has been rejected by reviewers |
| deprecated | Decision is no longer recommended (but was once accepted) |
| superseded | Decision has been replaced by a newer decision |
- Decision Author creates a decision (status:
proposed) - Author assigns reviewers to the decision
- Author transitions status to
under_review - Assigned Reviewers submit their verdicts (approve/reject)
- Based on verdicts, decision transitions to
acceptedorrejected - Only assigned reviewers can submit verdicts (one per reviewer)
- Decision authors can assign/remove reviewers
- Only assigned reviewers can submit verdicts
- Each reviewer can submit exactly one verdict per decision
- Org admins can override any status using the admin endpoint
- All status changes are logged in the audit trail
| Role | Permissions |
|---|---|
| org_admin | Full control over organization, teams, users, and all resources. Can override decision workflows. |
| team_admin | Manage team members, create invitations, manage team projects. Can perform both architect and reviewer transitions. |
| architect | Create and manage decisions, assign reviewers, manage decision status (within workflow rules). |
| developer | View decisions, vote on options, comment on decisions, participate as assigned reviewer. |
The system uses three main context types for authorization:
- OrgContext: Validates user belongs to the organization
- OrgAdminContext: Requires org_admin role
- TeamAdminContext: Requires team_admin or org_admin role
These are implemented as FastAPI dependencies:
@router.post("/admin-only-endpoint")
def admin_endpoint(ctx: OrgContext = Depends(get_org_admin_context)):
# Only org admins can access this
passAll data queries in route handlers MUST use OrgScopedQuery.
# ✅ CORRECT
def get_projects(sq: OrgScopedQuery = Depends(get_scoped_query)):
projects = sq.projects().all()
return projects
# ❌ INCORRECT - Will be rejected in code review
def get_projects(db: SessionDB):
projects = db.query(Project).all() # Bypasses tenant isolation!
return projectsAllowed exceptions for raw db.query():
- Inside
get_scoped_query()implementation /auth/bootstrapendpoint (first-time setup)OrgScopedQueryclass implementation- Global resources (e.g., Tag) that aren't tenant-scoped
- Always use Pydantic schemas for request/response validation
- Use dependency injection for database sessions and authentication
- Handle errors gracefully with appropriate HTTP status codes
- Log audit events for all sensitive operations
- Validate permissions at the route handler level
- Use transactions for multi-step database operations
- Write tests for all new features and bug fixes
# Run all tests
pytest
# Run with coverage
pytest --cov=app --cov-report=html- Follow PEP 8 style guide
- Use type hints for all function parameters and return values
- Write docstrings for all public functions and classes
- Keep functions focused and small (single responsibility)
We welcome contributions! Please see CONTRIBUTING.md for detailed guidelines.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes following the development guidelines
- Ensure all tests pass
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Code follows project style guidelines
- All route handlers use
OrgScopedQuery(no rawdb.query()) - New features include tests
- Documentation is updated
- Commit messages are clear and descriptive
- No breaking changes (or clearly documented)
For questions, issues, or feature requests:
- Issues: GitHub Issues
- Documentation: See
/docsendpoint when running - Email: codes.xdev@gmail.com
This project is licensed under the MIT License - see the LICENSE file for details.
- FastAPI framework for excellent async Python web development
- SQLAlchemy for robust ORM capabilities
- PostgreSQL for reliable multi-tenant data storage
- The open-source community for various dependencies
Built with ❤️ for better architecture decision management
