docs: remove admin SPA references and update production URLs
The admin SPA (apps/admin/) has been retired. Its functionality now lives in apps/app/ under /platform/* routes for super_admin users. Updated all documentation to reflect: 2 SPAs instead of 3, removed FRONTEND_ADMIN_URL/port 5173 references, changed production URL from app.crewli.app to crewli.app. Retired admin-specific security audit findings (A13-2, A13-4, A13-5, A13-7) and APPS-01 backlog item. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,16 +10,16 @@
|
||||
│ INTERNET │
|
||||
└─────────────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
┌───────────────────────────┼───────────────────────────┐
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
|
||||
│ Admin SPA │ │ Organizer │ │ Portal SPA │
|
||||
│ (Super Admin)│ │ SPA (Main) │ │ (External) │
|
||||
│ :5173 │ │ :5174 │ │ :5175 │
|
||||
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
|
||||
│ │ │
|
||||
└───────────────────────────┼───────────────────────────┘
|
||||
┌───────────────┼───────────────┐
|
||||
│ │
|
||||
▼ ▼
|
||||
┌───────────────┐ ┌───────────────┐
|
||||
│ Organizer + │ │ Portal SPA │
|
||||
│ Admin SPA │ │ (External) │
|
||||
│ :5174 │ │ :5175 │
|
||||
└───────┬───────┘ └───────┬───────┘
|
||||
│ │
|
||||
└───────────────┼───────────────┘
|
||||
│ CORS + Sanctum tokens
|
||||
▼
|
||||
┌───────────────────────┐
|
||||
@@ -38,32 +38,17 @@
|
||||
└───────────┘ └───────────┘ └───────────┘
|
||||
```
|
||||
|
||||
**Golden Rule:** Laravel is exclusively a JSON REST API. No Blade views, no Mix, no Inertia. Every response is `application/json`. Vue handles ALL UI via three SPAs.
|
||||
**Golden Rule:** Laravel is exclusively a JSON REST API. No Blade views, no Mix, no Inertia. Every response is `application/json`. Vue handles ALL UI via two SPAs.
|
||||
|
||||
---
|
||||
|
||||
## Applications
|
||||
|
||||
### Admin Dashboard (`apps/admin/`)
|
||||
|
||||
**Purpose**: Super Admin platform management.
|
||||
|
||||
**Users**: Platform owner only (super_admin role).
|
||||
|
||||
**Features**:
|
||||
- Organisation management (CRUD, billing status)
|
||||
- Platform user management
|
||||
- Global settings
|
||||
|
||||
**Vuexy Version**: `typescript-version/full-version`
|
||||
|
||||
---
|
||||
|
||||
### Organizer App (`apps/app/`)
|
||||
|
||||
**Purpose**: Main application for event management per organisation.
|
||||
**Purpose**: Main application for event management per organisation. Also serves as the platform admin interface for `super_admin` users via `/platform/*` routes.
|
||||
|
||||
**Users**: Organisation Admins, Event Managers, Staff Coordinators, Artist Managers, Volunteer Coordinators.
|
||||
**Users**: Organisation Admins, Event Managers, Staff Coordinators, Artist Managers, Volunteer Coordinators, Super Admins (platform management via `/platform/*`).
|
||||
|
||||
**Features**:
|
||||
- Event lifecycle management (Draft through Closed)
|
||||
@@ -77,6 +62,7 @@
|
||||
- Form builder with conditional logic
|
||||
- Supplier & production management
|
||||
- Reporting & insights
|
||||
- Platform admin: organisation management, billing, platform users (`/platform/*` routes, `super_admin` only)
|
||||
|
||||
**Vuexy Version**: `typescript-version/full-version` (customized navigation)
|
||||
|
||||
@@ -424,15 +410,14 @@ POST /portal/production-request
|
||||
|
||||
## Security & CORS
|
||||
|
||||
Three frontend origins in `config/cors.php` (via env):
|
||||
Two frontend origins in `config/cors.php` (via env):
|
||||
|
||||
| App | Dev URL | Env Variable |
|
||||
|-----|---------|--------------|
|
||||
| Admin | `http://localhost:5173` | `FRONTEND_ADMIN_URL` |
|
||||
| App | `http://localhost:5174` | `FRONTEND_APP_URL` |
|
||||
| Portal | `http://localhost:5175` | `FRONTEND_PORTAL_URL` |
|
||||
|
||||
Production (registered domain **crewli.app**): API `https://api.crewli.app` (`APP_URL`); SPAs `https://admin.crewli.app`, `https://app.crewli.app`, `https://portal.crewli.app` via the same env keys. Frontends use `VITE_API_URL=https://api.crewli.app/api/v1`. `SANCTUM_STATEFUL_DOMAINS` = comma-separated SPA hostnames only (e.g. `admin.crewli.app,app.crewli.app,portal.crewli.app`). **`crewli.nl`** is reserved for a future marketing site only — not used for this application stack.
|
||||
Production (registered domain **crewli.app**): API `https://api.crewli.app` (`APP_URL`); SPAs `https://crewli.app`, `https://portal.crewli.app` via the same env keys. Frontends use `VITE_API_URL=https://api.crewli.app/api/v1`. `SANCTUM_STATEFUL_DOMAINS` = comma-separated SPA hostnames only (e.g. `crewli.app,portal.crewli.app`). **`crewli.nl`** is reserved for a future marketing site only — not used for this application stack.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ Crewli is a multi-tenant SaaS platform for professional event and festival manag
|
||||
| Component | Technology | Location | Port |
|
||||
|-----------|------------|----------|------|
|
||||
| API | Laravel 12 + Sanctum + Spatie Permission | `api/` | 8000 |
|
||||
| Admin (Super Admin) | Vue 3 + Vuexy (full) | `apps/admin/` | 5173 |
|
||||
| Organizer App (Main) | Vue 3 + Vuexy (full) | `apps/app/` | 5174 |
|
||||
| Organizer + Admin App (Main) | Vue 3 + Vuexy (full) | `apps/app/` | 5174 |
|
||||
| Portal (External) | Vue 3 + Vuexy (stripped) | `apps/portal/` | 5175 |
|
||||
| Database | MySQL 8 | Docker | 3306 |
|
||||
| Cache / Queues | Redis | Docker | 6379 |
|
||||
@@ -205,8 +204,7 @@ make services-stop # Stop services
|
||||
### Development Servers
|
||||
```bash
|
||||
make api # Laravel on :8000
|
||||
make admin # Admin SPA on :5173
|
||||
make app # Organizer SPA on :5174
|
||||
make app # Organizer + Admin SPA on :5174
|
||||
make portal # Portal SPA on :5175
|
||||
```
|
||||
|
||||
|
||||
@@ -123,8 +123,7 @@ crewli/
|
||||
| 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` |
|
||||
| Organizer + Admin SPA | `http://localhost:5174` | `FRONTEND_APP_URL` |
|
||||
| Portal SPA | `http://localhost:5175` | `FRONTEND_PORTAL_URL` |
|
||||
| MySQL | `localhost:3306` | - |
|
||||
| Redis | `localhost:6379` | - |
|
||||
@@ -137,12 +136,11 @@ crewli/
|
||||
| Service | URL | Env variable |
|
||||
|---------|-----|--------------|
|
||||
| API | `https://api.crewli.app` | `APP_URL` |
|
||||
| Admin SPA | `https://admin.crewli.app` | `FRONTEND_ADMIN_URL` |
|
||||
| Organizer SPA | `https://app.crewli.app` | `FRONTEND_APP_URL` |
|
||||
| Organizer + Admin SPA | `https://crewli.app` | `FRONTEND_APP_URL` |
|
||||
| Portal SPA | `https://portal.crewli.app` | `FRONTEND_PORTAL_URL` |
|
||||
|
||||
### CORS
|
||||
Three frontend origins configured in `config/cors.php` via env variables. Each Vite dev server gets its own port for CORS isolation. In production, set the same env vars to the `https://…` origins above (see `api/.env.example`).
|
||||
Two frontend origins configured in `config/cors.php` via env variables. Each Vite dev server gets its own port for CORS isolation. In production, set the same env vars to the `https://...` origins above (see `api/.env.example`).
|
||||
|
||||
## Git Conventions
|
||||
|
||||
|
||||
@@ -18,15 +18,12 @@ alwaysApply: true
|
||||
|
||||
## App-Specific Rules
|
||||
|
||||
### `apps/admin/` (Super Admin)
|
||||
- Full Vuexy template unchanged (sidebar, dark mode, customizer)
|
||||
- Minimal modifications needed
|
||||
|
||||
### `apps/app/` (Organizer - Main App)
|
||||
### `apps/app/` (Organizer + Platform Admin - Main App)
|
||||
- Sidebar nav customized for Crewli structure
|
||||
- Remove Vuexy demo/customizer components
|
||||
- Full Vuetify component usage
|
||||
- 90% of development work happens here
|
||||
- Super admin functionality under `/platform/*` routes for `super_admin` users
|
||||
|
||||
### `apps/portal/` (External Portal)
|
||||
- Stripped Vuexy: no sidebar, no customizer, no dark mode toggle
|
||||
|
||||
@@ -189,14 +189,13 @@ class PortalTokenMiddleware
|
||||
```php
|
||||
// config/cors.php
|
||||
'allowed_origins' => [
|
||||
env('FRONTEND_ADMIN_URL', 'http://localhost:5173'),
|
||||
env('FRONTEND_APP_URL', 'http://localhost:5174'),
|
||||
env('FRONTEND_PORTAL_URL', 'http://localhost:5175'),
|
||||
],
|
||||
'supports_credentials' => true,
|
||||
```
|
||||
|
||||
Production example (subdomains on **crewli.app**): `FRONTEND_ADMIN_URL=https://admin.crewli.app`, `FRONTEND_APP_URL=https://app.crewli.app`, `FRONTEND_PORTAL_URL=https://portal.crewli.app`, and `SANCTUM_STATEFUL_DOMAINS=admin.crewli.app,app.crewli.app,portal.crewli.app`.
|
||||
Production example (subdomains on **crewli.app**): `FRONTEND_APP_URL=https://crewli.app`, `FRONTEND_PORTAL_URL=https://portal.crewli.app`, and `SANCTUM_STATEFUL_DOMAINS=crewli.app,portal.crewli.app`.
|
||||
|
||||
## Shift Claiming & Approval Flow
|
||||
|
||||
|
||||
@@ -7,14 +7,13 @@
|
||||
|
||||
## 1. Authentication Overview
|
||||
|
||||
Crewli uses **stateless token-based authentication** via Laravel Sanctum. Three SPA clients communicate with a single REST API. Tokens are stored exclusively in **httpOnly cookies** set by the server — they are never exposed to JavaScript via response bodies, localStorage, or JS-readable cookies.
|
||||
Crewli uses **stateless token-based authentication** via Laravel Sanctum. Two SPA clients communicate with a single REST API. Tokens are stored exclusively in **httpOnly cookies** set by the server — they are never exposed to JavaScript via response bodies, localStorage, or JS-readable cookies.
|
||||
|
||||
### Client Applications
|
||||
|
||||
| App | URL (dev) | URL (prod) | Purpose |
|
||||
|-----|-----------|------------|---------|
|
||||
| Admin | localhost:5173 | admin.crewli.app | Super admin / platform management |
|
||||
| App | localhost:5174 | app.crewli.app | Organiser dashboard |
|
||||
| App | localhost:5174 | crewli.app | Organiser dashboard + platform admin (`/platform/*` for super_admin) |
|
||||
| Portal | localhost:5175 | portal.crewli.app | Volunteers, artists, suppliers |
|
||||
|
||||
### Access Modes
|
||||
@@ -30,7 +29,6 @@ The Portal supports two access modes:
|
||||
|
||||
| App | Cookie Name | Domain | Secure | httpOnly | SameSite | Max-Age |
|
||||
|-----|-------------|--------|--------|----------|----------|---------|
|
||||
| Admin | `crewli_admin_token` | `.crewli.app` (prod) / `localhost` (dev) | Yes (prod) | Yes | Strict | 7 days |
|
||||
| App | `crewli_app_token` | `.crewli.app` (prod) / `localhost` (dev) | Yes (prod) | Yes | Strict | 7 days |
|
||||
| Portal | `crewli_portal_token` | `.crewli.app` (prod) / `localhost` (dev) | Yes (prod) | Yes | Strict | 7 days |
|
||||
|
||||
@@ -57,7 +55,7 @@ The `CookieBearerToken` middleware (registered before `auth:sanctum` in the API
|
||||
3. Reads only that cookie and sets `Authorization: Bearer` on the request
|
||||
4. Sanctum's existing token validation processes the header normally
|
||||
|
||||
**Cross-app isolation:** In local development, all three SPAs share `localhost` (different ports). Browsers do not scope cookies by port, so all three app cookies are sent with every API request. The middleware prevents cross-app authentication by only reading the cookie that matches the requesting app's Origin header. Without this, logging into one app would authenticate all apps.
|
||||
**Cross-app isolation:** In local development, both SPAs share `localhost` (different ports). Browsers do not scope cookies by port, so both app cookies are sent with every API request. The middleware prevents cross-app authentication by only reading the cookie that matches the requesting app's Origin header. Without this, logging into one app would authenticate the other.
|
||||
|
||||
If the `Origin` header is absent (e.g. server-to-server requests), the middleware falls back to the first available cookie. If an `Authorization` header is already present (e.g. from the portal token flow), the middleware skips cookie injection entirely.
|
||||
|
||||
@@ -170,7 +168,6 @@ Request
|
||||
| Setting | Location | Purpose |
|
||||
|---------|----------|---------|
|
||||
| `SESSION_DOMAIN` | `.env` | Cookie domain (`.crewli.app` in prod, `localhost` in dev) |
|
||||
| `FRONTEND_ADMIN_URL` | `.env` / `config/app.php` | Admin SPA origin (cookie name resolution + CORS) |
|
||||
| `FRONTEND_APP_URL` | `.env` / `config/app.php` | App SPA origin |
|
||||
| `FRONTEND_PORTAL_URL` | `.env` / `config/app.php` | Portal SPA origin |
|
||||
| `sanctum.expiration` | `config/sanctum.php` | Token TTL (7 days = 10080 minutes) |
|
||||
|
||||
@@ -351,15 +351,9 @@ voor third-party integraties (ticketing, HR, etc.)
|
||||
|
||||
## Apps & Platforms
|
||||
|
||||
### APPS-01 — apps/admin/ volledig bouwen
|
||||
### ~~APPS-01 — apps/admin/ volledig bouwen~~ RETIRED
|
||||
|
||||
**Aanleiding:** Super Admin panel voor platform-beheer.
|
||||
**Wat:**
|
||||
|
||||
- Alle organisaties beheren
|
||||
- Billing status wijzigen
|
||||
- Platform-gebruikers beheren
|
||||
- Usage statistieken
|
||||
**Status:** Retired — admin SPA (`apps/admin/`) is afgeschaft. Super admin functionaliteit is verplaatst naar `apps/app/` onder `/platform/*` routes voor `super_admin` gebruikers.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -17,9 +17,8 @@ Crewli is a multi-tenant SaaS platform for event and festival management.
|
||||
|
||||
- **Backend:** Laravel 12 REST API (no Blade views, no Inertia), Sanctum auth,
|
||||
Spatie Permission, MySQL 8, Redis
|
||||
- **Frontend:** Three standalone Vue 3 + TypeScript SPAs on Vuexy 9.5 /
|
||||
Vuetify 3.10 — `apps/admin/` (port 5173), `apps/app/` (port 5174),
|
||||
`apps/portal/` (port 5175)
|
||||
- **Frontend:** Two standalone Vue 3 + TypeScript SPAs on Vuexy 9.5 /
|
||||
Vuetify 3.10 — `apps/app/` (port 5174), `apps/portal/` (port 5175)
|
||||
- **State:** Pinia + TanStack Vue Query
|
||||
- **Forms:** VeeValidate + Zod
|
||||
- **API base path:** `/api/v1/`
|
||||
@@ -47,8 +46,7 @@ crewli/
|
||||
│ │ └── seeders/
|
||||
│ └── tests/Feature/Api/V1/
|
||||
├── apps/
|
||||
│ ├── admin/ # Super Admin SPA
|
||||
│ ├── app/ # Organizer SPA (main app)
|
||||
│ ├── app/ # Organizer + Platform Admin SPA (main app)
|
||||
│ │ └── src/
|
||||
│ │ ├── lib/axios.ts # THE ONLY axios instance
|
||||
│ │ ├── composables/api/ # TanStack Query composables
|
||||
|
||||
@@ -15,9 +15,8 @@ Crewli — multi-tenant SaaS for event/festival management.
|
||||
|
||||
- **Frontend:** Vue 3 + TypeScript + Vuexy 9.5 (Vuetify 3.10) + Pinia +
|
||||
TanStack Vue Query + VeeValidate + Zod
|
||||
- **Three SPAs:**
|
||||
- `apps/admin/` — Super Admin (port 5173)
|
||||
- `apps/app/` — Organizer main app (port 5174)
|
||||
- **Two SPAs:**
|
||||
- `apps/app/` — Organizer + Platform Admin main app (port 5174)
|
||||
- `apps/portal/` — Dual-mode portal (port 5175)
|
||||
- **API base:** `VITE_API_URL` from `.env.local` (default `http://localhost:8000`)
|
||||
- **Axios instance:** `src/lib/axios.ts` — this is the ONLY axios instance.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- **Total findings: 57**
|
||||
- **Critical: 10 | High: 19 | Medium: 18 | Low: 10**
|
||||
|
||||
Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
Audit scope: all files under `api/` and `apps/` (app, portal).
|
||||
|
||||
---
|
||||
|
||||
@@ -337,7 +337,7 @@ Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
#### [MEDIUM] A05-3: Session `SameSite=Lax` may break cross-subdomain Sanctum cookie auth
|
||||
|
||||
- **File:** `api/config/session.php:202`
|
||||
- **Description:** With three SPAs on different subdomains calling `api.crewli.app`, `SameSite=Lax` blocks session cookies on cross-origin requests.
|
||||
- **Description:** With two SPAs on different subdomains calling `api.crewli.app`, `SameSite=Lax` blocks session cookies on cross-origin requests.
|
||||
- **Risk:** Sanctum SPA authentication may fail silently in production.
|
||||
- **Fix:** Set `SESSION_DOMAIN=.crewli.app` and `SESSION_SAME_SITE=none` (with `SESSION_SECURE_COOKIE=true`) in production.
|
||||
|
||||
@@ -364,7 +364,7 @@ Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
|
||||
#### Positive findings (A05)
|
||||
|
||||
- CORS `allowed_origins` correctly restricted to three specific SPAs (not `*`).
|
||||
- CORS `allowed_origins` correctly restricted to two specific SPAs (not `*`).
|
||||
- `supports_credentials: true` correctly set for Sanctum.
|
||||
- `APP_DEBUG` defaults to `false` in `config/app.php`.
|
||||
- No Telescope/Horizon routes found (not installed).
|
||||
@@ -378,21 +378,21 @@ Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
|
||||
#### [CRITICAL] A06-1: `@casl/ability` 6.7.3 — Prototype Pollution
|
||||
|
||||
- **File:** `apps/*/package.json`
|
||||
- **Description:** CASL is used for frontend permission enforcement across all three apps. Prototype pollution could corrupt ability checks.
|
||||
- **File:** `apps/app/package.json`, `apps/portal/package.json`
|
||||
- **Description:** CASL is used for frontend permission enforcement across both apps. Prototype pollution could corrupt ability checks.
|
||||
- **Risk:** Permission bypass in the frontend. Admin tokens at elevated risk.
|
||||
- **Fix:** Upgrade to `>=6.7.5` in all three apps.
|
||||
- **Fix:** Upgrade to `>=6.7.5` in both apps.
|
||||
|
||||
#### [CRITICAL] A06-2: `axios` ~1.13.x — SSRF and metadata exfiltration
|
||||
|
||||
- **File:** `apps/*/package.json`
|
||||
- **File:** `apps/app/package.json`, `apps/portal/package.json`
|
||||
- **Description:** Two critical CVEs: `NO_PROXY` hostname normalization bypass (SSRF) and unrestricted cloud metadata exfiltration via header injection.
|
||||
- **Risk:** Cloud metadata theft, SSRF in SSR contexts.
|
||||
- **Fix:** Upgrade to `>=1.15.0` in all three apps.
|
||||
- **Fix:** Upgrade to `>=1.15.0` in both apps.
|
||||
|
||||
#### [CRITICAL] A06-3: `swiper` 11.2.10 — Prototype Pollution
|
||||
|
||||
- **File:** `apps/*/package.json`
|
||||
- **File:** `apps/app/package.json`, `apps/portal/package.json`
|
||||
- **Description:** Prototype pollution vulnerability.
|
||||
- **Risk:** Client-side code execution.
|
||||
- **Fix:** Upgrade to `>=12.1.2` (major version bump — review migration guide).
|
||||
@@ -420,7 +420,7 @@ Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
|
||||
#### [LOW] A06-7: Frontend dev dependencies — 45 vulnerabilities in build tools
|
||||
|
||||
- **File:** `apps/*/pnpm-lock.yaml`
|
||||
- **File:** `apps/app/pnpm-lock.yaml`, `apps/portal/pnpm-lock.yaml`
|
||||
- **Description:** `vite`, `rollup`, `tar`, `undici`, `minimatch`, `svgo`, `flatted`, `immutable`, `lodash`, `picomatch` — various high/moderate vulnerabilities in dev/build-time dependencies.
|
||||
- **Risk:** Not shipped to production. CI/CD pipeline risk.
|
||||
- **Fix:** Update dev dependencies: `pnpm update` for each app.
|
||||
@@ -554,58 +554,51 @@ Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
|
||||
#### [CRITICAL] A13-1: Bearer tokens stored in `localStorage` (apps/app and apps/portal)
|
||||
|
||||
- **File:** `apps/app/src/stores/useAuthStore.ts:7,10,30,66`
|
||||
- **File:** `apps/portal/src/stores/useAuthStore.ts:6,9,18,20`
|
||||
- **File:** `apps/app/src/stores/useAuthStore.ts`
|
||||
- **File:** `apps/portal/src/stores/useAuthStore.ts`
|
||||
- **Description:** Sanctum bearer tokens stored in `localStorage` under `crewli_token` and `crewli_portal_token`. Accessible to any JavaScript on the page.
|
||||
- **Risk:** Any XSS vulnerability (or supply-chain attack) can steal tokens and impersonate users indefinitely.
|
||||
- **Fix:** Migrate to `httpOnly; Secure; SameSite=Strict` cookies set by the Laravel backend. Remove `setItem`/`getItem` usage.
|
||||
|
||||
#### [HIGH] A13-2: Admin app cookies lack `httpOnly`, `Secure`, and `SameSite` flags
|
||||
#### ~~[HIGH] A13-2: Admin app cookies lack `httpOnly`, `Secure`, and `SameSite` flags~~ RETIRED
|
||||
|
||||
- **File:** `apps/admin/src/@core/composable/useCookie.ts:38-43`
|
||||
- **Description:** Token, user data, and ability rules stored in cookies written via `document.cookie` with no `httpOnly`, `secure`, or `sameSite`.
|
||||
- **Risk:** XSS token theft and CSRF.
|
||||
- **Fix:** Refactor to have the API set httpOnly cookies via `Set-Cookie` response header. Add `sameSite: 'strict'` as interim measure.
|
||||
- **File:** `apps/admin/` (removed)
|
||||
- **Description:** The admin SPA has been retired. Its functionality now lives in `apps/app/` under `/platform/*` routes.
|
||||
- **Resolution:** Finding no longer applicable — `apps/admin/` has been removed.
|
||||
|
||||
#### [HIGH] A13-3: Open redirect vulnerability on post-login redirect (all apps)
|
||||
|
||||
- **File:** `apps/portal/src/pages/login.vue:61,74-76`
|
||||
- **File:** `apps/app/src/pages/login.vue:55`
|
||||
- **File:** `apps/admin/src/pages/login.vue:97`
|
||||
- **Description:** All login pages accept `?to=` query parameter and redirect to it after login without validating it's a relative path. Portal falls back to `window.location.href` with the raw value.
|
||||
- **Risk:** Phishing: `https://portal.crewli.app/login?to=https://evil.com/steal`.
|
||||
- **Fix:** Validate that redirect target starts with `/` before using it.
|
||||
|
||||
#### [HIGH] A13-4: `v-html` with API-sourced data in admin app (template pages)
|
||||
#### ~~[HIGH] A13-4: `v-html` with API-sourced data in admin app (template pages)~~ RETIRED
|
||||
|
||||
- **File:** `apps/admin/src/pages/front-pages/help-center/article/[title].vue:59-62`
|
||||
- **File:** `apps/admin/src/pages/apps/academy/course-details.vue:154`
|
||||
- **Description:** Template/demo pages from Vuexy render API data with `v-html` — stored XSS vector.
|
||||
- **Risk:** XSS within the admin app where users have super_admin privileges.
|
||||
- **Fix:** Remove these template demo pages entirely, or sanitize with DOMPurify.
|
||||
- **File:** `apps/admin/` (removed)
|
||||
- **Description:** The admin SPA has been retired. Its functionality now lives in `apps/app/` under `/platform/*` routes.
|
||||
- **Resolution:** Finding no longer applicable — `apps/admin/` has been removed.
|
||||
|
||||
#### [HIGH] A13-5: Admin router guard relies on JS-readable cookie without server validation
|
||||
#### ~~[HIGH] A13-5: Admin router guard relies on JS-readable cookie without server validation~~ RETIRED
|
||||
|
||||
- **File:** `apps/admin/src/plugins/1.router/guards.ts:40-42`
|
||||
- **Description:** Guard reads `userData`/`accessToken` from `document.cookie`. Does not call API to validate — just checks truthy value.
|
||||
- **Risk:** An XSS attacker who steals cookies bypasses the guard. Stale or tampered cookies pass validation.
|
||||
- **Fix:** Use the `authStore.initialize()` pattern from the app/portal guards (server-validates token on init).
|
||||
- **File:** `apps/admin/` (removed)
|
||||
- **Description:** The admin SPA has been retired. Its functionality now lives in `apps/app/` under `/platform/*` routes.
|
||||
- **Resolution:** Finding no longer applicable — `apps/admin/` has been removed.
|
||||
|
||||
#### [MEDIUM] A13-6: Server error messages forwarded to UI
|
||||
|
||||
- **File:** `apps/admin/src/pages/events/create.vue:74`
|
||||
- **File:** `apps/app/src/pages/login.vue:59-69`
|
||||
- **File:** `apps/portal/src/pages/login.vue:51`
|
||||
- **Description:** Raw `data.message` from API errors rendered in UI. Could expose internal details if backend misconfigured.
|
||||
- **Risk:** Information disclosure (table names, file paths).
|
||||
- **Fix:** Use safelist-based error mapping. The portal's `mapLoginErrorMessage` is a good pattern — extend it.
|
||||
|
||||
#### [MEDIUM] A13-7: Admin `main.ts` mount-error handler uses `innerHTML` interpolation
|
||||
#### ~~[MEDIUM] A13-7: Admin `main.ts` mount-error handler uses `innerHTML` interpolation~~ RETIRED
|
||||
|
||||
- **File:** `apps/admin/src/main.ts:41`
|
||||
- **Description:** Error fallback injects `error` object via template string into `innerHTML`.
|
||||
- **Risk:** XSS if error message is attacker-influenced.
|
||||
- **Fix:** Use `document.createTextNode(String(error))` instead.
|
||||
- **File:** `apps/admin/` (removed)
|
||||
- **Description:** The admin SPA has been retired. Its functionality now lives in `apps/app/` under `/platform/*` routes.
|
||||
- **Resolution:** Finding no longer applicable — `apps/admin/` has been removed.
|
||||
|
||||
#### [MEDIUM] A13-8: Portal localStorage event state persists across session expiry
|
||||
|
||||
@@ -616,8 +609,8 @@ Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
|
||||
#### [LOW] A13-9: No Content Security Policy on any SPA — RESOLVED
|
||||
|
||||
- **File:** `apps/*/index.html`, `api/app/Http/Middleware/SecurityHeaders.php`, `deploy/nginx/`
|
||||
- **Description:** ~~None of the three apps set a CSP meta tag or header.~~
|
||||
- **File:** `apps/app/index.html`, `apps/portal/index.html`, `api/app/Http/Middleware/SecurityHeaders.php`, `deploy/nginx/`
|
||||
- **Description:** ~~Neither app set a CSP meta tag or header.~~
|
||||
- **Risk:** Injected scripts have unrestricted access.
|
||||
- **Resolution:** API CSP enforced via `SecurityHeaders` middleware (`default-src 'none'; frame-ancestors 'none'`). SPA CSP configured via Nginx snippets (`deploy/nginx/csp-spa.conf`, `csp-portal.conf`). Dev CSP meta tags added to all `index.html` files for local testing. See `deploy/README.md` for rollout instructions.
|
||||
|
||||
@@ -632,7 +625,7 @@ Audit scope: all files under `api/` and `apps/` (admin, app, portal).
|
||||
The following security measures ARE correctly implemented:
|
||||
|
||||
1. **Password hashing:** bcrypt with `BCRYPT_ROUNDS=12`. `$password` in User model's `$hidden` array.
|
||||
2. **CORS origins:** Correctly restricted to three specific SPA origins (not `*`). `supports_credentials: true` set.
|
||||
2. **CORS origins:** Correctly restricted to two specific SPA origins (not `*`). `supports_credentials: true` set.
|
||||
3. **SQL injection prevention:** All Eloquent queries use PDO parameter binding. All `whereRaw()`/`selectRaw()` calls use `?` placeholders.
|
||||
4. **No shell execution:** No `exec()`, `shell_exec()`, `system()`, `proc_open()`, or `passthru()` in application code.
|
||||
5. **Blade escaping:** All Blade output uses `{{ }}` (escaped). Zero instances of `{!! !!}`.
|
||||
@@ -685,5 +678,5 @@ The following security measures ARE correctly implemented:
|
||||
| 17 | A01-13: Move event routes under org prefix | Large |
|
||||
| 18 | A09-1/2/3: Add security logging | Medium |
|
||||
| 19 | A07-3: Strengthen password rules | Small |
|
||||
| 20 | A13-2/5: Fix admin cookie security | Medium |
|
||||
| 20 | ~~A13-2/5: Fix admin cookie security~~ RETIRED (apps/admin removed) | N/A |
|
||||
| 21 | A06-3: Upgrade swiper (major version) | Medium |
|
||||
|
||||
@@ -82,7 +82,7 @@ Requirements:
|
||||
- Use the command: composer create-project laravel/laravel api
|
||||
- After creation, install Sanctum: composer require laravel/sanctum
|
||||
- Configure for API-only (we don't need web routes)
|
||||
- Set up CORS for localhost:5173, localhost:5174, localhost:5175
|
||||
- Set up CORS for localhost:5174, localhost:5175
|
||||
- Use MySQL with these credentials:
|
||||
- Host: 127.0.0.1
|
||||
- Database: crewli
|
||||
@@ -111,33 +111,26 @@ DB_DATABASE=crewli
|
||||
DB_USERNAME=crewli
|
||||
DB_PASSWORD=secret
|
||||
|
||||
FRONTEND_ADMIN_URL=http://localhost:5173
|
||||
FRONTEND_APP_URL=http://localhost:5174
|
||||
FRONTEND_PORTAL_URL=http://localhost:5175
|
||||
SANCTUM_STATEFUL_DOMAINS=localhost:5173,localhost:5174,localhost:5175
|
||||
SANCTUM_STATEFUL_DOMAINS=localhost:5174,localhost:5175
|
||||
SESSION_DOMAIN=localhost
|
||||
```
|
||||
|
||||
**Production (domain `crewli.app`):** set `APP_URL=https://api.crewli.app`, point `FRONTEND_ADMIN_URL` / `FRONTEND_APP_URL` / `FRONTEND_PORTAL_URL` to `https://admin.crewli.app`, `https://app.crewli.app`, and `https://portal.crewli.app`, and `SANCTUM_STATEFUL_DOMAINS=admin.crewli.app,app.crewli.app,portal.crewli.app` (hostnames only). Each SPA build should use `VITE_API_URL=https://api.crewli.app/api/v1`. Full template: `api/.env.example`. The product uses **`crewli.app`** only; **`crewli.nl`** is for a future public marketing site, not this API or SPAs.
|
||||
**Production (domain `crewli.app`):** set `APP_URL=https://api.crewli.app`, point `FRONTEND_APP_URL` / `FRONTEND_PORTAL_URL` to `https://crewli.app` and `https://portal.crewli.app`, and `SANCTUM_STATEFUL_DOMAINS=crewli.app,portal.crewli.app` (hostnames only). Each SPA build should use `VITE_API_URL=https://api.crewli.app/api/v1`. Full template: `api/.env.example`. The product uses **`crewli.app`** only; **`crewli.nl`** is for a future public marketing site, not this API or SPAs.
|
||||
|
||||
---
|
||||
|
||||
## Step 3: Vuexy frontends (this repo)
|
||||
|
||||
This monorepo already contains three SPAs under `apps/`:
|
||||
This monorepo already contains two SPAs under `apps/`:
|
||||
|
||||
| Directory | Role | Typical Vuexy source |
|
||||
|-----------|------|----------------------|
|
||||
| `apps/admin/` | Super Admin | full-version (TypeScript) |
|
||||
| `apps/app/` | Organizer (main product) | full-version or customized starter |
|
||||
| `apps/app/` | Organizer + Platform Admin (main product) | full-version (TypeScript) |
|
||||
| `apps/portal/` | External portal (volunteers, token links) | stripped starter / custom layout |
|
||||
|
||||
If you ever need to re-copy from a Vuexy ZIP, use the paths above — not legacy `apps/band` or `apps/customers`.
|
||||
|
||||
```bash
|
||||
# Example only — adjust to your Vuexy download path
|
||||
cp -r ~/Downloads/vuexy/typescript-version/full-version/* apps/admin/
|
||||
```
|
||||
Super admin functionality lives in `apps/app/` under `/platform/*` routes, accessible to `super_admin` users.
|
||||
|
||||
---
|
||||
|
||||
@@ -146,19 +139,12 @@ cp -r ~/Downloads/vuexy/typescript-version/full-version/* apps/admin/
|
||||
### Install Dependencies
|
||||
|
||||
```bash
|
||||
cd apps/admin && pnpm install
|
||||
cd ../app && pnpm install
|
||||
cd apps/app && pnpm install
|
||||
cd ../portal && pnpm install
|
||||
```
|
||||
|
||||
### Create Environment Files
|
||||
|
||||
**apps/admin/.env.local**
|
||||
```env
|
||||
VITE_API_URL=http://localhost:8000/api/v1
|
||||
VITE_APP_NAME="Crewli Admin"
|
||||
```
|
||||
|
||||
**apps/app/.env.local**
|
||||
```env
|
||||
VITE_API_URL=http://localhost:8000/api/v1
|
||||
@@ -173,13 +159,13 @@ VITE_APP_NAME="Crewli Portal"
|
||||
|
||||
### Dev server ports
|
||||
|
||||
From the repo root, `make admin`, `make app`, and `make portal` start Vite on **5173**, **5174**, and **5175** respectively. If you run `pnpm dev` manually, configure the same ports in each app’s `vite.config.ts` under `server.port`.
|
||||
From the repo root, `make app` and `make portal` start Vite on **5174** and **5175** respectively. If you run `pnpm dev` manually, configure the same ports in each app’s `vite.config.ts` under `server.port`.
|
||||
|
||||
---
|
||||
|
||||
## Step 5: API client in SPAs
|
||||
|
||||
`apps/admin/src/lib/api-client.ts`, `apps/app/src/lib/api-client.ts`, and `apps/portal/src/lib/api-client.ts` share the same pattern: `VITE_API_URL` base, Bearer token from the `accessToken` cookie, 401 → clear cookies and redirect to `/login`. Build new composables on `apiClient`; keep Vuexy `useApi` for template demos only.
|
||||
`apps/app/src/lib/api-client.ts` and `apps/portal/src/lib/api-client.ts` share the same pattern: `VITE_API_URL` base, Bearer token from the `accessToken` cookie, 401 → clear cookies and redirect to `/login`. Build new composables on `apiClient`; keep Vuexy `useApi` for template demos only.
|
||||
|
||||
---
|
||||
|
||||
@@ -214,13 +200,10 @@ make services
|
||||
# Tab 2: Laravel API
|
||||
make api
|
||||
|
||||
# Tab 3: Admin SPA (optional)
|
||||
make admin
|
||||
|
||||
# Tab 4: Organizer SPA (optional)
|
||||
# Tab 3: Organizer SPA (optional)
|
||||
make app
|
||||
|
||||
# Tab 5: Portal SPA (optional)
|
||||
# Tab 4: Portal SPA (optional)
|
||||
make portal
|
||||
```
|
||||
|
||||
@@ -267,7 +250,7 @@ Check `api/config/cors.php` allows your frontend origins.
|
||||
|
||||
### Vuexy TypeScript Errors
|
||||
```bash
|
||||
cd apps/admin
|
||||
cd apps/app
|
||||
pnpm install
|
||||
pnpm type-check
|
||||
```
|
||||
@@ -278,7 +261,7 @@ pnpm type-check
|
||||
|
||||
1. Services running (Docker)
|
||||
2. Laravel API configured and migrated
|
||||
3. SPAs installed (`apps/admin`, `apps/app`, `apps/portal`)
|
||||
3. SPAs installed (`apps/app`, `apps/portal`)
|
||||
4. Environment files for API + each SPA
|
||||
5. Authentication and organisation switching
|
||||
6. Events, sections, time slots, shifts
|
||||
|
||||
@@ -53,8 +53,7 @@ crewli/ # Monorepo root
|
||||
│ │ └── seeders/
|
||||
│ └── tests/Feature/Api/V1/ # PHPUnit feature tests per controller
|
||||
├── apps/
|
||||
│ ├── admin/ # Super Admin SPA (Vuexy)
|
||||
│ ├── app/ # Organizer SPA (Vuexy) -- HOOFDAPP
|
||||
│ ├── app/ # Organizer + Platform Admin SPA (Vuexy) -- HOOFDAPP
|
||||
│ └── portal/ # Externe portals (vrijwilliger, artiest, leverancier)
|
||||
├── docs/ # Design document, API docs, ERD
|
||||
│ ├── design-document.md
|
||||
@@ -91,7 +90,7 @@ php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvid
|
||||
php artisan vendor:publish --provider="Spatie\LaravelActivitylog\ActivitylogServiceProvider"
|
||||
```
|
||||
|
||||
**Frontend — alle apps (apps/app/, apps/admin/, apps/portal/)**
|
||||
**Frontend — alle apps (apps/app/, apps/portal/)**
|
||||
|
||||
```bash
|
||||
# TanStack Query voor API state management
|
||||
@@ -103,7 +102,7 @@ npm install vee-validate zod @vee-validate/zod
|
||||
# Drag-and-drop (form builder, timetable, prioriteitsranking)
|
||||
npm install vuedraggable@next
|
||||
|
||||
# In apps/app/ en apps/admin/ ook:
|
||||
# In apps/app/ ook:
|
||||
npm install @fullcalendar/vue3 @fullcalendar/timeline @fullcalendar/resource-timeline
|
||||
```
|
||||
|
||||
@@ -138,8 +137,7 @@ Design Document: /resources/design/design-document.md
|
||||
|
||||
## Repository Structuur
|
||||
- api/ Laravel backend
|
||||
- apps/app/ Organizer SPA (hoofdapp)
|
||||
- apps/admin/ Super Admin SPA
|
||||
- apps/app/ Organizer + Platform Admin SPA (hoofdapp, super admin onder /platform/*)
|
||||
- apps/portal/ Externe portals (vrijwilliger, artiest, leverancier)
|
||||
|
||||
## Backend Regels (STRIKT VOLGEN)
|
||||
|
||||
@@ -12,12 +12,12 @@ Dit is de volledige, vastgestelde architectuur van Crewli. Alle beslissingen hie
|
||||
|
||||
### 1.1 Systeemoverzicht
|
||||
|
||||
| **apps/admin/** | **apps/app/** | **apps/portal/** |
|
||||
|---|---|---|
|
||||
| Super Admin SPA | Organizer SPA | Portal SPA |
|
||||
| **apps/app/** | **apps/portal/** |
|
||||
|---|---|
|
||||
| Organizer + Platform Admin SPA | Portal SPA |
|
||||
|
||||
Vuexy + Vue 3 + TypeScript | Pinia + TanStack Query | Axios → CORS → Sanctum Token
|
||||
Alle drie apps zijn Vue 3 SPA's — Vuexy template — communiceren uitsluitend via REST API
|
||||
Beide apps zijn Vue 3 SPA's — Vuexy template — communiceren uitsluitend via REST API
|
||||
|
||||
**api/ — Laravel 12 REST API (ENIGE backend — geen Blade views)**
|
||||
PHP 8.2 | Sanctum | Spatie Permission | MySQL 8 | Redis | Queue Workers
|
||||
@@ -35,16 +35,14 @@ PHP 8.2 | Sanctum | Spatie Permission | MySQL 8 | Redis | Queue Workers
|
||||
| **App / Laag** | **Technology** | **Gebruik & verantwoordelijkheid** |
|
||||
|----|----|----|
|
||||
| api/ | Laravel 12 + Sanctum | REST API, authenticatie, business logic, database, queue workers, e-mail, PDF-generatie. Geen enkele HTML pagina. |
|
||||
| apps/admin/ | Vue 3 + Vuexy (vol) | Super Admin SPA: organisations beheren, billing, platform-gebruikers. Klein en eenvoudig. |
|
||||
| apps/app/ | Vue 3 + Vuexy (vol) | Organizer SPA: de hoofdapp. Events, shifts, persons, artists, briefings, Mission Control. 90% van je werk. |
|
||||
| apps/app/ | Vue 3 + Vuexy (vol) | Organizer + Platform Admin SPA: de hoofdapp. Events, shifts, persons, artists, briefings, Mission Control. Super admin functionaliteit onder `/platform/*` routes. |
|
||||
| apps/portal/ | Vue 3 + Vuexy (gestript) | Portal SPA: twee toegangsmodi. Login voor vrijwilligers/crew. Token voor artiesten/leveranciers/pers. |
|
||||
|
||||
### 1.3 Vuexy — waar en hoe
|
||||
|
||||
| **App / Laag** | **Technology** | **Gebruik & verantwoordelijkheid** |
|
||||
|----|----|----|
|
||||
| apps/admin/ | Vuexy volledig | Admin template ongewijzigd: sidebar, dark mode, customizer. Weinig aanpassingen nodig. |
|
||||
| apps/app/ | Vuexy volledig | Sidebar nav aanpassen voor Crewli-structuur. Customizer/demo-componenten verwijderen. Full Vuetify component gebruik. |
|
||||
| apps/app/ | Vuexy volledig | Sidebar nav aanpassen voor Crewli-structuur. Customizer/demo-componenten verwijderen. Full Vuetify component gebruik. Super admin functionaliteit onder `/platform/*` routes. |
|
||||
| apps/portal/ | Vuexy gestript | Geen sidebar nav, geen customizer, geen dark mode toggle. Wel: Vuetify componenten, Vuexy SCSS variabelen, Vuexy fonts. Eigen layout: top-bar met event-logo + naam. Mobile-first. |
|
||||
|
||||
### 1.4 Portal: twee toegangsmodi
|
||||
@@ -109,11 +107,11 @@ Route::prefix('v1')->group(function () {
|
||||
|
||||
> **LET OP — CORS**
|
||||
>
|
||||
> Laravel CORS config (config/cors.php) moet drie origins toestaan:
|
||||
> Laravel CORS config (config/cors.php) moet twee origins toestaan:
|
||||
>
|
||||
> admin.crewli.app | app.crewli.app | portal.crewli.app
|
||||
> crewli.app | portal.crewli.app
|
||||
>
|
||||
> In development: http://localhost:5173 | :5174 | :5175
|
||||
> In development: http://localhost:5174 | :5175
|
||||
|
||||
## 2 — Actielijst: Wat Je Nu Doet
|
||||
|
||||
@@ -187,17 +185,16 @@ Een centrale axios instance — dubbele laag verwijderen
|
||||
|
||||
- ☐ Verwijder daarna: src/lib/api-client.ts en src/utils/api.ts
|
||||
- ☐ Hernoem src/composables/useApi.ts → src/composables/useApiHelpers.ts (algemene helpers)
|
||||
- ☐ Doe hetzelfde voor apps/portal/ en apps/admin/ (zelfde patroon)
|
||||
- ☐ Doe hetzelfde voor apps/portal/ (zelfde patroon)
|
||||
|
||||
### Stap 3 — TanStack Query installeren **NU**
|
||||
|
||||
Ontbreekt nog — vereist voor alle API state management
|
||||
|
||||
- ☐ **Installeer in alle drie apps (app/, admin/, portal/)**
|
||||
- ☐ **Installeer in beide apps (app/, portal/)**
|
||||
|
||||
```sh
|
||||
cd apps/app && pnpm add @tanstack/vue-query
|
||||
cd ../admin && pnpm add @tanstack/vue-query
|
||||
cd ../portal && pnpm add @tanstack/vue-query
|
||||
```
|
||||
|
||||
@@ -216,7 +213,7 @@ Ontbreekt nog — vereist voor alle API state management
|
||||
})
|
||||
```
|
||||
|
||||
- ☐ Installeer ook formuliervalidatie (alle apps)
|
||||
- ☐ Installeer ook formuliervalidatie (beide apps)
|
||||
|
||||
```sh
|
||||
pnpm add vee-validate zod @vee-validate/zod
|
||||
@@ -251,12 +248,11 @@ Spatie packages zijn vereist voor fase 1
|
||||
# Registreer in bootstrap/app.php als 'portal.token'
|
||||
```
|
||||
|
||||
- ☐ Update config/cors.php voor drie frontend origins
|
||||
- ☐ Update config/cors.php voor twee frontend origins
|
||||
|
||||
```php
|
||||
// config/cors.php
|
||||
'allowed_origins' => [
|
||||
env('FRONTEND_ADMIN_URL', 'http://localhost:5173'),
|
||||
env('FRONTEND_APP_URL', 'http://localhost:5174'),
|
||||
env('FRONTEND_PORTAL_URL','http://localhost:5175'),
|
||||
],
|
||||
@@ -285,9 +281,9 @@ CLAUDE.md, .cursorrules, docs/ — dit is het belangrijkste wat je doet
|
||||
- Login-based (auth:sanctum): vrijwilligers, crew — persons met user_id
|
||||
- Token-based (portal.token middleware): artiesten, leveranciers, pers — persons zonder user_id
|
||||
|
||||
- apps/ mapping: admin/ = Super Admin, app/ = Organizer, portal/ = Externe gebruikers
|
||||
- apps/ mapping: app/ = Organizer + Platform Admin (super admin via /platform/*), portal/ = Externe gebruikers
|
||||
|
||||
- CORS: drie origins configureren in zowel Laravel als Vite dev server
|
||||
- CORS: twee origins configureren in zowel Laravel als Vite dev server
|
||||
|
||||
### Stap 6 — Vite dev ports configureren **NU**
|
||||
|
||||
@@ -296,7 +292,6 @@ Elk frontend-app een eigen port zodat CORS werkt
|
||||
- ☐ **Pas vite.config.ts aan in elke app**
|
||||
|
||||
```ts
|
||||
// apps/admin/vite.config.ts → port: 5173
|
||||
// apps/app/vite.config.ts → port: 5174
|
||||
// apps/portal/vite.config.ts → port: 5175
|
||||
server: {
|
||||
@@ -440,12 +435,12 @@ Na werkende apps/app/ basis
|
||||
| **1** | apps/band/ hernoemd naar apps/portal/ | ☐ Klaar |
|
||||
| **2** | Demo-rommel verwijderd uit apps/app/ | ☐ Klaar |
|
||||
| **3** | Dubbele API-laag opgeruimd → een src/lib/axios.ts per app | ☐ Klaar |
|
||||
| **4** | TanStack Query geinstalleerd in alle drie apps + geregistreerd in main.ts | ☐ Klaar |
|
||||
| **5** | VeeValidate + Zod geinstalleerd in alle drie apps | ☐ Klaar |
|
||||
| **4** | TanStack Query geinstalleerd in beide apps + geregistreerd in main.ts | ☐ Klaar |
|
||||
| **5** | VeeValidate + Zod geinstalleerd in beide apps | ☐ Klaar |
|
||||
| **6** | Spatie packages geinstalleerd in api/ + configs gepubliceerd | ☐ Klaar |
|
||||
| **7** | PortalTokenMiddleware skeleton aangemaakt | ☐ Klaar |
|
||||
| **8** | config/cors.php: drie frontend origins geconfigureerd | ☐ Klaar |
|
||||
| **9** | Vite dev ports: admin=5173, app=5174, portal=5175 | ☐ Klaar |
|
||||
| **8** | config/cors.php: twee frontend origins geconfigureerd | ☐ Klaar |
|
||||
| **9** | Vite dev ports: app=5174, portal=5175 | ☐ Klaar |
|
||||
| **10** | .env.local aangemaakt per app met VITE_API_URL | ☐ Klaar |
|
||||
| **11** | CLAUDE.md aangemaakt en volledig ingevuld (Dev Guide sectie 3.1 + portal architectuur) | ☐ Klaar |
|
||||
| **12** | .cursorrules aangemaakt (Dev Guide sectie 3.2) | ☐ Klaar |
|
||||
|
||||
Reference in New Issue
Block a user