Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
laravel-auto-sequence
madebyclowd/laravel-auto-sequence
claude-code
auto-sequence
eloquent
sequence-generation
multi-tenant
fiscal-year
migrations

Use this skill for madebyclowd/laravel-auto-sequence package in Laravel applications. ALWAYS use this skill when configuring or generating auto-incrementing document/record sequences, setting up multiple conditional sequence rules on models, adjusting concurrency database/Redis locks, setting up Hi/Lo pre-allocation caching, or running sequence artisan commands. Covers: HasSequenceNumber trait, Sequence facade, composite sequence key partitions, and sequence verification tools.

Install
php artisan boost:add-skill madebyclowd/laravel-auto-sequence

Save this content to: .claude/skills/laravel-auto-sequence/SKILL.md

# Laravel AutoSequence Development

## Quick Reference

### Installation and Setup

Run the setup wizard to publish the config, publish database migrations, and run migrations:
```bash
php artisan sequence:install
```

To manually republish individual assets:
```bash
php artisan vendor:publish --tag=auto-sequence-config
php artisan vendor:publish --tag=auto-sequence-migrations
```

This skill and the accompanying guideline are auto-discovered by Laravel Boost directly from
`resources/boost/` in the package — no publish step or manual registration needed.

### Basic Usage

To add a sequence to a model, implement the `Sequenceable` contract and use the `HasSequenceNumber` trait:

```php
use MadeByClowd\AutoSequence\Contracts\Sequenceable;
use MadeByClowd\AutoSequence\Traits\HasSequenceNumber;
use Illuminate\Database\Eloquent\Model;

class Invoice extends Model implements Sequenceable
{
    use HasSequenceNumber;

    /**
     * Define sequence configs.
     */
    public function getSequenceConfig(): array
    {
        return [
            'number' => [
                'module' => 'invoice',
                'type_code' => 'INV',
                'period' => 'monthly', // daily, weekly, monthly, quarterly, yearly, never (or custom date format/callable)
                'format_template' => '{type_code}-{YYYY}-{MM}-{seq:5}', // INV-2026-06-00001
                'pad_length' => 5,
            ]
        ];
    }
}
```

### Advanced Features

#### 1. Dynamic Type Code Resolution (`type_relation`)

If you want the sequence prefix to change based on a relationship (e.g. `$invoice->branch->code`):

```php
public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_relation' => 'branch', // Resolves relationship and uses the $branch->code attribute
            'default_type' => 'HQ',       // Fallback if relationship or code is missing
            'period' => 'yearly',
            'format_template' => '{type_code}-{YYYY}-{seq:6}',
        ]
    ];
}
```

If the relationship column is not named `code`, use the array syntax:
```php
'type_relation' => [
    'relation' => 'category',
    'column' => 'id_code',
]
```

#### 2. Multi-Tenant Scoping (`scope`)

Keep sequence pools strictly isolated across tenants or branches by specifying the `scope` configuration:

```php
public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'scope' => 'tenant_id', // Resolves $model->tenant_id dynamically to scope the sequence pool
            'period' => 'monthly',
            'format_template' => '{type_code}-{YYYY}-{MM}-{seq:5}',
        ]
    ];
}
```

#### 3. Custom Reset Callables / Fiscal Years

For complex ERP requirements where sequences reset on custom dates (e.g. fiscal year starting April 1st):

```php
public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'period' => function ($model) {
                // Return custom partition period string based on fiscal calendar
                $createdAt = $model->created_at ?? now();
                $year = $createdAt->month >= 4 ? $createdAt->year : $createdAt->year - 1;
                return "FY{$year}";
            },
            'format_template' => '{type_code}-{period}-{seq:5}',
        ]
    ];
}
```

#### 4. Multiple Sequences per Model

You can auto-generate sequences for multiple columns on the same model:

```php
public function getSequenceConfig(): array
{
    return [
        'invoice_number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'format_template' => '{type_code}-{YYYY}-{seq:5}',
        ],
        'internal_ref' => [
            'module' => 'internal',
            'type_code' => 'REF',
            'period' => 'never',
            'format_template' => '{type_code}-{seq:8}',
        ]
    ];
}
```

#### 5. Flexible Custom Date Formats

While standard shorthand tokens (like `{YYYY}` or `{MM}`) are quick and easy for common templates, the `{date:FORMAT}` token gives you complete control using any standard PHP date formatting parameters (e.g., to output month names, day names, custom separators, etc.):

