Problem
Reach plc — owner of the Daily Mirror, Daily Express, OK! Magazine and 70+ other titles — wanted to build a more engaged relationship with readers than scroll-and-bounce. Comment threads on individual articles existed, but they were siloed per title and structured around the article, not the reader.
The brief: a forum-style mobile app where readers could discuss news stories, follow other readers, and post their own takes — across the entire Reach portfolio in one feed. Built to handle the volume and the moderation reality of mass-market UK news.
Process
I joined as a full-stack developer working across the mobile (React Native) and web (React) builds, with shared backend services on AWS. Three areas where I focused effort:
- The unified feed. Articles from 70+ titles needed a single ranking and surfacing model — by reader interests, by topic, and with editorial weighting. We worked closely with Reach's product team on the ranking signals and built the API to be tunable post-launch.
- The comment / post model. Threads needed to be richer than article comments — replies, reactions, image uploads, mentions — but moderate-able at scale. We picked a hierarchical schema with explicit moderation states baked into every record.
- Moderation workflow. Tabloid comment sections without aggressive moderation become impossible. We built a moderation queue with auto-flagging (profanity lists, link detection, repeat-offender heuristics) feeding a human review tool.
I also led the documentation standards push — the team had inconsistent README quality, and onboarding new developers was slow. I established a template, refactored the top-traffic repos onto it, and wrote the onboarding playbook.
Outcome
Two production applications shipped — mobile (iOS + Android via React Native) and web — both consuming a shared API. The community sat alongside Reach's traditional article-comments model, giving readers a place to engage that wasn't tied to a single article. Documentation standards I established got carried forward across other Reach teams.
For engineersTechnical Deep DiveExpand
The unified feed
Each title in Reach's portfolio publishes hundreds of articles a day. Aggregated across 70+ titles you have tens of thousands of items daily. A reader's feed needs to surface ~50 of those.
Architecture:
CMS publishes article → SNS (per-title topic)
│
▼
Lambda ingests → enriches with topic embeddings
│
▼
DynamoDB articles table (PK: ARTICLE#<id>, GSIs by topic, by title, by recency)
│
▼
Feed-builder Lambda runs per user request:
├─ Pull user's interests (topics, followed users, source titles)
├─ Score-and-rank candidate articles (recency × interest × editorial)
└─ Cache result for 60s in DynamoDB (PK: USER#<id>#FEED, TTL)
Editorial weight was a per-article number set by Reach's curation team — gave them a way to surface a breaking-news story in everyone's feed without polluting the personalisation logic.
Comments and posts
Both used the same hierarchical record:
type Post = { id: string; // POST#<uuid> parentId?: string; // POST#<uuid> for replies, ARTICLE#<id> for top-level on article authorId: string; body: string; attachments?: Attachment[]; reactions: Record<string, number>; state: "live" | "pending" | "hidden" | "removed"; createdAt: string; flaggedAt?: string; flaggedReason?: string; };
DynamoDB layout: PK = PARENT#<parentId>, SK = POST#<createdAt>#<id> for fast in-thread reads in chronological order. The same record served article comments and forum posts — the only difference was the parent type.
Moderation workflow
Auto-flag rules ran inline on submission and bumped state to "pending" when triggered. Human moderators worked through a queue ordered by flag severity. Repeat offenders' future posts went straight to "pending" regardless of content for a configurable cooldown.
We deliberately kept the auto-flag rules simple — heuristics, not ML — because false positives in news comments carry an editorial cost. Moderation is a human-in-the-loop problem, not an automation problem.
Trade-offs
- No real-time push. We polled rather than streamed comment updates. Real-time felt aspirational; the user behaviour we observed was that readers refreshed when they wanted to see new replies.
- Single API for mobile and web. Tempting to fork and optimise per platform, but the shared API kept feature parity tight and let small front-end teams ship fast. The cost was occasional over-fetching that Apollo-style field selection would have avoided.
