Skip to content

feat: Enable database detection and backup support for Docker Compose via GitHub App#8430

Closed
sushi-levanter wants to merge 1 commit intocoollabsio:v4.xfrom
sushi-levanter:feat/7528-compose-database-detection-backup
Closed

feat: Enable database detection and backup support for Docker Compose via GitHub App#8430
sushi-levanter wants to merge 1 commit intocoollabsio:v4.xfrom
sushi-levanter:feat/7528-compose-database-detection-backup

Conversation

@sushi-levanter
Copy link
Copy Markdown

Summary

Enables database detection and backup support for Docker Compose deployments via GitHub App (dockercompose buildpack). Previously, database services in these deployments were not detected and ServiceDatabase records were not created, meaning automated backups were unavailable.

Issue

Resolves #7528

/claim #7528

Category

  • Bug fix
  • New Feature

Technical Details

Root Cause

parseDockerComposeFile() in bootstrap/helpers/shared.php has two code paths:

Path Model Calls isDatabaseImage() Creates ServiceDatabase Backups
Service model (lines ~1263-2025) Service
Application model (lines ~2026+) Application ✅ (already) missing

The Application path already called isDatabaseImage() and set is_database, but never created ServiceDatabase records because the existing FK (service_id) only pointed to the services table.

Database Changes

New migration: Adds nullable application_id FK (constrained to applications, cascade on delete) to service_databases table. Makes service_id nullable so Application-owned databases do not need it.

Model Changes

ServiceDatabase:

  • Added application() relationship (belongsTo Application)
  • Added helper methods for owner-agnostic resolution:
    • isApplicationOwned() — checks if owned by Application vs Service
    • getOwner() — returns the owning Service or Application
    • getOwnerUuid() — UUID of the owner
    • getServer() — resolves server through either ownership path
    • getNetwork() — resolves network through either ownership path
  • Updated restart(), getServiceDatabaseUrl(), team(), workdir() to use helpers
  • Updated ownedByCurrentTeam() and ownedByCurrentTeamAPI() to query both ownership paths

Application:

  • Added composeDatabases() HasMany relationship
  • Cleanup of compose databases when switching away from dockercompose build pack
  • Cleanup on forceDeleting

Parser Changes (shared.php)

  • In the Application model path of parseDockerComposeFile(), after isDatabaseImage() detection, creates/updates ServiceDatabase records with application_id (skips preview deployments)
  • Cleans up stale ServiceDatabase records when services are removed from the compose file
  • Updated getResourceByUuid team ownership check to handle Application-owned ServiceDatabases

Updated Code Paths

All locations that previously used hardcoded ->service->server, ->service->uuid, ->service->destination->network chains now use the new getServer(), getOwnerUuid(), getNetwork() helpers:

  • DatabaseBackupJob: Server resolution, container naming, network for S3 upload
  • StartDatabaseProxy / StopDatabaseProxy: Network, server, container name resolution
  • BackupExecutions: Server resolution for backup deletion and download
  • BackupEdit: Server resolution, redirect for Application-owned databases
  • ScheduledDatabaseBackup: Server resolution
  • Import: Server, container name, network resolution
  • LocalFileVolume: Server/workdir resolution for file storage operations
  • databases.php helper: Server resolution for backup cleanup
  • web.php download route: Server resolution for backup file downloads

UI Changes

  • Added "Backups" tab to Application configuration sidebar (only for dockercompose build pack when databases are detected)
  • Created ComposeBackups Livewire component with database selector and backup management
  • Reuses existing ScheduledBackups and CreateScheduledBackup components

Steps to Test

  1. Create a new Application using the dockercompose buildpack via GitHub App
  2. Use a repo with a docker-compose.yml containing a database service (e.g., postgres:16-alpine) and at least one non-database service
  3. Deploy the Application
  4. Navigate to Project > Environment > Application > Configuration > Backups
  5. Verify the database service is listed and you can create a scheduled backup
  6. Run a backup and confirm a new execution entry is created
  7. Verify that removing the database from the compose file and redeploying cleans up the ServiceDatabase record

AI Usage

  • AI is used in the process of creating this PR

Contributor Agreement

Important

  • I have read and understood the contributor guidelines. If I have failed to follow any guideline, I understand that this PR may be closed without review.
  • I have tested the changes thoroughly and am confident that they will work as expected without issues when the maintainer tests them

… deployments via GitHub App

- Add nullable application_id FK to service_databases table so a
  ServiceDatabase can belong to either a Service or an Application
- Create ServiceDatabase records in the Application model parsing path
  of parseDockerComposeFile() when isDatabaseImage() detects a database
- Add helper methods (getServer, getOwnerUuid, getNetwork, isApplicationOwned)
  to ServiceDatabase for owner-agnostic resolution
- Update all code paths that resolve server/network/uuid through
  ServiceDatabase to use the new helpers instead of hardcoded
  ->service-> chains
- Add composeDatabases() relationship to Application model with cleanup
  on build_pack change and force delete
- Add Backups tab to Application configuration UI for dockercompose apps
- Create ComposeBackups Livewire component with database selector

Files modified:
- database/migrations: new migration for application_id column
- app/Models/ServiceDatabase.php: application() relationship + helpers
- app/Models/Application.php: composeDatabases() relationship + cleanup
- bootstrap/helpers/shared.php: ServiceDatabase creation in App path
- app/Jobs/DatabaseBackupJob.php: owner-agnostic server/uuid resolution
- app/Actions/Database/Start/StopDatabaseProxy.php: same
- app/Livewire/Project/Database/*: same
- app/Models/ScheduledDatabaseBackup.php: same
- app/Models/LocalFileVolume.php: same
- bootstrap/helpers/databases.php: same
- routes/web.php: new route + updated download handler
- resources/views: Backups tab + compose-backups view

Resolves #7528
@algora-pbc algora-pbc bot added the 🙋 Bounty claim Issues or PRs that have a Bounty ready to be claimed. label Feb 18, 2026
@github-actions github-actions bot added quality/rejected and removed 🙋 Bounty claim Issues or PRs that have a Bounty ready to be claimed. labels Feb 18, 2026
@github-actions
Copy link
Copy Markdown
Contributor

This PR did not pass quality checks so it will be closed. If you believe this is a mistake please let us know.

@github-actions github-actions bot closed this Feb 18, 2026
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Enhancement]: Integrated backups for Git based Docker Composes

1 participant