- FeatureTable: dispatch { featureId } object instead of raw ID
- ProjectMap: selectFeature listener accepts both formats (direct ID or { featureId })
- project-map.blade.php: move selectFeature inside livewire:init handler so Livewire.emit is available
- Added logging for debugging
Fixes: 'Livewire.emit is not a function' on map click and 'Only arrays and Traversables can be unpacked' on table button
El importador de plantillas solo parseaba name/label/type/required/options/
min/max/step, dejando fuera group (sección), question (pregunta corta) y help
(ayuda) que el builder manual sí soporta.
- Nuevo orden de columnas: group,name,label,question,type,required,options,min,max,step,help
- parseRows() rellena las 11 claves (coincide con addField()).
- readFileRows() ya no descarta filas por la 1ª columna (ahora es `group`, que
puede ir vacía); filtra por "fila con algún contenido" y parseRows descarta
las que no tengan `name`.
- CSV de ejemplo actualizado (con BOM UTF-8) y con filas que muestran group/
question/help/select.
- Modal de importación: texto de columnas y tabla de preview muestran Grupo y
Pregunta.
Tests: nuevo test csv_import_parses_group_question_and_help. Suite 95 passing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Nueva InspectionTemplatesTable (DataTableComponent): columnas Plantilla,
Descripción, Campos, Proyectos (uso) y Acciones; filtros en cabecera por nombre,
descripción y uso (en uso / sin uso). Gateada por manage templates.
- GlobalTemplateManager: el listado HTML se sustituye por la tabla embebida.
Acciones Editar/Borrar viajan por eventos (template-edit/template-delete);
el manager emite templates-changed al guardar/borrar/importar para que la tabla
se refresque (#[On('templates-changed')]).
Tests: GlobalTemplatesTest amplía con tabla (render + permiso, evento edit). Suite 91 passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Migración: tabla pivot inspection_template_project; drop de phase_id (asociación
a fase descartada); project_id se mantiene en inspection_templates por compat.
Migra automáticamente las plantillas existentes (project_id → pivot).
- Modelos: Project::inspectionTemplates() ↔ InspectionTemplate::projects() (BTM);
retirada la relación phase() de InspectionTemplate.
- GlobalTemplateManager (nuevo, ruta /inspection-templates, permiso manage templates):
catálogo único global, CRUD + import CSV; sin asociación a fase ni a proyecto.
- ProjectTemplatesPicker (nuevo, ruta projects.templates, permiso edit projects):
lista global con checkbox para asignar/desasignar plantillas al proyecto.
- ProjectMap: el selector de plantillas del mapa lee SOLO las asignadas al proyecto
vía pivot. API móvil (bundle + /templates) adaptado al pivot.
- Eliminado el viejo TemplateManager por-proyecto, su vista wrapper y la tabla
ImportTemplatesTable (ya no aplica: todas son globales).
- Acceso "Plantillas" añadido al menú principal (gate manage templates).
Tests: GlobalTemplatesTest (4). Suite 89 passing.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sustituye el modal (proyecto + checkboxes) por una tabla Rappasoft:
- ImportTemplatesTable lista todas las plantillas de proyectos accesibles (excluye el
destino), con filtros en cabecera (nombre, proyecto) y checkbox de selección (bulk).
- Acción masiva "Importar seleccionadas" copia al proyecto destino (dedupe por nombre)
y avisa a TemplateManager por evento (templates-imported) para refrescar/cerrar.
- TemplateManager: eliminada la lógica vieja (importProjectId/importableTemplates/
selectedImportTemplateIds/importFromProject); el modal embebe la tabla.
Tests: TemplateImportTest adaptado (selección+import, excluye destino). Suite 92 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Parte 2 del bloque de plantillas/inspecciones:
- Formulario de inspección (mapa): campos agrupados por sección, muestra la
"pregunta" del campo (con la etiqueta como subtexto) y la ayuda; al final,
apartado de Comentarios (notes) y subida de Fotos (media en la inspección).
- ProjectMap: WithFileUploads + inspectionPhotos; saveInspection adjunta las fotos
como media; Inspection gana relación media().
- Visor de inspección: datos agrupados por sección con pregunta/valor, comentarios
y galería de fotos.
Tests: InspectionFormTest (registra inspección con comentarios + foto). Suite 91 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Builder de plantillas (parte 1 del bloque):
- Cada campo admite "Grupo / sección" (título), "Pregunta / revisar" (texto corto,
tras la etiqueta) y "Comentarios / ayuda" (texto largo, al final).
- Plantillas híbridas: toggle "Global" → project_id null; el listado de un proyecto
muestra sus plantillas + las globales (badge "Global").
Tests: TemplateCreationTest (grupo/pregunta/ayuda persisten; global sin proyecto y
visible en otros proyectos). Suite 90 passing.
Pendiente (parte 2): adaptar el formulario de inspección (grupos, comentarios, fotos)
y el visor de inspección.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Migración: tabla feature_types + columnas feature_type_id (FK) e is_active en features.
Modelo FeatureType; Feature gana featureType() + casts is_active.
- Catálogo de tipos (FeatureTypeManager, ruta /feature-types): CRUD con modal
(nombre, descripción, color), contador de usos; gateado por edit layers.
- Editor de elementos del proyecto (FeatureManager, ruta projects.features):
tabla Rappasoft ProjectFeaturesTable (filtros nombre/capa/tipo en cabecera),
toggle activo/inactivo y borrado individual; modal para editar nombre/tipo/activo.
- Acceso: botón "Elementos" en el dashboard del proyecto (edit layers) y enlace a
"Tipos de elemento" desde el editor.
Tests: FeatureManagementTest (6). Suite 87 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Usa la cabecera secundaria de Rappasoft (setSecondaryHeaderEnabled + secondaryHeaderFilter):
- Elementos: Elemento (texto), Capa (select), Fase (select).
- Inspecciones: Fecha (date), Elemento (texto), Resultado (select), Usuario (select);
Plantilla sin filtro.
Tests: MapTablesTest amplía con filtro de capa funcional. Suite 75 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- FeatureTable e InspectionTable (DataTableComponent) sustituyen las tablas HTML
de las pestañas "Elementos" e "Inspecciones" del mapa: búsqueda, orden, filtro
(progreso) y acciones.
- Selección de elemento e "ver inspección" se comunican al ProjectMap por eventos
(map-select-feature / map-view-inspection, vía #[On]); seleccionar abre el panel
de edición y centra el mapa igual que antes.
- Las relaciones requieren sus FKs en additionalSelects (layer_id / feature_id,
template_id, user_id) porque Rappasoft no selecciona '*'.
Tests: MapTablesTest (3). Suite 74 passing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- app/Livewire: 34 componentes agrupados en Issues/, Projects/, Phases/,
Companies/, Users/, Admin/, Inspections/, Layers/, Media/, Common/
(Client/, Reports/, Forms/, Actions/ ya estaban). Namespaces actualizados.
- resources/views/livewire: vistas sueltas movidas a subcarpetas espejo
(companies/, users/, phases/, roles/, inspections/, media/, common/);
render() actualizado.
- Referencias actualizadas sin romper nada: rutas (FQN, nombres de ruta intactos),
tags <livewire:...>/@livewire() a alias con punto, y use de los tests.
- No tocado: Volt de Breeze (auth/profile/navigation), y el portal cliente
(user-nav/client-projects) que ya tenía referencias inconsistentes.
Verificado: 69 rutas OK, vistas compilan, suite 69 passing (solo 2 pre-existentes
sqlite). autoload regenerado con --ignore-platform-reqs (PHP 8.2).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Permiso 'assign companies' propio (antes empresas reutilizaba 'assign users');
concedido a los roles que ya tenían 'assign users'.
- ProjectUsersTable y ProjectCompaniesTable (Rappasoft): búsqueda, filtro por rol,
cambio de rol en línea y quitar; gateadas por assign users / assign companies.
- ProjectUsers/ProjectCompanies quedan como contenedor (form de asignación) que
embebe la tabla y refresca el desplegable vía eventos.
- Unificadas confirmaciones (wire:confirm) y notificaciones (dispatch notify).
Tests: ProjectAssignmentsTest (4). Suite 69 passing (solo 2 pre-existentes sqlite).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- PhaseList pasa a contenedor: botón "Agregar fase" + modal crear/editar con todos
los parámetros (nombre, descripción, orden, color, progreso, fechas previstas y
reales) y validación. Antes "Agregar fase" creaba directamente 'Nueva fase'.
- PhaseTable (Rappasoft): orden, nombre+descripción, barra de progreso, fechas,
color y acciones (editar abre el modal vía evento, actualizar progreso, eliminar);
búsqueda y ordenación. Gateado por 'manage phases' + acceso al proyecto.
Tests: PhaseManagementTest (4). Suite 65 passing (solo 2 pre-existentes sqlite).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Issue::TYPES + typeLabels() (ES) + accessors type_label/type_color; columna type
(string, default 'other') + fillable.
- IssueForm: select "Tipo de incidencia" con validación/carga/guardado.
- IssueTable: columna Tipo (badge) + SelectFilter por tipo.
- IssueDetail: badge de tipo en la cabecera.
- Sync offline: issue.create/update aceptan type; bundle (mapIssue) lo incluye.
Tests: IssuesEnhancementsTest (create muestra el campo vía HTTP, edición persiste) +
MobileApiTest (create con type). Suite 61 passing (solo 2 pre-existentes sqlite).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Campo "Idioma por defecto" al crear/editar usuario (columna locale ya existente),
como desplegable Alpine con banderas SVG reales (no emoji, que en Windows se ven
como "ES"/"GB") servidas localmente: public/images/flags/{es,gb}.svg.
- User: locale añadido a fillable. UserForm: propiedad/validación/guardado de locale.
- LanguageSwitcher de la cabecera usa las mismas banderas SVG.
- Regla CSS [x-cloak] en el layout para evitar parpadeo de desplegables Alpine.
Tests: UserLocaleTest (2) — crear/editar persisten el idioma.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Notificaciones (DB): asignación de incidencia (IssueAssigned), asignación de tarea
(IssueTaskAssigned), comentario (IssueCommented) y cambio de estado
(IssueStatusChanged) a reporter+asignado excluyendo al actor.
- Plantillas de checklist: tabla issue_checklist_templates + modelo, gestor CRUD
(IssueChecklistManager, ruta projects.issues.checklists) y "Aplicar plantilla" en
el detalle (alta masiva de tareas).
- Alertas de vencimiento: columna overdue_notified_at + scope overdue, comando
issues:notify-overdue (programado a diario) que avisa al asignado una sola vez;
badge "vencidas" en la tabla y resaltado por tarea en el detalle.
- Reporte desde el mapa: botón "Incidencia" en el panel del feature seleccionado →
formulario con feature pre-vinculado (IssueForm lee ?feature=).
Tests: IssuesEnhancementsTest (7). Suite 57 passing (solo 2 pre-existentes sqlite).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Web:
- IssueTask + IssueComment (modelos, migraciones, soft-deletes, campos de sync).
Issue gana tasks()/comments() y accessor de % de avance derivado de tareas.
- IssueDetail (página): checklist con asignado/fecha límite/progreso, hilo de
comentarios con foto por comentario, galería de fotos de la incidencia y flujo
de verificación open→in_review→resolved/closed (+reabrir) con notas.
- Creación/edición en páginas propias (IssueForm), sin modal; al guardar redirige
al detalle. Rutas projects.issues.create/edit/show.
- Listado con tabla Rappasoft (IssueTable): filtros por estado/prioridad, búsqueda,
barra de progreso y acciones por fila gateadas por permisos; IssueManager queda
como contenedor (cabecera + stats) que embebe la tabla.
- Seguridad: pertenencia al proyecto + permisos por acción (view/create/edit/delete
issues, upload/delete media) en todos los componentes.
API móvil (offline):
- /sync: issue_task.create/update y issue_comment.create (idempotente, LWW).
- /media: parent_entity issue_task / issue_comment.
- bundle + tombstones incluyen issue_tasks / issue_comments.
- openapi.yaml + MOBILE_SYNC_PROTOCOL.md actualizados.
Tests: MobileApiTest 23 passing (+5); IssuesTablePageTest (3) smoke de la tabla.
Branding: logo RTE International — MAI Group (public/images/logo-rte.png) en login
y navegación; application-logo pasa de SVG por defecto a <img>.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Finishes Phase 2: the /admin route group no longer requires 'manage all'
globally. Each route is gated by its specific permission so a non-super-admin
role can be granted partial admin access:
- /admin/users (+show) -> can:view users; create -> can:create users;
edit -> can:edit users
- /admin/roles, roles/*, permissions -> can:manage roles
- Aligned the role screens' mount checks (RoleForm/RoleView/RolePermissionManager)
from 'manage all' to 'manage roles'.
- Nav 'Administrator' link now shows on can('view users').
Admins keep full access via Gate::before (manage all). Closure routes
(users/roles lists) are now protected at the route level.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Permissions now actually govern access instead of the hard-coded Admin role:
- Super-admin bypass (see all projects / full access) -> can('manage all')
in Project::scopeAccessibleBy, ProjectMap, ProjectDashboard, PhaseGantt,
LayerManager, ProjectReportController.
- Redundant '|| hasRole(Admin)' fallbacks dropped (Gate::before already lets
manage-all through can()): LayerManager (upload/delete layers), MediaManager
(upload), ProjectMap (update progress), ProjectUsers/ProjectCompanies
(assign users).
- Admin-only screens now gated by the matching permission: AdminUsers/UserView
-> can('view users'), UserForm -> can('create users')|can('edit users'),
CompanyView -> can('view companies').
- MediaManager delete: can('delete media') OR owner.
- Kept UserForm's domain guard (can't remove your own Admin role).
Note: the /admin route group still has middleware can:manage all, so admin
screens stay super-admin-only until that group is relaxed per-route.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New 'Ficha' tab (first, default) on the user view: basic info card
(name/username/email/phone/address/member since) plus the 'Validez de acceso'
card and the Empresa card, moved here from the Permissions tab. The Permissions
tab now focuses on roles + the direct-permissions form.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1. Role view (Details tab): a small form to add users to the role (select of
users not yet in the role + Add) and a per-row remove button. Uses
assignRole/removeRole.
2. User view (Permissions tab): the same grouped, collapsible permissions form
with switches — operating on the user's DIRECT permissions
(givePermissionTo/revokePermissionTo). Permissions inherited from a role show
as checked+disabled with a 'from role' tag; per-group All/None too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Permissions tab in the role view:
1. Each section is now a collapsible card (Alpine, chevron rotates).
2. Section header has 'All' / 'None' buttons (setGroup grants/revokes every
permission of that group for the role; Admin keeps 'manage all').
3. Permissions render in a single column: name+description on the left, control
on the right.
4. Controls are DaisyUI toggle switches.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Migration: add 'group' and 'description' columns to the permissions table.
- PermissionCatalogSeeder (idempotent updateOrCreate): full catalogue across 11
sections — Proyectos, Fases y progreso, Capas y elementos, Inspecciones,
Incidencias, Empresas, Usuarios, Roles, Informes, Archivos, General. Sets
group + description on existing and creates the new ones; does NOT touch role
assignments. Registered in DatabaseSeeder.
- RoleView: group permission toggles by the 'group' column in a defined section
order and show each permission's description.
DB updated locally (migrate + seed run).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1. Roles list now uses a Rappasoft table (RoleTable): search/sort, per-row
view/edit/delete, and built-in bulk selection + 'Delete selected'. The
/admin/roles page is a plain view embedding <livewire:role-table />.
RoleForm create/edit now only has Name + Description (permissions removed).
2. New RoleView page (/admin/roles/{role}) with two tabs:
- 'Details': header with role name + Back button; description with Edit/Delete
buttons; table of users holding the role (avatar+name | last name | status).
- 'Permissions': all permissions grouped by section (by resource), each with a
toggle switch to grant/revoke for this role (Admin keeps 'manage all').
Removed the old RoleManager component/view (superseded).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per feedback, 'New role' (and Edit) now open a dedicated page instead of a
modal:
- New RoleForm full-page component + view at /admin/roles/create and
/admin/roles/{role}/edit (name, description, permission checkboxes; saves
and redirects back to the list).
- RoleManager trimmed: the create/edit modal and its logic removed; 'New role'
and the per-row/view-modal Edit are now links to the new pages.
- Kept the read-only View modal, single + bulk delete, and protections.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per request:
- Migration: add nullable 'description' to the roles table.
- RoleManager Livewire component + view at /admin/roles:
* Roles list table with per-row checkboxes for bulk selection (+ select-all)
and a 'Delete selected' bulk action (protected roles skipped).
* 'New role' opens a modal form with just Name + Description (and permission
checkboxes to assign).
* Per-row View / Edit / Delete buttons (View modal shows description,
counts and assigned permissions).
- Admin role stays protected (no rename/delete/lose 'manage all').
- /admin/users links to the new Roles screen; the phase-1 permission matrix
stays available via a 'Matrix view' link.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 1 (additive, doesn't touch existing checks):
- Gate::before grants everything to holders of 'manage all' (the Admin role),
robustly (returns true/null, never false; swallows missing-permission).
- New RolePermissionManager Livewire component + view at /admin/permissions:
editable Roles x Permissions matrix (toggle saves instantly), create/delete
roles, create/delete permissions. Admin role and 'manage all' are protected.
- Link to the screen from /admin/users header.
Roles are editable from the UI as chosen.
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>
Rebuilt IssueManager to match the 403-line draft view that had no companion
component:
- Modal create/edit form (title, description, priority, status, assignee,
resolution notes shown when resolved/closed)
- Stats bar (open/in_review/resolved/closed/total) and a styled table
- New methods: openForm/closeForm, resolve, close (+ existing save/delete),
projectUsers for the assignee dropdown, resolved_at kept in sync with status
- render() now points to livewire.issues.issue-manager; deleted the old
89-line stub livewire/issue-manager.blade.php
The Issue model already had everything (resolution_notes, resolved_at,
priority_color/status_color accessors, reporter/feature/assignee relations).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deleted (all superseded, recoverable in git history):
- resources/views/projects/edit.blade.php + ProjectController@edit()
- resources/views/projects/create.blade.php + ProjectController@create()
(projects.create/edit routes point to the Livewire ProjectForm; these
controller methods were excluded from the resource and never invoked)
- app/Livewire/ProjectEditTabs.php + project-edit-tabs.blade.php
(old tabbed editor, functionality recovered inside ProjectForm)
- app/Livewire/LayerUpload.php + layer-upload.blade.php (superseded by LayerManager)
Kept resources/views/livewire/issues/issue-manager.blade.php as a reference
for the future rich Issues screen (its companion component was never built).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The edit/create project page used a stripped-down inline form. Rewired it
to the existing-but-orphaned pieces:
- Project Data uses the rich partial project-data-form (labels-left/field-right
layout, sections Identification/Location/Planning, address search + Leaflet
map with draggable marker + reverse/forward geocoding, country dropdown)
- When editing, tabs added for Phases / Users / Companies (nested Livewire
components phase-list / project-users / project-companies)
- ProjectForm now provides $countryList (the partial's country dropdown needs it)
- Added the map JS the partial was missing: inits #project-location-map, search
box, and calls $this->setLocation(lat,lng,address,country) so the wire:model
fields update
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Full restore of the 7d854ff snapshot (2026-06-16 18:05, before the security
review). Forward commit, no history rewrite — f8a1310 and all later commits
remain recoverable in history.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restores all files to the f8a1310 security-review snapshot as requested,
plus the 2 boot-critical fixes from a24c8a2 (config/session.php env()
instead of app()->environment(), and removal of the duplicate $activeTab
in ProjectMap.php) so the application actually boots.
Forward commit, no history rewrite. The 7d854ff state remains in history.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Restores all 27 files changed by the security commit (f8a1310) and later
work back to their 7d854ff state (2026-06-16 18:05), as requested. The
security rewrite regressed map functionality (tabs, inspection editor,
collapsing layers panel) without adding protections the 7d854ff version
did not already have (XSS escaping + IDOR checks were already present).
Done as a forward commit (no history rewrite / force-push) so f8a1310,
a24c8a2 and the merge remain in history and are fully recoverable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>