Skip to content

Latest commit

Β 

History

History
355 lines (274 loc) Β· 9.36 KB

File metadata and controls

355 lines (274 loc) Β· 9.36 KB

Architecture

Technical stack and design principles of Ackify.

Overview

Ackify is a modern monolithic application with clear backend/frontend separation.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Client Browser                β”‚
β”‚  (Vue.js 3 SPA + TypeScript)            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ HTTPS / JSON
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Go Backend (API-first)          β”‚
β”‚  β”œβ”€ RESTful API v1 (chi router)         β”‚
β”‚  β”œβ”€ OAuth2 Service                      β”‚
β”‚  β”œβ”€ Ed25519 Crypto                      β”‚
β”‚  └─ SMTP Email (optional)               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
               β”‚ PostgreSQL protocol
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       PostgreSQL 16 Database            β”‚
β”‚  (Signatures + Metadata + Sessions)     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Backend (Go)

Simplified Clean Architecture

backend/
β”œβ”€β”€ cmd/
β”‚   β”œβ”€β”€ community/        # Entry point + dependency injection
β”‚   └── migrate/          # SQL migrations tool
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ domain/
β”‚   β”‚   └── models/       # Business entities (User, Signature, Document)
β”‚   β”œβ”€β”€ application/
β”‚   β”‚   └── services/     # Business logic (SignatureService, etc.)
β”‚   β”œβ”€β”€ infrastructure/
β”‚   β”‚   β”œβ”€β”€ auth/         # OAuth2 service
β”‚   β”‚   β”œβ”€β”€ database/     # PostgreSQL repositories
β”‚   β”‚   β”œβ”€β”€ email/        # SMTP service
β”‚   β”‚   β”œβ”€β”€ config/       # Environment variables
β”‚   β”‚   └── i18n/         # Backend i18n
β”‚   └── presentation/
β”‚       β”œβ”€β”€ api/          # HTTP handlers API v1
β”‚       └── handlers/     # Legacy OAuth handlers
β”œβ”€β”€ pkg/
β”‚   β”œβ”€β”€ crypto/           # Ed25519 signatures
β”‚   β”œβ”€β”€ logger/           # Structured logging
β”‚   β”œβ”€β”€ services/         # OAuth provider detection
β”‚   └── web/              # HTTP server setup
β”œβ”€β”€ migrations/           # SQL migrations
β”œβ”€β”€ templates/            # Email templates (HTML/text)
└── locales/              # Backend translations

Applied Go Principles

Interfaces:

  • βœ… Defined in the package that uses them
  • βœ… Principle "accept interfaces, return structs"
  • βœ… Repositories implemented in infrastructure/database/

Dependency Injection:

  • βœ… Explicit constructors in main.go
  • βœ… No complex DI container
  • βœ… Clear and visible dependencies

Code Quality:

  • βœ… go fmt and go vet clean
  • βœ… No dead code
  • βœ… Simple and focused interfaces

Frontend (Vue.js 3)

SPA Structure

webapp/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ components/       # Reusable components
β”‚   β”‚   β”œβ”€β”€ ui/          # shadcn/vue components
β”‚   β”‚   └── ...
β”‚   β”œβ”€β”€ pages/           # Pages (router views)
β”‚   β”‚   β”œβ”€β”€ Home.vue
β”‚   β”‚   β”œβ”€β”€ Admin.vue
β”‚   β”‚   └── ...
β”‚   β”œβ”€β”€ services/        # API client (axios)
β”‚   β”œβ”€β”€ stores/          # Pinia state management
β”‚   β”œβ”€β”€ router/          # Vue Router config
β”‚   β”œβ”€β”€ locales/         # Translations (fr, en, es, de, it)
β”‚   └── composables/     # Vue composables
β”œβ”€β”€ public/              # Static assets
└── scripts/             # Build scripts

Frontend Stack

  • Vue 3 - Composition API
  • TypeScript - Type safety
  • Vite - Build tool (fast HMR)
  • Pinia - State management
  • Vue Router - Client routing
  • Tailwind CSS - Utility-first styling
  • shadcn/vue - UI components
  • vue-i18n - Internationalization

Routing

const routes = [
  { path: '/', component: Home },               // Public
  { path: '/signatures', component: MySignatures }, // Auth required
  { path: '/admin', component: Admin }          // Admin only
]

Frontend handles:

  • Route / with query param ?doc=xxx β†’ Signature page
  • Route /admin β†’ Admin dashboard
  • Route /signatures β†’ My signatures

Database

PostgreSQL Schema

Main tables:

  • signatures - Ed25519 signatures
  • documents - Document metadata
  • expected_signers - Signer tracking
  • reminder_logs - Email history
  • checksum_verifications - Integrity verifications
  • oauth_sessions - OAuth2 sessions + refresh tokens

See Database for complete schema.

