HomeAboutExperienceProjectsContactBlog
RésuméDex0/17
← Projects

Inview

A marketplace where creators auction product placement in the rooms they film in.

LEADER NOWCOMMITBRAND BHOLDS ITAAUTHORIZEVOID ABRAND CSAW BB409NOW $790ROW LOCKPRICESTEP +25%$500A$630B$790NEXT

Both sent at once, and B got the lock first. B found A still in the lead, so its card was held for $630 and the takeover committed. A's hold was voided after the commit. C expected A but found B, so it got 409 PRICE_CHANGED before its card was touched. Its page now offers $790.

This runs the repo's takeover checks and price math in your browser. The Postgres row lock is stood in for by taking turns.

Racing takeovers serialize on a row lock. The client sends the leader it saw; a stale view gets 409 PRICE_CHANGED with the new price before any card is touched. A partial unique index (one leading hold per round) backstops both. The previous leader's authorization is voided only after commit, and a rollback hook voids the new one if the transaction fails.

A creator lists a set and marks two to five spots, then opens a public takeover auction for one month of placement. Brands hold a spot with a card; anyone can take it over at the current price plus a step. The winner's payment is held until the creator posts proof the product was on camera.

What it is

Background product placement usually gets sold through DMs, with no price discovery, no proof of delivery, and payment risk on both sides. Inview puts the price in public (an auction), puts the platform in the money flow, and ties the payout to proof.

The hard part is that it's an auction with real money moving: two brands can click take over in the same millisecond, card authorizations are side effects outside the database, and a round has to close exactly once.

How it's put together

BROWSERBRANDCREATORADMINNEXT.JS SERVERPAGESAPIRATE LIMITIN MEMORYSERVICESPLAIN SQLGATEWAYTEST MODECRONPOSTGRES14 TABLES
One Next.js server renders the pages and the API, and each change runs as one Postgres transaction in plain SQL; rate limits live in that process's memory. Card holds go through a gateway interface, a built-in test gateway today, and closed rounds settle on page reads or when a scheduler calls the cron route.

Trade-offs

Card holds, not charge-and-refund. A takeover voids the previous authorization for free, and only the winner is captured at close. The downside: Authorizations expire in about a week, which caps rounds at five days.

Pessimistic lock + optimistic token + unique index. The lock serializes, the token gives the loser a clear answer before any money call, and the index guarantees correctness even if the code regresses. The downside: Takeovers on one hot round queue behind each other (fine at this scale).

Lazy settlement plus a cron drain, no queue. Page reads settle a handful of due rounds inline; a cron endpoint drains the rest with FOR UPDATE SKIP LOCKED so callers never double-settle or block each other. The downside: Settlement leans on traffic or a scheduler being present.

What I'd do next

Build the real payments adapter behind the existing gateway interface; today it runs a test gateway.

Move rate limits out of process memory before running more than one server.

Next: GoodnightApple Health sleep stages in, a phased overnight bed-temperature plan out. On device.

Year
2026
Platform
Web
Status
Pre-launch, test-mode payments
Code
Private
Built with
Next.js 16, React 19, TypeScript, PostgreSQL, plain SQL (pg), zod, Vitest, Playwright
  • 18.7k lines of TypeScript
  • 150+ tests (unit, integration, e2e)
  • 14 Postgres tables
  • 3 layers of race protection

The code is private, so this page is an overview.