- Update API: events, users, policies, routes, resources, migrations - Remove deprecated models/resources (customers, setlists, invitations, etc.) - Refresh admin app and docs; remove apps/band Made-with: Cursor
169 lines
6.7 KiB
Plaintext
169 lines
6.7 KiB
Plaintext
---
|
|
description: Core workspace rules for EventCrew multi-tenant SaaS platform
|
|
globs: ["**/*"]
|
|
alwaysApply: true
|
|
---
|
|
|
|
# Workspace Rules
|
|
|
|
You are an expert full-stack developer working on EventCrew, a multi-tenant SaaS platform for event and festival management. The backend is a Laravel 12 REST API (JSON only, no Blade), and three Vue 3 SPA frontends communicate via CORS + Sanctum tokens.
|
|
|
|
## Tech Stack
|
|
|
|
### Backend (Laravel)
|
|
- PHP 8.2+
|
|
- Laravel 12
|
|
- Laravel Sanctum (SPA token auth)
|
|
- Spatie laravel-permission (three-level roles)
|
|
- Spatie laravel-activitylog (audit log)
|
|
- Spatie laravel-medialibrary (file management)
|
|
- MySQL 8 (primary), Redis (cache, queues, sessions)
|
|
- Laravel Horizon (queue monitoring)
|
|
- PHPUnit for testing
|
|
|
|
### Frontend (Vue)
|
|
- TypeScript 5.9+
|
|
- Vue 3.5+ (Composition API, `<script setup>` only)
|
|
- Vite 7+
|
|
- Vuexy 9.5 + Vuetify 3.10
|
|
- Pinia 3 (client state)
|
|
- TanStack Query / Vue Query (server state)
|
|
- Axios (HTTP client)
|
|
- VeeValidate + Zod (form validation)
|
|
- VueDraggable (drag-and-drop)
|
|
- Vue I18n (internationalization)
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
event-crew/
|
|
├── api/ # Laravel 12 REST API (JSON only)
|
|
│ ├── app/
|
|
│ │ ├── Http/
|
|
│ │ │ ├── Controllers/Api/V1/
|
|
│ │ │ ├── Middleware/ # OrganisationRoleMiddleware, EventRoleMiddleware, PortalTokenMiddleware
|
|
│ │ │ ├── Requests/Api/V1/ # Form Request validation
|
|
│ │ │ └── Resources/Api/V1/ # API Resources
|
|
│ │ ├── Models/ # Eloquent models with HasUlids
|
|
│ │ ├── Policies/ # Authorization (never hardcode roles)
|
|
│ │ ├── Services/ # Complex business logic
|
|
│ │ ├── Events/ + Listeners/
|
|
│ │ └── Jobs/ # Queue jobs (briefings, PDF, notifications)
|
|
│ ├── database/
|
|
│ │ ├── migrations/
|
|
│ │ ├── factories/
|
|
│ │ └── seeders/
|
|
│ └── tests/Feature/Api/V1/
|
|
│
|
|
├── apps/
|
|
│ ├── admin/ # Super Admin SPA (Vuexy full)
|
|
│ │ └── src/
|
|
│ │ ├── @core/ # Vuexy core (NEVER modify)
|
|
│ │ ├── @layouts/ # Vuexy layouts (NEVER modify)
|
|
│ │ ├── components/
|
|
│ │ ├── composables/ # useModule.ts composables
|
|
│ │ ├── lib/ # axios.ts (single instance)
|
|
│ │ ├── pages/
|
|
│ │ ├── plugins/ # vue-query, casl, vuetify
|
|
│ │ ├── stores/ # Pinia stores
|
|
│ │ └── types/ # TypeScript interfaces
|
|
│ │
|
|
│ ├── app/ # Organizer SPA (Vuexy full) - MAIN APP
|
|
│ │ └── src/ # Same structure as admin/
|
|
│ │
|
|
│ └── portal/ # External Portal SPA (Vuexy stripped)
|
|
│ └── src/ # No sidebar, no customizer, top-bar only
|
|
│
|
|
├── resources/design/ # Design documents (source of truth)
|
|
└── .cursor/ # Cursor AI configuration
|
|
```
|
|
|
|
## Multi-Tenancy Rules (CRITICAL)
|
|
|
|
1. **EVERY query on event-data MUST scope on `organisation_id`** via `OrganisationScope` Eloquent Global Scope.
|
|
2. **Never use direct id-checks in controllers** - always use Policies.
|
|
3. **Never use `Model::all()` without a where-clause** - always scope.
|
|
4. **Never hardcode role strings** like `$user->role === 'admin'` - use `$user->hasRole()` and Policies.
|
|
|
|
## Naming Conventions
|
|
|
|
### PHP (Laravel)
|
|
|
|
| Type | Convention | Example |
|
|
|------|------------|---------|
|
|
| Models | Singular PascalCase | `Event`, `FestivalSection`, `ShiftAssignment` |
|
|
| Controllers | PascalCase + Controller | `EventController`, `ShiftController` |
|
|
| Form Requests | Action + Resource + Request | `StoreEventRequest`, `UpdateShiftRequest` |
|
|
| Resources | Resource + Resource | `EventResource`, `PersonResource` |
|
|
| Services | PascalCase + Service | `ZenderService`, `BriefingService` |
|
|
| Migrations | snake_case with timestamp | `create_events_table` |
|
|
| Tables | Plural snake_case | `events`, `festival_sections`, `shift_assignments` |
|
|
| Columns | snake_case | `organisation_id`, `slots_total`, `created_at` |
|
|
| Enums | Singular PascalCase | `EventStatus`, `BookingStatus` |
|
|
|
|
### TypeScript (Vue)
|
|
|
|
| Type | Convention | Example |
|
|
|------|------------|---------|
|
|
| Components | PascalCase | `ShiftAssignPanel.vue`, `PersonCard.vue` |
|
|
| Composables | use-prefix camelCase | `useShifts.ts`, `usePersons.ts` |
|
|
| Pinia Stores | use-prefix + Store suffix | `useEventStore.ts`, `useAuthStore.ts` |
|
|
| Types/Interfaces | PascalCase | `Event`, `Person`, `ShiftAssignment` |
|
|
| Variables | camelCase | `slotsFilled`, `fillRate` |
|
|
|
|
### Database
|
|
- Primary keys: ULID via `HasUlids` trait (NOT UUID v4, NOT auto-increment for business tables)
|
|
- Pure pivot tables: auto-increment integer PK for join performance
|
|
- DB columns: `snake_case`
|
|
|
|
## Environment Configuration
|
|
|
|
### Development URLs
|
|
|
|
| Service | URL | Env Variable |
|
|
|---------|-----|--------------|
|
|
| API | `http://localhost:8000/api/v1` | - |
|
|
| Admin SPA | `http://localhost:5173` | `FRONTEND_ADMIN_URL` |
|
|
| Organizer SPA | `http://localhost:5174` | `FRONTEND_APP_URL` |
|
|
| Portal SPA | `http://localhost:5175` | `FRONTEND_PORTAL_URL` |
|
|
| MySQL | `localhost:3306` | - |
|
|
| Redis | `localhost:6379` | - |
|
|
| Mailpit | `http://localhost:8025` | - |
|
|
|
|
### CORS
|
|
Three frontend origins configured in `config/cors.php` via env variables. Each Vite dev server gets its own port for CORS isolation.
|
|
|
|
## Git Conventions
|
|
|
|
### Branch Names
|
|
- `feature/shift-planning`
|
|
- `fix/organisation-scoping`
|
|
- `refactor/accreditation-engine`
|
|
|
|
### Commit Messages
|
|
```
|
|
feat: add shift claiming with approval flow
|
|
fix: enforce organisation scope on persons query
|
|
refactor: extract briefing logic to BriefingService
|
|
test: add accreditation assignment tests
|
|
```
|
|
|
|
## Forbidden Patterns
|
|
|
|
- NEVER: `$user->role === 'admin'` (use Policies + Spatie roles)
|
|
- NEVER: `Model::all()` without where-clause (always scope)
|
|
- NEVER: `dd()` or `var_dump()` left in code
|
|
- NEVER: Hardcode `.env` values in code
|
|
- NEVER: JSON columns for queryable/filterable data
|
|
- NEVER: UUID v4 as primary key (use HasUlids for ULID)
|
|
- NEVER: Blade views or Inertia (API-only backend)
|
|
- NEVER: Business logic in controllers without Policy authorization
|
|
|
|
## Code Style Principles
|
|
|
|
1. **Explicit over implicit** - Be clear about types, returns, and intentions
|
|
2. **Single Responsibility** - Each class/function does one thing well
|
|
3. **Type Safety** - PHP type hints and TypeScript strict mode everywhere
|
|
4. **Multi-tenant first** - Every feature must respect organisation boundaries
|
|
5. **Mobile-first** - Responsive design, minimum 375px width
|