```php
public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            // Generates e.g., INV-16-Jun-2026-00001 (using 'd-M-Y' PHP date format)
            'format_template' => '{type_code}-{date:d-M-Y}-{seq:5}', 
        ]
    ];
}
```

#### 6. Advanced Enterprise Features

For enterprise numbering requirements, the following properties are supported directly within the model sequence configuration:

```php
public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'format_template' => 'INV-{YYYY}-{seq:5}',
            
            // Starting value (default 1)
            'start_value' => 1000, 
            
            // Custom increment step (default 1)
            'step' => 2, 
            
            // Maximum sequence limit (throws SequenceExhaustedException if exceeded)
            'max_value' => 99999, 
            
            // Set to false to throw a validation exception on manual input overrides
            'allow_manual' => false, 
            
            // Enable continuous sequence recycling (deleted numbers are recycled and reused)
            'continuous' => true, 
            
            // Database connection override for this specific sequence
            'connection' => 'custom_connection', 
        ]
    ];
}
```

#### 7. Manual Sequence Facade Generation

To manually query, increment, or recycle sequences in service classes, jobs, or custom commands:

```php
use MadeByClowd\AutoSequence\Facades\Sequence;

// Fetch and increment next sequence value
$number = Sequence::generate(
    'order', 
    'SO', 
    '202606', 
    '{type_code}-{YYYY}-{seq:5}', 
    5, 
    'tenant_1',
    null,      // $model context
    null,      // $connection override
    1,         // $startValue
    1,         // $step
    false,     // $continuous
    99999      // $maxValue
);

// Manually recycle a number back into the continuous queue
Sequence::recycle('order', 'SO', '202606', 'tenant_1', 105);

// Get the current number without incrementing
$current = Sequence::getCurrent('order', 'SO', '202606', 'tenant_1');

// Reset or offset the sequence
Sequence::reset('order', 'SO', '202606', 'tenant_1', 100); // Next number will be 101
```

---

## Artisan Commands Checklist

1. **List Active Sequences**:
   ```bash
   php artisan sequence:list
   php artisan sequence:list --module=invoice
   ```
2. **Reset/Offset Counter**:
   ```bash
   php artisan sequence:reset invoice INV --value=500
   ```
3. **Verify and Repair Sequence Drift**:
   Compare the highest generated number in the actual model table with the database counter to verify synchronization:
   ```bash
   php artisan sequence:verify "App\Models\Invoice" number
   # To automatically repair drift by fast-forwarding the counter:
   php artisan sequence:verify "App\Models\Invoice" number --repair
   ```

---

## Common Pitfalls

- **Bypassing the Trait check**: Manually assigning the sequence column to a value before saving will trigger the **Manual Override Protection**, skipping generation. Make sure the column is empty/null if you want the package to generate the value.
- **Cache connection locks**: If using `'cache'` driver for locking, ensure your cache configuration (`config/cache.php`) supports locks (e.g. `redis`, `memcached`, `database` drivers. `file` and `array` do not support concurrent locks properly).
- **Composite keys in DB**: If raw querying sequences, remember that the table primary key is composite `['module', 'type_code', 'period', 'scope']`. Always run queries enlisting all four columns to guarantee locking performance and accuracy.
- **Hi/Lo Caching Reset**: If you manually alter a sequence counter directly in the database while `pre_allocation` is enabled, remember to clear the cached sequence pool using `Cache::store(config('auto-sequence.pre_allocation.store'))->forget('auto-sequence_pool:module:type:period:scope')` or by running `php artisan sequence:reset`.
- **Soft Deletes & Recycling**: If a model uses Laravel's `SoftDeletes` trait, its sequence number is **not** recycled on soft delete to prevent collisions if the record is later restored. Recycling only occurs when the record is permanently deleted via `forceDelete()`.
- **Pre-Allocation & Gapless Incompatibility**: High-performance pre-allocation (`pre_allocation.enabled => true`) cannot be used with `'gapless'` transaction mode. Ensure `transaction_mode` is set to `'gap_tolerant'` when enabling pre-allocation, otherwise a configuration exception will be thrown.
- **Dedicated Pre-Allocation Cache Store**: To prevent silent gaps in pre-allocated sequences due to default cache flushes or LRU evictions, specify a dedicated, non-evicting cache store (e.g. Redis with `noeviction` policy) under `pre_allocation.store`.
- **FPM Worker Exhaustion & Database Locking**: The `database` locking driver sets a native database session/local lock wait timeout based on `locking.timeout` (default 5s) instead of blocking the PHP execution thread indefinitely. Avoid long-running transactions to prevent fast-failing lock acquisition exceptions.
- **`load_migrations => false` in tests**: The package's bundled migrations now respect this config during your app's own test suite too. If your app ships a replacement `sequences` table migration under its own name and sets `load_migrations => false`, that's honored in `phpunit`/`php artisan test` runs, not just in normal/prod environments.