Migrations

  • Format: XXXX_description.up.sql / XXXX_description.down.sql
  • Applied automatically on startup (service ackify-migrate)
  • Tool: /backend/cmd/migrate

Security

Cryptography

Ed25519:

  • Digital signatures (elliptic curve)
  • 256-bit private key
  • Guaranteed non-repudiation

SHA-256:

  • Payload hashing before signing
  • Tampering detection
  • Blockchain-like chaining (prev_hash)

AES-256-GCM:

  • OAuth2 refresh token encryption
  • Key derived from ACKIFY_OAUTH_COOKIE_SECRET

OAuth2 + PKCE

Flow:

  1. Client generates code_verifier (random)
  2. Calculates code_challenge = SHA256(code_verifier)
  3. Auth request with code_challenge
  4. Provider returns code
  5. Token exchange with code + code_verifier

Security:

  • Protection against code interception
  • S256 method (SHA-256)
  • Automatically enabled

Sessions

  • Secure cookies (HttpOnly, Secure, SameSite=Lax)
  • HMAC-SHA256 encryption
  • PostgreSQL storage with encrypted refresh tokens
  • Duration: 30 days
  • Automatic cleanup: 37 days

Build & Deployment

Multi-Stage Docker

# Stage 1 - Frontend build
FROM node:22-alpine AS frontend
COPY webapp/ /build/webapp/
RUN npm ci && npm run build
# Output: webapp/dist/

# Stage 2 - Backend build + embed frontend
FROM golang:alpine AS backend
ENV GOTOOLCHAIN=auto
COPY backend/ /build/backend/
COPY --from=frontend /build/webapp/dist/ /build/backend/cmd/community/web/dist/
RUN go build -o community ./cmd/community
# Frontend embedded via embed.FS

# Stage 3 - Runtime (distroless)
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=backend /build/backend/community /app/community
CMD ["/app/community"]

Result:

  • Final image < 30 MB
  • Single binary (backend + frontend)
  • No runtime dependencies

Runtime Injection

ACKIFY_BASE_URL is injected into index.html at startup:

// Replaces __ACKIFY_BASE_URL__ with actual value
html = strings.ReplaceAll(html, "__ACKIFY_BASE_URL__", baseURL)

Allows changing domain without rebuild.

Performance

Backend

  • Connection pooling PostgreSQL (25 max)
  • Prepared statements - SQL injection prevention
  • Rate limiting - 5 auth/min, 10 doc/min, 100 req/min
  • Structured logging - JSON with request IDs

Frontend

  • Code splitting - Lazy loading routes
  • Tree shaking - Dead code elimination
  • Minification - Optimized production builds
  • HMR - Hot Module Replacement (dev)

Database

  • Indexes on (doc_id, user_sub, session_id)
  • Constraints UNIQUE for guarantees
  • Triggers for immutability
  • Autovacuum enabled

Scalability

Current Limits

  • βœ… Monolith: ~10k req/s
  • βœ… PostgreSQL: Single instance
  • βœ… Sessions: In-database (no Redis)

Horizontal Scaling (future)

For > 100k req/s:

  1. Load Balancer - Multiple backend instances
  2. PostgreSQL read replicas - Separate read/write
  3. Redis - Session cache + rate limiting
  4. CDN - Static assets

Monitoring

Structured Logs

JSON format:

{
  "level": "info",
  "timestamp": "2025-01-15T14:30:00Z",
  "request_id": "abc123",
  "method": "POST",
  "path": "/api/v1/signatures",
  "duration_ms": 42,
  "status": 201
}

Health Check

GET /api/v1/health

Response:

{
  "status": "healthy",
  "database": "connected"
}

Metrics (future)

  • Prometheus metrics endpoint
  • Grafana dashboards
  • Alerting (PagerDuty, Slack)

Tests

Coverage

72.6% code coverage (unit + integration)

  • Unit tests: 180+ tests
  • Integration tests: 33 PostgreSQL tests
  • CI/CD: GitHub Actions + Codecov

See Development to run tests.

Technical Choices

Why Go?

  • βœ… Native performance (compiled)
  • βœ… Simple concurrency (goroutines)
  • βœ… Strong typing
  • βœ… Single binary
  • βœ… Simple deployment

Why Vue 3?

  • βœ… Modern Composition API
  • βœ… Native TypeScript
  • βœ… Reactive by default
  • βœ… Rich ecosystem
  • βœ… Excellent performance

Why PostgreSQL?

  • βœ… ACID compliance
  • βœ… Integrity constraints
  • βœ… Triggers
  • βœ… JSON support
  • βœ… Mature and stable

Why Ed25519?

  • βœ… Modern security (elliptic curve)
  • βœ… Performance > RSA
  • βœ… Short signatures (64 bytes)
  • βœ… Standard crypto/ed25519 Go

References