Skip to main content

Case study · Tale of Two Rivers

A site for advisors, not agents.

Francis and Evan run four service lines in Morgantown — rental management, bookkeeping, tax, homebuying guidance. They are not a brokerage. Their own line, verbatim from the repo: “We don’t sell homes — we help you make better decisions about them.”

Role
Designer & developer
Timeline
April 2026 — present
Stack
Next.js 16 · React 19 · TypeScript · Sanity 5 · CSS variables · Turbo monorepo
Status
Live · 3 weeks of initial build, ongoing iteration · Visit live site ↗
Outcome
Francis and Evan update service descriptions, founder bios, listings, and contact details themselves in Sanity, with visual editing showing changes on the real page before they publish — no developer in the loop for day-to-day copy.
§ I

The job

Francis Molina and Evan Weisberg run a multi-service operation out of Morgantown, West Virginia. Four service lines: short-, mid-, and long-term rental management; bookkeeping; tax planning and preparation; homebuying guidance. Same owner-investor often hires them across more than one of those lines.

They are not a brokerage. They are not real estate agents. The website had to read as advisory and operational rather than transactional — and it had to make that distinction without making the whole site defensive.

§ II

Constraints

The four service lines cross two domains. Rental management and homebuying guidance live on the operations side (Francis). Bookkeeping and tax live on the finance side (Evan). Same audience, different mental models. The information architecture had to surface both without forcing visitors to learn which co-founder handles what.

Francis and Evan needed to update service descriptions, founder bios, listings, and contact details without a developer in the loop. Sanity was the right fit — and the content model needed to give them room to tune copy per page rather than locking them to a single shared service taxonomy.

The brokerage distinction is a one-sentence positioning point, not a feature. The challenge was making sure the right people read it at the right moment — without turning the rest of the site into an extended disclaimer.

§ III

What I built

pnpm + Turborepo monorepo. Three workspaces: `apps/web` for the public Next.js site, `apps/studio` for the standalone Sanity Studio, `packages/sanity-config` for the schema shared between them.

Next.js 16 App Router, React 19, TypeScript. Plain CSS with CSS custom properties for the design tokens — Lora for serif headings, Inter for body, a forest-green and warm-gold palette that reads as Appalachian without leaning on costume.

Sanity 5 with 10 document types (8 singletons — 7 pages plus a `siteSettings` document for shared identity — and two collections: founders and listings) and 4 reusable object types (SEO, link, service item, testimonial). Service items are embedded portable-text arrays per page, not a separate global taxonomy. Each page frames its own services in its own voice — the homebuying page is allowed to describe “buyer education” differently from how the for-owners page describes “guest communication.” The small duplication cost buys the team flexibility to tune copy per context.

Founders are represented as Sanity documents with name, role, bio, and email — no headshot field in the schema. That is a deliberate omission. Francis and Evan own the operational and financial positioning; photographs can land when they want them to, and the site does not block on them.

Visual editing is enabled in the Studio, so the team sees edits land in their actual page layout rather than guessing from a form view. Live mode propagates draft changes through preview without a publish step.

§ IV

What I deliberately did not build

Most real-estate sites in Morgantown are agent funnels. The whole point of Tale of Two Rivers is that it is not one of those.

  • No MLS feed, no IDX widget — they are not an agent, so they do not display third-party brokerage listings.
  • No offer submission, no transaction workflow — they help owners make decisions; closings happen with someone else.
  • No global services taxonomy — each page describes its own services in its own voice, so the homebuying page can read as buyer-side guidance and the for-owners page can read as operational support.
  • No founder headshots in the schema yet — bios carry the founder identity; photos can land when Francis and Evan want them to.
  • No “concierge real estate” framing — the line they wrote is direct, and the site keeps it that way.
§ V

What the team does without me

Sanity Studio for everything visitor-facing: hero copy, service descriptions, testimonials, founder bios, individual listings, contact details, SEO defaults. Visual editing lets the team author against the rendered page; live mode lets them preview without publishing.

A future engineer (or me, six months from now) extends the site by adding a schema in `packages/sanity-config` and reading it from a new page in `apps/web`. No infrastructure work, no new deploy targets.

The contact form posts through a Server Action to a Next.js route at `/api/contact`. The route validates each submission and logs it server-side. Resend for email delivery is the next integration — once it lands, the route will forward to the team’s inbox.

Four service lines, one company, no brokerage. The site says that and gets out of the way.