Laravel AutoSequence Development

Quick Reference

Installation and Setup

Run the setup wizard to publish the config, publish database migrations, and run migrations:

php artisan sequence:install

To manually republish individual assets:

php artisan vendor:publish --tag=auto-sequence-config
php artisan vendor:publish --tag=auto-sequence-migrations

This skill and the accompanying guideline are auto-discovered by Laravel Boost directly from resources/boost/ in the package — no publish step or manual registration needed.

Basic Usage

To add a sequence to a model, implement the Sequenceable contract and use the HasSequenceNumber trait:

use MadeByClowd\AutoSequence\Contracts\Sequenceable;
use MadeByClowd\AutoSequence\Traits\HasSequenceNumber;
use Illuminate\Database\Eloquent\Model;

class Invoice extends Model implements Sequenceable
{
    use HasSequenceNumber;

    /**
     * Define sequence configs.
     */
    public function getSequenceConfig(): array
    {
        return [
            'number' => [
                'module' => 'invoice',
                'type_code' => 'INV',
                'period' => 'monthly', // daily, weekly, monthly, quarterly, yearly, never (or custom date format/callable)
                'format_template' => '{type_code}-{YYYY}-{MM}-{seq:5}', // INV-2026-06-00001
                'pad_length' => 5,
            ]
        ];
    }
}

Advanced Features

1. Dynamic Type Code Resolution (type_relation)

If you want the sequence prefix to change based on a relationship (e.g. $invoice->branch->code):

public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_relation' => 'branch', // Resolves relationship and uses the $branch->code attribute
            'default_type' => 'HQ',       // Fallback if relationship or code is missing
            'period' => 'yearly',
            'format_template' => '{type_code}-{YYYY}-{seq:6}',
        ]
    ];
}

If the relationship column is not named code, use the array syntax:

'type_relation' => [
    'relation' => 'category',
    'column' => 'id_code',
]

2. Multi-Tenant Scoping (scope)

Keep sequence pools strictly isolated across tenants or branches by specifying the scope configuration:

public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'scope' => 'tenant_id', // Resolves $model->tenant_id dynamically to scope the sequence pool
            'period' => 'monthly',
            'format_template' => '{type_code}-{YYYY}-{MM}-{seq:5}',
        ]
    ];
}

3. Custom Reset Callables / Fiscal Years

For complex ERP requirements where sequences reset on custom dates (e.g. fiscal year starting April 1st):

public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'period' => function ($model) {
                // Return custom partition period string based on fiscal calendar
                $createdAt = $model->created_at ?? now();
                $year = $createdAt->month >= 4 ? $createdAt->year : $createdAt->year - 1;
                return "FY{$year}";
            },
            'format_template' => '{type_code}-{period}-{seq:5}',
        ]
    ];
}

4. Multiple Sequences per Model

You can auto-generate sequences for multiple columns on the same model:

public function getSequenceConfig(): array
{
    return [
        'invoice_number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'format_template' => '{type_code}-{YYYY}-{seq:5}',
        ],
        'internal_ref' => [
            'module' => 'internal',
            'type_code' => 'REF',
            'period' => 'never',
            'format_template' => '{type_code}-{seq:8}',
        ]
    ];
}

5. Flexible Custom Date Formats

While standard shorthand tokens (like {YYYY} or {MM}) are quick and easy for common templates, the {date:FORMAT} token gives you complete control using any standard PHP date formatting parameters (e.g., to output month names, day names, custom separators, etc.):

public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            // Generates e.g., INV-16-Jun-2026-00001 (using 'd-M-Y' PHP date format)
            'format_template' => '{type_code}-{date:d-M-Y}-{seq:5}', 
        ]
    ];
}

6. Advanced Enterprise Features

For enterprise numbering requirements, the following properties are supported directly within the model sequence configuration:

