Imported from thanawat-c/SmashHub (
AGENTS.md). Install upstream withnpx skills add thanawat-c/SmashHub. Copyright stays with the author.
AGENTS.md - Project Rules & Architecture Guide
1. Project Overview
Project Name: SmashHub (ระบบจองสนามแบดมินตันผ่าน LINE LIFF พร้อมมินิสโตร์และระบบตรวจสลิปอัตโนมัติ) Goal: Production-grade portfolio project demonstrating atomic transactions, concurrency control, automated payment slip verification, and real-time POS backoffice management.
2. Tech Stack & Directory Structure
Use a clean Monorepo structure:
/docker-compose.yml: PostgreSQL 16 service/backend: Go (Golang) + Gin Framework + GORM + PostgreSQL/cmd/server/main.go: Entry point/internal/models: Database structs & enums/internal/handlers: HTTP REST & SSE handlers/internal/services: Business logic, DB transactions, slip verifier, cron worker/migrations: SQL migration & seed files
/frontend: Vue 3 (Composition API<script setup>) + Vite + Pinia + Vue Router + Tailwind CSS + Element Plus/src/views/liff: Mobile-first customer storefront (/liff)/src/views/admin: Desktop store backoffice & POS (/admin)/src/views/demo: Split-screen interactive portfolio showcase (/demo)/src/stores: Pinia state stores
3. Non-Negotiable Engineering Rules
- Prevent Double Booking (Database Level):
- Table
booking_courtsMUST enforce a Partial Unique Index:CREATE UNIQUE INDEX idx_unique_active_court_slot ON booking_courts (court_id, play_date, start_hour) WHERE is_slot_locked = TRUE; - When a booking becomes
EXPIREDorCANCELLED, updateis_slot_locked = FALSEso the court slot can be booked again.
- Table
- Atomic Booking & Stock Deduction:
- Creating a booking (
POST /api/v1/bookings) MUST run inside a single database transaction (db.Transaction). - Lock product rows using
SELECT ... FOR UPDATE, verifystock_qty >= requested_qty, deduct stock, and lock court slots atomically. - Set
expires_at = NOW() + 10 minutesforPENDING_PAYMENTbookings.
- Creating a booking (
- 4-Step Slip Verification & Portfolio Mock Mode:
- Endpoint
POST /api/v1/bookings/:id/verify-slipmust supportmock_scenariopayload for recruiter testing:MOCK_VALID: Passes all checks -> booking status becomesCONFIRMED.MOCK_DUPLICATE: Fails step 1 (duplicatetrans_refinpayment_slips) ->REJECTED_DUPLICATE.MOCK_UNDERPAID: Fails step 3 (amount < net_total) ->REJECTED_AMOUNT_MISMATCH.MOCK_API_DOWN: External verifier timeout -> booking status becomesMANUAL_REVIEWand slip becomesAPI_ERROR_PENDING_ADMIN.
- Endpoint
- Server-Side Calculation Only:
- Never trust price totals sent from Frontend. Always recalculate
court_total,item_total, andnet_totalon the Backend using database prices.
- Never trust price totals sent from Frontend. Always recalculate
- Real-Time Sync:
- Broadcast booking/slip state changes via Server-Sent Events (
GET /api/v1/events/stream) so the/adminand/demoviews update immediately without page refresh.
- Broadcast booking/slip state changes via Server-Sent Events (
4. Agent Workflow Instructions (IMPORTANT)
- Work Phase-by-Phase: Only implement the phase explicitly requested by the user. Do NOT jump ahead to future phases.
- Verify via Terminal: After writing code in any phase, run the build/tests or
curlcommands in the terminal to verify there are no syntax or runtime errors before finishing the turn. - Maintain
PROGRESS.md: At the end of each phase, update/PROGRESS.mdwith completed features, database tables, and exact API endpoint paths/payloads so the next phase stays 100% aligned.
