npm 11 (local) dedupe y omitía un typescript@5.9.3 anidado que npm 10.9.4
(el de EAS Build) exige, provocando `npm ci` EUSAGE "out of sync" y el fallo
en la fase Install dependencies. Regenerado con npm@10.9.4 para paridad.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Las plantillas solo llegaban a local en el bundle al abrir un proyecto
online. Ahora, al cargar la lista de proyectos con conexión, se prefetchan
TODAS las plantillas accesibles (GET /templates, antes sin usar) y se
guardan en local, para poder inspeccionar offline aunque el proyecto no se
haya abierto todavía. Tolerante a fallo: no bloquea la lista.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
El backend devuelve el modelo completo (toArray) en un conflicto: incluye
geometry como array y columnas inexistentes en local (uuid, created_at,
deleted_at, client_updated_at...). Volcarlo tal cual en SQLite lanzaba
"no such column"/error de bind y abortaba el ciclo de sync entero ante
cualquier edición concurrente. Ahora se proyecta por los mismos pick* del PULL.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auditoría de exports sin uso:
- Eliminados: getPhases, getLayers, getTemplate, countRows (repositories),
setCursor (redundante: applyBundle escribe el cursor por SQL), y la
constante TOKEN_ABILITY (config). getPhases/getTemplate quedaron huérfanos
al quitar la pestaña Fases y cambiar el selector de plantillas.
- purgeSentOperations existía pero NADIE la llamaba (el outbox acumulaba
filas 'sent' sin límite): ahora runSync la invoca al final del ciclo.
Sin mocks, TODOs ni simulaciones en el código. Typecheck limpio.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- pushMedia sube en lotes de 3 en paralelo (Promise.all por chunk) en vez
de una a una; contadores del report seguros al ser el runtime monohilo.
- SyncStatusBar: fondo rojo cuando hay conflictos/errores (prioridad sobre
el estado de conexión), para que el problema salte a la vista.
- ProjectDetail: el auto-sync silencioso ahora avisa una vez con Alert
cuando un ciclo produce conflictos/errores, con acceso directo a la cola.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Elimina recordProgressUpdate (quedó huérfano al quitar la pestaña Fases;
el progreso se edita vía feature.update) y initialPull (redundante).
- ProjectsScreen: al abrir un proyecto siempre runSync — su fase de pull ya
resuelve snapshot (sin cursor) y delta (con cursor), y el outbox está vacío
la primera vez. Menos ramas, misma semántica.
- client.ts: AbortController con timeout (30s JSON / 120s multipart) y
NetworkError que distingue timeout de error de red genérico.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Los botones (nueva incidencia, nueva inspección, editar, subir foto) se
ocultaban a usuarios Admin: el backend los autoriza vía el bypass de
super-admin (Gate::before → 'manage all'), pero el rol Admin no tiene los
permisos granulares (create issues, create inspections, edit issues,
upload media, view issues) asignados explícitamente, así que /me no los
devolvía. hasPermission ahora trata 'manage all' como comodín.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- ProjectDetail: pestañas reducidas a Features | Incidencias (Features por
defecto); PhasesSection eliminada.
- InspectionForm en dos pasos: 1) selector de plantillas asignadas al
proyecto (la de la feature marcada como sugerida ★, opción de inspección
libre), 2) formulario dinámico. Enlace "Cambiar plantilla" para volver.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- config.ts: BASE_URL/ORIGIN dejan de ser constantes; ahora hay
setServerOrigin/getBaseUrl/getServerOrigin con normalizeServerUrl
(añade http:// si falta, quita barras finales y el sufijo /api/v1).
- client.ts: construye las URLs con getBaseUrl() en cada petición.
- session: signIn recibe la URL, la fija antes del login y la persiste
en SecureStore (clave server_url); se rehidrata al arrancar junto al token.
- LoginScreen: campo "Servidor" precargado con el último valor usado.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /projects responde { "projects": [...] } (ProjectApiController@index),
pero normalize() solo contemplaba un array o { data } → siempre [].
Ahora normalize acepta {projects}/{data}/array, los tipos de listProjects
y getTemplates reflejan la envoltura real ({projects}/{templates}), y el
fallback offline loguea el motivo en vez de tragarse el error.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- feature_types: nueva tabla local + tipo FeatureType + upsert en applyBundle
+ getFeatureTypes(); FeatureDetail muestra badge del tipo con su color.
- feature: columnas feature_type_id + is_active (migración BD v3);
feature.update acepta ambas; toggle "Activa" en el detalle con badge
"inactiva" cuando corresponde.
- templates: ahora catálogo global asignado por pivot — getTemplates() ya no
filtra por project_id (informativo); phase_id eliminado del tipo y del pick.
- Formulario de inspección: soporta fields[].group (secciones), question
(etiqueta principal), help (texto de ayuda) y required (validación al
guardar con aviso de campos faltantes).
- Bundle: tipa issue_tasks correctamente como IssueTask[].
- docs/: sincronizados openapi.yaml y MOBILE_APP_BRIEF.md v1.1 del backend.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- app.json: bundleIdentifier + buildNumber para iOS
- eas.json: perfiles iOS (development con simulador, preview ipa, production)
y appleId para submit
- app.config.js: inyección de GOOGLE_MAPS_IOS_KEY (opcional; por defecto
la app usa Apple Maps en iOS sin necesitar key)
- FeatureMap: MAP_PROVIDER = PROVIDER_GOOGLE en Android, PROVIDER_DEFAULT
(Apple Maps) en iOS; elimina dependencia de Google Maps key en iOS
Pendiente: generar /ios con 'npx expo prebuild --platform ios' desde macOS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Elimina /android del .gitignore y committea el resultado de
expo prebuild --platform android (Gradle, AndroidManifest, MainActivity,
recursos de icono/splash). Android Studio puede abrirlo directamente
desde la carpeta android/ sin necesidad de ejecutar prebuild.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
expo prebuild actualiza los scripts a expo run:android / expo run:ios
para compilar el proyecto nativo directamente.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- FooterOverlay: franja oscura (logo izquierda, campos derecha) superpuesta
sobre la foto antes de encolarla; tamaños proporcionales a la resolución.
- MediaStrip: capta coordenadas GPS (expo-location) al abrir el picker,
estampa el footer con react-native-view-shot (view off-screen + onLoad),
y añade icono ⚙ → PhotoSettings. Fallback: usa foto original si el stamp falla.
- PhotoSettingsScreen (modal): toggle general, selector de logo cuadrado,
activar/desactivar/editar etiqueta de cada campo (proyecto, fecha, coords)
y añadir campos personalizados con etiqueta + valor estático.
- footerConfig: persiste en meta table (clave 'photo_footer_config').
- repositories: añade getProject(id).
- navigation: ruta PhotoSettings como modal.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Elimina la sección "Pendiente" del scaffold inicial (ya todo implementado)
y la sustituye por tabla de estado con referencia a cada archivo, más la
lista real de próximos pasos (Maps key, test en dispositivo, background sync).
También añade .idea/ al .gitignore.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fase 0: config Android (package, permisos, orientación), eas.json (APK), deps
nativas (react-native-maps, image-picker, location), app.config.js para la key
de Google Maps por secreto EAS.
Fase 1: capa responsive (useLayout) + componente MasterDetail (dos paneles en
tablet, navegación en móvil).
Fase 2: pantallas funcionales — detalle de proyecto con secciones Fases/Features/
Incidencias, edición de progreso/estado, formulario de inspección dinámico
desde plantilla, incidencias maestro-detalle (checklist + comentarios), alta de
incidencia; gating por permisos Spatie.
Fase 3: fotos (cámara/galería) → cola de media, con miniaturas pendientes/sync.
Fase 4: mapa de features (Google Maps) con geometría GeoJSON y selección.
Fase 5: auto-sync (foreground/reconexión/intervalo, con candado) + reconciliación
de creaciones offline (id temporal negativo → server_id, remapeo de FKs hijas).
Fase 6: revisión de conflictos/errores del outbox, indicadores y APK preview.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Capa API tipada de los 8 endpoints, BD local espejo del bundle + outbox
(operaciones y media) + cursor de sync, motor runSync (PUSH /sync ->
PUSH /media -> PULL bundle?since) con idempotencia por uuid y last-write-wins,
mutaciones de alto nivel (write local + encolar), sesion con token en
SecureStore, conectividad NetInfo y UI minima (Login -> Proyectos -> Detalle).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>