39294-vm/06_AGENT_PROMPTS.md
2026-03-24 15:28:07 +00:00

28 KiB
Raw Blame History

Agent Prompts — Swish Auto Care GMS

All Prompts for Claude Opus 4 in Claude Code (Antigravity)

How to use this file: Copy each prompt exactly as written into Claude Code, one phase at a time. Wait for the phase to complete and be verified before moving to the next prompt. All context files should be in the same project folder so the agent can reference them.


INITIAL SETUP PROMPT (Run This First — Before Any Phase)

You are building the Swish Auto Care Garage Management System (GMS) from scratch. 

Before you write any code, read these context files in this exact order:
1. 00_PROJECT_OVERVIEW.md — master context and what you're building
2. 01_DATABASE_SCHEMA.md — all MySQL tables and relationships
3. 02_API_REFERENCE.md — all backend API routes
4. 03_FRONTEND_PAGES.md — all frontend pages and their behavior
5. 04_BUSINESS_LOGIC.md — rules, calculations, and validations
6. 05_IMPLEMENTATION_PLAN.md — the build order and phases

After reading all 6 files, confirm you understand the full system by giving me:
- A one-paragraph summary of what Swish Auto Care GMS does
- The tech stack you will use (exact packages)
- The 10 modules you will build (M1M10)
- Confirmation that you understand the 6-phase build order

Do NOT write any code yet. Just confirm your understanding.

PHASE 1 PROMPT — Foundation

You are building the Swish Auto Care GMS. Read 00_PROJECT_OVERVIEW.md, 01_DATABASE_SCHEMA.md, 02_API_REFERENCE.md, and 04_BUSINESS_LOGIC.md before starting.

Build Phase 1 — Foundation. Do all of these tasks in order:

BACKEND:
1. Create the folder structure: swish-gms/backend/src/config/, middleware/, routes/
2. Initialize npm in backend/ and install: express mysql2 jsonwebtoken bcryptjs dotenv cors
3. Install dev dependency: nodemon
4. Create backend/.env with:
   PORT=5000, DB_HOST=localhost, DB_USER=root, DB_PASS=root, DB_NAME=swish_gms, JWT_SECRET=swishgms_jwt_secret_2026_local
5. Create backend/src/config/db.js — MySQL connection pool using mysql2/promise with promise wrapper
6. Create backend/src/config/schema.sql — complete SQL with all 8 tables (from 01_DATABASE_SCHEMA.md). Include CREATE DATABASE IF NOT EXISTS.
7. Create backend/src/config/seed.js — a runnable Node.js script that:
   a. Hashes the password 'swish@2024' using bcryptjs
   b. Inserts admin user (username: admin)
   c. Inserts 4 sample staff members (from seed data in 01_DATABASE_SCHEMA.md)
   d. Inserts 5 sample parts (from seed data in 01_DATABASE_SCHEMA.md)
   e. Prints "Seed complete" when done
