ogkify is a full-stack e-commerce application built with TanStack Start. It provides a customer storefront for browsing and purchasing products, plus an admin dashboard for managing the store catalog and orders.
- Customer storefront with product listing, product details, search, cart, checkout, profile, and order history
- Admin dashboard for managing products, categories, colors, sizes, and orders
- Email and password authentication with Better Auth
- Product catalog stored in PostgreSQL using Drizzle ORM
- Product image upload support through Cloudinary
- Stripe payment integration with webhook support
- Responsive UI built with Tailwind CSS v4 and shadcn/ui components
- Framework: TanStack Start, TanStack Router, React, Vite
- Language: TypeScript
- Database: PostgreSQL
- ORM: Drizzle ORM, Drizzle Kit
- Authentication: Better Auth
- Payments: Stripe
- Image Uploads: Cloudinary
- UI: Tailwind CSS v4, shadcn/ui, Base UI, lucide-react
- Forms and Validation: React Hook Form, TanStack Form, Zod
- Data Fetching: TanStack Query
- Testing: Vitest
- Package Manager: pnpm
Make sure you have the following installed or prepared:
- Node.js 20 or later
- pnpm
- A PostgreSQL database
- A Stripe account for payment testing
- A Cloudinary account for image uploads
pnpm installCopy the example environment file:
cp .env.example .envThen fill in the values in .env:
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE"
BETTER_AUTH_SECRET="your-better-auth-secret"
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."
VITE_STRIPE_PUBLISHABLE_KEY="pk_test_..."
VITE_BASE_URL="http://localhost:3000"
VITE_CLOUDINARY_CLOUD_NAME="your-cloudinary-cloud-name"
VITE_CLOUDINARY_UPLOAD_PRESET="your-cloudinary-upload-preset"| Variable | Required | Description |
|---|---|---|
DATABASE_URL |
Yes | PostgreSQL connection string used by Drizzle |
BETTER_AUTH_SECRET |
Yes | Secret key used by Better Auth |
STRIPE_SECRET_KEY |
Yes | Stripe server-side secret key |
STRIPE_WEBHOOK_SECRET |
Yes | Stripe webhook signing secret |
VITE_STRIPE_PUBLISHABLE_KEY |
Yes | Stripe publishable key used on the client |
VITE_BASE_URL |
Yes | Base URL of the app, usually http://localhost:3000 in development |
VITE_CLOUDINARY_CLOUD_NAME |
Yes | Cloudinary cloud name for image uploads |
VITE_CLOUDINARY_UPLOAD_PRESET |
Yes | Cloudinary unsigned upload preset |
Push the Drizzle schema to your database:
pnpm db:pushSeed demo data:
pnpm db:seedOpen Drizzle Studio:
pnpm db:studioStart the development server:
pnpm devThe app will run at:
http://localhost:3000If you need a clean Vite cache:
pnpm dev:cleanCreate a production build:
pnpm buildStart the production server:
pnpm startRun the production server locally with .env loaded:
pnpm start:local| Command | Description |
|---|---|
pnpm dev |
Start the development server on port 3000 |
pnpm dev:clean |
Clear Vite cache and start the dev server |
pnpm build |
Build the app for production |
pnpm start |
Start the production server |
pnpm start:local |
Start the production server with .env loaded |
pnpm test |
Run tests with Vitest |
pnpm typecheck |
Run TypeScript type checking |
pnpm lint |
Run oxlint |
pnpm lint:fix |
Fix lint issues |
pnpm format |
Check formatting with oxfmt |
pnpm format:fix |
Format files |
pnpm check |
Fix lint issues and format files |
pnpm db:push |
Push database schema changes |
pnpm db:studio |
Open Drizzle Studio |
pnpm db:seed |
Seed demo data |
src/
components/
dashboard/ Admin dashboard components
shop/ Customer storefront components
shared/ Shared components
ui/ Reusable UI primitives
db/
schema.ts Database schema and relations
seed.ts Demo data seed script
env/
client.ts Client environment variable schema
server.ts Server environment variable schema
lib/
auth.ts Better Auth configuration
routes/
(auth)/ Login and signup routes
(shop)/ Customer-facing routes
api/ API routes and webhooks
dashboard/ Admin dashboard routes
server/
*.ts Server-side queries and mutationsFor local Stripe webhook testing, forward events to:
http://localhost:3000/api/webhooks/stripeSet the generated webhook signing secret as STRIPE_WEBHOOK_SECRET in .env.