public function getSequenceConfig(): array
{
    return [
        'number' => [
            'module' => 'invoice',
            'type_code' => 'INV',
            'format_template' => 'INV-{YYYY}-{seq:5}',
            
            // Starting value (default 1)
            'start_value' => 1000, 
            
            // Custom increment step (default 1)
            'step' => 2, 
            
            // Maximum sequence limit (throws SequenceExhaustedException if exceeded)
            'max_value' => 99999, 
            
            // Set to false to throw a validation exception on manual input overrides
            'allow_manual' => false, 
            
            // Enable continuous sequence recycling (deleted numbers are recycled and reused)
            'continuous' => true, 
            
            // Database connection override for this specific sequence
            'connection' => 'custom_connection', 
        ]
    ];
}

7. Manual Sequence Facade Generation

To manually query, increment, or recycle sequences in service classes, jobs, or custom commands:

use MadeByClowd\AutoSequence\Facades\Sequence;

// Fetch and increment next sequence value
$number = Sequence::generate(
    'order', 
    'SO', 
    '202606', 
    '{type_code}-{YYYY}-{seq:5}', 
    5, 
    'tenant_1',
    null,      // $model context
    null,      // $connection override
    1,         // $startValue
    1,         // $step
    false,     // $continuous
    99999      // $maxValue
);

// Manually recycle a number back into the continuous queue
Sequence::recycle('order', 'SO', '202606', 'tenant_1', 105);

// Get the current number without incrementing
$current = Sequence::getCurrent('order', 'SO', '202606', 'tenant_1');

// Reset or offset the sequence
Sequence::reset('order', 'SO', '202606', 'tenant_1', 100); // Next number will be 101

Artisan Commands Checklist

  1. List Active Sequences:
    php artisan sequence:list
    php artisan sequence:list --module=invoice
    
  2. Reset/Offset Counter:
    php artisan sequence:reset invoice INV --value=500
    
  3. Verify and Repair Sequence Drift: Compare the highest generated number in the actual model table with the database counter to verify synchronization:
    php artisan sequence:verify "App\Models\Invoice" number
    # To automatically repair drift by fast-forwarding the counter:
    php artisan sequence:verify "App\Models\Invoice" number --repair
    

Common Pitfalls

  • Bypassing the Trait check: Manually assigning the sequence column to a value before saving will trigger the Manual Override Protection, skipping generation. Make sure the column is empty/null if you want the package to generate the value.
  • Cache connection locks: If using 'cache' driver for locking, ensure your cache configuration (config/cache.php) supports locks (e.g. redis, memcached, database drivers. file and array do not support concurrent locks properly).
  • Composite keys in DB: If raw querying sequences, remember that the table primary key is composite ['module', 'type_code', 'period', 'scope']. Always run queries enlisting all four columns to guarantee locking performance and accuracy.
  • Hi/Lo Caching Reset: If you manually alter a sequence counter directly in the database while pre_allocation is enabled, remember to clear the cached sequence pool using Cache::store(config('auto-sequence.pre_allocation.store'))->forget('auto-sequence_pool:module:type:period:scope') or by running php artisan sequence:reset.
  • Soft Deletes & Recycling: If a model uses Laravel's SoftDeletes trait, its sequence number is not recycled on soft delete to prevent collisions if the record is later restored. Recycling only occurs when the record is permanently deleted via forceDelete().
  • Pre-Allocation & Gapless Incompatibility: High-performance pre-allocation (pre_allocation.enabled => true) cannot be used with 'gapless' transaction mode. Ensure transaction_mode is set to 'gap_tolerant' when enabling pre-allocation, otherwise a configuration exception will be thrown.
  • Dedicated Pre-Allocation Cache Store: To prevent silent gaps in pre-allocated sequences due to default cache flushes or LRU evictions, specify a dedicated, non-evicting cache store (e.g. Redis with noeviction policy) under pre_allocation.store.
  • FPM Worker Exhaustion & Database Locking: The database locking driver sets a native database session/local lock wait timeout based on locking.timeout (default 5s) instead of blocking the PHP execution thread indefinitely. Avoid long-running transactions to prevent fast-failing lock acquisition exceptions.
  • load_migrations => false in tests: The package's bundled migrations now respect this config during your app's own test suite too. If your app ships a replacement sequences table migration under its own name and sets load_migrations => false, that's honored in phpunit/php artisan test runs, not just in normal/prod environments.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource