Building CraveView: A Technical Deep-Dive into the Crave T3 Tablet Inventory Dashboard
TL;DR
I built CraveView, a tablet inventory dashboard, using Next.js 15, TypeScript, and Tailwind v4, with a Prisma schema for data modeling. This technical deep-dive explores the architecture decisions, code changes, and lessons learned during development.
The Problem
The goal was to create a dashboard for managing Crave T3 tablet inventory. The initial problem was setting up a robust tech stack for handling data synchronization from Google Sheets (CSV export) to a database, and then to the dashboard.
What I Tried First
Initially, I scaffolded the project using create-next-app with TypeScript and Tailwind CSS. I then focused on setting up Prisma for data modeling and database connection. The first challenge was configuring Prisma to work with a Neon database.
The Implementation
The implementation involved several key steps:
Setting Up the Database and Prisma
First, I added the database URL to .env.example:
# --- Database (Neon) ---
DATABASE_URL="postgresql://user:password@ep-xxxx-pooler.region.aws.neon.tech/craveview?sslmode=require"
DATABASE_URL_UNPOOLED="postgresql://user:password@ep-xxxx-pooler.region.aws.neon.tech/craveview?sslmode=require"
Then, I defined the Prisma schema in prisma/schema.prisma:
model CraveDevice {
id String @id @default(cuid())
clientId String @unique
// Additional fields...
}
Configuring Next.js and Tailwind
I updated next.config.ts to include Tailwind CSS:
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
// Config options...
};
export default nextConfig;
In eslint.config.mjs, I added ESLint configuration:
import { dirname } from "path";
import { fileURLToPath } from "url";
import { FlatCompat } from "@eslint/eslintrc";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const compat = new FlatCompat(__dirname, {
// Compat options...
});
// ESLint rules...
Building the Dashboard
The dashboard page is located at src/app/(dashboard)/inventory/page.tsx:
import { useState, useEffect } from 'react';
const InventoryPage = () => {
const [devices, setDevices] = useState([]);
useEffect(() => {
// Fetch devices from API or database...
}, []);
return (
<div>
<h1>Inventory Dashboard</h1>
<ul>
{devices.map((device) => (
<li key={device.id}>{device.clientId}</li>
))}
</ul>
</div>
);
};
export default InventoryPage;
Key Takeaway
One key lesson learned was the importance of configuring lint-staged and Husky for automated code quality checks. I added .husky/pre-commit with:
npx lint-staged
And configured .lintstagedrc.json:
{
"*.{ts,tsx,js,jsx}": ["eslint --fix", "prettier --write"],
"*.{json,css,md}": ["prettier --write"]
}
What's Next
The next step is to implement data synchronization from Google Sheets to the dashboard. I plan to create an API endpoint for handling CSV uploads and integrating it with the Prisma schema.
vibecoding #buildinpublic #Nextjs #TypeScript #TailwindCSS #Prisma
Part of my Build in Public series — sharing the real process of building SaaS projects from Playa del Carmen, México.
Repo: zaerohell/craveview · 2026-07-10
#playadev #buildinpublic
Top comments (0)