Frontend: - Consolidate duplicate API layers into single src/lib/axios.ts per app - Remove src/lib/api-client.ts and src/utils/api.ts (admin) - Add src/lib/query-client.ts with TanStack Query config per app - Update all imports and auto-import config Backend: - Fix organisations.billing_status default to 'trial' - Fix user_invitations.invited_by_user_id to nullOnDelete - Add MeResource with separated app_roles and pivot-based org roles - Add cross-org check to EventPolicy view() and update() - Restrict EventPolicy create/update to org_admin/event_manager (not org_member) - Attach creator as org_admin on organisation store - Add query scopes to Event and UserInvitation models - Improve factories with Dutch test data - Expand test suite from 29 to 41 tests (90 assertions) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
151 lines
6.4 KiB
Markdown
151 lines
6.4 KiB
Markdown
# Crewli
|
||
|
||
Multi-tenant SaaS platform for **event and festival operations**: planning, people, accreditation, artist advancing, volunteer shifts, briefings, and show-day tooling (Mission Control). The backend is a **JSON-only** Laravel API; all user interfaces are **Vue 3** single-page apps.
|
||
|
||
---
|
||
|
||
## What Crewli covers
|
||
|
||
- **Organisations & events** — Multi-tenant data with organisation-scoped access; events move through a defined lifecycle (draft → published → registration → buildup → show day → teardown → closed).
|
||
- **Festival structure** — Sections, time slots, shifts, assignments, claiming/approval flows for volunteers and crew.
|
||
- **People & crowds** — Crowd types (crew, volunteers, artists, guests, press, partners, suppliers), persons, lists, and (planned) rich accreditation (items, zones, hand-out).
|
||
- **Artists & advancing** — Booking status, stages/timetable concepts, advance sections and token-based portal access for external artists.
|
||
- **Communication** — Briefings, campaigns, and operational messaging (see architecture doc for target modules).
|
||
- **Portal (external users)** — One portal app, two modes: **login** (Sanctum) for long-term users such as volunteers, and **token** access for per-event links (e.g. artists, suppliers).
|
||
|
||
Implementation is phased; the authoritative feature and schema list lives in the architecture and design references below.
|
||
|
||
---
|
||
|
||
## Applications
|
||
|
||
| App | Path | Port | Role |
|
||
|-----|------|------|------|
|
||
| **Admin** | `apps/admin/` | 5173 | Platform **super admin**: organisations, billing-style flags, global settings. Full Vuexy shell. |
|
||
| **Organizer** | `apps/app/` | 5174 | Main product for **org and event staff**: events, sections, shifts, people, artists, accreditation, briefings, reports, etc. |
|
||
| **Portal** | `apps/portal/` | 5175 | **External** users: stripped layout; login- or token-based access. |
|
||
|
||
All apps talk to the API over **CORS** with **Laravel Sanctum** tokens.
|
||
|
||
---
|
||
|
||
## Tech stack
|
||
|
||
| Layer | Technology |
|
||
|-------|------------|
|
||
| API | PHP 8.2+, Laravel 12, Sanctum, Spatie Permission (and Activity Log / Media Library where used) |
|
||
| Data | MySQL 8, Redis (cache/queues) |
|
||
| Frontends | Vue 3, TypeScript, Vite, Vuexy + Vuetify, Pinia, TanStack Query, VeeValidate + Zod |
|
||
| Local services | Docker Compose (MySQL, Redis, Mailpit) |
|
||
|
||
**Rule of thumb:** business tables use **ULID** primary keys; event-related data is scoped by **organisation** (global scopes + policies), not ad hoc `where` clauses in controllers.
|
||
|
||
---
|
||
|
||
## Project structure
|
||
|
||
```
|
||
crewli/
|
||
├── api/ # Laravel 12 REST API (JSON only)
|
||
├── apps/
|
||
│ ├── admin/ # Super Admin SPA
|
||
│ ├── app/ # Organizer SPA (primary UI)
|
||
│ └── portal/ # External portal SPA
|
||
├── docker/ # Docker / Compose assets
|
||
├── docs/ # SETUP, API notes, schema notes
|
||
├── resources/
|
||
│ ├── design/ # Product source of truth (design docs, see table below)
|
||
│ └── vuexy-admin-*/ # Vuexy template reference (bundled kit)
|
||
├── .cursor/ # ARCHITECTURE.md, instructions.md, rules for AI/helpers
|
||
└── Makefile # Dev commands
|
||
```
|
||
|
||
Vuexy **`@core/`** and **`@layouts/`** in each app should stay untouched; customize via app config, navigation, and app-level components.
|
||
|
||
---
|
||
|
||
## Quick start
|
||
|
||
```bash
|
||
# 1. Infrastructure
|
||
make services
|
||
|
||
# 2. API env, dependencies, database (see docs/SETUP.md)
|
||
cd api && cp .env.example .env && composer install && php artisan key:generate && php artisan migrate
|
||
|
||
# 3. Run API + the SPAs you need (separate terminals)
|
||
make api
|
||
make admin # optional
|
||
make app # optional
|
||
make portal # optional
|
||
```
|
||
|
||
Detailed setup: **[docs/SETUP.md](docs/SETUP.md)**.
|
||
|
||
---
|
||
|
||
## Development URLs
|
||
|
||
| Service | Development | Env / notes |
|
||
|---------|-------------|-------------|
|
||
| API | http://localhost:8000/api/v1 | Base path `/api/v1` |
|
||
| Admin | http://localhost:5173 | `FRONTEND_ADMIN_URL` in Laravel CORS |
|
||
| Organizer | http://localhost:5174 | `FRONTEND_APP_URL` |
|
||
| Portal | http://localhost:5175 | `FRONTEND_PORTAL_URL` |
|
||
| Mailpit | http://localhost:8025 | Local mail capture |
|
||
|
||
### Production (crewli.app)
|
||
|
||
**Domains:** **`crewli.app`** is this product (API + organizer/admin/portal SPAs, transactional email from the app, seeds, etc.). **`crewli.nl`** is reserved for a future **public marketing site** only — do not point this codebase’s `APP_URL`, CORS, Sanctum, or app mail at `crewli.nl`.
|
||
|
||
Typical layout (configure the same values in `api/.env` — see `api/.env.example`):
|
||
|
||
| Service | URL | Env variable |
|
||
|---------|-----|----------------|
|
||
| API | `https://api.crewli.app` | `APP_URL` |
|
||
| Admin | `https://admin.crewli.app` | `FRONTEND_ADMIN_URL` |
|
||
| Organizer | `https://app.crewli.app` | `FRONTEND_APP_URL` |
|
||
| Portal | `https://portal.crewli.app` | `FRONTEND_PORTAL_URL` |
|
||
|
||
Frontends: set `VITE_API_URL=https://api.crewli.app/api/v1` in each app’s env for production builds. `SANCTUM_STATEFUL_DOMAINS` must list the **hostnames only** of the three SPAs (e.g. `admin.crewli.app,app.crewli.app,portal.crewli.app`).
|
||
|
||
---
|
||
|
||
## Makefile commands
|
||
|
||
```bash
|
||
make services # MySQL, Redis, Mailpit
|
||
make services-stop
|
||
make api # Laravel on :8000
|
||
make admin # Admin on :5173
|
||
make app # Organizer on :5174
|
||
make portal # Portal on :5175
|
||
make migrate
|
||
make fresh # migrate:fresh --seed
|
||
make db-shell
|
||
```
|
||
|
||
---
|
||
|
||
## Documentation
|
||
|
||
| Resource | Contents |
|
||
|----------|----------|
|
||
| [resources/design/](resources/design/) | **Canonical product specs** in Markdown. Referenced by `.cursor` and `CLAUDE.md` as source of truth for features and data model: `design-document.md`, `dev-guide.md`, `start-guide.md`. |
|
||
| [.cursor/ARCHITECTURE.md](.cursor/ARCHITECTURE.md) | System diagram, apps, multi-tenancy, roles, event lifecycle, API route map, core schema overview (summarises `resources/design` when present) |
|
||
| [.cursor/instructions.md](.cursor/instructions.md) | Quick reference, phased roadmap, module build order |
|
||
| [.cursor/rules/](.cursor/rules/) | Workspace, Laravel, Vue, testing conventions |
|
||
| [docs/SETUP.md](docs/SETUP.md) | Environment and local setup |
|
||
| [docs/API.md](docs/API.md) | API notes (if maintained) |
|
||
| [docs/SCHEMA.md](docs/SCHEMA.md) | Schema notes (if maintained) |
|
||
|
||
---
|
||
|
||
## Testing
|
||
|
||
```bash
|
||
cd api && php artisan test
|
||
```
|
||
|
||
Feature tests should cover happy paths plus **401** (unauthenticated), **403** (wrong organisation), and **422** (validation) where applicable.
|