Skip to content
Softworks
Softworks
hi@softworks.studio
Instagram LinkedIn
← Back to the Journal

Engineering field notes 03

Advanced application architecture

The last slot is a concurrency problem.

What appointment booking, limited promotions and stock allocation have in common—and how database constraints, scoped retries and explicit state protect the final unit of capacity.

Three metal rails approach one occupied opening, with one sage token accepted and two ivory tokens waiting.
Read the engineering story

The common problem

Availability is an observation. Allocation is an authoritative decision made against current state.

A booking page shows 10:00 as free. A promotion has one use remaining. A warehouse has one unit left. Several people can see the same correct answer and then act on it at the same time.

Across Bookalto, Salony and Varqio, we found that the difficult part was preserving a shared invariant across simultaneous, repeated and interrupted requests. The interface can help people understand the decision. It cannot make a stale read reserve anything. The write path has to own that responsibility.

Grounded in the work

  • Bookalto

    Branch-level write serialization, exclusive-resource constraints and one-winner local contention checks.

  • Salony

    Capacity-aware reservations, safe moves and independent payment/appointment states.

  • Varqio

    A reproduced promotion over-allocation regression and capacity-bound allocation correction.

01 / 06

Write down the thing that must remain true.

“Prevent double booking” sounds precise until a service needs both a professional and a room. Does choosing two resources mean either one is acceptable, or both are required? Does the occupied time include cleaning? Does a waiting customer reserve a slot?

Bookalto's implementation answers these questions explicitly. A service requires its selected exclusive resources together. Occupancy includes service time and a trailing buffer. A waiting queue ticket reserves no capacity; promotion acquires the resources and creates the appointment in one transaction.

The invariant is therefore about active allocations for each required resource over an occupied interval. It is not simply uniqueness of an appointment's start time. Two appointments can start at different times and still overlap. Two adjacent intervals can legitimately meet at a boundary.

Salony has a different domain shape: staff skills, staff-specific duration, existing appointments, blocks and relevant chair capacity influence candidate slots. Its availability result is richer than an opening-hours flag. These products share an engineering concern without having identical schemas or reservation algorithms.

Before choosing a lock or queue, specify the entity, scope, capacity, time interval and states that count as occupied. Then define the behavior for cancellation, expiry, retry and rescheduling. Those exception paths are part of the invariant.

02 / 06

Coordinate the decision and constrain the result.

Bookalto takes a branch-level row lock before booking-related writes. Inside the transaction it rechecks the service, resources, business hours, booking horizon, closures and occupied intervals. PostgreSQL separately rejects overlapping active allocations on an exclusive resource.

The lock and the constraint solve different problems. The lock gives application decisions a consistent order. The constraint independently protects the database against an invalid final allocation. PostgreSQL's locking documentation describes how row locks block conflicting writers until the transaction ends.

Below is a standalone schema illustration, not Bookalto's migration. The tenant/resource foreign keys and application authorization are omitted. The half-open interval lets one appointment end exactly when another begins.

sql
CREATE EXTENSION IF NOT EXISTS btree_gist;

CREATE TABLE resource_allocation (
  id uuid PRIMARY KEY,
  tenant_id uuid NOT NULL,
  resource_id uuid NOT NULL,
  appointment_id uuid NOT NULL,
  occupied tstzrange NOT NULL,
  active boolean NOT NULL DEFAULT true,
  CHECK (
    NOT isempty(occupied)
    AND NOT lower_inf(occupied)
    AND NOT upper_inf(occupied)
    AND lower_inc(occupied)
    AND NOT upper_inc(occupied)
  ),
  EXCLUDE USING gist (
    tenant_id WITH =,
    resource_id WITH =,
    occupied WITH &&
  ) WHERE (active)
);

-- A 30-minute service + 15-minute cleanup buffer:
-- tstzrange(start_at, start_at + interval '45 minutes', '[)')

PostgreSQL's range-type guide documents ranges, overlap operators and exclusion constraints. A composite key containing tenant identity helps keep allocation scope explicit; it does not replace server-side access control.

Expiry also needs a write. Wall-clock time passing will not automatically change an allocation's active flag. Bookalto expires overdue holds when a booking write acquires the branch lock, alongside a cleanup worker. That prevents worker delay from being the sole reason old capacity remains occupied.

03 / 06

A failed move should preserve the original appointment.

An ivory token remains seated while a metal transfer arm holds a sage replacement over a second bay.

Acquire the replacement before releasing the original.

The original reservation remains protected while the replacement is checked. The shared mechanism represents one transaction: either every required resource moves together, or the existing booking stays intact.

Seated token
The original appointment is still held.
Replacement bay
Every required resource must be acquired.
Shared linkage
Commit the complete move or roll it back.

Rescheduling is an allocation replacement, not “cancel, then hope.” If the replacement requires a professional and a room, acquiring only one resource is not partial success. The whole proposed change must fail while the original remains valid.

Bookalto replaces allocations and updates the appointment within one transaction. Its local database tests cover rejected moves, duration extensions and multi-resource rollback. Its browser scenario verifies that the original appointment remains after a conflict.

Salony's documented move flow similarly preserves the old reservation while attempting the target and reuses overlapping time where appropriate. The mechanics differ, but the product promise is recognizable: an unsuccessful edit must not destroy a valid booking.

