-
Notifications
You must be signed in to change notification settings - Fork 2
Getting Started with Development
This guide walks you through setting up your local development environment for both the TMI server (Go) and the TMI web application (Angular/TypeScript).
TMI consists of two main components:
- TMI Server - Go-based RESTful API server with WebSocket support
- TMI-UX - Angular-based web application for threat modeling
- Go 1.26+ - Download
- Docker Desktop - For PostgreSQL and Redis containers
- Make - Build automation (pre-installed on macOS/Linux)
- Node.js 22.x (>=22.0.0 <23.0.0) - Download
- pnpm - Fast, disk space efficient package manager - Install
-
Newman - API testing --
pnpm install -g newman -
Grype - Container vulnerability scanning --
brew install grype - golangci-lint - Go code linting
# Clone the repository
git clone https://github.com/ericfitz/tmi.git
cd tmi
# Start development environment (database + Redis + server)
make start-dev
# Server will be running on http://localhost:8080The make start-dev command automatically:
- Starts PostgreSQL container on port 5432
- Starts Redis container on port 6379
- Waits for database to be ready
- Starts the TMI server on port 8080 (using
config-development.yml)
Terminal 1 - Start Server:
cd tmi
make start-devTerminal 2 - Start Web Application:
cd tmi-ux
pnpm install
pnpm run devThe web application will be available at http://localhost:4200
TMI uses YAML configuration files with environment variable overrides. On first setup, copy config-example.yml to config-development.yml:
# Copy example config and customize
cp config-example.yml config-development.ymlEnvironment variables use the TMI_ prefix and override any YAML value. Key variables:
-
TMI_DATABASE_URL- Database connection URL (required), e.g.,postgres://user:pass@localhost:5432/tmi?sslmode=disable -
TMI_SERVER_PORT- Server port (default: 8080) -
TMI_JWT_SECRET- JWT signing secret
The configuration file covers:
- Database connection via URL (PostgreSQL, MySQL, SQLite, SQL Server, Oracle)
- Redis connection (caching and sessions)
- OAuth provider credentials
- Server settings (ports, timeouts, TLS)
- Cookie-based authentication settings
Development uses Docker containers for PostgreSQL:
# Start PostgreSQL only
make start-database
# Wait for database to be ready
make wait-database
# Run migrations
make migrate-database
# Check migration status
make check-databaseConnection details:
- Host:
localhost:5432 - User:
tmi_dev - Password:
dev123 - Database:
tmi_dev
To enable authentication, configure OAuth providers in config-development.yml. TMI supports Google, GitHub, and Microsoft providers.
- Go to Google Cloud Console
- Create OAuth 2.0 credentials
- Add redirect URI:
http://localhost:8080/oauth2/callback - Set environment variables or update
config-development.yml:
# Via environment variables (recommended):
export OAUTH_PROVIDERS_GOOGLE_CLIENT_ID=YOUR_CLIENT_ID.apps.googleusercontent.com
export OAUTH_PROVIDERS_GOOGLE_CLIENT_SECRET=YOUR_CLIENT_SECRET# Or via config-development.yml under auth.oauth.providers.google:
auth:
oauth:
callback_url: "http://localhost:8080/oauth2/callback"
providers:
google:
id: "google"
name: "Google"
enabled: true
client_id: "YOUR_CLIENT_ID.apps.googleusercontent.com"
client_secret: "YOUR_CLIENT_SECRET"
authorization_url: "https://accounts.google.com/o/oauth2/auth"
token_url: "https://oauth2.googleapis.com/token"
userinfo:
- url: "https://www.googleapis.com/oauth2/v3/userinfo"
claims: {}
scopes:
- "openid"
- "profile"
- "email"For development, you can use the built-in TMI provider (no configuration needed):
# Access TMI OAuth provider (creates random user)
curl "http://localhost:8080/oauth2/authorize?idp=tmi"The TMI provider creates users like: testuser-12345678@tmi.local
For predictable test users, use login hints:
# Create specific test user 'alice@tmi.local'
curl "http://localhost:8080/oauth2/authorize?idp=tmi&login_hint=alice"# Development
make start-dev # Start complete dev environment (database + Redis + server)
make restart-dev # Restart the dev environment
make clean-everything # Clean up all containers, processes, logs, and files
# Building
make build-server # Build server binary
make build-migrate # Build migration tool
make build-cats-seed # Build CATS database seeding tool
make clean-build # Clean build artifacts
make generate-api # Generate API code from OpenAPI spec
# Database
make start-database # Start PostgreSQL container
make stop-database # Stop PostgreSQL container
make clean-database # Remove container and data
make reset-database # Drop and recreate database (DESTRUCTIVE)
make migrate-database # Run migrations
make wait-database # Wait for database to accept connections
make check-database # Check migration status
# Testing
make test-unit # Run Go unit tests
make test-integration # Run integration tests (PostgreSQL)
make test-integration-pg # Run integration tests (PostgreSQL, explicit)
make test-api # Run Newman API tests
make test-coverage # Generate coverage reports
# Services
make start-redis # Start Redis container
make stop-redis # Stop Redis container
make clean-redis # Remove Redis container
# Server control
make start-server # Start server
make stop-server # Stop server# Check server status
curl http://localhost:8080/
# Expected response
{
"api": {
"version": "1.0",
"build": "0.9.0"
},
"service": {
"name": "TMI API Server",
"build": "0.9.0-abc123"
}
}cd tmi-ux
pnpm installTMI-UX supports multiple environment configurations:
# Default development (uses environment.ts)
pnpm run dev
# Test environment
pnpm run dev:test
# Production environment (local)
pnpm run dev:prod- Copy example:
cp src/environments/environment.example.ts src/environments/environment.local.ts - Configure
environment.local.ts:
import { Environment } from './environment.interface';
export const environment: Environment = {
production: false,
logLevel: 'DEBUG',
apiUrl: 'http://localhost:8080',
authTokenExpiryMinutes: 1440, // 24 hours for dev
operatorName: 'TMI Development',
operatorContact: 'dev@example.com',
operatorJurisdiction: '',
suppressAboutLink: false,
suppressPrivacyTosLinks: false,
serverPort: 4200,
serverInterface: 'localhost',
enableTLS: false,
tlsKeyPath: undefined,
tlsCertPath: undefined,
tlsSubjectName: undefined,
enableConfidentialThreatModels: false,
defaultThreatModelFramework: 'STRIDE',
};- Update
angular.jsonto add configuration:
"configurations": {
"local": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.local.ts"
}
]
}
}# Development
pnpm run dev # Start dev server on localhost:4200 (opens browser)
pnpm run dev:test # Start with test config
pnpm run dev:prod # Start with production config
pnpm run shannon # Start on 0.0.0.0 (accessible from network)
# Building
pnpm run build # Development build
pnpm run build:prod # Production build
pnpm run build:test # Test build
# Testing (Vitest)
pnpm run test # Run Vitest unit tests
pnpm run test:watch # Run tests in watch mode
pnpm run test:ui # Run tests with Vitest UI
pnpm run test:coverage # Generate coverage report
# E2E Testing (Playwright)
pnpm run test:e2e # Run Playwright E2E tests
pnpm run test:e2e:ui # Open Playwright UI
pnpm run test:e2e:debug # Run E2E tests in debug mode
pnpm run test:e2e:headed # Run E2E tests in headed browser
# Code Quality
pnpm run lint # Lint TypeScript/HTML files
pnpm run lint:scss # Lint SCSS files
pnpm run lint:all # Lint everything
pnpm run format # Format code with Prettier
pnpm run format:check # Check formatting
pnpm run check # Run format:check + lint:all
# Validation
pnpm run validate-json # Validate JSON files
pnpm run validate-json:i18n # Validate i18n files
pnpm run validate-jsonc # Validate JSONC files
pnpm run validate-all # Run all validation checks# Start dev server
pnpm run dev
# Open browser to http://localhost:4200
# You should see the TMI login page# Terminal 1: Start services
cd tmi
make start-dev
# Terminal 2: Run tests on code changes
make test-unit
# Terminal 3: Watch logs
tail -f logs/server.log# Terminal 1: Start server
cd tmi
make start-dev
# Terminal 2: Start web app
cd tmi-ux
pnpm run dev
# Hot reload is enabled - changes reflect immediately# Terminal 1: Start server
cd tmi
make start-dev
# Terminal 2: Start web app
cd tmi-ux
pnpm run dev
# Terminal 3: Run E2E tests
cd tmi-ux
pnpm run test:e2etmi/
├── api/ # API handlers and types
├── api-schema/ # OpenAPI spec (tmi-openapi.json), AsyncAPI, Arazzo
├── auth/ # Authentication services
├── cmd/
│ ├── server/ # Server entry point
│ ├── migrate/ # Database migration tool
│ ├── cats-seed/ # CATS database seeding tool
│ └── dedup-group-members/ # Group member deduplication
├── config/ # Configuration loading
├── internal/ # Internal packages
├── docs/
│ └── developer/ # Developer documentation
├── scripts/ # Build and utility scripts
├── test/
│ └── postman/ # Newman API test collections
├── terraform/ # Infrastructure as code
├── config-example.yml # Example configuration
├── config-development.yml # Dev configuration (create from example)
└── Makefile # Build automation
tmi-ux/
├── src/
│ ├── app/
│ │ ├── auth/ # Authentication components
│ │ ├── core/ # Core services, guards
│ │ ├── generated/ # Generated API types
│ │ ├── i18n/ # Internationalization setup
│ │ ├── pages/ # Page components
│ │ ├── shared/ # Shared components
│ │ └── types/ # TypeScript type definitions
│ ├── assets/ # Static assets, i18n JSON files
│ └── environments/ # Environment configs
├── e2e/ # Playwright E2E tests
├── docs/
│ ├── mockups/ # UI mockups
│ └── reference/ # Architecture docs
├── scripts/ # Build and utility scripts
├── playwright.config.ts # Playwright configuration
└── package.json # Dependencies and scripts
This section outlines the file naming conventions for the TMI-UX project.
| Type | Pattern | Example | Usage |
|---|---|---|---|
| Components | *.component.ts |
user-preferences-dialog.component.ts |
All Angular components |
| Services | *.service.ts |
threat-model.service.ts |
All @Injectable() classes that provide business logic |
| Guards | *.guard.ts |
auth.guard.ts |
All route guards |
| Interceptors | *.interceptor.ts |
jwt.interceptor.ts |
All HTTP interceptors |
| Resolvers | *.resolver.ts |
threat-model.resolver.ts |
All route resolvers |
| Models | *.model.ts |
threat-model.model.ts |
Data models and interface definitions |
| Interfaces | *.interface.ts |
auth.interface.ts |
Interface definitions (alternative to .model.ts) |
| Types | *.types.ts |
websocket-message.types.ts |
Type definitions and type aliases |
| Constants | *-constants.ts |
styling-constants.ts |
Constant values and configuration objects |
| Utilities |
*.util.ts or *.utils.ts
|
cell-normalization.util.ts |
Utility functions and helper methods |
| Adapters | *.adapter.ts |
infra-x6-graph.adapter.ts |
Infrastructure adapters for external libraries |
| Tests | *.spec.ts |
auth.service.spec.ts |
Unit tests |
| Routes | *.routes.ts |
tm.routes.ts |
Route configuration files |
| State | *.state.ts |
dfd.state.ts |
State management files |
| Barrel Exports | index.ts |
src/app/shared/index.ts |
Re-exporting multiple items from a directory |
The DFD (Data Flow Diagram) module uses a layered DDD architecture:
src/app/pages/dfd/
├── application/ # Application services (orchestration, coordinators)
│ ├── executors/ # Operation executors
│ ├── services/ # app-*.service.ts files
│ └── validators/ # Operation validators
├── domain/ # Domain models and events
│ ├── entities/ # Domain entities
│ ├── events/ # Domain events
│ └── value-objects/ # Value objects
├── infrastructure/ # External library adapters
│ ├── adapters/ # infra-*.adapter.ts files
│ ├── constants/ # Infrastructure configuration
│ ├── interfaces/ # Adapter interfaces
│ └── services/ # infra-*.service.ts files
├── presentation/ # UI components and services
│ ├── components/ # UI components
│ └── services/ # ui-*.service.ts files
├── constants/ # Shared constants
├── interfaces/ # Shared interfaces
├── state/ # State management
├── types/ # Type definitions
└── utils/ # Utility functions
-
Use kebab-case for file names
- Correct:
threat-model.service.ts - Incorrect:
ThreatModelService.tsorthreat_model_service.ts
- Correct:
-
Be descriptive in naming
- Correct:
threat-model-authorization.service.ts - Incorrect:
tm-auth.service.ts
- Correct:
-
Group related files by feature
- Keep related components, services, and models together
- Use barrel exports (index.ts) for clean imports
-
Match class names to file names
- File:
threat-model.service.ts - Class:
ThreatModelService
- File:
-
Use layer prefixes in DFD module
- Application layer:
app-*.service.ts - Infrastructure layer:
infra-*.service.ts,infra-*.adapter.ts - Presentation layer:
ui-*.service.ts
- Application layer:
When renaming files:
- Update all imports in the codebase
- Update any barrel exports (index.ts files)
- Check for impacts on tests
- Run build and tests to verify
- Define endpoint in OpenAPI spec:
api-schema/tmi-openapi.json - Generate API code:
make generate-api - Implement handler in
api/ - Add database operations if needed
- Write unit tests
- Write integration tests in
api/*_integration_test.go - Add Newman tests in
test/postman/
- Generate component:
pnpm exec ng generate component pages/my-feature - Add to routing:
src/app/app.routes.ts - Create service if needed:
pnpm exec ng generate service core/services/my-service - Add i18n keys:
src/assets/i18n/en-US.json - Write unit tests:
*.spec.ts - Write E2E tests:
e2e/tests/*.spec.ts(Playwright)
# Check if port 8080 is in use
lsof -ti :8080
# Stop server and clean up
make stop-server
# Check database connection
make start-database
make wait-database
docker exec tmi-postgresql pg_isready -U tmi_dev# Check migration status
make check-database
# Reset database (DESTRUCTIVE - deletes all data)
make reset-database
# Manual migration (set TMI_DATABASE_URL first)
export TMI_DATABASE_URL=postgres://tmi_dev:dev123@localhost:5432/tmi_dev?sslmode=disable
cd cmd/migrate
go run main.go up- Check server is running:
curl http://localhost:8080/ - Verify
apiUrlin environment file - Check browser console for CORS errors
- Ensure you're authenticated (valid JWT token)
- Check OAuth config in
config-development.yml - Verify redirect URI matches OAuth provider
- Use TMI provider for development:
?idp=tmi - Check server logs:
tail -f logs/server.log
- Architecture-and-Design -- Understand system architecture
- API-Integration -- Learn to integrate with TMI APIs
- Testing -- Testing strategies and tools
- Contributing -- Contribution guidelines
-
Documentation: See
/docsin both repositories - Issues: https://github.com/ericfitz/tmi/issues
- API Reference: http://localhost:8080/ (when server is running)
-
OpenAPI Spec:
api-schema/tmi-openapi.json
- Using TMI for Threat Modeling
- Accessing TMI
- Authentication
- Creating Your First Threat Model
- Understanding the User Interface
- Working with Data Flow Diagrams
- Managing Threats
- Collaborative Threat Modeling
- Using Notes and Documentation
- Timmy AI Assistant
- Metadata and Extensions
- Planning Your Deployment
- Terraform Deployment (AWS, OCI, GCP, Azure)
- Deploying TMI Server
- OCI Container Deployment
- Certificate Automation
- Deploying TMI Web Application
- Setting Up Authentication
- Database Setup
- Component Integration
- Post-Deployment
- Branding and Customization
- Monitoring and Health
- Cloud Logging
- Database Operations
- Security Operations
- Performance and Scaling
- Maintenance Tasks
- Getting Started with Development
- Architecture and Design
- API Integration
- Testing
- Contributing
- Extending TMI
- Dependency Upgrade Plans
- DFD Graphing Library Reference
- Migration Instructions