Skip to main content
Projects

Overview

Rargus is a SaaS platform that aggregates customer feedback from multiple sources — app store reviews, support tickets, chat transcripts, NPS responses — normalizes them into a unified schema, and surfaces analytics so product teams can identify themes and prioritize work.

The challenge was twofold: ingest heterogeneous data reliably at scale, and present it through a GraphQL API that felt like a single coherent data model regardless of source.

My Role

I was a full-stack engineer on the core platform, owning the GraphQL API layer, the Cognito authentication flows, the serverless ingestion backend, and the CI/CD pipeline.

  • Designed and implemented the GraphQL API using AWS AppSync — defined the schema, wrote resolvers, and built the DynamoDB data model for normalized feedback records
  • Built the Cognito authentication flows including PKCE for the SPA, refresh token handling, and user pool group-based authorization (admin vs. standard user roles)
  • Architected the serverless ingestion layer: Lambda functions per source type, SNS fan-out for multi-destination routing, Fargate workers for high-volume batch ingestion jobs
  • Set up the full CI/CD pipeline: GitHub Actions → build Docker image → push to ECR → deploy to Fargate via ECS task definition update. Zero-downtime rolling deployments with health check gates

Architecture

React SPA (RTK Query + GraphQL)
       │
       ▼
AWS AppSync (GraphQL API)
  ├── Cognito authorizer (JWT validation)
  └── DynamoDB resolvers (VTL)
       │
       ▼
Ingestion layer
  ├── Lambda (per-source adapters: App Store, Play Store, Intercom, Zendesk, CSV)
  │     └── SNS topic (fan-out to: DynamoDB writer, analytics aggregator, webhook notifier)
  └── Fargate workers (batch ingestion for large CSV dumps / historical backfills)
       │
       ▼
DynamoDB (normalized feedback schema)

Each feedback source had a dedicated Lambda adapter responsible for fetching, normalizing, and publishing to an SNS topic. Downstream consumers subscribed independently — the DynamoDB writer, the analytics aggregator, and the webhook notifier were all decoupled from the ingestion source.

Key Challenges & Decisions

GraphQL vs. REST. AppSync + GraphQL was chosen because the product team needed flexible querying — filter by source, date range, sentiment, tag, or any combination. A REST API would have required many specialized endpoints. AppSync let us expose a single typed schema and let the frontend compose queries. The tradeoff was VTL resolver complexity; we mitigated this with Lambda resolvers for anything non-trivial.

Cognito PKCE + refresh token edge cases. The SPA used the Authorization Code flow with PKCE. The tricky part was handling token expiry gracefully: a silent refresh needed to happen before any GraphQL request when the access token was within 60 seconds of expiry. I implemented a token refresh interceptor in the RTK Query baseQuery wrapper that checked expiry on every request and refreshed proactively. This eliminated the "logged out unexpectedly" complaints from beta users.

Fargate vs. Lambda for batch ingestion. Lambda has a 15-minute timeout. Historical backfills for large clients (hundreds of thousands of records) exceeded that. Rather than chain Lambdas, I moved batch ingestion to Fargate tasks — triggered by S3 events when a CSV was uploaded, spun up for the duration of the job, then torn down. This kept the cost profile lean (no idle capacity) while handling arbitrary-length jobs.

SNS fan-out for extensibility. Early designs had Lambda adapters writing directly to DynamoDB. I pushed to add SNS between ingestion and storage, which meant: (1) new consumers (analytics, webhooks) could subscribe without changing the adapter, and (2) we could replay messages if a downstream consumer failed.

Impact & Outcomes

  • Feedback from multiple sources normalized into a single queryable schema via GraphQL
  • Serverless ingestion (Lambda + Fargate) scaled to demand rather than running always-on capacity
  • CI/CD pipeline via GitHub Actions → ECR → ECS gave the team automated deploys with rollback capability
  • Proactive token refresh via RTK Query interceptor eliminated auth session drop issues in testing

Visualization

Animated cloud architecture diagram coming in Phase 3 — will trace a feedback record from source adapter through SNS fan-out to DynamoDB, and show a Fargate batch worker processing a CSV upload.