The same rule extends to mutable screens. A staff member who last read version seven should not overwrite version eight unknowingly. Carry the expected version into the write, reject stale changes and explain what remains intact. Refresh frequency improves freshness; it does not eliminate the race between reading and saving.

Explore the failure boundary

Move the booking only when every resource is acquired.

A conceptual transaction with an original 14:00 appointment and a proposed 13:00 slot.

  1. Original

    14:00 retained

    Existing allocations remain protected.

  2. Replacement

    13:00 rejected

    The professional is free, but the required room is occupied.

  3. Transaction

    Rolled back

    No partial professional reservation remains.

The customer still has the original appointment.

04 / 06

The last discount exposes the same race.

Varqio's promotion work provides a useful counterexample to the idea that individual valid writes guarantee a valid aggregate. Its recorded regression reproduced over-allocation when several checkouts competed for a limited promotion. The correction connected candidate allocation to the actual capacity boundary and retained bounded conflict handling, replay and released-capacity reuse.

The reconstructed test scenario involved twelve checkout attempts and a single remaining use. The specification also asked what happens when one checkout retries, a reservation is released, or the limit is reduced. A capacity check must stay correct across all of those states.

Do not transplant a PostgreSQL recipe into MongoDB without examining its transaction boundary. MongoDB documents atomicity at the single-document level and distinguishes that from multi-document transactions. A read-then-write across records needs coordination appropriate to the actual model.

For a simple counter, an atomic predicate can ensure the current quantity permits a decrement. For a capacity pool with reusable slots and per-checkout identity, the proof is more involved: every allocated slot must be valid under the current limit, and a retry must find its existing allocation. This article describes the invariant from Varqio's evidence, not a replacement implementation for its allocation service.

A rejected allocation is a normal business outcome. Record it clearly and offer another choice. Treating all conflicts as server faults encourages aggressive retries against the very resource already under contention.

05 / 06

Idempotency and state machines answer different questions.

Idempotency asks whether this is the same intention arriving again. Concurrency control asks whether competing intentions may both commit. A unique request ID handles neither question by magic.

Bookalto stores an idempotency key within an operation scope with a representation of the request content. Same key and same content resolve the recorded result; changed content conflicts. This matters when the booking commits but the response disappears. It does not give a second customer permission to occupy the same time.

Payment state introduces another independent dimension. Salony separates financial verification from branch approval and appointment progress. Varqio separates payment attempts and provider events from orders, inventory and fulfillment. A successful payment must not imply that an item shipped or an appointment was attended.

Likewise, provider delivery can repeat. A repeated event needs a durable identity and guarded business transition. If the transport sends the same accepted outcome twice, downstream work should converge on one business result. If two distinct legitimate payments arrive, a blanket “ignore all subsequent events” rule would be wrong.

Write transitions around allowed current states and relevant versions. Preserve the distinction between a duplicate, a conflicting request, a late event and a new valid operation. Their recovery actions differ.

06 / 06

Measure contention before narrowing the lock.

Bookalto's branch-level lock is conservative by design. It serializes more work than a carefully partitioned resource-lock strategy might, but it is easier to reason about. The case study's one-winner checks with one hundred competing requests show correctness under those local conditions. They are not a production throughput or latency benchmark.

If realistic workloads later show excessive lock waiting, measure hold duration, contention per branch, query cost and transaction length. Move unrelated work outside the transaction first. External provider calls should not hold a scheduling lock while a network timeout runs.

Finer resource locking adds its own burden: acquire resources in a stable order, account for all resources involved in a move, handle deadlocks with bounded retries and keep the database constraint. Re-run the multi-resource, expiry, replay and failed-move scenarios after any optimization.

A strong verification matrix includes simultaneous different intentions, repeated identical intentions, same-key changed payloads, expired holds, stale versions and a resource failure after an earlier allocation was attempted. Check the final database state as well as the returned status.

Across the three products, the durable lesson is that correctness needs an explicit place to live. The availability screen explains possibilities. The transaction decides. The persisted model makes the decision enforceable, and the interface tells the person what that decision means.

Carry this into your next system

Three decisions to keep.

  1. Specify capacity and occupied state before choosing a locking strategy.
  2. Use atomic writes and database constraints for authoritative allocation.
  3. Prove replay, rollback, expiry and stale-edit behavior before optimizing contention.

Trace the reasoning

References & further reading.

Project claims link to the published case studies. External references are primary technical documentation, reviewed on 18 October 2026. Code and interactive scenarios are teaching examples with the limits described alongside them.

  1. Bookalto engineering case study

    The actual scheduling implementation, local 100-request contention checks and their throughput limits.

  2. Salony engineering case study

    Staff/chair capacity, reservation moves and separate appointment/payment states.

  3. Varqio engineering case study

    The documented promotion capacity regression and correction; beta qualification boundaries.

  4. PostgreSQL — Explicit Locking

    Authoritative row-lock and transaction behavior.

  5. PostgreSQL — Range Types

    Time ranges, overlap and exclusion constraints.

  6. MongoDB — Atomicity and Transactions

    Single-document atomicity and multi-document transaction boundaries.

Case-study evidence retains its original scope and date. This article does not represent a new test run against the underlying products, a hardware certification or a production performance benchmark.

Softworks

Softworks Studio