Major changes to the file disk subsystem:
- Each FileDisk now gets a unique Laravel disk name (disk_{id}) instead
of temp_{driver}, fixing the bug where multiple local disks with
different roots overwrote each other's config.
- Move disk registration logic from FileDisk model to FileDiskService
(registerDisk, getDiskName). Model keeps only getDecodedCredentials
and a deprecated setConfig() wrapper.
- Add Disk Assignments admin UI (File Disk tab) with three purpose
dropdowns: Media Storage, PDF Storage, Backup Storage. Stored as
settings (media_disk_id, pdf_disk_id, backup_disk_id).
- Backup tab now uses the assigned backup disk instead of a per-backup
dropdown. BackupsController refactored to use BackupService which
centralizes disk resolution. Removed stale 4-second cache.
- Add local_public disk to config/filesystems.php so system disks
are properly defined.
- Local disk roots stored relative to storage/app/ with hint text
in the admin modal explaining the convention.
- Fix BaseModal watchEffect -> watch to prevent infinite request
loops on the File Disk page.
- Fix string/number comparison for disk purpose IDs from settings.
- Add safeguards: prevent deleting disks with files, warn on
purpose change, prevent deleting system disks.
New backend endpoint POST /invoices/{id}/convert-to-estimate that
creates a draft estimate from an invoice, copying items, taxes,
custom fields, and financial data. Frontend wired with dropdown
action, store method, and API service call.
- Add manifest.json generation script (scripts/generate-manifest.php)
- Add Updater::cleanStaleFiles() that removes files not in manifest
- Add /api/v1/update/clean endpoint with backward compatibility
- Add configurable update_protected_paths in config/invoiceshelf.php
- Update frontend to use clean step instead of delete step
- Add GitHub Actions release workflow triggered on version tags
- Add .github/release.yml for auto-generated changelog categories
- Update Makefile to include manifest generation and scripts directory
Desktop sidebar can be toggled between full width (w-56/w-64) and
collapsed icon-only mode (w-16). Collapsed state persists in
localStorage. Icons enlarge to w-6 h-6 when collapsed, labels
hidden, v-tooltip shows item names on hover. Group labels replaced
with thin dividers when collapsed. Toggle button pinned at bottom
with ChevronLeft/Right icon. Content area padding animates smoothly
with transition-all duration-300.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Personalize welcome heading with user name, add descriptive subtitle,
improve invitation card styling, remove redundant logout button. Fix
hasCreateAbilities check in header to actually call the function.
Widen company switcher dropdown and improve invitation row layout.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Members Index:
- "Invite Member" button opens InviteMemberModal (email + role dropdown)
- Pending invitations section shows below members table with cancel buttons
- Members store gains inviteMember, fetchPendingInvitations, cancelInvitation
CompanySwitcher:
- Shows pending invitations greyed out below active companies
- Each with Accept/Decline mini-buttons
- Accepting refreshes bootstrap and switches to new company
NoCompanyView:
- Standalone page for users with zero accepted companies
- Shows pending invitations with Accept/Decline or "no companies" message
- Route: /admin/no-company
Invitation Pinia store:
- Manages user's own pending invitations (fetchPending, accept, decline)
- Bootstrap populates invitations from API response
Global store:
- Bootstrap action stores pending_invitations from response
Match the Company Settings design pattern: sidebar navigation on desktop
with dropdown on mobile, child routes rendered via RouterView. Each tab
(General, Profile Photo, Security) is now a BaseSettingCard with its own
route under /admin/user-settings/{general,profile-photo,security}.
Backend:
- Extract user profile methods (show, update, uploadAvatar) from
CompanyController into new UserProfileController
- CompanyController now only handles company concerns (updateCompany,
uploadCompanyLogo)
- Remove Account Settings from setting_menu config
Frontend:
- New /admin/user-settings page with 3 tabs: General, Profile Photo,
Security (password change)
- User dropdown now links to /admin/user-settings instead of
/admin/settings/account-settings
- Settings sidebar defaults to Company Information as first item
- Remove old monolithic AccountSetting.vue
- Add Administration sidebar section (super-admin only) with Companies, Users, and Global Settings pages
- Add super-admin middleware, controllers, and API routes under /api/v1/super-admin/
- Allow super-admins to manage all companies and users across tenants
- Add user impersonation with short-lived tokens, audit logging, and UI banner
- Move system-level settings (Mail, PDF, Backup, Update, File Disk) from per-company to Administration > Global Settings
- Convert save_pdf_to_disk from CompanySetting to global Setting
- Add per-company mail configuration overrides (optional, falls back to global)
- Add CompanyMailConfigService to apply company mail config before sending emails