programado/komando

Laravel utilities by programado, including database synchronization and reusable GraphQL file attachments.

Maintainers

Package info

github.com/programado-kun-pasio/komando

Type:laravel-package

pkg:composer/programado/komando

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.0 2026-08-29 13:04 UTC

This package is auto-updated.

Last update: 2026-08-29 13:10:53 UTC


README

GraphQL file attachments

Komando provides reusable named file slots and unassigned file attachments for Eloquent models and Lighthouse mutations. The package includes a ready-to-use file model, file and attachment migrations, a download route and the complete attachment lifecycle. Applications only keep their slot enum, authorization and legacy data migrations.

Requirements

  • Configure Lighthouse with transactional_mutations enabled so the parent mutation and its files share one transaction.
  • Enable the file module before running migrations.
  • Custom file models must contain name, mime_type, extension, size and metadata columns.

The package migrations create files and file_attachments. Laravel derives file_id as an integer, UUID or ULID through the configured file model. attachable_id follows Laravel's global morph key type.

Schema::morphUsingUuids();
// Or Schema::morphUsingUlids() when attachment owners use ULIDs.

Existing applications keep project-specific data migrations, for example renaming an old polymorphic table or mapping legacy tags to slots. Set migrate_file_table to false when the application already owns the files table. Keep this setting stable so migration rollback uses the same table ownership decision. Set migrations to false only when the application deliberately owns all package tables.

Configuration

Publish the configuration and configure the application's file model:

php artisan vendor:publish --provider="Programado\Komando\Providers\KomandoServiceProvider" --tag="config"
'files' => [
    'enabled' => true,
    'migrations' => true,
    'migrate_file_table' => true,
    'file_model' => Programado\Komando\Files\Models\File::class,
    'attachment_model' => Programado\Komando\Files\Models\FileAttachment::class,
    'factory' => Programado\Komando\Files\Services\DefaultStoredFileFactory::class,
    'disk' => 'files',
    'attachment_table' => 'file_attachments',
    'graphql_slot_type' => 'FileSlot',
    'download' => [
        'enabled' => true,
        'path' => 'api/files/{file}/download',
        'middleware' => [],
    ],
],

The default file model uses ULIDs and exposes storageName(), name(), path() and url(). Its download route is named komando.files.download. The path and middleware can be configured without changing the generated URLs.

Applications can replace it with a custom model implementing StoredFileContract and using IsStoredFile:

use Programado\Komando\Files\Contracts\StoredFileContract;
use Programado\Komando\Files\Traits\IsStoredFile;

class File extends Model implements StoredFileContract
{
    use HasUlids, IsStoredFile;
}

Models that own files implement HasFileAttachmentsContract:

use Programado\Komando\Files\Contracts\HasFileAttachmentsContract;
use Programado\Komando\Files\Traits\HasFileAttachments;

class Workspace extends Model implements HasFileAttachmentsContract
{
    use HasFileAttachments;
}

The application owns and registers its concrete backed FileSlot enum. Alternatively, keep the default graphql_slot_type value String and quote slot names in the schema.

Publish the shared attachment input:

php artisan vendor:publish --provider="Programado\Komando\Providers\KomandoServiceProvider" --tag="komando-files-graphql"

The directives are discovered automatically and work on output and input fields:

type Workspace {
  logo_light: File @fileSlot(slot: WORKSPACE_LOGO_LIGHT)
  files: [File!]! @fileAttachments
}

input UpsertWorkspaceInput {
  id: ID
  logo_light: Upload @fileSlot(slot: WORKSPACE_LOGO_LIGHT)
  files: FileAttachmentChangesInput @fileAttachments
}

For @fileSlot, omitted input keeps the slot unchanged, an Upload replaces it and null removes it. @fileAttachments accepts add: [Upload!] and remove: [ID!]; removal is restricted to unassigned files related to the mutated owner. New physical files are deleted after rollback, while replaced files are only deleted after commit and only when no attachment references remain.

