Solution Architecture
Product: Spec Doc | Foundation: Constellation | Style: Layered Monolith
System Overviewโ
User Browser (Angular SPA)
โโ Project Dashboard
โโ Spec Viewer (iframe โ GitHub Pages)
โโ Edit Interface
โ HTTPS/REST
Spring Boot Backend
โโ REST API (Auth, Projects, GitHub, AI)
โโ Business Logic (Services)
โโ Data Access (JPA)
โ JDBC
PostgreSQL (metadata only, specs in GitHub)
External: GitHub API (OAuth, Repos, Pages) | AI (OpenAI/Anthropic)
Architecture Principlesโ
| Principle | Implementation |
|---|---|
| Leverage Constellation | Reuse: Spring Boot, Angular, PostgreSQL, JWT auth, security hardening |
| Git as Source of Truth | Database: metadata only. GitHub: specs, history, diffs |
| Stateless API | JWT authentication, no sessions, horizontal scaling ready |
| Loose Coupling | Service abstraction for GitHub + AI, swap providers without core changes |
Technology Stackโ
| Layer | Technology |
|---|---|
| Frontend | Angular 18+, TypeScript 5.3+, Tailwind CSS, RxJS, Vite |
| Backend | Spring Boot 3.2+, Java 21, Gradle 8+, Spring Security 6+ |
| Database | PostgreSQL 15+, Flyway, HikariCP |
| GitHub | OkHttp 4.x, GitHub REST API v3, OAuth 2.0 |
| AI | OpenAI/Anthropic Java SDKs (provider-agnostic) |
| Static Site | Docusaurus 3.x (in user repos), GitHub Pages |
| Monitoring | Spring Boot Actuator, Micrometer, SLF4J + Logback |
Database Schemaโ
Core Tablesโ
-- Extends existing Constellation users table
ALTER TABLE users ADD COLUMN github_username VARCHAR(100);
ALTER TABLE users ADD COLUMN github_user_id BIGINT;
ALTER TABLE users ADD COLUMN github_avatar_url VARCHAR(500);
-- GitHub Tokens (encrypted at rest)
CREATE TABLE github_tokens (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id) UNIQUE,
access_token TEXT NOT NULL, -- AES-256 encrypted
scope TEXT,
created_at TIMESTAMP DEFAULT NOW(),
expires_at TIMESTAMP
);
-- Projects (specs metadata, content in GitHub)
CREATE TABLE projects (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT REFERENCES users(id),
name VARCHAR(100) NOT NULL,
slug VARCHAR(100) NOT NULL,
github_repo_full_name VARCHAR(200),
github_repo_id BIGINT,
github_pages_url VARCHAR(500),
github_pages_enabled BOOLEAN DEFAULT FALSE,
status VARCHAR(20) DEFAULT 'INITIALIZING', -- INITIALIZING|ACTIVE|BUILDING|ERROR|ARCHIVED
template_id BIGINT REFERENCES templates(id),
created_at TIMESTAMP DEFAULT NOW(),
deleted_at TIMESTAMP, -- Soft delete
UNIQUE(user_id, slug)
);
-- Templates
CREATE TABLE templates (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
github_repo_url VARCHAR(500) NOT NULL,
category VARCHAR(50),
is_default BOOLEAN DEFAULT FALSE,
usage_count INTEGER DEFAULT 0
);
-- Edit History (lightweight, GitHub has full history)
CREATE TABLE edit_sessions (
id BIGSERIAL PRIMARY KEY,
project_id BIGINT REFERENCES projects(id),
user_id BIGINT REFERENCES users(id),
file_path VARCHAR(500),
instruction TEXT,
ai_provider VARCHAR(50),
ai_model VARCHAR(50),
ai_tokens_used INTEGER,
ai_cost_cents INTEGER,
commit_sha VARCHAR(40),
commit_url VARCHAR(500),
success BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT NOW()
);
Volume (1 year, 10K users): Users: 10K | Projects: 50K | Edit Sessions: 1M | DB Size: ~500MB
API Designโ
Endpointsโ
# Auth (extends Constellation)
POST /api/auth/github/callback
GET /api/auth/github/status
DELETE /api/auth/github/disconnect
# Projects
GET /api/projects
POST /api/projects
GET /api/projects/\{id\}
PUT /api/projects/\{id\}
DELETE /api/projects/\{id\}
# GitHub Operations
GET /api/projects/\{id\}/commits
GET /api/projects/\{id\}/files/*
# AI Editing
POST /api/projects/\{id\}/edit
POST /api/projects/\{id\}/commit
GET /api/projects/\{id\}/edit-history
# Templates
GET /api/templates
Request Examplesโ
Create Project:
POST /api/projects
{ "name": "My Product Spec", "visibility": "private", "templateId": 1 }
Response 201:
{ "id": 123, "slug": "my-product-spec", "status": "INITIALIZING" }
AI Edit:
POST /api/projects/123/edit
{ "filePath": "docs/overview.md", "instruction": "Tighten scope to MVP", "autoCommit": false }
Response 200:
{ "sessionId": 456, "rewrittenContent": "...", "diff": "...", "tokensUsed": 850, "costCents": 2 }
Securityโ
Authentication Flowโ
1. User clicks "Sign in with GitHub"
2. Redirect to GitHub OAuth (scope: repo, user:email)
3. User authorizes
4. Backend exchanges code for token
5. Backend fetches user profile, creates/updates user, encrypts token
6. Issues JWT
7. Frontend stores JWT, future requests use Authorization: Bearer \{JWT\}
Authorization & Securityโ
- Users can ONLY access their own projects/repos
- GitHub tokens encrypted at rest (AES-256)
- JWT secrets in environment variables
- Rate limiting: 100 req/min per user, 10 AI edits/hour (MVP)
- CORS: Whitelist frontend domain only
- CSRF: Token-based protection
External Integrationsโ
GitHub Integrationโ
- API Client: OkHttpClient with GitHub REST API v3
- Operations: Create repo, commit files, enable Pages
- Rate Limiting: 5,000 req/hour (authenticated), exponential backoff
- Caching: User data (5 min TTL)
AI Integrationโ
public interface AIProvider {
AIResponse complete(AIRequest request);
}
@Service OpenAIProvider implements AIProvider { }
@Service AnthropicProvider implements AIProvider { }
Cost Management:
- OpenAI GPT-4: $0.023/edit (Input $10/1M tokens, Output $30/1M)
- Anthropic Claude 3.5 Sonnet: $0.010/edit (Input $3/1M, Output $15/1M)
- Budget (10K users, 10 edits/user/month): $1K-$2.3K/month
Deploymentโ
Environmentsโ
| Environment | Setup |
|---|---|
| Development | Frontend: ng serve (4200), Backend: ./gradlew bootRun (8080), DB: Docker PostgreSQL |
| Staging | Docker Compose, Managed PostgreSQL, staging.specdoc.io |
| Production | CDN (CloudFlare), 2+ backend instances (load balanced), Primary + read replica DB, Monitoring (Datadog) |
CI/CD (GitHub Actions)โ
- On push to main: Tests โ Lint โ Build images โ Push to registry
- On tag (vX.Y.Z): Full tests โ Build โ Deploy to staging โ Smoke tests โ Manual approval โ Production โ Health check
- Database: Flyway migrations (backup first)
Monitoringโ
Metricsโ
# Spring Boot Actuator
/actuator/health, /actuator/metrics, /actuator/info
# Custom Metrics
- projects.created (counter)
- ai.edits.completed (counter)
- ai.edits.cost (gauge)
- github.api.calls/errors (counter)
- github.pages.build.time (histogram)
Alertsโ
- Critical (PagerDuty): Service down, DB unreachable, GitHub rate limit exceeded
- Warning (Slack): AI error rate >5%, Pages build failure >10%, slow queries >5s
Configurationโ
Environment Variablesโ
# Core
SPRING_PROFILES_ACTIVE=production
DATABASE_URL=postgresql://...
# GitHub
GITHUB_CLIENT_ID=...
GITHUB_CLIENT_SECRET=...
# AI
AI_PROVIDER=anthropic
AI_API_KEY=sk-ant-...
AI_MODEL=claude-3-5-sonnet-20241022
# Security
JWT_SECRET=...
ENCRYPTION_KEY=... # For GitHub tokens
FRONTEND_URL=https://specdoc.io # CORS
Performance Targetsโ
| Endpoint | Target (p95) |
|---|---|
| GET /api/projects | <200ms |
| POST /api/projects | <3000ms (includes GitHub API) |
| POST /api/projects/{id}/edit | <8000ms (includes AI) |
| Time to Interactive (frontend) | <3s |
Scalabilityโ
- Year 1: 100 concurrent, 10K total users, 50K projects, 5K daily AI edits
- Year 2: 1K concurrent, 100K total users, 500K projects, 50K daily AI edits
Data Flowโ
Create Projectโ
User โ Frontend โ Backend:
1. Validate request
2. GitHub API: Create repo, initialize from template, enable Pages
3. Save metadata to database
4. Return project ID
5. Frontend polls for Pages status
6. Iframe loads rendered spec when ready
AI Editโ
User โ Frontend โ Backend:
1. Fetch content from GitHub
2. Call AI API with prompt
3. Return preview
4. User reviews, clicks "Commit"
5. Create commit via GitHub API
6. Log edit session
7. GitHub Actions triggers rebuild
8. Pages updates (~30-60s)
Architecture Decision Recordsโ
ADR-001: Git as Source of Truthโ
- Decision: Specs in Git, not database
- Why: Leverage version control, native diff/rollback, developer-friendly, no lock-in
- Trade-off: Slower than DB, depends on GitHub availability
ADR-002: Static Site Renderingโ
- Decision: Docusaurus + GitHub Pages
- Why: No custom renderer, professional output, free hosting
- Trade-off: Build time (~60s), limited customization
ADR-003: AI Provider Abstractionโ
- Decision: Provider-agnostic interface
- Why: Switch providers (cost optimization), A/B test models, fallback
- Trade-off: Abstraction complexity
Alternatives Consideredโ
Instant Feedback Problem (GitHub Pages has 60s rebuild delay)โ
| Alternative | Pros | Cons | Decision |
|---|---|---|---|
| Client-Side Rendering โญ | Instant (<1ms), simple, offline | No SSR | CHOSEN |
| Self-Hosted SSG | Full control, faster builds (10-15s) | Infrastructure cost, still has delay | Not MVP |
| Real-Time Collaboration | Multi-user, instant sync | Complex, conflicts with Git | Over-engineering |
| Hybrid (render on save) | Balance | Still has delay, confusing UX | Doesn't solve problem |
| WebAssembly Rendering | Instant + production-quality | Highly experimental, 5-10MB bundle | Too experimental |
Chosen: Client-side (marked.js) because:
- Instant feedback (<1ms vs 60s)
- Simple (50KB library)
- 60% faster development (no build pipeline)
- 97% lower cost (no hosting)
- Works offline (bonus)
Trade-off accepted: No SSR initially (can add later for SEO)
Related Documentsโ
| Document | Purpose |
|---|---|
| Overview | Navigation and quick start |
| Epic | Product scope and MVP |
| Business Analysis | Market and pricing |
| UX Vision | Interface philosophy |
Status: Ready for implementation after Constellation Phase 2