Skip to main content

Implementation Overview

This section describes the architectural decisions, technology choices, and development practices that guide the Percus platform development.

Philosophy

Percus is built with these core principles:

  • Quality First: High test coverage, strict linting, code reviews
  • Domain-Driven Design: Business logic drives the architecture
  • Serverless First: Focus on value delivery, not infrastructure management
  • Security by Design: Authentication, encryption, and audit logging from day one
  • Progressive Enhancement: Start simple, add complexity when needed

Technology Stack

Backend

Runtime & Language:

  • AWS Lambda with .NET 10 (C#)
  • Serverless architecture for automatic scaling and cost optimization
  • .NET 10 chosen for improved cold start performance (~850ms-1s cold start)

Why AWS Lambda + .NET?

  • Zero infrastructure management
  • Automatic scaling (0 to thousands of concurrent executions)
  • Pay only for actual usage
  • .NET provides strong typing, mature tooling, and excellent performance
  • Native async/await support for scalable I/O operations

Database:

  • Amazon Aurora Serverless v2 with PostgreSQL 15
  • Auto-scales from 0.5 to 128 ACU based on load
  • Multi-AZ deployment for high availability
  • Automated backups and point-in-time recovery

Why PostgreSQL over MySQL?

  • Superior JSON support (JSONB type with indexing)
  • Built-in full-text search
  • Array and composite types
  • Better support with Entity Framework Core
  • More advanced query features (CTEs, window functions)

ORM:

  • Entity Framework Core
  • Type-safe queries with LINQ
  • Automated migrations for schema evolution
  • Change tracking and unit of work pattern

Storage:

  • Amazon S3 for templates, assets, and generated videos
  • CloudFront CDN for global content delivery
  • Signed URLs for secure private content access

API:

  • API Gateway (REST API)
  • Built-in throttling, monitoring, and caching
  • Integration with Lambda proxy pattern

Frontend

Framework:

  • Next.js 15 (App Router) with TypeScript
  • Server-side rendering (SSR) for better SEO and performance
  • Static generation (SSG) for cacheable pages
  • Deployed on Vercel for zero-configuration deployment

Styling:

  • Tailwind CSS for rapid UI development
  • Custom design system with defined color palette
  • Responsive-first approach

State Management:

  • TanStack Query (React Query) for server state
  • Zustand for client state
  • Automatic caching, refetching, and optimistic updates

Forms & Validation:

  • React Hook Form for performant forms
  • Zod for schema validation
  • Type-safe form data with TypeScript

Architectural Patterns

Domain-Driven Design (DDD)

We organize the system around business domains, not technical layers.

Bounded Contexts:

The platform is divided into 4 independent bounded contexts:

  1. Identity & Access Context

    • Organizations, users, roles, permissions
    • Authentication and authorization
  2. Campaign Management Context

    • Projects (marketing campaigns)
    • Templates (video structures with versioning)
  3. Integration Context

    • API credentials
    • Webhook configurations
    • Email delivery settings
  4. Analytics Context

    • Video generation events
    • Engagement tracking (views, completions)

Each context has its own:

  • Domain model (entities, value objects, aggregates)
  • Business rules and invariants
  • Database context (Entity Framework)
  • Lambda function (microservice)

Why DDD?

  • Aligns code with business language
  • Clear boundaries reduce coupling
  • Easier to understand, test, and maintain
  • Team members can work independently on different contexts

Clean Architecture

We follow the dependency inversion principle with clear layers:

┌─────────────────────────────────┐
│ API Layer (Lambda) │ ← HTTP, JSON, DTOs
├─────────────────────────────────┤
│ Application Layer (Use Cases) │ ← Orchestration, validation
├─────────────────────────────────┤
│ Domain Layer (Entities) │ ← Business logic, invariants
├─────────────────────────────────┤
│ Infrastructure (EF, S3, etc.) │ ← Persistence, external services
└─────────────────────────────────┘

Layer Responsibilities:

Domain Layer:

  • Entities with business rules
  • Value objects for validation
  • Aggregates that enforce invariants
  • Domain events for communication
  • No dependencies on other layers

Application Layer:

  • Use cases (one per user action)
  • Domain services (complex business logic)
  • Authorization checks
  • Transaction coordination

Infrastructure Layer:

  • Entity Framework DbContexts
  • Repositories (data access)
  • S3 client (file storage)
  • External API clients

API Layer:

  • Lambda function handlers
  • Request/response DTOs
  • Input validation
  • Error handling and logging

Benefits:

  • Testable (domain has no dependencies)
  • Flexible (swap infrastructure without touching domain)
  • Maintainable (clear separation of concerns)

Microservices Architecture

Each bounded context is deployed as an independent Lambda function:

  • Identity Service: User authentication and management
  • Campaign Service: Projects and templates
  • Integration Service: API credentials and webhooks
  • Analytics Service: Event tracking and metrics

Communication:

  • Synchronous: Direct API calls (when needed)
  • Asynchronous: Domain events (preferred for cross-context)

Why Microservices?

  • Independent deployment and scaling
  • Team autonomy (each team owns a service)
  • Technology flexibility (can use different languages if needed)
  • Fault isolation (one service failure doesn't bring down the whole system)

Development Practices

Test-Driven Development (TDD)

We write tests before implementation.

Coverage Requirements:

  • Overall: 90% minimum
  • Domain layer: >95% (business logic is critical)
  • Application layer: >90%
  • Infrastructure layer: >85%
  • API layer: >90%
  • Frontend: >90%

Test Types:

Unit Tests (Fast, Isolated):

  • Domain entities and value objects
  • Use cases with mocked dependencies
  • Pure functions and utilities

Integration Tests (Database, External Services):

  • Repository queries (using Testcontainers for real PostgreSQL)
  • API endpoints (using WebApplicationFactory)
  • End-to-end user flows (using Playwright)

Why High Coverage?

  • Confidence in refactoring
  • Documentation of behavior
  • Early detection of regressions
  • Forces better design (testable code is usually better code)

Domain-First Development

Implementation Order (Strict):

  1. Domain Layer (Tests → Implementation → Coverage >95% → Lint clean)
  2. Application Layer (Tests → Implementation → Coverage >90% → Lint clean)
  3. Infrastructure Layer (Tests → Implementation → Coverage >85% → Lint clean)
  4. API Layer (Tests → Implementation → Coverage >90% → Lint clean)
  5. Frontend (Tests → Implementation → Coverage >90% → Lint clean)

Rule: Do not move to the next layer until the current layer is 100% complete.

Why Domain-First?

  • Business logic is the most valuable code
  • If domain is wrong, everything else is wrong
  • Testing domain is easiest (no dependencies)
  • Provides solid foundation for other layers

Code Quality Standards

Linting (Enforced in CI/CD):

  • Backend: dotnet format --verify-no-changes
  • Frontend: ESLint + Prettier
  • No merge if linting fails

Static Analysis:

  • Backend: StyleCop, ReSharper
  • Frontend: TypeScript strict mode
  • Security: Snyk, Dependabot for vulnerability scanning

Code Reviews:

  • All code must be reviewed before merge
  • Automated checks (tests, lint, coverage) must pass
  • At least one approval required

Quality Gates (Block Merge If):

  • ❌ Test coverage drops below 90%
  • ❌ Any test failures
  • ❌ Lint errors
  • ❌ TypeScript errors
  • ❌ Security vulnerabilities (high/critical)

Key Architectural Decisions

Authentication: Google Workspace SSO

Decision: Use Google OAuth for all authentication (no passwords).

Rationale:

  • No password management burden (no hashing, reset flows, breach risk)
  • Convenient for business users (most have Google accounts)
  • Google handles MFA and security audits
  • Free for basic OAuth implementation

Implementation:

  • NextAuth.js on frontend
  • JWT tokens for API authorization
  • User creation on first login

Database: Aurora Serverless PostgreSQL

Decision: Use Aurora Serverless v2 with PostgreSQL 15.

Rationale:

  • Auto-scaling: Scales compute capacity automatically (0.5-128 ACU)
  • Cost-effective: Pay only for capacity used
  • High availability: Multi-AZ with automatic failover
  • PostgreSQL benefits: Better JSON support, full-text search, advanced features

vs DynamoDB:

  • Relational model fits our domain better
  • Complex queries are simpler (JOINs, GROUP BY)
  • Transactions across multiple tables

vs Self-hosted PostgreSQL:

  • No server management
  • Automatic scaling
  • Built-in backups and HA

ORM: Entity Framework Core

Decision: Use Entity Framework Core for all database access.

Rationale:

  • Type safety: C# models mapped to database tables
  • Migrations: Version control for database schema
  • LINQ queries: Strongly-typed, compile-time checked
  • Change tracking: Automatic dirty detection and updates

Migration Strategy:

  • Developers create migrations locally: dotnet ef migrations add
  • Migrations stored in Git
  • GitHub Actions runs migrations during deployment
  • Fallback Migration Lambda for manual runs

Why not raw SQL or Dapper?

  • EF provides more productivity (less boilerplate)
  • Migrations are critical for schema evolution
  • Trade-off: Slightly slower, but worth it for maintainability

Deployment: Serverless + IaC

Decision: Use Terraform for infrastructure as code.

Rationale:

  • Reproducible: Same infrastructure in staging and production
  • Version controlled: Changes tracked in Git
  • Multi-cloud: Can migrate away from AWS if needed
  • Modular: Reusable modules for common patterns

CI/CD:

  • GitHub Actions for all automation
  • Push to develop → Deploy to staging
  • Push to main → Deploy to production
  • Automated tests, linting, coverage checks

Monitoring: CloudWatch + Sentry

Decision: Use CloudWatch for infrastructure, Sentry for application errors.

CloudWatch:

  • Lambda logs, metrics, alarms
  • API Gateway request logs
  • Database query performance

Sentry:

  • Frontend error tracking
  • Backend exception monitoring
  • Release tracking, source maps

Alerts:

  • Slack/Email when errors spike
  • PagerDuty for critical issues (production down)

Security Architecture

Defense in Depth

Layer 1: Edge Protection

  • CloudFront + AWS WAF
  • DDoS protection, rate limiting
  • Geographic restrictions (if needed)

Layer 2: API Gateway

  • Request throttling (100 req/min per user)
  • API key validation
  • Request/response size limits

Layer 3: Application

  • JWT token validation
  • Role-based access control (RBAC)
  • Organization-level data isolation

Layer 4: Data

  • Encryption at rest (AWS KMS)
  • Encryption in transit (TLS 1.3)
  • Database credentials in AWS Secrets Manager

Layer 5: Audit

  • All critical actions logged
  • User activity tracking
  • Audit log retention: 1 year

Compliance Readiness

GDPR:

  • Data export on request
  • Data deletion on request (soft delete + anonymize)
  • Consent tracking
  • Right to be forgotten

SOC 2:

  • Access controls (RBAC)
  • Audit logging
  • Encryption (rest + transit)
  • Incident response plan

Performance Goals

API Response Time:

  • Less than 500ms for 95th percentile
  • Less than 1s for 99th percentile

Frontend Page Load:

  • Less than 2 seconds for dashboard
  • Less than 3 seconds for project details

Database Queries:

  • Less than 100ms for simple queries
  • Less than 500ms for complex analytics

Video Generation:

  • Less than 10 seconds for typical template
  • Less than 30 seconds for complex templates

Availability:

  • 99.9% uptime SLA
  • Multi-AZ deployment for redundancy

Cost Optimization

Serverless Benefits:

  • Pay only for actual usage (no idle servers)
  • Automatic scaling (no over-provisioning)
  • No operational overhead

Estimated Costs (Monthly):

  • MVP (100 users): ~$200
  • Scale (1,000 users): ~$800
  • Enterprise (10,000 users): ~$3,000

Cost Controls:

  • Reserved concurrency on critical Lambdas
  • Aurora auto-pause when idle (development)
  • S3 lifecycle policies (archive old videos)
  • CloudFront caching (reduce origin requests)

Scalability Strategy

Horizontal Scaling:

  • Lambda: Automatic, up to account limits
  • Aurora: Add read replicas for read-heavy workloads
  • S3: Unlimited storage

Vertical Scaling:

  • Lambda: Increase memory allocation (also increases CPU)
  • Aurora: Scale up ACU capacity (0.5 → 128 ACU)

Caching:

  • CloudFront: Cache static assets (templates, images)
  • API Gateway: Cache GET responses (1-5 minutes)
  • Application: Redis/ElastiCache if needed (Phase 2+)

Database Optimization:

  • Indexes on foreign keys and search fields
  • Partitioning for large tables (analytics events)
  • Materialized views for complex analytics

Future Enhancements

Phase 2 (6-12 months):

  • Real-time notifications (WebSockets)
  • Advanced analytics (A/B testing, heatmaps)
  • Template marketplace
  • Multi-language support (Spanish, Portuguese)

Phase 3 (12-24 months):

  • AI-powered features (auto-generate scripts)
  • Mobile app (iOS/Android)
  • Advanced integrations (Salesforce, HubSpot)
  • White-label option for enterprise clients

Summary

Key Takeaways:

Serverless Architecture: Lambda + Aurora for automatic scaling and cost optimization

Domain-Driven Design: 4 bounded contexts with clear boundaries

Clean Architecture: Domain → Application → Infrastructure → API layers

Test-First Development: 90% coverage requirement, domain-first approach

Quality Standards: Linting enforced, code reviews required, automated quality gates

Security by Design: OAuth, encryption, RBAC, audit logging from day one

Modern Stack: .NET 10, Next.js 15, PostgreSQL 15, TypeScript

This architecture enables us to:

  • Build quickly (serverless, modern tooling)
  • Scale efficiently (auto-scaling, microservices)
  • Maintain quality (tests, linting, reviews)
  • Deliver value (focus on domain, not infrastructure)

Next: See detailed planning documentation in the percus-backoffice repository (.plan/ folder).