Crash course · 8 modules · ~3 hours

Build a real Hardware POS in one afternoon.

Follow this crash course and ship HardwarePOS — a point-of-sale system a hardware shop in Kampala could use today. Inventory, sales, payment methods, downloadable receipts, deployed to a custom domain. Powered by VibeKit + your favorite AI coding agent.

Watch the full crash course on YouTube as you follow the modules below · Watch on YouTube
WHAT YOU'LL BUILD

HardwarePOS — a real shop POS.

Not a tutorial toy. Real auth, real database, real transactions, real receipts. A hardware shop owner could install this Monday morning and start using it.

Features you'll ship

  • Email + Google OAuth sign-in (Better Auth)
  • Inventory: products with SKU, price (UGX), stock, category
  • Six seeded categories: Tools, Hardware, Paint, Plumbing, Electrical, Other
  • Low-stock alerts (configurable per product)
  • POS sale screen: product search, cart, live total
  • Three payment methods: Cash, Mobile Money, Card
  • Optional customer name + phone capture
  • Receipt PDF download (@react-pdf/renderer)
  • Sales history with date-range filtering
  • Dashboard: today's revenue, top products, weekly chart
  • Light + dark mode
  • Deployed to Vercel + custom domain

Skills you'll learn

  • Planning a real product with Claude before any code
  • Reading a phase-by-phase build plan
  • Modeling transactional data in Prisma v7 (Sale + SaleItem pattern)
  • Wiring auth-guarded API routes with Zod validation
  • Atomic stock decrements inside Prisma transactions
  • Building a fast product search with React Query
  • Generating styled PDFs with @react-pdf/renderer
  • Aggregating data with groupBy for dashboards
  • Currency formatting (UGX, no decimals, comma-separated)
  • Running a senior-level pre-deploy audit
  • Deploying with Vercel + Cloudflare DNS + SSL
Total time
~3 hrs
Modules
8
Lines you write
~0
Cost (free tiers)
$0
MODULE 00 · 2 min · OPTIONAL BUT RECOMMENDED

Check your environment first

Before signing up for accounts, make sure your machine has the four tools VibeKit needs: Node 20+, pnpm 9+, git, and gh CLI. The fastest way to check is to paste the OS-specific prompt at vibekit.desishub.com/setup into your AI coding agent — it scans your machine, reports what's installed, and gives you one-line install commands for anything missing. Without installing anything itself.

If you already have all four installed, skip to Module 01.

MODULE 01 · 5 min

Set up the accounts you'll need

All of these have free tiers that cover the entire course. Sign up first so you don't break flow later.

Local tools

  • Node.js 20+ (or 22+) — node -v to check
  • pnpmnpm i -g pnpm if missing
  • git — already installed on most systems
Tip
Don't have a Resend account? You can skip it for now and add it during Module 04 — auth still works without email verification in dev.
MODULE 02 · 15 min

Plan with Claude (claude.ai)

VibeKit's planning step turns a one-line idea into 4 production-ready files. You paste a prompt, answer questions, and Claude does the rest.

Step 1 — Open the planning prompt

Go to /docs/quickstart and copy CLAUDE_PROMPT.md from the first code block (or grab it directly from the repo).

Step 2 — Open Claude

Go to claude.ai/new. Paste the entire CLAUDE_PROMPT.md as your first message. Then on a new line, paste the HardwarePOS brief:

Append after CLAUDE_PROMPT.md contentHardwarePOS brief
I want to build HardwarePOS — a point-of-sale system for a small hardware shop in
Uganda. The shop owner uses it to ring up sales of items like nails, paint,
plumbing fittings, electrical supplies, and hand tools. Single user (the shop
owner / cashier) — no team features, no customer-facing storefront, no online
ordering. Strictly in-shop POS.

Core flows:

1. POS Sale (the main screen): search products by name or SKU, add to cart,
   adjust quantities, see live total. Choose payment method (Cash / Mobile Money /
   Card). Capture optional customer name and phone. Complete sale, then download
   a receipt PDF.

2. Inventory: list products with name, SKU, category, price (UGX), and stock
   quantity. Add new products, edit price/stock, delete. Low-stock alerts when
   stock falls below a configurable threshold per product.

3. Sales history: list of past sales with date, total, payment method, items
   count, customer (if captured). Filter by date range and payment method. View
   a single sale's full line items. Export the day's sales to a PDF report.

4. Dashboard: today's sales total + transaction count, top 5 products this week,
   low-stock alert count, weekly revenue chart (last 7 days).

Seed the database with these categories on first run: Tools, Hardware, Paint,
Plumbing, Electrical, Other.

No image uploads — text-only products (name + SKU + category is enough).
No e-commerce / cart abandonment / online ordering / customer accounts.
Currency: UGX (Ugandan Shillings) with comma-separated formatting and no decimals
(e.g., 25,000 not 25,000.00).

Single user, single device. Light + dark mode. Aesthetic: clean dashboard like
Linear or Vercel — bold large numbers so the cashier can read totals at a glance.
Brand color: indigo (#4F46E5).

Step 3 — Paste a Dribbble reference (mandatory)

Claude will now ask for a UI reference image. This is non-skippable — even though the HardwarePOS brief is detailed, words like "clean dashboard" are too vague to design from. A real Dribbble shot tells Claude exactly which color palette, font weight, card style, and button shape to match.

  1. Claude will suggest 2–3 search terms (e.g. "pos dashboard ui", "retail point of sale").
  2. Open dribbble.com/search and search one of them.
  3. Pick a shot whose aesthetic you'd want HardwarePOS to match. Open the shot in full size.
  4. Right-click → Copy Image, then paste it into the Claude chat. (Don't paste a Dribbble URL — paste the image itself.)
  5. Claude will analyze it and echo back the palette + typography + card spec it extracted. Confirm or correct.
Tip
For HardwarePOS specifically, look for shots with bold large numbers (cashier-readable totals), clean tables, soft cards. Avoid shots that are too "creative agency" — POS UIs need to be fast and legible, not editorial.

Step 4 — Wait for Claude's confirmation summary

The HardwarePOS brief above is detailed, so Claude will probably skip the interview. Instead, it will write a structured summary like this:

What Claude will produce
## What I understood

App: HardwarePOS — a single-user POS for a hardware shop in Uganda
Primary user: the shop owner / cashier
Core features:
  - POS sale flow (search → cart → payment → receipt)
  - Inventory with low-stock alerts
  - Sales history with date filters
  - Dashboard with daily revenue + top products + weekly chart
Data model: Category, Product, Sale, SaleItem (with snapshot fields)
Integrations: Better Auth (email + Google OAuth), Resend (auth emails only),
  Payments: NONE (payment method is just a captured label),
  File uploads: NONE, Dark mode: Yes
Visual design: indigo (#4F46E5), Geist + JetBrains Mono,
  "fast, focused, large numbers", Linear/Vercel inspiration
Out of scope (v1): online ordering, customer accounts, multi-cashier roles

Does this match your intent? Reply 'Yes, generate the files' to proceed,
or tell me what to adjust.

If anything's wrong, correct it now (e.g., "Add Excel export to the sales history"). Otherwise, reply:

Reply to Claude
Yes, generate the files

Step 5 — Download the 4 files

Claude will produce 4 downloadable Artifacts (one per file) in the right-side panel. Each has a download icon — click it to save the file.

terminalCreate the project folder first
mkdir hardware-pos && cd hardware-pos
# Then drop the 4 downloaded files into this folder:
# - project-description.md
# - project-phases.md
# - design-style-guide.md
# - prompt.md
Tip
Prefer one-shot creation? At the end of Claude's message there's a single bash heredoc block that creates all 4 files at once — copy it, paste into your terminal inside hardware-pos/, hit enter. Done.
Tip
If Claude tries to skip the confirmation step and dives straight into generating, paste: "Stop. First show me the structured 'What I understood' summary and wait for my confirmation. Don't generate anything yet."
MODULE 03 · 10 min

Initialize the project

Scaffold the Next.js 16 project, copy the framework's coding constitution into it, open your coding agent.

Step 1 — Scaffold Next.js

terminalFrom inside the hardware-pos folder
pnpm create next-app@latest . --typescript --tailwind --app --eslint --import-alias "@/*" --turbopack --no-src-dir

Accept the prompts. When it finishes, you have a base Next.js 16 project.

Step 2 — Copy the framework files

Clone the VibeKit repo to grab the framework files:

terminalOne-time clone (delete after copying)
git clone https://github.com/MUKE-coder/vibekit.git /tmp/vibekit

cp /tmp/vibekit/master_prompt.md ./master_prompt.md
cp /tmp/vibekit/jb-components.md ./jb-components.md
cp /tmp/vibekit/pre-deploy-review.md ./pre-deploy-review.md

Step 3 — Install the VibeKit rules for your AI agent

VibeKit ships rules for every major AI coding agent. Pick your agent below and run the one-line install. The rules auto-load whenever you open the agent in this project — no need to paste long prompts every session.

terminalProject-local install (recommended)
mkdir -p .claude/skills/vibekit
curl -fsSL https://raw.githubusercontent.com/MUKE-coder/vibekit/main/skill/SKILL.md \
  -o .claude/skills/vibekit/SKILL.md

Restart Claude Code. Type /vibekit to invoke, or it auto-loads when framework files are detected.

Using a different agent (Continue, Cody, Junie, etc.)? See skill/README.md for the full install table — same one-line curl, just a different filename.

Tip
Switching between agents on the same project? Install for all of them at once — see the "Multi-agent setup" section in skill/README.md. One canonical file, symlinked to each agent's expected path.

Step 4 — Verify your project root

You should now have these 7 files in your project root:

ls -laExpected files
hardware-pos/
├── master_prompt.md            # framework — coding rules
├── jb-components.md            # framework — component registry
├── pre-deploy-review.md        # framework — security audit prompt
├── project-description.md      # generated by Claude
├── project-phases.md           # generated by Claude
├── design-style-guide.md       # generated by Claude
├── prompt.md                   # generated by Claude — paste this next
│
# ONE of these from Step 3 (depending on your agent):
├── .claude/skills/vibekit/SKILL.md   # Claude Code
├── .cursor/rules/vibekit.mdc         # Cursor
├── AGENTS.md                         # Codex CLI / universal
├── .clinerules                       # Cline
├── .windsurfrules                    # Windsurf
├── GEMINI.md                         # Gemini CLI
└── package.json + Next.js scaffold

Step 5 — Open in your coding agent

Open the hardware-pos folder in Claude Code (claude in the project terminal), Cursor, Cline, or whichever agent you chose.

MODULE 04 · 30 min

Phase 1 — Foundation

First big build moment. Your agent reads all 7 files, then executes Phase 1: Prisma + Neon, Better Auth, layout shell, design tokens, custom 404/error pages.

Step 1 — Get a Neon database URL

  1. Go to console.neon.tech and create a new project.
  2. Copy the connection string (starts with postgres://).
  3. Use the direct (non-pooled) connection — Prisma migrations require it.

Step 2 — Paste the build prompt

In your coding agent, paste the entire contents of prompt.md as your first message. The agent will:

  1. Read master_prompt.md, design-style-guide.md, jb-components.md, project-description.md, project-phases.md
  2. Execute Phase 1 tasks
  3. Stop after Phase 1 for your confirmation

Step 3 — Provide secrets when asked

The agent creates .env.local and asks for values. Provide:

.env.localPhase 1 minimum env vars
DATABASE_URL="postgres://USER:PASS@ep-xxx.neon.tech/neondb?sslmode=require"
BETTER_AUTH_SECRET="<run: openssl rand -base64 32>"
BETTER_AUTH_URL="http://localhost:3000"

# Optional but recommended
RESEND_API_KEY=""
RESEND_FROM_EMAIL="onboarding@resend.dev"

# For Google OAuth
GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""

Step 4 — Push the schema + start dev

terminalPhase 1 verification
pnpm db:push
pnpm db:generate
pnpm dev

Open http://localhost:3000 and verify:

  • Landing page redirects unauthenticated users to /auth/sign-in
  • Sign up with email or Google works
  • You land on /dashboard (currently empty)
  • Sidebar layout with theme toggle (light/dark)
Tip
Stuck? Tell the agent: "Verify all of Phase 1's tasks are complete. Read project-phases.md and check off what's done." Anything unfinished, it'll fix.
MODULE 05 · 30 min

Phase 2 — Products & Inventory

Build the inventory side first — the cashier needs products to exist before they can sell. Categories + Products with full CRUD, plus low-stock badges.

Step 1 — Confirm Phase 1 done, start Phase 2

Prompt
Phase 1 is verified working. Proceed to Phase 2 — Products & Inventory.

Build:
- Category and Product Prisma models (schema below)
- A seed script that inserts the 6 categories on first run: Tools, Hardware, Paint, Plumbing, Electrical, Other
- API routes /api/categories and /api/products with auth guards + Zod validation
- /inventory page using JB Data Table to list products with columns: SKU, Name, Category, Price (UGX), Stock, Status (low-stock badge)
- /inventory/new and /inventory/[id]/edit pages with React Hook Form + Zod
- A formatUGX(amount: number) utility in lib/format.ts that returns "UGX 25,000" style strings (no decimals, comma separators)

Stop after Phase 2 is complete and ask me to verify.

Step 2 — Verify the schema

The agent should produce a Prisma schema like this. If it differs, ask for these exact fields:

prisma/schema.prismaCategories + Products
model Category {
  id        String    @id @default(cuid())
  name      String    @unique
  color     String    @default("#4F46E5")
  products  Product[]
  userId    String
  user      User      @relation(fields: [userId], references: [id], onDelete: Cascade)
  createdAt DateTime  @default(now())
}

model Product {
  id                  String     @id @default(cuid())
  sku                 String
  name                String
  priceUgx            Int        // store as integer, no decimals
  stockQuantity       Int        @default(0)
  lowStockThreshold   Int        @default(5)
  categoryId          String
  category            Category   @relation(fields: [categoryId], references: [id])
  saleItems           SaleItem[]
  userId              String
  user                User       @relation(fields: [userId], references: [id], onDelete: Cascade)
  createdAt           DateTime   @default(now())
  updatedAt           DateTime   @updatedAt

  @@unique([userId, sku])  // SKUs unique per user
  @@index([userId])
  @@index([categoryId])
}

Step 3 — Test inventory CRUD

  1. Verify the 6 categories appear in the sidebar / category dropdown
  2. Add 8–10 products across categories (e.g. NAIL-3IN 3-inch nails 800 UGX stock 200; PAINT-WHT-4L White paint 4L 45,000 UGX stock 12)
  3. Edit a product's stock down to 2 — confirm the low-stock badge appears
  4. Delete a product — confirm it's removed
  5. Search by SKU and by name — both should work in the data table
Tip
UGX prices stored as integers (not decimals) avoids rounding bugs. The formatUGX() utility handles display. Tell your agent if it tries to use Decimal/Float for currency — that's a foot-gun.
MODULE 06 · 45 min

Phase 3 — POS Sale flow + Receipt PDF

The core of the app. Cashier searches a product, adds to cart, sets quantity, picks payment, completes sale. Stock decrements atomically. PDF receipt downloads immediately.

Step 1 — Add the Sale + SaleItem schema

Prompt
Phase 2 is verified. Proceed to Phase 3 — POS Sale flow.

Add to the Prisma schema:

model Sale {
  id              String        @id @default(cuid())
  totalUgx        Int
  paymentMethod   PaymentMethod
  customerName    String?
  customerPhone   String?
  items           SaleItem[]
  userId          String
  user            User          @relation(fields: [userId], references: [id], onDelete: Cascade)
  createdAt       DateTime      @default(now())
  @@index([userId, createdAt])
}

model SaleItem {
  id          String   @id @default(cuid())
  saleId      String
  sale        Sale     @relation(fields: [saleId], references: [id], onDelete: Cascade)
  productId   String
  product     Product  @relation(fields: [productId], references: [id])
  productName String   // snapshot of product name at sale time
  productSku  String   // snapshot of SKU at sale time
  unitPriceUgx Int     // snapshot of price at sale time
  quantity     Int
  lineTotalUgx Int
  @@index([saleId])
  @@index([productId])
}

enum PaymentMethod { CASH MOBILE_MONEY CARD }

Then run pnpm db:push and pnpm db:generate.
Tip
Why snapshot productName/productSku/unitPriceUgx on each SaleItem? Because product details change over time, but a historical sale receipt should reflect what was sold at that moment. This is a real-world pattern that AI agents often skip — make sure it's there.

Step 2 — Build the POS screen

Prompt
Build /pos as the main POS screen with this layout:

LEFT (60%) — Product search + grid:
- Search input at top (search by SKU or product name)
- Product grid below: each card shows SKU, name, price (UGX), stock. Click adds 1 to cart (or increments quantity if already in cart). Out-of-stock products are visually disabled.
- Use React Query for product data with staleTime 30000.

RIGHT (40%) — Cart:
- "New Sale" header
- List of cart items: product name, qty controls (+/-), unit price, line total, remove button
- Optional customer name + phone fields
- Payment method select: Cash / Mobile Money / Card
- Live total in big numbers (32px font, accent color)
- "Complete Sale" button (disabled when cart is empty)

API:
POST /api/sales accepts { items: [{ productId, quantity }], paymentMethod, customerName?, customerPhone? } and:
1. Validates with Zod
2. Wraps everything in db.$transaction:
   a. Reads each product (FOR UPDATE not needed — Prisma handles this with the txn)
   b. Verifies stock >= quantity for each item; throws 400 if not
   c. Creates the Sale with snapshot SaleItems (copy productName, sku, unitPriceUgx)
   d. Decrements product stockQuantity by quantity for each item
3. Returns the new sale id

After successful sale, redirect to /sales/[id] which shows the sale detail + a "Download Receipt" button.

Use the existing JB Searchable Select for the payment method dropdown.

Step 3 — Receipt PDF with @react-pdf/renderer

Prompt
Build /api/sales/[id]/receipt that returns a PDF response using @react-pdf/renderer.

The receipt should look like a real till receipt:
- Centered header: shop name placeholder ("HARDWARE POS"), "RECEIPT" subtitle, date/time
- Sale ID (last 8 chars), payment method, optional customer name/phone
- Line items table: SKU | Item | Qty | Unit Price | Line Total
- Total row in bold
- Footer: "Thank you for your purchase"
- Use Helvetica or the closest equivalent in @react-pdf — small fonts (10–11pt)
- A4 portrait page size
- Currency formatted via formatUGX()

Wire the "Download Receipt" button on the sale detail page to fetch this endpoint and download the file as receipt-<saleId>.pdf.

Step 4 — Test a real sale end-to-end

  1. Open /pos, search "nail", add to cart
  2. Adjust quantity to 5, search "paint", add to cart
  3. Verify the live total matches manually (5 × nail price + 1 × paint price)
  4. Type a customer name and phone
  5. Pick "Mobile Money" as payment method
  6. Click Complete Sale → you land on /sales/[id]
  7. Download the receipt PDF and open it
  8. Go to /inventory — verify stock decremented for both products
MODULE 07 · 25 min

Phase 4 — Dashboard + Sales History

With sales flowing, the dashboard becomes useful. Today's revenue, top products, low-stock counter, weekly chart. Plus the full sales history.

Step 1 — Dashboard analytics

Prompt
Build /dashboard with these sections:

STAT CARDS ROW (4 cards across):
- Today's Revenue (UGX) — sum of Sale.totalUgx where DATE(createdAt) = today
- Today's Transactions — count of sales today
- Low-Stock Alerts — count of products where stockQuantity <= lowStockThreshold
- This Week's Revenue — sum of Sale.totalUgx where createdAt >= start of current ISO week

Each card: label (uppercase mono 11px), big number (28px semibold), small comparison vs yesterday/last week (12px secondary).

WEEKLY REVENUE CHART:
- Bar chart of daily revenue for the last 7 days
- Use a simple SVG bar chart in a custom component (no external chart library needed for 7 bars)
- Labels: day name (Mon, Tue, ...). Y-axis: UGX values formatted with formatUGX.
- Bar color: var(--accent), with bg-muted fill for the active day's bar

TOP 5 PRODUCTS THIS WEEK:
- Aggregate SaleItem rows where Sale.createdAt >= start of week
- groupBy productId, sum quantity, sum lineTotalUgx
- Display as a table: rank, name, units sold, revenue
- Order by units sold descending

LOW-STOCK LIST:
- List of products where stockQuantity <= lowStockThreshold
- Show name, SKU, current stock, threshold
- Link to /inventory/[id]/edit

All queries should be in API routes, scoped to session.user.id, served via React Query.

Step 2 — Sales history page

Prompt
Build /sales — full sales history list:

- JB Data Table with columns: Date (formatted "Jan 15, 2024 14:30"), Sale ID (last 8 chars), Items count, Payment Method (badge), Total (UGX, right-aligned monospace), Customer (if any), Action (View)
- Server-side pagination via /api/sales (page, limit, default 20)
- Filters above the table:
  - Date range picker (default: last 30 days)
  - Payment method dropdown (All / Cash / Mobile Money / Card)
- Filter state lives in URL query params so refresh preserves it
- "Export today's sales as PDF" button at the top — generates a daily report PDF with a header summary + sales table

Clicking a row goes to /sales/[id] (already exists from Phase 3) showing full line items and the receipt download button.

Step 3 — Test the analytics

  1. Make 3–5 sales of varying amounts and payment methods
  2. Refresh /dashboard — verify the 4 stat cards reflect those sales
  3. Check the weekly revenue chart — today's bar should be highlighted
  4. Verify the top-5 products list orders correctly
  5. Drop a product's stock to below threshold — verify it appears in low-stock list
  6. On /sales, filter to "Mobile Money only" — verify the URL updates and the table filters
  7. Export today's sales as PDF — open the file, verify totals match the dashboard
MODULE 08 · 40 min

Pre-deploy review + Deploy

The two highest-leverage steps: catch security holes before launch, then ship.

Step 1 — Run the pre-deploy audit

Open Step 7 of the quickstart (or open pre-deploy-review.md in your project root). Paste the entire prompt into your coding agent.

The agent writes findings to pre-deploy-review-report.md. Expected for HardwarePOS:

  • Critical — missing rate limiting on auth, possibly missing transaction wrapping on the sale endpoint (this would let stock go negative under concurrent sales)
  • High — missing index on Sale.createdAt for the dashboard date queries, N+1 on the sales history when fetching items count
  • Medium — missing Zod refinements (e.g. quantity must be > 0), verbose console.log on success paths

Step 2 — Fix every Critical

For each Critical, paste back to the agent:

Prompt
Fix Critical issue #1 from pre-deploy-review-report.md. Apply the suggested fix exactly, run a quick test, confirm the issue is resolved. Do not introduce changes outside the scope of this fix.

Re-run the audit until Critical count = 0. High and Medium can wait until after launch.

Step 3 — Push to GitHub

terminalInitial commit + push
git init
git add .
git commit -m "Initial commit — HardwarePOS built with VibeKit"
gh repo create hardware-pos --private --source=. --push
# OR manually create on github.com and:
# git remote add origin https://github.com/YOU/hardware-pos.git
# git push -u origin main

Step 4 — Import to Vercel + set env vars

  1. Go to vercel.com/new
  2. Import the hardware-pos repo. Framework auto-detects as Next.js.
  3. Build command: prisma generate && prisma migrate deploy && next build
  4. Don't deploy yet — set env vars first.
Vercel → Settings → Environment VariablesProduction env
DATABASE_URL=<your Neon prod connection string>
BETTER_AUTH_SECRET=<a NEW 32+ char string, NOT the dev one>
BETTER_AUTH_URL=https://hardware-pos.vercel.app
RESEND_API_KEY=<from resend.com>
RESEND_FROM_EMAIL=noreply@yourshop.com
GOOGLE_CLIENT_ID=<from Google Cloud Console>
GOOGLE_CLIENT_SECRET=<from Google Cloud Console>
NEXT_PUBLIC_APP_URL=https://hardware-pos.vercel.app

Step 5 — Add OAuth redirect URI

In Google Cloud Console → APIs & Services → Credentials → your OAuth client → Authorized redirect URIs, add:

Production redirect
https://hardware-pos.vercel.app/api/auth/callback/google

Step 6 — Deploy + smoke test

Hit Deploy. Wait ~2 min. Visit the URL and run through the full flow:

  • Sign up + verify welcome email
  • Add 5 products in /inventory
  • Make a real sale via /pos with Mobile Money payment
  • Download the receipt PDF
  • Verify the dashboard updated
  • Toggle dark mode on a phone

Step 7 — Custom domain (optional)

  1. Buy a domain on Cloudflare Registrar (or your provider)
  2. Vercel → Settings → Domains → add your domain
  3. Cloudflare DNS → add the records Vercel shows (set to DNS only, grey cloud, not orange)
  4. Update BETTER_AUTH_URL and NEXT_PUBLIC_APP_URL to the custom domain
  5. Add the new redirect URI in Google Cloud Console
  6. Redeploy

You shipped it.

That's a real POS — auth, transactions, atomic stock decrements, downloadable receipts, audited for security, deployed to a custom domain. A hardware shop owner could actually use this.

Share what you built in the community — and tag it with #shipped-with-vibekit.

WHAT'S NEXT

Take it further.

The patterns you just learned scale to anything. Some natural next steps for HardwarePOS or your next build:

  • Add real Mobile Money

    Install JB DGateway Shop and wire actual MoMo settlement to the sale flow. ~45 min.

  • Multi-cashier support

    Add a 'cashier' role + sale.cashierId so you can see who rang up which sales. ~30 min.

  • Barcode scanner input

    Hook a USB scanner into the SKU search — it's just keyboard input. ~15 min.

  • Stock-in / restock flow

    Track inventory deliveries with a separate StockMovement model. ~45 min.

  • Daily Z-report (end of day)

    Closing report with sales by payment method + cash drawer reconciliation. ~30 min.

  • Build something else

    Restart from Module 02 with a new app idea. The flow is fully repeatable.