Denta Fund
Next.jsTypeScriptZustandshadcn/uiGoogle OAuthFintech

Denta Fund

Freelance frontend build, from scratch, for Denta Fund — a platform connecting investors with dental clinics raising capital. Built the Next.js application end to end: Google OAuth authentication with role-based onboarding for the two sides of the marketplace, investor and clinic dashboards, and a shadcn/ui + Tailwind design system built from zero.

Tech used

Next.jsTypeScriptZustandshadcn/uiTailwind CSSGoogle OAuthJWT

Situation

Denta Fund set out to connect investors with dental clinics looking to raise capital — a two-sided marketplace where each side needs a different view of the same funding data. There was no existing frontend, no design system, and no component conventions. Everything started from an empty repository.

Task

Own the frontend as the sole developer on the freelance engagement: build the Next.js application from scratch, ship Google OAuth with role-aware onboarding that routes investors and clinic owners into the right experience, deliver dashboards that make funding status legible to both sides, and establish a reusable design system so the product could keep growing without accumulating UI drift.

Action

Built the application on Next.js (App Router) with TypeScript, using Zustand for client state and TanStack-style server data patterns to keep fetching predictable. Implemented Google OAuth as the single sign-in path, with a role-based onboarding flow that branches investors and clinic owners into separate paths after first login and gates routes by role. Built dashboards for both sides — funding progress, clinic listings, and investment status — with data tables, filters, and status indicators designed to stay readable as record counts grow. Established the design system from scratch on shadcn/ui and Tailwind CSS: tokens, theming, and a shared component layer so every new screen composes existing primitives instead of introducing new patterns.

Result

Delivered a complete frontend from an empty repository to a working two-sided platform. Google OAuth plus role-based onboarding removed password handling entirely and put each user in the correct dashboard on first login. The shadcn/ui design system made new screens a composition task rather than a build task, keeping the UI consistent as scope expanded. Project is pre-launch — public link pending.

Overview

Denta Fund is a platform connecting investors with dental clinics raising capital. I took it on as a freelance engagement, owning the frontend from an empty repository through to a working two-sided product.

Stack: Next.js, TypeScript, Zustand, shadcn/ui, Tailwind CSS, Google OAuth.

Two Sides, One Dataset

The core design problem is that a funding round means different things to each party. A clinic owner sees how close am I to my target. An investor sees what am I in, and how is it performing. Same underlying records, two different questions.

That shaped the architecture early: shared data layer, role-specific views on top, and routing that decides which one you get before the page renders.

Auth and Onboarding

Google OAuth as the single sign-in path — no passwords to store, reset, or leak.

The interesting part is what happens after. First login lands a user without a role, so onboarding branches: clinic owner or investor. That choice determines their dashboard, their navigation, and which routes they can reach. Route guards enforce it rather than the UI merely hiding links.

Dashboards

Both roles get a dashboard built on the same primitives — data tables, filters, status indicators, funding progress — configured differently per role.

The constraint I designed against was growth. A dashboard that reads well with five records and falls apart at five hundred isn't finished. Filtering, sorting, and pagination were in from the start, not retrofitted.

Design System from Scratch

No existing components, no established conventions. I built the system on shadcn/ui and Tailwind CSS: design tokens, theming, and a shared component layer above the primitives.

The payoff is compounding. Once the layer existed, new screens became composition — assemble existing pieces — instead of construction. That's what keeps a growing product from drifting into five slightly different button styles.

State

Zustand handles client state: session and role context, UI state, filter and view preferences. Small stores with narrow responsibilities, kept separate from server data so cached remote state and local UI state never blur together.

Status

Pre-launch. Public link to follow.