AtecoCode — StoreAtecoCodeRequest Form Request — inline validation moved from AtecoCodeController::store() to a dedicated StoreAtecoCodeRequest; controller now calls $request->validated()
Business Settings — Billing Tool URL — new billing_tool_url field in the Integrations tab; stores the URL of the invoicing tool used to issue bills; migration adds nullable billing_tool_url column to business_settings; validated as nullable|url|max:255; translations added to all 13 language files
Payments — Billing Tool button — row action button in the project payments table; opens billing_tool_url in a new tab; visible only when the URL is configured; injected via View Composer in AppServiceProvider as $billingToolUrl (no extra DB query, reuses the existing BusinessSettings::current() singleton)
Task type: maintenance — new type for package/software updates and dependency maintenance; added to Task::TYPES and to all 13 lang/*/tasks.php files
Payments — Google Calendar button for pending payments — now visible on any payment with paid_at or due_date; uses paid_at if collected, falls back to due_date for pending
Payments — row actions stacked vertically — Google Calendar, Billing Tool, Edit, and Delete icons now in a vertical column for a more compact layout
Payments — reference and notes placeholders — updated in all 13 languages to reflect actual use (e.g. "Server consulting, Feature development..." / "Description of work performed..."); notes label updated to "Note / Descrizione" in Italian
Client name links to client show page — in <x-client-summary>, the client name is now a clickable link to clients.show; applies everywhere the component is used (project show page, etc.)
Task row actions stacked vertically — Google Calendar, edit, and delete icons in the task table are now in a vertical column instead of horizontal row for a more compact layout
Task Documents sub-module — file attachments for tasks; task_documents table with task_id, name, file_path, uploaded_at, notes; full upload/preview/download/delete lifecycle via TaskDocumentController and TaskDocumentService (both under Tasks/ namespace); StoreTaskDocumentRequest validates file (30MB max, pdf/jpg/jpeg/png/webp/zip/7z/rar); Task::taskDocuments() hasMany relationship; toFormPayload() extended to include documents array; translations in all 13 languages (lang/*/task_documents.php)
Document indicators on task table rows — both project show and global task index now show: eye + download icons for single attachment, paperclip with numeric badge for multiple attachments; TaskIndexQuery and ProjectShowQuery eager-load taskDocuments
Cost types: hardware and meal — hardware for equipment purchases (keyboard, mouse, monitor, etc.), meal for business meals; <x-costs.type-badge> updated with slate badge (🖥️) and lime badge (🍽️); translations added to all 13 language files
Preview/download on client show cards — payments, costs, tasks, and documents cards on the client show page now display inline preview and download buttons when an attachment is present (hasInvoice(), hasReceipt(), taskDocuments); ClientShowQuery eager-loads taskDocuments to prevent N+1; task rows follow the same single/multiple document pattern as the task index table
Preview/download on dashboard list cards — same inline preview/download buttons added to recent payments, recent costs, and tasks due soon cards; DashboardListsQuery eager-loads taskDocuments on getTasksDueSoon()
Google Calendar embed URL via env — GOOGLE_CALENDAR_EMBED_URL env variable replaces the hardcoded src in calendar/index.blade.php; added to .env.example; configuration docs updated
Top 10 most profitable projects on statistics page — annual view only; table shows project, client, income, costs and profit ranked by profit descending; powered by new TopProjectsQuery sub-query; each project name links to projects.show; included in PDF export as well
Dashboard list rows clickable — all 5 quick lists (tasks due soon, upcoming meetings, recent payments, recent costs, overdue payments) are now fully clickable links to the relevant project tab (projects.show?tab=*)
Dashboard list badges — tasks show <x-tasks.type-badge>, meetings show <x-meetings.status-badge>, payments show <x-payments.method-badge>, costs show <x-costs.type-badge>; no inline badge logic in Blade
Client show list rows clickable — all 5 lists (tasks, meetings, payments, costs, documents) on the client show page now link to the relevant project tab
payments.method_not_set translation — default label was "Da incassare" (wrong semantic); corrected to "Non specificato" / "Not specified" across all 13 languages
Monthly detail tables on statistics page — when a specific month is selected, two tables appear below the summary cards: costs (date, project/client, type, amount) and payments (date, project/client, amount); projects without a client show "Internal"; powered by new MonthlyDetailQuery sub-query
Monthly detail in PDF export — same two tables included in the PDF when exporting a single month, followed by the month profit line; all values come from the backend ($stats['summary']), no logic in the view
Task types: hardware and documentation — added to Task::TYPES and to all 13 lang/*/tasks.php files
Cost type travel relabeled — now shown as "Trasporti/Viaggi" to cover travel, commute, and transit subscriptions
Lead Follow-up module — full CRUD for follow-up logs on lead clients; client_followups table with type (call, email, whatsapp, meeting, note), note, contacted_at; ClientFollowup model implements CalendarEventable
Follow-up section on client show page — amber-bordered section visible only when $client->isLead(); includes quick action buttons (call, WhatsApp, email) and a chronological follow-up log; disappears automatically once the client is converted to active
clientFollowupModal Alpine.js component — resources/js/components/clientFollowupModal.js; single modal handles create and edit; registered via Alpine.data() in app.js; uses data-action/data-payload pattern (no inline JS in Blade)
<x-followup-type-icon> Blade component — accepts :type prop (call, email, whatsapp, meeting, note); replaces @switch/@case blocks with a PHP array map; reused in follow-up list rows and quick-action buttons
Google Calendar integration for follow-ups — each follow-up row has an "Add to Calendar" link; pre-filled as an all-day event on contacted_at via ClientFollowup::googleCalendarUrl()
Client::isLead() helper — returns true if status === 'lead'; single source of truth for conditional UI in Blade
Follow-up translations — followup key group added to all 13 lang/*/clients.php files (type labels, action labels, modal titles, validation messages)
Client::whatsappUrl() model method — WhatsApp URL building logic (phone_prefix + phone → wa.me/ URL) moved from Blade component to the model; single source of truth used by <x-whatsapp-link>, _quick-actions.blade.php, and any other consumer
<x-whatsapp-link> refactored — now accepts href (pre-built URL) and slot text instead of phone+prefix props; component is pure display with no URL logic
ClientStatsQuery — leads excluded from total — total client count now covers only active and archived statuses; leads are prospects, not yet clients; calculation moved entirely inside ClientStatsQuery::handle(), removed from the controller
Inline field editing — Project overview tab — description and notes fields on the project show page are now editable inline without opening the modal; a dedicated PATCH /projects/{project}/field endpoint handles the update via PatchProjectFieldRequest (allowlist: description, notes); the patchField() method was added directly to ProjectController
inlineField Alpine.js component — new resources/js/components/inlineField.js registered as Alpine.data('inlineField', inlineField) in app.js; accepts patchUrl, fieldName, initialValue, msgSaved, msgError as parameters; translated messages are passed from Blade to avoid hardcoding strings in JS
ui.saved / ui.error_saving translation keys — added to all 13 language files (lang/*/ui.php)
Task types: marketing and improvement — added to Task::TYPES constant and to all 13 lang/*/tasks.php files
tasks.due_today translation key — added to all 13 lang/*/tasks.php files; shown on the due date badge when the task deadline is today
Inline text newline preservation — description and notes display divs use whitespace-pre-wrap so saved newlines render correctly without nl2br
Project show tab limit raised to 50 — ProjectShowQuery::$limit increased from 10 to 50; all "View all" threshold checks in _tab-tasks, _tab-meetings, _tab-payments, _tab-costs, _tab-documents updated from > 10 to > 50
Clickable project name in project index — project name in _row-name.blade.php is now a link to projects.show
Clickable client name in client cells — x-client-name-cell component and x-projects.client-badge component now link to clients.show
Clickable project column in task / meeting / payment / cost / document indexes — _row-project.blade.php in all five modules now links directly to projects.show with the relevant tab pre-selected (tab=tasks, tab=meetings, etc.)
Task due date badge — overdue vs. today — due-date.blade.php now checks isToday() before isPast(); tasks due today show "Da fare oggi" / "Due today" instead of "Overdue"
Trix dark mode link dialog — .trix-dialog, .trix-dialog input, and .trix-dialog .trix-button now have explicit dark-mode overrides in app.css; the dialog is no longer invisible on dark backgrounds
Projects — Editor tab — new rich text editor tab on the project show page powered by Trix; supports bold, italic, links, headings, lists, quotes and inline image upload (PNG, JPG, GIF, max 20MB); content saved as HTML in the new editor_notes column (separate from the plain-text notes field)
Private image storage for editor — images uploaded via the editor are stored privately (local disk, editor-images/{project_id}/); served through an authenticated route (GET /projects/{project}/editor/images/{filename}) with Cache-Control: private
Taxes module — full CRUD for tax payment tracking: amount, description, due date, paid date, reference year, optional notes, and document attachment (upload / preview / download); four stat cards (total all time, this year, unpaid amount, count this year); filters by year, paid status, and free-text search
Tax document attachment — upload PDF/image documents per tax record; stored locally with a locale-aware filename prefix; supports preview, download and delete
Google Calendar integration for taxes — each unpaid tax shows a calendar icon next to the due date; clicking it opens Google Calendar with the event pre-filled (title includes date, description and reference year; body includes all tax details and notes)
Taxes translations — full taxes.php lang file in all 13 supported languages (it, en, de, fr, es, pt, nl, pl, ro, ru, uk, da, zh)
Project type badge — <x-projects.type-badge> now displayed in the project column of all index tables: tasks, payments, costs, meetings, timesheets, documents
Timesheets index — project column now shows client name when a project is linked to a client (was missing)
Statistics MySQL compatibility — MonthlyBreakdownQuery was using SQLite-only strftime(); replaced with a dateExpr() helper that outputs DATE_FORMAT for MySQL and strftime for SQLite
GitHub Integration — Repository tab — each project with a GitHub repo_url now shows a dedicated Repository tab with: commit activity heatmap (52 weeks × 7 days), recent commits list (author, relative date, SHA linked to GitHub), and repo info badges (stars, forks, default branch); data is lazy-loaded via a JSON endpoint (GET /projects/{project}/repository) and cached 10 minutes server-side
GitHubService — new app/Services/GitHub/GitHubService.php wrapping the GitHub REST API (commit_activity, commits, repo info endpoints) with per-repo cache and silent failure handling
Business Settings — Integrations tab — new tab in Business Settings for third-party integrations; first integration: GitHub PAT (github_pat field) with required scopes info box
repositoryTab Alpine.js component — registered in app.js, handles fetch, loading/error states, heatmap color logic, month label computation and relative date formatting
Dashboard — Recent Costs list — new _recent-costs.blade.php card showing the 5 most recent registered costs (amount in red with -, project name, type badge, date); added getRecentCosts() to DashboardListsQuery and included costs in hydrateProjects() batch loading to prevent N+1 queries
Timesheet PDF report — download a monthly worked hours report as PDF directly from the project timesheet tab; includes business info, project/client details, worked days table, and total earnings; filename is locale-aware ({report-title-slug}-{project-slug}-{mm}-{yyyy}.pdf)
Blaze — enabled livewire/blaze function compiler on all anonymous Blade components (resources/views/components/) for faster rendering pipeline
Timesheets module — monthly worked hours tracking per project with daily hour grid, hourly rate snapshot, and reactive earnings calculation (Alpine.js)
Timesheets global index — paginated list with filters (project name, month, year), four stat cards (hours/earnings this month and this year), and direct links to the correct month on the project show page
Clients / Projects index — stat cards showed filtered counts when filters were active; stats now always reflect the real unfiltered totals
Invoice PDF — bold text (<strong>, .invoice-number, .description-amount, etc.) was not rendering as bold because the @font-face bold declaration pointed to the same Regular TTF file
Invoice PDF font — switched primary font from Noto Sans CJK to DejaVu Sans for cleaner, more professional typography; Noto Sans CJK retained as fallback for CJK characters