Applications with additional required file columns can configure a custom implementation of StoredFileFactoryContract.

After the database record and physical file are stored successfully, Komando dispatches StoredFileStored. The event implements ShouldDispatchAfterCommit, so listeners only run after the complete Lighthouse transaction commits.

Database sync

Description

This Artisan command enables the synchronization of databases between a remote system and your local development environment. It creates a dump of the remote database, compresses it, transfers it to your local system, and imports it into your local database.

Requirements

Local Requirements

  • scp - for secure file transfer
  • 7z - for compressing/decompressing database dumps
  • mysql - for importing the database

Remote Requirements

  • mysqldump - for creating database dumps
  • 7z - for compressing database dumps

Installation

  1. Install the package via Composer:
composer require programado/komando
  1. Publish the configuration file:
php artisan vendor:publish --provider="Programado\Komando\Providers\KomandoServiceProvider" --tag="config"
  1. Configure your environment variables in .env:
KOMANDO_SSH_HOST=your-remote-host.com
KOMANDO_SSH_USER=app
KOMANDO_SSH_PORT=22
KOMANDO_REMOTE_DB_HOST=127.0.0.1
KOMANDO_REMOTE_DB_USER=default
KOMANDO_REMOTE_DB_PASSWORD=your-password

Configuration

The package uses a configuration file config/komando.php with the following structure:

return [
    'database_sync' => [
        'default_connection' => 'mysql',
        'connections' => ['mysql'], // Database connections to sync
        
        'ssh' => [
            'host' => env('KOMANDO_SSH_HOST'),
            'user' => env('KOMANDO_SSH_USER', 'app'),
            'port' => env('KOMANDO_SSH_PORT', 22),
        ],
        
        'remote_database' => [
            'host' => env('KOMANDO_REMOTE_DB_HOST', '127.0.0.1'),
            'user' => env('KOMANDO_REMOTE_DB_USER', 'default'),
            'password' => env('KOMANDO_REMOTE_DB_PASSWORD'),
        ],
        
        'commands' => [
            'local' => ['scp', '7z', 'mysql'],
            'remote' => ['mysqldump', '7z'],
        ],
        
        'compression' => [
            'level' => 9, // 7z compression level (1-9)
        ],
        
        'mysqldump' => [
            'options' => ['--skip-lock-tables'],
        ],
        
        'safety' => [
            'allow_production_wipe' => false,
        ],
    ],
];

Usage

php artisan komando:sync:database

The command now reads all configuration from the config file and environment variables. No command-line parameters are needed.

Configuration Options

  • connections: Array of database connection names to sync
  • ssh.host: SSH hostname (required)
  • ssh.user: SSH username (default: 'app')
  • ssh.port: SSH port (default: 22)
  • remote_database.*: Remote database connection settings
  • commands.*: Required commands for local and remote systems
  • compression.level: 7z compression level (1-9)
  • mysqldump.options: Additional mysqldump options
  • safety.allow_production_wipe: Allow database wipe in production (default: false)

Process

The command performs the following actions for each specified database connection:

  1. Checks if all required commands are available on both local and remote systems
  2. Creates a dump of the remote database
  3. Compresses the dump on the remote system
  4. Transfers the compressed dump to your local system
  5. Extracts the dump locally
  6. Wipes your local database (with safeguards for production environments)
  7. Imports the dump into your local database
  8. Runs migrations

Security Notes

  • This command wipes your local database before import! In production environments, additional confirmation is requested.
  • Ensure your SSH credentials are secure.
  • Avoid using production systems as the target destination.

Troubleshooting

If the command fails, check the following points:

  1. Are all required commands available on both local and remote systems?
  2. Do you have access to the remote server via SSH?
  3. Does the SSH user have sufficient permissions for database access?
  4. Are the database connection settings in your .env file correctly configured?