docs
This commit is contained in:
@@ -101,6 +101,121 @@ npm run dev # Development server
|
||||
|
||||
SabreDAV is bundled with PHP‑FPM and Composer. The Docker image installs dependencies automatically during the container start‑up.
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Test Infrastructure
|
||||
|
||||
Crussell has a comprehensive Go testing infrastructure located in `backend/testutils/`:
|
||||
|
||||
| Component | File | Description |
|
||||
|-----------|------|-------------|
|
||||
| **Database** | `testutils/testdb/testdb.go` | PostgreSQL test pool, migrations, table truncation |
|
||||
| **HTTP Helpers** | `testutils/helpers.go` | Request builders, auth helpers, assertions |
|
||||
| **JWT** | `testutils/jwt/jwt.go` | Test token generation for users/admins |
|
||||
| **HTTP Client** | `testutils/httptest/client.go` | REST client wrapper with auth support |
|
||||
| **Fixtures** | `testutils/fixtures/fixtures.go` | Factory functions for test data |
|
||||
| **Validators** | `internal/validators/validators.go` | ID validation utilities |
|
||||
|
||||
### Test Files
|
||||
|
||||
The project includes 16 test files covering all major handlers:
|
||||
|
||||
```
|
||||
backend/
|
||||
├── bookings.test # Main booking integration tests
|
||||
├── portfolio.test # Portfolio system tests
|
||||
├── handlers/
|
||||
│ ├── admin/
|
||||
│ │ ├── bookings_test.go # Admin booking management
|
||||
│ │ ├── today_test.go # Today's view
|
||||
│ │ ├── users_test.go # User management
|
||||
│ │ └── services_test.go # Service CRUD
|
||||
│ ├── auth/
|
||||
│ │ └── auth_test.go # Authentication
|
||||
│ ├── bookings/
|
||||
│ │ └── bookings_test.go # User booking flow
|
||||
│ ├── portfolio/
|
||||
│ │ └── images_test.go # Image upload/management
|
||||
│ ├── scheduling/
|
||||
│ │ └── scheduling_test.go # Availability logic
|
||||
│ ├── services/
|
||||
│ │ └── services_test.go # Service eligibility
|
||||
│ ├── user/
|
||||
│ │ └── profile_test.go # User profile
|
||||
│ └── handlers_test.go # Common handler tests
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
|
||||
# Run all tests
|
||||
go test ./...
|
||||
|
||||
# Run with verbose output
|
||||
go test -v ./...
|
||||
|
||||
# Run specific test file
|
||||
go test -v ./handlers/bookings
|
||||
|
||||
# Run tests matching pattern
|
||||
go test -v -run "TestBooking" ./...
|
||||
```
|
||||
|
||||
### Test Database Setup
|
||||
|
||||
Tests use a dedicated PostgreSQL database. Set the connection string via:
|
||||
|
||||
```bash
|
||||
export TEST_DB_DSN="postgres://user:pass@localhost:5432/crussell_test?sslmode=disable"
|
||||
go test ./...
|
||||
```
|
||||
|
||||
Default DSN: `postgres://myuser:mypassword@localhost:5432/crussell_test?sslmode=disable`
|
||||
|
||||
### Test Utilities Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"crussell/testutils"
|
||||
"crussell/testutils/testdb"
|
||||
"crussell/testutils/fixtures"
|
||||
"crussell/testutils/jwt"
|
||||
)
|
||||
|
||||
func TestMyHandler(t *testing.T) {
|
||||
// Setup test database
|
||||
cleanup := testutils.SetupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create test data
|
||||
adminID, _ := fixtures.CreateTestAdminUser(db.DB)
|
||||
userID, _ := fixtures.CreateTestUser(db.DB)
|
||||
serviceID, _ := fixtures.CreateTestService(db.DB)
|
||||
|
||||
// Generate tokens
|
||||
adminToken := jwt.GenerateAdminToken()
|
||||
userToken := jwt.GenerateUserToken(userID)
|
||||
|
||||
// Make authenticated requests
|
||||
w := testutils.MakeAdminRequest(router, "GET", "/api/admin/bookings", nil, adminID)
|
||||
w := testutils.MakeUserRequest(router, "GET", "/api/bookings", nil, userID)
|
||||
|
||||
// Assert results
|
||||
testutils.AssertStatusCode(t, w, http.StatusOK)
|
||||
testutils.AssertJSONResponse(t, w, &response)
|
||||
}
|
||||
```
|
||||
|
||||
### Test Conventions
|
||||
|
||||
- All test files use `//go:build test` build tag
|
||||
- Database is migrated fresh per test run via `testdb.Migrate()`
|
||||
- Tables are truncated between tests via `testdb.TruncateTables()`
|
||||
- Test tokens use a fixed secret: `test-secret-key-for-testing-only`
|
||||
- Fixtures auto-generate unique emails to avoid conflicts
|
||||
|
||||
## 📂 Environment Variables
|
||||
|
||||
| Variable | Purpose | Example |
|
||||
@@ -176,8 +291,11 @@ docker compose exec backend sh
|
||||
| Image Metadata Stripping | ✅ | ❌ | EXIF/GPS stripped on upload via `imaging` library |
|
||||
| Profile Pictures | ✅ | ✅ | Upload to separate bucket, cropper, circular display, CalDAV sync |
|
||||
| Auto-Booking Status | ✅ | ✅ | Auto-transition: confirmed → in_progress → completed based on time |
|
||||
| Simplified Deposits | ✅ | ❌ | `deposits_required` INT on users table (3 default), reduces on payment |
|
||||
| Simplified Deposits | ✅ | ⚠️ | `deposits_required` INT on users table (3 default), 48h notice, reduces on payment |
|
||||
| Contact Page | ✅ | ✅ | Dynamic data from first admin user via `/api/contact` endpoint |
|
||||
| Email Verification | ✅ | ❌ | Verification codes, generate/check endpoints |
|
||||
| Calendar Export | ✅ | ⚠️ | ICS download endpoint, Add to Calendar button (backend complete) |
|
||||
| Loyalty Stamps | ✅ | ✅ | Backend complete, displayed in account page |
|
||||
|
||||
### ⚠️ Partially Complete
|
||||
|
||||
@@ -352,17 +470,18 @@ grep -rn "console\.log" frontend/src/ --include="*.svelte" --include="*.ts"
|
||||
|------|--------|
|
||||
| `account_role` | `user`, `admin` |
|
||||
| `account_type` | `standard`, `vip`, `guest` |
|
||||
| `booking_status` | `pending`, `confirmed`, `in_progress`, `completed`, `cancelled`, `no_show` |
|
||||
| `booking_status` | `pending`, `confirmed`, `in_progress`, `completed`, `client_cancelled`, `we_cancelled`, `re-schedule`, `no_show`, `no_deposit` |
|
||||
| `payment_type` | `deposit`, `full`, `refund` |
|
||||
| `payment_method` | `cash`, `card`, `bank_transfer`, `square` |
|
||||
| `payment_status` | `pending`, `completed`, `failed`, `refunded` |
|
||||
| `admin_notification_reason` | `pending_booking`, `cancelled_booking`, `rescheduled_booking`, `1_week_no_pay`, `1_month_no_pay`, `affiliate_claim` |
|
||||
| `admin_notification_reason` | `pending_booking`, `cancelled_booking`, `rescheduled_booking`, `1_week_no_pay`, `1_month_no_pay`, `affiliate_claim`, `late_cancellation`, `no_deposit`, `deposit_paid` |
|
||||
|
||||
### Key Tables
|
||||
|
||||
| Table | Purpose |
|
||||
|-------|---------|
|
||||
|-------|--------|
|
||||
| `users` | Customer and admin accounts |
|
||||
| `verification_codes` | Email verification and password reset codes |
|
||||
| `services` | Salon service catalog |
|
||||
| `bookings` | Appointment records |
|
||||
| `booking_services` | Services per booking (many-to-many) |
|
||||
|
||||
@@ -108,11 +108,10 @@
|
||||
- [x] Book (`/book`) - Full wizard with service selection, date/time, customer details
|
||||
- [x] Portfolio (`/portfolio`) - S3/R2 storage with tag filtering, category filters, pagination, ?img= featured image, admin upload
|
||||
- [x] Today (`/today`) - Admin only, real-time schedule view with auto-status transitions
|
||||
- [x] Schedule (`/schedule`) - User's upcoming bookings with .ics export
|
||||
- [x] Account (`/account`) - Profile management, profile picture upload with cropper
|
||||
- [x] Schedule (`/schedule`) - User's upcoming bookings with .ics export and calendar download button
|
||||
- [x] Account (`/account`) - Profile management, profile picture upload with cropper, loyalty stamps display
|
||||
- [x] Login (`/login`)
|
||||
- [x] Manage (`/manage`)
|
||||
- [x] Manage (`/manage`)
|
||||
|
||||
#### Admin Dashboard (`/admin`)
|
||||
- [x] Auth guard with role check
|
||||
@@ -171,6 +170,74 @@
|
||||
|
||||
---
|
||||
|
||||
## Testing Infrastructure
|
||||
|
||||
Crussell has a comprehensive Go testing infrastructure located in `backend/testutils/`:
|
||||
|
||||
### Test Utilities
|
||||
|
||||
| Component | File | Description |
|
||||
|-----------|------|-------------|
|
||||
| **Database** | `testutils/testdb/testdb.go` | PostgreSQL test pool, migrations, table truncation |
|
||||
| **HTTP Helpers** | `testutils/helpers.go` | Request builders, auth helpers, assertions |
|
||||
| **JWT** | `testutils/jwt/jwt.go` | Test token generation for users/admins |
|
||||
| **HTTP Client** | `testutils/httptest/client.go` | REST client wrapper with auth support |
|
||||
| **Fixtures** | `testutils/fixtures/fixtures.go` | Factory functions for test data (users, services, bookings) |
|
||||
| **Validators** | `internal/validators/validators.go` | ID validation utilities |
|
||||
|
||||
### Test Files
|
||||
|
||||
16 test files covering all major handlers:
|
||||
|
||||
```
|
||||
backend/
|
||||
├── bookings.test # Main booking integration tests
|
||||
├── portfolio.test # Portfolio system tests
|
||||
├── handlers/
|
||||
│ ├── admin/
|
||||
│ │ ├── bookings_test.go # Admin booking management
|
||||
│ │ ├── today_test.go # Today's view
|
||||
│ │ ├── users_test.go # User management
|
||||
│ │ └── services_test.go # Service CRUD
|
||||
│ ├── auth/
|
||||
│ │ └── auth_test.go # Authentication
|
||||
│ ├── bookings/
|
||||
│ │ └── bookings_test.go # User booking flow
|
||||
│ ├── portfolio/
|
||||
│ │ └── images_test.go # Image upload/management
|
||||
│ ├── scheduling/
|
||||
│ │ └── scheduling_test.go # Availability logic
|
||||
│ ├── services/
|
||||
│ │ └── services_test.go # Service eligibility
|
||||
│ ├── user/
|
||||
│ │ └── profile_test.go # User profile
|
||||
│ └── handlers_test.go # Common handler tests
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
go test ./...
|
||||
go test -v ./handlers/bookings
|
||||
go test -v -run "TestBooking" ./...
|
||||
```
|
||||
|
||||
### Test Database
|
||||
|
||||
- DSN: `postgres://myuser:mypassword@localhost:5432/crussell_test?sslmode=disable`
|
||||
- Override: `export TEST_DB_DSN="..."`
|
||||
- Uses `testdb.Migrate()` to run init-script.sql
|
||||
- Tables truncated between tests via `testdb.TruncateTables()`
|
||||
|
||||
### Conventions
|
||||
|
||||
- All test files use `//go:build test` build tag
|
||||
- Test tokens use fixed secret: `test-secret-key-for-testing-only`
|
||||
- Fixtures auto-generate unique emails to avoid conflicts
|
||||
|
||||
---
|
||||
|
||||
## Current Architecture
|
||||
|
||||
### Overview Diagram
|
||||
@@ -234,6 +301,9 @@ flowchart TD
|
||||
| GET | `/api/services/eligible-for/{user_id}` | List services filtered by user's age and patch test status (admin only) |
|
||||
| POST | `/api/register` | Create new user account |
|
||||
| POST | `/api/login` | Authenticate and receive JWT |
|
||||
| POST | `/api/verify/generate` | Generate email verification or password reset code |
|
||||
| POST | `/api/verify/check` | Verify code (email verification or password reset) |
|
||||
| GET | `/api/contact` | Get business contact info (from first admin user) |
|
||||
| GET | `/api/scheduling/default-hours` | Get weekly default hours |
|
||||
| GET | `/api/scheduling/exceptional-groups` | List holiday/special hour groups |
|
||||
| GET | `/api/scheduling/working-hours` | Get merged working hours for date range |
|
||||
@@ -245,11 +315,13 @@ flowchart TD
|
||||
|--------|------|-------------|
|
||||
| GET | `/api/user/profile` | Get current user profile |
|
||||
| PUT | `/api/user/profile` | Update profile |
|
||||
| POST | `/api/user/profile-picture` | Upload profile picture with cropper |
|
||||
| DELETE | `/api/user/account` | Delete account (GDPR) |
|
||||
| GET | `/api/user/loyalty` | Get loyalty stamp count |
|
||||
| GET | `/api/bookings` | List user's bookings |
|
||||
| POST | `/api/bookings` | Create booking |
|
||||
| GET | `/api/bookings/{id}` | Get specific booking |
|
||||
| GET | `/api/bookings/{id}/calendar` | Download ICS calendar file |
|
||||
| PUT | `/api/bookings/{id}` | Update booking |
|
||||
| DELETE | `/api/bookings/{id}` | Cancel booking |
|
||||
|
||||
@@ -310,11 +382,12 @@ flowchart TD
|
||||
```sql
|
||||
account_role: unverified_email | verified_email | admin | guest | affiliate
|
||||
account_type: email | google | microsoft | facebook | guest
|
||||
booking_status: pending | confirmed | in_progress | completed | client_cancelled | we_cancelled | re-schedule | no_show
|
||||
booking_status: pending | confirmed | in_progress | completed | client_cancelled | we_cancelled | re-schedule | no_show | no_deposit
|
||||
verification_purpose: email_verify | password_reset
|
||||
payment_type: deposit | full | tip | balance | partial
|
||||
payment_method: online_square | in_person_card | cash | giftcard | discount
|
||||
payment_status: pending | completed | failed | refunded
|
||||
admin_notification_reason: pending_booking | cancelled_booking | rescheduled_booking | 1_week_no_pay | 1_month_no_pay | affiliate_claim
|
||||
admin_notification_reason: pending_booking | cancelled_booking | rescheduled_booking | 1_week_no_pay | 1_month_no_pay | affiliate_claim | late_cancellation | no_deposit | deposit_paid
|
||||
```
|
||||
|
||||
**Suggested additional `admin_notification_reason` values:**
|
||||
@@ -333,6 +406,7 @@ admin_notification_reason: pending_booking | cancelled_booking | rescheduled_boo
|
||||
| Table | Purpose |
|
||||
|-------|---------|
|
||||
| `users` | User accounts with profile data |
|
||||
| `verification_codes` | Email verification and password reset codes |
|
||||
| `user_social_logins` | Social auth provider links |
|
||||
| `services` | Service offerings |
|
||||
| `user_service_patch_tests` | Patch test tracking |
|
||||
|
||||
Reference in New Issue
Block a user