Work

Case StudyMay 20265 min read

ArcPlan

ArcPlan is a full-stack SaaS platform that converts 2D architectural floor plans into 3D outputs using Gemini AI. Auth, billing, AI pipeline, file storage, test suite, and deployment — designed, built, and shipped solo.

ArcPlan — cover image

[Solo Full-Stack Build] · [Gemini AI + Stripe + Supabase] · [90+ Lighthouse]

Overview

ArcPlan gives architects a browser-based workflow for converting 2D floor plan drawings into structured 3D outputs — without CAD expertise or desktop software. The platform handles the complete product surface: identity, metered AI processing, subscription billing, file storage, and result delivery.

Every layer — schema design, component architecture, billing logic, AI integration, test coverage, and deployment — was designed, built, and shipped by one developer. That scope is the point.

The Challenge

The core problem was not the AI call. It was making three external systems — Supabase, Gemini, and Stripe — behave as one coherent product. Each operates on its own event model, its own failure modes, and its own latency profile. Stripe webhooks fire asynchronously. Gemini responses arrive after variable processing time. Supabase Storage uploads happen client-side before the server pipeline begins.

The product had to coordinate those systems without exposing the seams to the user. A credit deduction that fires before a failed AI response, a subscription state that lags a webhook event, or a file that uploads successfully but never enters the processing pipeline — any of those breaks the product promise. The architecture was designed to prevent all three.

My Role

I defined the product scope, built the design system from scratch — color tokens, typography scale, spacing, component patterns — and made every architectural decision: route group layout, server and client component boundaries, Supabase RLS policy design, Stripe webhook event handling, and the Gemini API integration contract.

I also wrote the test suite — unit coverage for all Zod schemas, server utilities, and credit-calculation logic, alongside Playwright end-to-end scenarios covering the full upload-to-output user journey. Deployment was configured on Netlify with the OpenNext adapter, environment-specific build contexts, and tag-based ISR invalidation.

No handoff. No second opinion. Every decision is in the codebase.

What I Built

Authentication and Route Protection

Five auth flows — register, login, forgot password, reset password, and update password. Route protection is enforced at the proxy layer via Next.js middleware, which refreshes the session on every request and redirects unauthenticated users before any page component executes. No auth check lives in a component that could be bypassed.

Multi-Step Plan Upload and AI Pipeline

The plan creation flow is a three-step wizard: file upload with client-side format and size validation, a configuration step for output format and processing style, and a live processing step that surfaces real-time status as the file moves through storage, AI inference, and result storage.

The transform pipeline runs server-side. The uploaded file is fetched from Supabase Storage, converted and passed to Gemini 2.0 Flash as a structured prompt, and the response is parsed, validated against a Zod schema, and written back to the database with processing time recorded. Credit availability is checked before the AI step triggers. If the check fails, an upgrade prompt surfaces in-place. If Gemini fails, the error is caught, logged, and surfaced with a retry path — not a silent dead end.

Stripe Subscription Billing

Three subscription tiers — Starter, Pro, and Agency — managed via Stripe Checkout and the Billing Portal. The webhook handler processes five event types. Every event is signature-verified before any database write. Monthly credit allocations reset on successful renewal. Billing state in the database reflects what Stripe has confirmed, not what the UI optimistically assumed.

Dashboard and Plan Management

The dashboard surfaces total plans, monthly usage, credits consumed, and storage used. The plans listing supports grid and table views, status filtering, and client-side search. Each plan has a detail view showing the original file alongside the output, a processing timeline, metadata, and download actions.

Testing and Infrastructure

The test suite covers all Zod schemas, server utilities, and credit logic with unit tests, and the full upload-to-output journey with Playwright end-to-end scenarios. The application reaches a Lighthouse score above 90 across all four categories — Performance, Accessibility, Best Practices, and SEO — on a codebase that includes AI calls, file uploads, and Stripe integrations. Static assets are served from Netlify's CDN edge. Deploy previews generate automatically on every pull request.

Results

The finished platform covers the complete lifecycle a paying SaaS requires: metered access, AI-powered core feature, subscription billing, file management, and transactional email. The codebase is structured for a team — server and client boundaries are explicit, all external contracts are typed against generated Supabase types and Zod schemas, and the test suite provides a documented baseline for regression coverage.

A 90+ Lighthouse score across all four categories on a full-stack AI SaaS is not a default outcome. It reflects decisions made early — about rendering strategy, asset handling, and component boundaries — that most projects defer until performance becomes a complaint.

Tech Stack

TechnologyPurpose
Next.js (App Router)Framework, routing, and server components
SupabaseAuth, database, storage, and RLS
Gemini 2.0 FlashAI floor plan processing
StripeSubscription billing and webhook events
Tailwind CSSDesign system and layout
ZodSchema validation across server and client
Playwright + JestEnd-to-end and unit test coverage
Netlify + OpenNextDeployment and edge CDN

Closing

Auth, AI, billing, storage, tests, deployment — solo, from schema to production. ArcPlan is what a developer who can own a full product looks like in code.