Diagnóstico (reproducido contra el servidor de pruebas con curl):
- POST /livewire/update (_startUpload) genera la URL firmada correcta:
https://avantee.duckdns.org/livewire/upload-file?expires=...&signature=...
- POST inmediato a esa misma URL → 401. La firma se valida contra la URL que
Laravel RECONSTRUYE de la petición entrante; en esa ruta el proxy no le hace
llegar X-Forwarded-Proto, Laravel percibe http:// y la firma no cuadra.
- Livewire muestra entonces el genérico "The uploadFile failed to upload".
Fix: middleware ForceHttpsScheme (prepend, antes de TrustProxies): si APP_URL
empieza por https://, fija X-Forwarded-Proto=https y X-Forwarded-Port=443 en
todas las peticiones. Con trustProxies('*') ya activo, generación y validación
de firmas usan siempre el mismo scheme. En local/tests (APP_URL http) no hace nada.
Nota servidor: git pull && php artisan config:clear && php artisan config:cache.
Sigue siendo recomendable client_max_body_size 60m en OpenResty para KML grandes.
Suite 94 passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sin trustProxies, la app tras un proxy HTTPS (OpenResty/Nginx) genera URLs con
http://, y las cookies "secure" no viajan → 419 en /livewire/update. Añadido
$middleware->trustProxies(at: '*') con los headers X-Forwarded-*.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Milestone 1 (auth foundation):
- Installed laravel/sanctum; HasApiTokens on User; published config + migration.
- routes/api.php with /api/v1; Sanctum 'ability' middleware alias registered.
- AuthController: POST login (long-lived revocable device token w/ ability
mobile-sync + devices table), GET me, POST logout. New Device model/table.
Milestone 2 (vertical slice, offline-first):
- progress_updates: +uuid (client-generated) +client_updated_at.
- ProjectApiController: GET projects (accessibleBy), GET projects/{id}/bundle
(project/phases/layers/features, membership-authorized).
- SyncController: POST sync — batch ops, idempotent by uuid, per-op result
(applied/duplicate/error), server-set user_id, authz by permission+membership.
Currently handles progress_update.create.
Tests: tests/Feature/Api/MobileApiTest (9 passing) — auth, accessible projects,
bundle authz, sync apply+idempotency, permission enforcement.
Also fixed a latent schema bug: projects.reference (and external_reference_1)
existed in the live DB but had no migration — added a guarded migration so fresh
installs match production.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Login authenticated fine but the landing page crashed (so it looked like
'login doesn't work'):
- bootstrap/app.php didn't register Spatie's middleware aliases -> any route
with role:/permission: threw 'Target class [role] does not exist'.
Registered role / permission / role_or_permission.
- config/livewire.php absent -> default layout is the non-existent
components.layouts.app. ProjectList, PhaseProgress and ReportsDashboard
lacked #[Layout('layouts.app')] -> MissingLayoutException. Added it (the
other 10 routed components already had it).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>