Project · Antimony

Fruugle

Untamed truth, for buyers who refuse to be fooled twice.

Essence

For the people who use it

Fruugle is a consumer-reporting platform for South Africa — the place where misleading ads, fake discounts and false product claims live in the open instead of being buried in private chat groups or one-star reviews nobody reads. The point is reach: a Fruugle report surfaces where the next buyer is already looking — Google.

Submitting takes about thirty seconds. Three required fields — product, store, what happened — and the system auto-tags the category and normalises the retailer name. Pages are SEO-engineered so that when somebody searches the product name a few hours later, the report is there. Vote "this happened to me too" to push the most common issues up. Add a comment, attach a photograph of the receipt or the packaging.

Existing review sites are either company-focused (HelloPeter), siloed inside a single marketplace (Takealot), or built for global commerce nowhere near the SA market. Fruugle is built for the South African shopper, on the South African retailer landscape, designed to be found by Google at the moment of decision.

Visit Fruugle

Construction

For the engineers

Stack

Frontend
Next.js 16 · React 19 · TypeScript · Tailwind v4 (PostCSS)
API
ASP.NET Core 10 minimal API on .NET 10 · C#
Data access
Dapper — raw, parameterised SQL
Database
MS SQL Server with native full-text search
Auth
Google & Facebook OAuth · JWT (HMAC)
Host
Windows · IIS + Kestrel · Node reverse proxy for the SSR app
Testing
xUnit + Moq on the API · Vitest on the frontend

Architecture

Two-app monorepo. src/api (the .NET backend) and src/web (the Next.js frontend) live side by side under one repo but deploy independently — each has its own pipeline and its own version stamp. They share nothing at the language level; the contract between them is the OpenAPI document the API publishes.

.NET Minimal APIs without controllers. Endpoints are static methods grouped by domain in Endpoints/*.cs files and registered through extension methods in Program.cs. No controller classes, no implicit routing magic — every route is one method, found in one place, debugged in seconds.

Dapper, raw SQL, schema as code. No EF Core; nothing migrated from a model. SQL lives in numbered files under database/migrations/. A DbConnectionFactory singleton hands out connections; scoped repositories use them and map rows to records. The schema in source control is the schema.

SEO automation as a first-class concern. AutoTagService normalises store names against a South African retailer alias table and auto-assigns categories. SeoMetadataService builds schema.org markup for every report. SlugService produces stable URL slugs. On publish, the site pings IndexNow so Bing and Yandex index immediately; the sitemap regenerates incrementally rather than wholesale.

Next.js App Router, dual fetch. serverFetch() drives ISR (60-second revalidation) for public report pages so they're fast and cheap to serve; apiFetch() handles authenticated client-side calls. A custom JWT middleware on the API side puts UserId into context.Items for endpoints to read.

Notable details