<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Beyond Digital Solutions]]></title><description><![CDATA[Practical development insights covering Next.js, PostgreSQL, booking systems, and modern business applications.]]></description><link>https://beyondds.hashnode.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1593680282896/kNC7E8IR4.png</url><title>Beyond Digital Solutions</title><link>https://beyondds.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 08:22:39 GMT</lastBuildDate><atom:link href="https://beyondds.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Prevent Double Bookings with PostgreSQL Exclusion Constraints]]></title><description><![CDATA[A booking page can show a slot as free, then receive two confirmations for that staff member and time. The availability response is a snapshot. It helps the customer choose, but it cannot reserve capa]]></description><link>https://beyondds.hashnode.dev/prevent-double-bookings-with-postgresql-exclusion-constraints</link><guid isPermaLink="true">https://beyondds.hashnode.dev/prevent-double-bookings-with-postgresql-exclusion-constraints</guid><category><![CDATA[PostgreSQL]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[database]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[seven Secret]]></dc:creator><pubDate>Thu, 15 Oct 2026 05:36:04 GMT</pubDate><content:encoded><![CDATA[<p>A booking page can show a slot as free, then receive two confirmations for that staff member and time. The availability response is a snapshot. It helps the customer choose, but it cannot reserve capacity by itself.</p>
<p>Generate candidate slots by intersecting business hours, staff eligibility, service duration, time off, existing reservations, time zone rules, and any before/after buffers. On confirmation, let the database arbitrate concurrent writes. For variable-length appointments, a PostgreSQL GiST exclusion constraint can reject overlapping effective ranges for the same staff member:</p>
<pre><code class="language-sql">CREATE EXTENSION IF NOT EXISTS btree_gist;

ALTER TABLE appointments
  ADD CONSTRAINT no_overlapping_active_staff_appointments
  EXCLUDE USING gist (
    staff_id WITH =,
    tstzrange(effective_starts_at, effective_ends_at, '[)') WITH &amp;&amp;
  )
  WHERE (status NOT IN (
    'CANCELLED_BY_CLIENT',
    'CANCELLED_BY_ADMIN',
    'RESCHEDULED'
  ));
</code></pre>
<p>This is an illustrative single-staff pattern, not a drop-in migration. The range uses <code>[)</code> so a booking ending at 10:00 can be followed by one starting at 10:00. Store buffer-adjusted effective times when setup or cleanup also consumes capacity. Adjust the status predicate to your actual lifecycle; temporary holds need an expiry policy.</p>
<p>When the constraint rejects a collision, PostgreSQL reports SQLSTATE <code>23P01</code>. Catch that at the server boundary, respond with a conflict such as HTTP 409, and refresh the available slots. The earlier calendar query cannot prevent two requests from racing.</p>
<p>Idempotency is a separate guarantee. Use a scoped request key and enforce its uniqueness in the database if simultaneous retries must resolve to one booking. A read-before-insert check backed only by a non-unique index speeds lookup but does not prevent duplicates.</p>
<p>Test the real database boundary: submit the same slot concurrently and assert that exactly one reservation succeeds; verify adjacent intervals are accepted; verify buffers and consuming statuses block overlaps; verify cancelled states release capacity; then retry the same idempotency key concurrently. An in-memory simulation can check interval arithmetic, but it cannot prove PostgreSQL constraint behavior.</p>
<p>The BDS v1.0.3 source package includes a PostgreSQL overlap constraint, an atomic booking RPC, and a database uniqueness constraint for its idempotency key. Its included test coverage also uses in-memory simulations; those do not replace executing the migrations and concurrency checks against PostgreSQL. Buyers configure and deploy their own copy; the ZENO demo is fictional and is not included. Review the delivered schema, test coverage, requirements, and chosen marketplace license before using any source package in a project.</p>
<p>Product scope and marketplace offers: <a href="https://beyond-ds.net/en/software/appointment-booking">https://beyond-ds.net/en/software/appointment-booking</a><br />ZENO demo: <a href="https://zeno.beyond-ds.net">https://zeno.beyond-ds.net</a></p>
<p><strong>Disclosure:</strong> I am part of Beyond Digital Solutions, which makes the source package mentioned above. No affiliate link is included. Store prices and license options vary by marketplace; verify the selected listing.</p>
]]></content:encoded></item></channel></rss>