Skip to main content

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โ€‹

PrincipleImplementation
Leverage ConstellationReuse: Spring Boot, Angular, PostgreSQL, JWT auth, security hardening
Git as Source of TruthDatabase: metadata only. GitHub: specs, history, diffs
Stateless APIJWT authentication, no sessions, horizontal scaling ready
Loose CouplingService abstraction for GitHub + AI, swap providers without core changes

Technology Stackโ€‹

LayerTechnology
FrontendAngular 18+, TypeScript 5.3+, Tailwind CSS, RxJS, Vite
BackendSpring Boot 3.2+, Java 21, Gradle 8+, Spring Security 6+
DatabasePostgreSQL 15+, Flyway, HikariCP
GitHubOkHttp 4.x, GitHub REST API v3, OAuth 2.0
AIOpenAI/Anthropic Java SDKs (provider-agnostic)
Static SiteDocusaurus 3.x (in user repos), GitHub Pages
MonitoringSpring 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โ€‹

EnvironmentSetup
DevelopmentFrontend: ng serve (4200), Backend: ./gradlew bootRun (8080), DB: Docker PostgreSQL
StagingDocker Compose, Managed PostgreSQL, staging.specdoc.io
ProductionCDN (CloudFlare), 2+ backend instances (load balanced), Primary + read replica DB, Monitoring (Datadog)

CI/CD (GitHub Actions)โ€‹

  1. On push to main: Tests โ†’ Lint โ†’ Build images โ†’ Push to registry
  2. On tag (vX.Y.Z): Full tests โ†’ Build โ†’ Deploy to staging โ†’ Smoke tests โ†’ Manual approval โ†’ Production โ†’ Health check
  3. 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โ€‹

EndpointTarget (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)โ€‹

AlternativeProsConsDecision
Client-Side Rendering โญInstant (<1ms), simple, offlineNo SSRCHOSEN
Self-Hosted SSGFull control, faster builds (10-15s)Infrastructure cost, still has delayNot MVP
Real-Time CollaborationMulti-user, instant syncComplex, conflicts with GitOver-engineering
Hybrid (render on save)BalanceStill has delay, confusing UXDoesn't solve problem
WebAssembly RenderingInstant + production-qualityHighly experimental, 5-10MB bundleToo 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)


DocumentPurpose
OverviewNavigation and quick start
EpicProduct scope and MVP
Business AnalysisMarket and pricing
UX VisionInterface philosophy

Status: Ready for implementation after Constellation Phase 2