Portfolio

Docs

How the site works, what it’s built with, how to run it locally, testing, and API endpoints.

Overview

This is a production-style admin dashboard for a Resident Experience Platform: multiple properties, onboarding per property, services marketplace, and analytics. The dashboard is its own route: select a property in the sidebar, then use Onboarding, Marketplace, or Analytics for that property.

Dashboard (/dashboard) includes the sidebar (property selector + sections) and Docs. Onboarding is scoped to the selected property: residents and tasks belong to that property. Marketplace and Analytics are placeholders.

Data is stored in PostgreSQL via Prisma. The UI calls REST APIs under /api/*. There is no authentication in this demo.

Tech stack

  • Next.js (App Router), TypeScript, Tailwind CSS, shadcn/ui
  • Prisma, PostgreSQL (Docker)
  • Zod, Vitest, Recharts, Sonner, next-themes

Package manager: pnpm.

Development setup

Prerequisites: Node 20+, pnpm, Docker.

git clone <repo-url> && cd portfolio
pnpm install
cp .env.example .env   # set DATABASE_URL
pnpm db:up && pnpm db:migrate && pnpm db:seed
pnpm dev

Open http://localhost:3000, then go to /dashboard. Optional: pnpm db:studio, pnpm db:reset.

Testing

Vitest + React Testing Library + jsdom.

pnpm test        # Watch
pnpm test:run     # CI

API reference

JSON responses: success { data: T }, errors { error: { code, message, details? } }.

Properties & Onboarding

  • GET /api/properties

    List all properties. Response: { id, name, slug, address }[].

  • GET /api/onboarding/residents?propertyId=:id

    List residents for a property. propertyId required.

  • GET /api/onboarding/categories

    List task categories.

  • GET /api/onboarding/tasks?residentId=:id

    List tasks for a resident.

  • POST /api/onboarding/tasks

    Create task (body: residentId, categoryId, title, optional status, owner, dueDate).

  • PATCH /api/onboarding/tasks/:id

    Update task. Idempotent completion.

  • DELETE /api/onboarding/tasks/:id
  • POST /api/onboarding/reset

    Reset onboarding demo data.

Marketplace

  • GET /api/marketplace/services

    List services. Optional query: category, enabled=false to include disabled.

  • POST /api/marketplace/services

    Create service (body: name, description?, category, priceCents, enabled?).

  • PATCH /api/marketplace/services/:id

    Update service (partial).

  • DELETE /api/marketplace/services/:id

    Delete service (fails if it has orders).

  • GET /api/marketplace/orders?propertyId=:id

    List orders for residents of the property. propertyId required.

  • GET /api/marketplace/orders/:id

    Get order with items and resident.