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 Document Numbering Laravel Package

vimatech/laravel-document-numbering

Laravel package for generating sequential document numbers for your models. Configure custom formats, prefixes, suffixes, date placeholders, padding, and reset periods, with database-backed, concurrency-safe numbering for invoices, orders, and other records.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What the package claims to be. A narrow, single-purpose Laravel package: allocate the next number in a sequence, safely, for a named document type (invoice, quote, credit note), scoped per tenant/company/series, with a configurable string pattern and a period-based reset (annual/monthly). The differentiating claim is row-lock-based concurrency safety with gap-free numbering by default — meaning the number is allocated inside the caller's transaction and only persists if that transaction commits.

Architecture fit. This is a classic "small library, high blast radius" component. The architectural surface is small — a service provider, a config file, one or two migrations (a counters table and possibly an allocations/audit table), a facade or injectable generator service, and a token-based pattern renderer. That means it composes cleanly with any Laravel app regardless of whether the domain layer is fat models, actions, or DDD-lite. The important architectural question is not where it plugs in but when it is called: the package can only be correct if allocation happens at the moment a document is finalized and persisted, not when a draft is created. If a draft burns a number and is later deleted, "gap-free" is a lie. Confirm that the intended usage pattern is "allocate inside the same DB transaction that writes the invoice row."

Integration feasibility. High on paper, low on evidence. Publishing config, running a migration, and calling a generator is a half-day of work for one engineer. The friction is entirely in the non-happy paths: backfilling existing sequences so the first generated number doesn't collide with history; seeding per-scope counters to the correct high-water mark; reconciling documents that already exist with ad-hoc numbering; and deciding what "period reset" means at a timezone boundary (a midnight UTC reset vs. a Europe/Madrid fiscal-year reset is a different legal answer).