8. Create backend/src/middleware/auth.js — JWT verify middleware (pattern in 04_BUSINESS_LOGIC.md)
9. Create backend/src/routes/auth.js — POST /login (validate, return JWT + user) and GET /me (protected)
10. Create backend/src/server.js — Express app with CORS (origin: http://localhost:5173), JSON body parser, /api/auth route mounted
11. Add scripts to package.json: "dev": "nodemon src/server.js", "seed": "node src/config/seed.js"

FRONTEND:
12. Create frontend/ using: npm create vite@latest frontend -- --template react-ts
13. Install: react-router-dom axios
14. Create frontend/src/api/axios.ts — Axios instance (baseURL: http://localhost:5000/api) with request interceptor for JWT and response interceptor for 401 auto-logout (pattern in 03_FRONTEND_PAGES.md)
15. Create frontend/src/context/AuthContext.tsx — AuthContext with user, token, login(), logout(), isAuthenticated (store token in localStorage key 'gms_token')
16. Create frontend/src/pages/Login.tsx — full login form page (centered card, username + password fields, submit calls POST /api/auth/login, stores JWT, redirects to /dashboard)
17. Create frontend/src/components/Layout/Sidebar.tsx — sidebar with all 12 nav links listed in 03_FRONTEND_PAGES.md
18. Create frontend/src/components/Layout/TopBar.tsx — shows "Swish Auto Care GMS", current date in DD/MM/YYYY, "Admin" label, Logout button
19. Create frontend/src/components/Layout/Layout.tsx — wrapper that renders Sidebar + TopBar + main content area
20. Create placeholder page files (just return <div>PageName Page</div>) for: Dashboard, JobCards, JobCardNew, StatusBoard, Staff, Attendance, Salary, Parts, PartsSales, CashLedger, Accounts, DailyReport, Exports
21. Create frontend/src/App.tsx — React Router setup with: /login (public), all other routes wrapped in ProtectedRoute (redirects to /login if not authenticated), / redirects to /dashboard
22. Verify frontend/src/main.tsx wraps App in AuthContext provider

TESTING INSTRUCTIONS I WILL RUN:
- Terminal 1: cd backend && npm run dev → should print "Server running on port 5000"
- MySQL: Run schema.sql, then npm run seed → "Seed complete"
- Test login: curl -X POST http://localhost:5000/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"swish@2024"}' → should return token
- Terminal 2: cd frontend && npm run dev → open http://localhost:5173
- Login page should show → login should work → sidebar should appear

Do not move on to Phase 2 tasks. Only deliver Phase 1.

PHASE 2 PROMPT — Job Cards & Status Board

Phase 1 is complete and working. Now build Phase 2 — Job Cards & Status Board.

Read 02_API_REFERENCE.md (Job Card Routes section) and 03_FRONTEND_PAGES.md (Pages 2-5) and 04_BUSINESS_LOGIC.md (Section 1) before starting.

BACKEND:
1. Create backend/src/routes/jobCards.js with these routes (all protected by auth middleware):
   - GET /api/job-cards — list with filters: status, date (YYYY-MM-DD), reg_no, page, limit. Join with staff table to get assigned_staff_name. Default: today's jobs.
   - POST /api/job-cards — create new job card. Auto-generate job_no using the SAC-YYYYMMDD-SEQ format (see 04_BUSINESS_LOGIC.md Section 1). Validate required fields based on job_type.
   - GET /api/job-cards/:id — single job card with staff name
   - PUT /api/job-cards/:id — update fields only if status = 'active'
   - POST /api/job-cards/:id/close — mark done: require final_amount > 0 and payment_mode, set status='done', closed_at=NOW(), reject if already done

2. Create backend/src/routes/dashboard.js (protected):
   - GET /api/dashboard/today — return: active_jobs (count where status='active' and DATE(job_date)=today), completed_jobs (count where status='done' and DATE(closed_at)=today), today_revenue (SUM of final_amount where status='done' and DATE(closed_at)=today), cash_balance (set to 0 for now — will add later), staff_present (set to 0 for now), date (formatted DD/MM/YYYY)

3. Mount both routes in server.js

FRONTEND:
4. Create frontend/src/components/shared/Badge.tsx — takes status prop ('active'|'done'|'full'|'wash'|'in'|'out'), returns colored pill span. Colors: active=amber, done=green, full=blue, wash=teal, in=green, out=red.

5. Create frontend/src/components/shared/Modal.tsx — overlay modal with title, close button (X), and children slot. Click outside to close.

6. Build frontend/src/pages/Dashboard.tsx:
   - Calls GET /api/dashboard/today on load
   - Shows 6 widget cards: Active Jobs, Completed Jobs, Today's Revenue (₹ format), Cash Balance (₹ format), Staff Present, Quick Actions
   - Quick actions card has 3 buttons: "New Job Card" (→ /job-cards/new), "Mark Attendance" (→ /attendance), "Daily Report" (→ /daily-report)
   - Show loading skeleton while fetching

7. Build frontend/src/pages/JobCards.tsx:
   - Calls GET /api/job-cards on load and on filter change
   - Search bar for reg_no (debounced 500ms)
   - Status dropdown filter (All / Active / Done)
   - Date picker (default today)
   - Table with columns: Job No, Type (Badge), Reg No, Car, Owner, Service, Staff, Amount (show final if done, estimated if active), Status (Badge), Date, Actions
   - Actions: View icon (expand row or simple alert for now), Edit icon (only if active — opens edit modal), Close icon (only if active — opens Close Job modal)
   - Close Job modal: Final Amount input (₹), Payment Mode dropdown (Cash/UPI/Card), "Mark as Done" button. On submit: POST /api/job-cards/:id/close, refresh list, show success toast
   - "+ New Job Card" button top right → navigate to /job-cards/new

8. Build frontend/src/pages/JobCardNew.tsx:
   - Toggle at top: "Full Service Job" | "Quick Wash Job" — switches which form renders
   - Full job form fields (all from 03_FRONTEND_PAGES.md Page 4): reg_no*, car_name*, owner_name*, mobile_no*, service_type* (dropdown with options from PRD), assigned_staff_id* (dropdown — fetch from GET /api/staff?is_active=1), estimated_amount, notes
   - Quick wash form fields: reg_no*, car_name*, mobile_no (optional), service_type* (Basic Wash/Premium Wash/Interior Clean), assigned_staff_id*, estimated_amount*
   - On submit: POST /api/job-cards, show success toast with job_no, navigate to /job-cards
   - Cancel button → navigate to /job-cards

9. Build frontend/src/pages/StatusBoard.tsx:
   - Two columns side by side: ACTIVE (amber header) | DONE (green header)
   - Fetch GET /api/job-cards with no date filter and show all active + today's done
   - Each card shows: job_no, reg_no — car_name, service_type | assigned_staff_name, amount, time
   - Active cards have "Mark Done" button → same Close Job modal as JobCards.tsx
   - Card counts in column headers: "ACTIVE (4)" | "DONE (7)"

10. Create simple toast notification system (can be a simple fixed-bottom-right div with auto-dismiss):
    frontend/src/components/shared/Toast.tsx

TESTING I WILL RUN:
- Create a Full Job card, verify job_no is SAC-[today]-001
- Create a Quick Wash job card
- See both in job cards list
- Mark one as done, verify status changes to Done with final_amount
- Dashboard shows updated counts
- Status board shows Active and Done columns

PHASE 3 PROMPT — Staff, Attendance & Salary

Phase 2 is complete. Build Phase 3 — Staff Management, Attendance, and Salary.

Read 02_API_REFERENCE.md (Staff, Attendance, Salary sections) and 03_FRONTEND_PAGES.md (Pages 6-8) and 04_BUSINESS_LOGIC.md (Sections 2-4).

BACKEND:
1. Create backend/src/routes/staff.js (all protected):
   - GET /api/staff — list all staff, filter by is_active query param
   - POST /api/staff — add staff, auto-generate staff_code (pattern in 04_BUSINESS_LOGIC.md Section 2)
   - PUT /api/staff/:id — update staff details
   - PATCH /api/staff/:id/toggle — flip is_active (1→0 or 0→1)

2. Create backend/src/routes/attendance.js (all protected):
   - GET /api/attendance?date=YYYY-MM-DD — return all active staff with their attendance status for the date (LEFT JOIN attendance ON staff_id and date). Null status if not marked.
   - POST /api/attendance/bulk — save array of {staff_id, status} for a given date. Use INSERT ... ON DUPLICATE KEY UPDATE (upsert). See 04_BUSINESS_LOGIC.md Section 3.
   - GET /api/attendance/summary/:staffId?month=3&year=2026 — count present/absent/half for the month, return with day-by-day records

3. Create backend/src/routes/salary.js (all protected):
   - GET /api/salary — list payments, filter by staff_id and/or payment_month
   - POST /api/salary — create payment record (all fields from schema)
   - GET /api/salary/calculate/:staffId?month=3&year=2026 — compute salary using formula: (monthly_salary / 26) × effectiveDays where effectiveDays = present + (half × 0.5). See 04_BUSINESS_LOGIC.md Section 4.

4. Update dashboard route: update staff_present to query COUNT from attendance where attendance_date = today AND status = 'present'

5. Mount all routes in server.js

FRONTEND:
6. Build frontend/src/pages/Staff.tsx:
   - Table: Staff Code, Name, Role, Mobile, Joining Date, Salary (₹ format), Status (Active/Inactive toggle), Actions (Edit)
   - "+ Add Staff" button → opens Add Staff modal
   - Search by name (filter on frontend)
   - Add/Edit Staff modal fields: Full Name*, Role*, Mobile No., Date of Joining, Monthly Salary ₹*, Active toggle
   - Toggle active: calls PATCH /api/staff/:id/toggle, refreshes list

7. Build frontend/src/pages/Attendance.tsx:
   - Date picker at top (default today, formatted DD/MM/YYYY)
   - On date change: fetch GET /api/attendance?date=YYYY-MM-DD
   - Attendance grid: each row = staff member with 3 radio buttons (Present / Absent / Half Day)
   - Pre-fill radio from fetched status (null = nothing selected yet)
   - "Save Attendance" button → POST /api/attendance/bulk with all rows
   - Show success toast "Attendance saved for DD/MM/YYYY"
   - Below table: clickable "View Monthly Summary" per staff → modal showing month grid and counts

8. Build frontend/src/pages/Salary.tsx — two sections:

   Section A (New Payment form, top):
   - Select Staff * (dropdown, active staff)
   - Payment Month * (text input e.g. "March 2026")
   - "Calculate" button → calls GET /api/salary/calculate/:id?month=&year= → fills Days Present and Calculated Salary (read-only display)
   - Payment Amount ₹ * (pre-filled from calculated, editable override)
   - Payment Type * (Full Salary / Advance / Bonus / Deduction)
   - Payment Mode * (Cash / Bank / UPI)
   - Notes (optional)
   - "Record Payment" button → POST /api/salary, show toast, reset form

   Section B (History table, below):
   - Filter by Staff (dropdown) and Month (text)
   - Table: Date | Staff | Month | Type | Mode | Amount | Notes

TESTING I WILL RUN:
- Add a new staff member, verify staff_code auto-generates
- Mark today's attendance for all staff, save, reload — verify it persists
- Calculate salary for a staff member (March 2026), verify formula: monthly_salary/26 × days
- Record a salary payment, verify it appears in history
- Dashboard staff_present count updates

PHASE 4 PROMPT — Parts, Sales & Cash Ledger

Phase 3 is complete. Build Phase 4 — Parts Inventory, Parts Sales POS, and Cash Ledger.

Read 02_API_REFERENCE.md (Parts, Parts Sales, Cash Ledger sections) and 03_FRONTEND_PAGES.md (Pages 9-11) and 04_BUSINESS_LOGIC.md (Sections 5-6).

BACKEND:
1. Create backend/src/routes/parts.js (all protected):
   - GET /api/parts — list all parts. Include is_low flag (stock_qty <= low_stock_alert). Filter: ?category=&low_stock=true
   - POST /api/parts — add part, auto-generate part_code (pattern in 04_BUSINESS_LOGIC.md Section 5)
   - PUT /api/parts/:id — update part details
   - PATCH /api/parts/:id/stock — manual stock adjustment: UPDATE parts SET stock_qty = stock_qty + ? WHERE id = ?

2. Create backend/src/routes/partsSales.js (all protected):
   - GET /api/parts-sales — list sales, join with parts for name. Filter by date.
   - POST /api/parts-sales — CRITICAL: 
     a. Validate quantity > 0
     b. Run: UPDATE parts SET stock_qty = stock_qty - ? WHERE id = ? AND stock_qty >= ?
     c. Check affectedRows — if 0, return 400 "Insufficient stock"
     d. If stock deducted, insert into parts_sales
     e. Return sale record with part name

3. Create backend/src/routes/cashLedger.js (all protected):
   - GET /api/cash-ledger — list entries. Filter by from/to date and type.
   - POST /api/cash-ledger — create entry. Validate: description is non-empty after trim, amount > 0, entry_type is 'in' or 'out'.

4. Update dashboard route: update today_revenue to include BOTH job revenue AND parts revenue:
   SELECT (job_revenue + parts_revenue) as today_revenue where both are summed for today

5. Mount all routes in server.js

FRONTEND:
6. Build frontend/src/pages/Parts.tsx:
   - Table: Part Code, Name, Category, Unit, Buy Price (₹), Sell Price (₹), Stock Qty, Low Stock (red badge if is_low), Actions
   - "+ Add Part" button → opens Add Part modal
   - Filter by Category dropdown, "Show Low Stock Only" toggle
   - Search by name
   - Restock modal: Adjustment quantity (positive integer), confirm button → calls PATCH /api/parts/:id/stock
   - Add/Edit Part modal: all fields from parts table

7. Build frontend/src/pages/PartsSales.tsx:
   - Date filter (default today)
   - Sales table: Date, Part Name, Qty, Unit Price (₹), Total (₹), Customer, Payment Mode, Job Card (if linked)
   - "+ Record Sale" button → New Sale modal:
     a. Select Part* (searchable dropdown — shows "Ceramic Coat 9H (Stock: 15)")
     b. Link to Job Card? (optional dropdown — show recent active + done job cards)
     c. Quantity * (number input — on blur, validate against available stock shown)
     d. Unit Price ₹ (auto-fills from part.selling_price, editable)
     e. Total Amount ₹ (auto-calculated = qty × unit_price, read-only)
     f. Customer Name (optional)
     g. Payment Mode * (Cash / UPI / Card)
     h. "Record Sale" button → POST /api/parts-sales. If 400 insufficient stock, show error in modal. On success: toast, close modal, refresh table.

8. Build frontend/src/pages/CashLedger.tsx:
   - Date range filter (from/to, default today to today)
   - Ledger table: Date, Type (IN/OUT Badge), Category, Description, Amount (₹)
   - Two buttons top right: "+ Cash In" and "+ Cash Out"
   - Both open same modal (pre-selects type based on which button):
     a. Entry Type (pre-filled, not editable)
     b. Amount ₹ *
     c. Category * (dropdown: Utilities, Supplies, Advance, Refund, Other)
     d. Description * (mandatory text)
     e. Date & Time (auto-filled with now, editable)
     f. "Save Entry" button

TESTING I WILL RUN:
- Add a new part, verify part_code auto-generates
- Record a parts sale: select part, quantity 3, verify stock decreases by 3
- Try to sell more than available stock — verify error message shows
- Enter a Cash In entry, verify it appears in table
- Enter a Cash Out entry (utility bill), verify it appears
- Dashboard today_revenue now includes parts sales

PHASE 5 PROMPT — Accounts, Reports & Exports

Phase 4 is complete. Build Phase 5 — Accounts, Daily Report, and Excel Exports.

Read 02_API_REFERENCE.md (Accounts, Reports, Exports sections), 03_FRONTEND_PAGES.md (Pages 12-14), and 04_BUSINESS_LOGIC.md (Sections 7-9).

BACKEND:
1. Install SheetJS: npm install xlsx (in backend/)

2. Create backend/src/utils/excel.js — helper function createExcelResponse(res, filename, sheetsData) that:
   - Takes sheetsData as array of {sheetName, data (array of objects)}
   - Creates XLSX workbook with XLSX.utils.book_new()
   - For each sheet: XLSX.utils.json_to_sheet(data) → book_append_sheet
   - Writes buffer: XLSX.write(wb, { type: 'buffer', bookType: 'xlsx' })
   - Sets Content-Type and Content-Disposition headers
   - Sends buffer response

3. Create backend/src/routes/accounts.js (protected):
   - GET /api/accounts/summary?from=YYYY-MM-DD&to=YYYY-MM-DD (default: today to today):
     Run 5 separate SQL queries (see 04_BUSINESS_LOGIC.md Section 7) for:
     job_revenue, parts_revenue, cash_in_other, staff_payments, cash_out_other
     Return structured JSON with income object, expense object, net_balance
   - GET /api/accounts/transactions?from=&to= — unified list of all transactions:
     UNION of completed jobs (type:'job'), parts sales (type:'parts'), cash_in (type:'cash_in'), cash_out (type:'cash_out'), salary payments (type:'salary')
     Each row: date, description, amount, type, reference (job_no or part_code etc.)
     ORDER BY date DESC

4. Create backend/src/routes/reports.js (protected):
   - GET /api/reports/daily?date=YYYY-MM-DD — return JSON with all 6 sections of the daily report data
   - GET /api/reports/daily/download?date=YYYY-MM-DD — generate and stream Excel file:
     Use createExcelResponse with 6 sheets per 04_BUSINESS_LOGIC.md Section 8
     Filename format: SwishGMS_DailyReport_DD-MM-YYYY.xlsx

5. Create backend/src/routes/exports.js (protected):
   - GET /api/exports/job-cards?from=&to= — all job cards as xlsx (join staff name)
     Columns: Job No, Type, Reg No, Car Name, Owner, Mobile, Service, Staff, Estimated ₹, Final ₹, Payment Mode, Status, Job Date, Closed At
   - GET /api/exports/staff-attendance?month=&year= — two sheets:
     Sheet 1: Staff Master (all staff columns)
     Sheet 2: Attendance (staff_name, date, status) for the given month
   - GET /api/exports/parts-inventory — all parts as xlsx
     Columns: Part Code, Name, Category, Unit, Buy Price, Sell Price, Stock Qty, Low Stock Alert
   - GET /api/exports/accounts?from=&to= — accounts ledger as xlsx
     Same columns as accounts/transactions response, formatted nicely

6. Update dashboard route: update cash_balance to sum all cash flows for today:
   cash_balance = job_revenue + parts_revenue + cash_in_other - staff_payments - cash_out_other

7. Mount all routes in server.js

FRONTEND:
8. Build frontend/src/pages/Accounts.tsx:
   - Date range filter at top with presets: "Today" | "This Week" | "This Month" | "Custom"
   - 3 summary cards: Total Income (₹, green) | Total Expense (₹, red) | Net Balance (₹, blue)
   - Two breakdown tables side by side:
     Income: Job Revenue | Parts Sales | Cash In (Other) | Total
     Expenses: Staff Payments | Cash Out (Other) | Total
   - "All Transactions" tab below showing unified list from /api/accounts/transactions
     Table: Date, Type (badge), Description, Amount (₹), Reference

9. Build frontend/src/pages/DailyReport.tsx:
   - Date picker (default today)
   - On date change: fetch GET /api/reports/daily?date=YYYY-MM-DD
   - Render on-screen preview:
     a. Header card: "Swish Auto Care — Daily Report" | date | Total Income | Total Expense | Net Balance
     b. Section tables: Completed Jobs, Parts Sales, Cash In, Cash Out, Staff Payments
     c. Day Totals row at bottom
   - "Download Excel" button (primary, prominent):
     Calls downloadExcel() helper (see 03_FRONTEND_PAGES.md Excel Download Pattern) with /api/reports/daily/download?date= and filename SwishGMS_DailyReport_DD-MM-YYYY.xlsx

10. Build frontend/src/pages/Exports.tsx:
    - 4 export cards in a 2×2 grid
    - Card 1 — Job Cards: From Date + To Date pickers + "Download xlsx" button
    - Card 2 — Staff & Attendance: Month selector (1-12) + Year (2026) + "Download xlsx" button
    - Card 3 — Parts Inventory: Just a "Download xlsx" button (no date filter needed)
    - Card 4 — Accounts Ledger: From Date + To Date pickers + "Download xlsx" button
    - Each download button uses the downloadExcel() helper with responseType: 'blob' and triggers browser file save
    - Show loading state on button while downloading (spinner, disable button)

11. Create frontend/src/utils/download.ts with the downloadExcel helper function:
    ```ts
    export async function downloadExcel(api: AxiosInstance, url: string, filename: string, params?: object) {
      const response = await api.get(url, { params, responseType: 'blob' });
      const blob = new Blob([response.data], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
      });
      const link = document.createElement('a');
      link.href = URL.createObjectURL(blob);
      link.download = filename;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
      URL.revokeObjectURL(link.href);
    }
    ```

TESTING I WILL RUN:
- Accounts page loads with today's summary (income, expense, balance)
- Change date range to "This Month" — totals update
- Daily Report page shows all sections for today
- Download daily report — verify it opens in Excel with correct data
- All 4 Export buttons produce downloadable .xlsx files with correct data
- Dashboard cash_balance now shows a real number

PHASE 6 PROMPT — Polish, Seed Data & Final Testing

Phase 5 is complete. Build Phase 6 — Final Polish, Seed Data, and Complete the Demo.

SEED DATA (create backend/src/config/fullSeed.js):
Create a comprehensive seed that inserts:
1. Admin user (username: admin, password: swish@2024, bcrypt hashed)
2. 4 staff members (already seeded in Phase 1, skip if exists)
3. 5 parts (already seeded, skip if exists)
4. 8 job cards across the last 7 days (mix of full and wash, some active some done):
   - 3 active job cards (today)
   - 5 done job cards (last 7 days, with final_amount and payment_mode)
5. Attendance for all 4 staff for the last 14 days (random mix of present/absent/half)
6. 2 salary payments (one salary, one advance)
7. 10 parts sales entries spread over last 7 days (various parts, quantities)
8. 12 cash ledger entries (mix of in/out, various categories)
Run this with: npm run fullseed (add to package.json)

UI POLISH tasks:
1. Add loading skeleton to all data tables (show 5 gray placeholder rows while fetching)
2. Add empty state components: when table has no data, show icon + message + action button
   Example: Job Cards empty → "No job cards yet" + "Create First Job Card" button
3. Add confirmation dialog before "Mark as Done" — "Are you sure? This cannot be undone."
4. Add toast notifications to ALL create/update actions that don't already have them:
   - Staff add/edit: "Staff added successfully"
   - Attendance save: "Attendance saved for DD/MM/YYYY"
   - Salary payment: "Payment of ₹X recorded for [Staff Name]"
   - Part add: "Part added to inventory"
   - Restock: "Stock updated for [Part Name]"
   - Cash entry: "Cash [In/Out] entry saved"
5. Fix all currency displays to use ₹ with Indian comma formatting (en-IN locale)
6. Fix all date displays to use DD/MM/YYYY format
7. Add active nav item highlight in Sidebar (bold + background for current route)
8. Make sure forms clear/reset after successful submission
9. Add "Required field" validation error messages below fields on submit with empty required fields
10. In Job Cards table, make Reg No uppercase on input

FINAL VERIFICATION — Run through all 10 Acceptance Criteria:
AC-01: Login with admin/swish@2024 → dashboard loads ✓
AC-02: Create Full job card + Quick Wash job card ✓
AC-03: Job shows as Active, mark Done with amount+payment ✓
AC-04: Mark attendance for all staff, save, reload ✓
AC-05: Log salary payment, view in history ✓
AC-06: Record parts sale, stock decreases ✓
AC-07: Cash in and cash out entries ✓
AC-08: Accounts shows today's income/expense/balance ✓
AC-09: Download daily report as Excel ✓
AC-10: All 4 export buttons produce Excel files ✓

Report any AC that fails and fix it.

Final output should be the complete running app with:
- Backend on http://localhost:5000
- Frontend on http://localhost:5173
- Login: admin / swish@2024
- All 10 ACs passing
- Realistic demo data preloaded

TROUBLESHOOTING PROMPTS

Use these if specific things break:

If MySQL connection fails:

The MySQL connection is failing. Debug this:
1. Check backend/.env has correct DB_USER, DB_PASS, DB_NAME
2. Verify MySQL is running: mysql -u root -p
3. Verify database exists: SHOW DATABASES; (should show swish_gms)
4. Check backend/src/config/db.js uses mysql2/promise createPool correctly
5. Test the pool with a simple query: SELECT 1 as test
Show me the exact error and fix it.

If CORS error in browser:

There's a CORS error in the browser console. Fix it in backend/src/server.js:
app.use(cors({
  origin: 'http://localhost:5173',
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));
Make sure cors() is called BEFORE any route definitions.

If Excel download doesn't work:

The Excel download is not working. Check:
1. Frontend axios call uses responseType: 'blob'
2. Backend sets correct Content-Type header: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
3. Backend sets Content-Disposition: attachment; filename="..."
4. XLSX.write uses { type: 'buffer', bookType: 'xlsx' }
5. res.send(buffer) not res.json(buffer)
Show me the current code and fix it.

If JWT auth stops working:

JWT authentication is broken — getting 401 on all protected routes. Debug:
1. Check frontend axios.ts request interceptor attaches 'Bearer <token>' header
2. Check localStorage has the key 'gms_token' (open DevTools → Application → Local Storage)
3. Check backend auth.js extracts token with: authHeader.split(' ')[1]
4. Check JWT_SECRET in .env matches what was used to sign the token
5. Log the token on backend: console.log('Token:', token) and verify it's not undefined

If stock deduction race condition:

Parts stock is going negative. Fix the stock deduction in partsSales route:
Use atomic UPDATE with stock check:
const [result] = await db.query(
  'UPDATE parts SET stock_qty = stock_qty - ? WHERE id = ? AND stock_qty >= ?',
  [quantity, part_id, quantity]
);
if (result.affectedRows === 0) {
  return res.status(400).json({ error: 'Insufficient stock' });
}
// Only insert sale AFTER successful stock deduction