Roots App

A private family media sharing platform for photos, videos, and prompts. Families create groups, invite members, and share content in a feed designed for close-knit use, not public broadcasting.

Technical Lead & Co-Founder, March 2025 to Present. Sole engineer across architecture, backend, frontend, infrastructure, and testing.

114

Cloud Functions

1,849

Automated Tests

75

Compound Indexes

3

Terraform Environments

Architecture

Flutter mobile client communicating over HTTPS with Firebase Cloud Functions v2 on GCP. Firestore for structured data, Cloud Storage for media. Clean architecture with BLoC state management and dependency injection via GetIt.

Flutter Client (iOS/Android)
  |
  +-- BLoC state management
  |     +-- Repository interfaces
  |           +-- Services
  |                 +-- ApiClient (HTTP + auth interceptor)
  |
  |------- HTTPS -------|
  |
Firebase Cloud Functions v2 (109 API endpoints, 5 background jobs)
  +-- Auth middleware (Firebase Admin SDK)
  +-- Family access middleware
  +-- Business logic handlers
  |
  +-- Firestore (75 compound indexes)
  +-- Cloud Storage (signed-URL delivery)
  +-- Firebase Auth (email/password, Google, Apple)
  +-- Cloud Scheduler + Cloud Tasks

End-to-End Encryption (Planned)

A zero-knowledge encryption layer is fully designed and will be integrated after the initial launch. The entire application architecture (API contracts, data models, and client-side service layers) was built from the start to support it. Every API endpoint has both encrypted and plaintext variants. Firestore documents include fields for wrapped keys, epoch references, and encrypted metadata. The client's repository layer abstracts encryption behind interfaces so the cryptographic layer activates without a rewrite. Shipping the product first validates core assumptions before adding protocol-level complexity.

The central problem is member revocation. A single shared family key would require re-encrypting all stored media when someone leaves. Epoch-based keys solve this: on member removal, a new epoch key is generated and wrapped individually for each remaining member via X25519. Old epochs stay readable for historical content but can't decrypt anything new. Posts are searchable via HMAC-SHA256 blind indexes computed client-side, so the server executes queries without seeing plaintext.

The protocol combines three proven systems: MLS (RFC 9420) for group key management, Signal's Double Ratchet for forward-secret messaging, and Proton's envelope model for media storage, adapted for multi-family group access patterns.

Three-Tier Architecture

Layer 1: Family Group Keys (MLS-inspired)
  Epoch-based group keys via simplified TreeKEM
  O(log n) key updates on member join/leave
  Forward secrecy across key rotations

Layer 2: Private Messaging (Double Ratchet)
  Per-conversation root key > sending/receiving chains
  Automatic key deletion after use (self-healing)
  Out-of-order message key storage

Layer 3: Media Encryption (Proton-inspired)
  Unique AES-256-GCM file key per photo/video
  Encrypted metadata (filenames, EXIF, timestamps)
  Granular share scopes: family, subset, or private

Key Hierarchy & Bundles

User Master Key (Argon2id: 3 iterations, 64 MB, 256-bit output)
  |
  +-- Identity Key Pair (Ed25519, signs all other keys)
  |
  +-- Device Keys (X25519, rotated every 90 days)
  |     +-- Pre-key bundle (uploaded to server for async setup)
  |
  +-- Family Epoch Keys (one per family group, per epoch)
  |     Wrapped per-member via X25519 ECDH key agreement
  |     Epoch increments on every member add/remove
  |     Old epochs retained read-only for historical content
  |
  +-- File Keys (unique random AES-256-GCM per media item)
  |     Wrapped with current Family Epoch Key
  |     Encrypts: content + metadata + all processed variants
  |
  +-- Message Chain Keys (Double Ratchet per conversation)
        Root key > chain key > message key (deleted after use)
        DH ratchet step on each reply exchange

MCP Servers

Two custom Model Context Protocol servers and eight integrated third-party servers that extend Claude Code with structured access to the project's API contracts, product requirements, and development tools.

Custom

API Documentation Server

Four tools: list/get API schemas, list/get endpoint definitions. Loads Swagger documentation from the backend and exposes it as structured tools. The AI agent queries real API specs during development instead of relying on its own assumptions.

Epics Management Server

Four tools plus two resources: list/search epics and user stories, browse the epic catalog by module, view requirement-to-story mappings. Parses markdown specification files and caches results in memory.

Both servers follow a dual-mode pattern (HTTP standalone or stdio for MCP-hub integration). They give the AI agent a structured interface to the project's actual specifications, reducing drift between what the AI thinks the API does and what it actually does.

Integrated

  • Context7: Pulls current library and framework documentation into the agent context so it works from real API references, not training data.
  • Sequential Thinking: Structured multi-step reasoning for complex debugging and architectural decisions.
  • Figma: Reads design files directly so the agent can implement UI from actual mockups.
  • Playwright: Browser automation for end-to-end testing and visual validation from within the agent loop.
  • Magic (21st.dev): Generates production-ready UI components from a curated pattern library.
  • Morphllm: Token-optimized bulk code transformations across multiple files.
  • Serena: Semantic code navigation with LSP integration and persistent project memory across sessions.
  • SuperClaude Framework: Behavioral framework that configures Claude Code with structured modes, flags, and rules for consistent agentic workflows.

Infrastructure

Terraform IaC

Three Firebase environments (dev/staging/prod) managed by Terraform with modular composition. Five modules (Storage, Firestore, IAM, KMS, Project APIs) are composed per-environment with shared variables. State stored in GCS with per-environment isolation.

roots-infra/
  environments/
  |  dev/       main.tf, providers.tf, variables.tf
  |  staging/   main.tf, providers.tf, variables.tf
  |  prod/      main.tf, providers.tf, variables.tf
  modules/
     storage/     5 buckets, lifecycle policies, CORS
     firestore/   database, security rules, indexes
     iam/         CI/CD service account, role bindings
     kms/         encryption key rings (prod)
     project-apis/  GCP API enablement

CI/CD

Seven GitHub Actions workflows across two repos. The Flutter CI pipeline runs analysis, formatting checks, and four parallel test categories (unit, widget, integration, API). Backend deploys are a reusable workflow that checks out the infra repo and runs `firebase deploy` against the target environment using per-environment service account keys. iOS builds use Fastlane with match for code signing and TestFlight distribution.

Push to main  ──>  CI (analyze + test matrix)  ──>  Deploy dev
Tag rc-v*     ──>  Build iOS (staging)  ──>  TestFlight
Tag v*        ──>  Build iOS (prod)     ──>  App Store

Backend deploy (reusable):
  checkout roots-infra  ──>  npm ci  ──>  firebase deploy
  (functions, firestore rules/indexes, storage rules)

Security

  • CI/CD service account per environment with least-privilege IAM (10 scoped roles)
  • KMS encryption key rings configurable per environment, enabled in prod
  • Uniform bucket-level access with public access prevention enforced on all buckets
  • Flutter flavors with separate bundle IDs, Firebase configs, and signing profiles per environment

Tech Stack

Frontend

Flutter, Dart, BLoC

Backend

Node.js, TypeScript, Cloud Functions v2

Database

Firestore, 75 compound indexes, signed-URL media delivery

Storage

Cloud Storage, lifecycle tiering, upload pipeline

Infrastructure

Terraform, GitHub Actions, Docker

Security

Firebase Auth, IAM least-privilege, E2EE designed (planned)

Auth

Firebase Auth (email, Google, Apple OAuth)

AI Tooling

Claude Code, custom MCP servers (2)