Technical risk. Concentrated in four places:

  1. Serialization bottleneck. Row-level SELECT ... FOR UPDATE on a single counter row serializes every allocation for that scope. That is correct and cheap at 10–100 documents/day and becomes a lock-contention and deadlock surface at thousands/hour, especially if the caller holds the lock across a slow transaction. Throughput ceiling must be measured, not assumed.
  2. Gap-free vs. throughput is a genuine trade-off. Block reservation (reserve 50 numbers, hand them out from memory) is the standard scaling answer, but it creates gaps on restart, which defeats the headline feature. There is no configuration that gives you both. Confirm what the "non-gap-free" mode actually guarantees.
  3. Compliance semantics. In many jurisdictions (EU VAT regimes, Italy's SdI, Spain's Verifactu, Germany's GoBD) invoice numbering is a statutory control: monotonic, gapless, unbroken per series per period, with immutability after issuance. A package asserting "gap-free by default" is making a compliance-adjacent claim that must be validated by finance/legal, not by the engineering team, and must be re-validated per country of operation.
  4. Maintainer and provenance risk. Zero stars, zero dependents, a 17/100 composite score, and a "last release" timestamp (2026-09-04) that is either forward-dated or a registry artifact — treat all metadata as unverified. Single-maintainer, pre-traction packages in a legally load-bearing code path are a bus-factor and abandonment risk. MIT licensing mitigates this substantially: the code is forkable and the surface is small enough to own outright.

Key questions to put to the maintainer (or answer by reading the source).

  • Does allocation occur inside the caller's transaction, and what happens to the counter on rollback — is the number returned to the pool, or consumed (gap)?
  • Which databases are supported and tested — MySQL/InnoDB, PostgreSQL, SQLite, MariaDB? What isolation level is assumed? Is SKIP LOCKED used or plain FOR UPDATE?
  • Is there deadlock detection and retry, or does the caller eat the exception?
  • How is the period boundary computed — application timezone, DB timezone, or config? What happens on a retroactive document dated into a prior period?
  • How is scope keyed (tenant ID + document type + series + year)? Is the scope key parameterized safely, or string-concatenated into the pattern?
  • Is there an immutable allocation ledger (who got number N, on which document, at what time)? Auditability is the difference between "convenient" and "defensible."
  • Is generation idempotent / retry-safe if the caller retries after a timeout?
  • What is the version support matrix (Laravel 10/11/12, PHP 33/8.4), is there CI, and are there tests covering concurrent allocation?
  • Does it work against a read/write split connection where reads go to a replica?

Absent satisfactory answers to the first, second, and sixth, this should not touch production invoices.

Integration Approach

Stack fit. Native Laravel, no exotic dependencies, no queue or external service required — which is the right shape. It slots into the existing Eloquent/transaction model and does not require a new piece of infrastructure. That is its main strategic advantage over "build a numbering microservice" or "use Redis INCR," both of which introduce a second consistency domain that must be reconciled with the database on every failure.

Build vs. buy. Be explicit that this is a ~200–400 line component. The purchase price of adoption is low, but so is the price of a clean-room internal implementation, and the internal version carries no maintainer risk and can be tuned to exactly the compliance regime you operate under. Recommendation: vendor the package (fork into an internal namespace) rather than depend on it via Composer. You get the MIT-licensed head start, you own the patch cadence, and you are not exposed to abandonment. If the team prefers a Composer dependency, pin it exactly and require a passing concurrency test suite in your own CI before merge.

Migration path. Assume the organization already has documents numbered by something weaker (auto-increment IDs, or date('Y').'-'.count() which is subtly racy). The migration is:

  1. Inventory every document type and where its number is currently produced. Find the ones that are not invoices — those are the safe pilot targets.
  2. Establish the high-water mark per scope per period from existing data, then seed counters to exactly that value. Off-by-one here produces duplicate invoice numbers, which is a correction-and-notification event with tax authorities in most regimes.
  3. Freeze the format before cutover. Do not change the pattern simultaneously with the mechanism; if the visible number format must change, that is a separate, legally-notified change with an explicit effective date (commonly a fiscal-year boundary).
  4. Dual-run in shadow mode for one period: generate numbers for a subset of document types, compare against the incumbent path, never let the shadow number reach a customer.
  5. Cut over per document type, lowest-risk first: quotes → credit notes → invoices.

Compatibility. Verify the Laravel/PHP support matrix against your actual runtime before anything else; a package released "recently" may still exclude the version you run. Confirm the migration is additive and reversible, and that it does not assume a specific table prefix or connection. If you run multi-tenant with per-tenant databases, confirm the counters table is created in each tenant connection, not just the central one — this is the single most common integration defect in packages of this class.

Sequencing (suggested 6–8 week path for a mid-size team).

Week Deliverable
1 Source read-through; written answers to the key questions above; go/no-go on fork-vs-depend
2 Spike branch: install, migrate, generate 10k numbers under 20-way concurrency; record p50/p99 latency and deadlock rate
3 Finance/legal review of the pattern, reset rule, and gap-free claim for each operating jurisdiction
4 Backfill script + reconciliation report; seed counters in staging
5–6 Shadow-mode run on quotes and credit notes; alarm on any gap or duplicate
7 Invoice cutover behind a feature flag with per-scope kill switch
8 Decommission legacy numbering path; document the new runbook

Operational Impact

Maintenance. Low code churn, but non-zero ownership. A numbering component changes rarely and breaks catastrophically. Budget for: a quarterly dependency review, an owner who understands the transaction semantics (not just the API), and a regression test that asserts monotonicity and gaplessness per scope under concurrency. If forked, add a short design note explaining why the lock is held and what would break if it were released early — future engineers will otherwise "optimize" it into a correctness bug.

Support and escalation. Incorrect invoice numbers are a finance and legal incident, not an engineering incident. Define the escalation path now: who can stop issuance, who can void and reissue, who notifies the tax authority if required. Duplicate numbers are worse than gaps in most regimes; both are reportable in some. The package should never be the only thing standing between a bug and a customer-facing invoice — wrap it in a thin internal service with validation (monotonic per scope, format matches regex, period matches document date) that fails loudly before persistence.

Scaling. Two regimes. Below roughly a few hundred documents per hour per scope, a row lock is fine and you should not over-engineer. Above that, expect contention, lock-wait timeouts, and deadlocks between concurrent transactions that each touch the counter and other rows in different orders. Mitigations, in order of preference: (a) keep the locked transaction as short as possible — allocate as the last write before commit; (b) shard scopes (per-entity or per-series counters rather than one global counter); (c) move to a dedicated allocation service with block reservation — accepting gaps, which requires a compliance decision. Also note that FOR UPDATE forces the read to the primary; read/write splitting will silently not help here.

Failure modes to instrument.

  • Lock-wait timeout / deadlock → user-facing 500 on document creation. Needs retry-with-backoff at the boundary.
  • Counter advanced but transaction rolled back → gap. Detect by reconciling the allocation ledger against persisted documents nightly.
  • Counter not advanced but document persisted (crash between) → duplicate. Rarer, more severe. Enforce a unique constraint on the number column as a hard backstop, always.
  • Period reset with wrong timezone → duplicate numbers across a year boundary, or documents numbered into the wrong fiscal year.
  • Backfill/seed error → collision with historical numbers on the first live document.
  • Multi-tenant misconfiguration → cross-tenant number leakage, which is both a correctness and a confidentiality problem.

Ramp-up. The API is small enough that a mid-level Laravel engineer is productive in under a day, and the config file is largely self-documenting. The conceptual ramp-up is the real cost: transaction isolation, row locking, and why "gap-free" and "high throughput" fight each other. Plan for a 30-minute walkthrough with the team plus a one-page ADR, and make sure at least two engineers — not one — can debug a numbering incident.

Overall recommendation. Treat as pilot-grade, not production-grade for invoices at adoption time. It solves a real, painful, frequently-botched problem with the right mechanism, and MIT licensing makes the code yours if you want it. But zero stars, zero dependents, a single maintainer, and a compliance-critical domain mean the decision is "we are adopting this code and its correctness", not "we are depending on a vendor." Fork it, test it under concurrency yourself, validate the gap-free guarantee with finance, pilot it on quotes and credit notes, and only then let it touch invoices — and even then, behind a unique constraint and a kill switch.

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.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast