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>
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>
User's manual changes: header slots with New-user/New-company actions, wider
max-w-7xl containers on /admin/users and /companies, plus tweaks to
user-view and projects index views. All views compile.
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>
Point 2 (migrate to Rappasoft tables):
- /admin/users now renders <livewire:user-table /> (+ a New user button)
instead of the custom admin-users component
- /companies now renders <livewire:company-table /> (+ New company button)
instead of the hand-rolled card list
Point 3 (delete): removed resources/views/welcome.blade.php (unused — '/'
redirects to dashboard).
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>
project-form.blade.php referenced $projectId, but the ProjectForm component
exposes $project (the model, null when creating). Caused 'Undefined variable
$projectId' on /projects/{id}/edit. Switched both usages to $project.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1. Editor tabs restyled as spaced DaisyUI buttons (btn-primary when active,
btn-ghost otherwise) — fixes cramped labels and missing active indicator.
2. Layer visibility now works at two levels:
- Phase toggle calls togglePhase() and shows/hides ALL its layers
(checked only when every layer of the phase is active)
- Each layer has its own independent toggle calling toggleLayer()
Map JS regrouped to build one Leaflet group per LAYER (keyed by layer id)
instead of per phase, so activeLayers (layer ids) drives visibility
correctly per layer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The DaisyUI .modal default z-index (999) was below the phases/layers panel
(z-1000) and its reopen button (z-1001), so they showed on top of the modal.
Set the modal to z-[2000].
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1.1 Edit tab: in fullscreen the content splits into 2 columns (Alpine :class)
1.2 Full-width feature title with progress as a number badge on the left;
removed the progress slider and the 'Save progress' button; Responsible
now auto-saves on blur (wire:blur)
2. Features table: zebra/pinned-rows styling, progress badge; removed the
Responsible and Template columns
3. Inspections table: same styling; wired the eye button to viewInspection()
and added the inspection viewer modal (uses existing component state)
6a. Phases/layers collapse button moved into the panel title; a small floating
button reopens it when collapsed (saves space)
6b. Base-layer switcher on the map: Streets / OpenStreetMap / Satellite (Esri)
Issues tab (point 5) intentionally left untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The tab-content wrapper comment contained the text '@if', which Blade
compiles even inside HTML comments, causing a ParseError on page load.
Reworded the comment to avoid the directive token.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The tab panel wrapper used class 'tab-content', which DaisyUI hides by
default (display:none) unless paired with a checked radio .tab sibling.
Since visibility is driven by Livewire @if($activeTab===...), the class
only kept the content permanently hidden. Replaced with a neutral wrapper.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Features and Inspections tab tables read $feature->layer->name and
$inspection->feature->name (and template/user) without null guards. When a
referenced feature/layer was soft-deleted, the relation is null and rendering
threw 'Attempt to read property name on null', returning HTTP 500 on every
Livewire update — which also prevented the tabs from switching (the update
that changes activeTab crashed during re-render).
Made all chained relation reads null-safe with ?-> and '—' fallbacks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1. Hide the project navigation bar (kept in DOM via 'hidden', not deleted)
2. Move the tabs into the panel header where the 'Map' title was
3. (tabs setActiveTab logic already correct — recompiled)
4. Make the phases/layers panel collapsible via an Alpine toggle button
5. Replace all emoji icons with blade-heroicons (<x-heroicon-o-*>)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Recovers the project-map progress from f8a1310 (project navigation bar +
Issues tab + embedded IssueManager) but applied on top of 7d854ff's
COMPLETE, working component (449 lines: setActiveTab, openIssuesCount,
inspection editor, filters, togglePhase/toggleLayer, IDOR checks).
f8a1310 had added this UI to the blade but simultaneously gutted the
component (down to 347 lines, removing setActiveTab) which broke the tabs.
This commit keeps the good component and adds only the blade UI, so the
tabs, inspection editor and Issues tab all work together.
Verified: all blade templates compile, routes (gantt/report/issues/
dashboard) exist, IssueManager::mount(Project) matches the passed param.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pre-existing bug in 7d854ff: the company type CSS-class @if block at
line 258 was closed with a bare 'endif' (no @), causing a ParseError on
GET /companies (unexpected 'endforeach').
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>
- Created Company model and migration with fields: name, tax_id, address, phone, email, website, type, notes
- Created company_project pivot table with role_in_project field
- Added relationships: Project.companies() and Company.projects()
- Created Livewire component ProjectCompanies for managing company assignments
- Added 'Companies' tab to project edit interface alongside Phases and Users tabs
- Implemented assign/remove company functionality with role selection
- Applied same permissions logic as user assignment (assign users permission or Admin role)