Flagged domains are served with X-Robots-Tag: noindex, nofollow via
Traefik and Caddy routing labels, so an auto-generated technical domain
can be excluded from indexing while the production domain on the same
resource stays indexable.
Use shared domain validation and normalization for application, service, and
preview domains so unsafe host input is rejected consistently.
Cover command-substitution payloads in application domain tests.
- Added `requiredPort` property to `ServiceApplicationView` to track the required port for services.
- Introduced modal confirmation for removing required ports, including methods to confirm or cancel the action.
- Enhanced `Service` model with `getRequiredPort` and `requiresPort` methods to retrieve port information from service templates.
- Implemented `extractPortFromUrl` method in `ServiceApplication` to extract port from FQDN URLs.
- Updated frontend views to display warnings when required ports are missing from domains.
- Created unit tests for service port validation and extraction logic, ensuring correct behavior for various scenarios.
- Added feature tests for Livewire component handling of domain submissions with required ports.
Resolved merge conflicts between Livewire model binding refactoring and UI/CSS updates from next branch. Key integrations:
- Preserved unique HTML ID generation for form components
- Maintained wire:model bindings using $modelBinding
- Integrated new wire:dirty.class styles (border-l-warning pattern)
- Kept both syncData(true) and validateDockerComposeForInjection in StackForm
- Merged security tests and helper improvements from next
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit addresses two critical issues with Docker Compose service management:
## Issue 1: Duplicate Services Created on Image Change
When changing the image in a docker-compose file, the parser was creating new
ServiceApplication/ServiceDatabase records instead of updating existing ones.
**Root Cause**: The parsers used `firstOrCreate()` with `['name', 'image', 'service_id']`,
meaning any image change would create a new record.
**Fix**: Remove `image` from `firstOrCreate()` queries and update it separately after
finding or creating the service record.
**Changes**:
- `bootstrap/helpers/parsers.php` (serviceParser v3): Fixed in presave loop (lines 1188-1203)
and main parsing loop (lines 1519-1539)
- `bootstrap/helpers/shared.php` (parseDockerComposeFile v2): Fixed null check logic
(lines 1308-1348)
## Issue 2: UI Not Refreshing After Changes
When compose file or domain was modified, the Configuration component wasn't receiving
events to refresh its data, requiring manual page refresh to see updates.
**Root Cause**: The Configuration component wasn't listening for refresh events dispatched
by child components (StackForm, EditDomain).
**Fix**: Add event listeners and dispatchers to enable real-time UI updates.
**Changes**:
- `app/Livewire/Project/Service/Configuration.php`: Added listeners for `refreshServices`
and `refresh` events (lines 36-37)
- `app/Livewire/Project/Service/EditDomain.php`: Added `refreshServices` dispatch (line 76)
- Note: `app/Livewire/Project/Service/StackForm.php` already had the dispatch
## Tests Added
- `tests/Unit/ServiceParserImageUpdateTest.php`: 4 tests verifying no duplicates created
- `tests/Unit/ServiceConfigurationRefreshTest.php`: 4 tests verifying event dispatching
All 8 new tests pass, and all existing unit tests continue to pass.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>