← All posts

AI & Engineering

From AI Prototype to Production: What Still Needs Work

A practical walkthrough of permissions, double bookings, retries, monitoring, and recovery using a hypothetical AI-built booking app.

Rommel Clarino 7 min read

At a glance

A working demo is a starting point. Before releasing a booking app, define what confirmation means, enforce permissions and capacity, make retries safe, and rehearse recovery. AI can help implement each step; verify the behavior before relying on it.

A working demo is the beginning

An AI coding tool helps you build a booking app. The calendar looks good, the form submits, and a confirmation appears. You can demonstrate the whole flow in a minute.

Then two people try to reserve the same appointment. Someone changes a booking ID in a request. An email provider times out after the reservation has already been saved.

The prototype has answered an important question: can this experience work? Production asks another: can people depend on it when inputs, timing, and services stop cooperating?

Let’s follow one hypothetical app from its first successful booking to a release we can explain and operate. The AI helps write the app; the app itself does not need an AI feature.

A booking app grows from a freestanding prototype into a supported production service.
An illustrative booking app moves from prototype to production. Select the image to view it full size.

1. Define what “booked” actually means

In a demo, a success message can make the task feel complete. In production, that message needs a precise meaning.

For our app, a confirmed booking means the server has accepted the request, reserved the slot exclusively, and saved a record belonging to the signed-in customer. Email delivery is a separate status. A failed email must not turn a valid reservation into a failed booking.

Write those rules before asking AI to harden the code. “Make this production-ready” leaves too much room for invented assumptions. “Prevent two confirmed reservations for the same slot” describes behavior you can inspect.

A prototype follows a straight line; production checks identity, ownership, availability, and persisted state before displaying confirmation.
The extra steps give the success message a meaning that the system can verify. This is a simplified request path, not a complete infrastructure diagram. Select the image to view it full size.

2. Put permissions where requests are handled

A login page establishes who someone is. Each protected operation still needs to decide what that person can do. OWASP recommends denying access by default and validating permissions on every request.

Suppose Alice owns booking A and Bob owns booking B. Alice can cancel A. If she submits B’s identifier, the server should refuse the action before changing any record. Hiding Bob’s booking in Alice’s interface does not enforce this rule.

Use the verified session to establish the customer identity. Validate the request on the server, check ownership, and apply the cancellation policy there. Keep service credentials out of browser code. Give administrative actions explicit permissions.

The useful verification is concrete: two customers, two reservations, and an attempted cancellation across that boundary. The unauthorized request must leave the reservation untouched.

3. Protect the booking rule when requests overlap

A prototype might read “slot available” and then insert a reservation. Two requests can both read the same available slot before either writes its booking.

For this example, appointments are fixed slots with a capacity of one. Enforce that rule with an atomic database operation and an appropriate uniqueness constraint for active reservations. Define how cancellation releases a slot. Flexible time ranges need a different overlap policy; a unique start time alone would be insufficient.

The interface should handle losing that race gracefully: “That appointment was just booked. Choose another time.” Availability displayed a moment ago is useful guidance, but the write decides whether the reservation succeeds.

AI can propose the transaction and constraint. Review whether they enforce your actual capacity and cancellation rules, then exercise two competing requests against the implementation.

4. Treat a timeout as an uncertain outcome

The server saves a reservation, but the response never reaches the browser. The customer clicks again. Without duplicate prevention, one intended action may create two records.

For our proposed design, the client creates a key for one booking attempt and reuses it on retries. The server scopes that key to the customer and operation, stores the result durably, and prevents competing requests from processing it twice. A reused key with different booking details should be rejected. Define its retention window and the behavior of requests still in progress.

An API provider may offer its own mechanism. Stripe, for example, documents idempotency keys for retrying requests, with specific rules for storing and reusing results. That provider feature does not automatically deduplicate your application’s booking records.

Email has another failure boundary. One option is to save the booking and an email job in the same database transaction, then let a worker deliver it with bounded retries. If delivery remains unsuccessful, preserve the reservation, show its notification status, and give someone a way to investigate. Duplicate email handling depends on the delivery provider’s guarantees.

A response is lost after a booking is saved. A retry with the same request key resolves to the existing booking.
One intended action keeps one stable request key, even when transport requires another attempt. Select the image to view it full size.

5. Make failures visible and actionable

“Something went wrong” gives both the customer and the developer very little to work with.

The customer needs an accurate next step: choose a different slot, sign in again, or check an existing reservation before trying another booking. Never show a definitive failure when the server may already have completed the action.

The operator needs evidence. Record a request identifier, booking identifier when available, processing stage, and outcome. Exclude credentials and unnecessary personal information. Combine structured logs with measures such as booking failures and notification backlog; use traces when following a request across services would help. OpenTelemetry explains how logs, metrics, and traces contribute to observing a system.

An alert also needs an owner and a response. “Notification jobs are accumulating” is useful when someone knows how to inspect the queue, restore delivery, and confirm that pending work resumed.

6. Rehearse release and recovery

Deploying the interface is only part of releasing the system. The application, database schema, configuration, and background jobs need to agree.

Run the important booking scenarios in staging. Check production configuration without exposing secrets. Apply schema changes in a way that remains compatible with the versions running during deployment. Rehearse restoring a backup rather than assuming that creating one proves recovery works.

Start with a limited audience where practical. Watch whether people can complete bookings and whether background work stays healthy. Decide in advance who can pause new bookings and how an application rollback interacts with database changes. Rolling back code does not undo reservations, emails, or incompatible migrations.

Release preparation moves through staging, recovery rehearsal, limited rollout, and observation, with an explicit recovery branch.
A staged rollout is useful only when someone can recognize a problem and act on it. Select the image to view it full size.

What I would verify before opening this app

These checks are a starting point for this example. Your app’s data, users, and integrations determine what else the release needs.

Release checks for the hypothetical booking app
ScenarioRequired outcome
Alice submits Bob’s booking IDNo unauthorized read or change
Two customers reserve one fixed slotAt most one confirmed reservation
The response disappears after savingRetry resolves to the same booking
A key is reused with different detailsRequest is rejected without a new booking
The email provider is unavailableBooking remains saved; notification work is recoverable
A deployment introduces a failureAn owner can pause the affected operation and follow a rehearsed recovery path

Give AI smaller, verifiable jobs

Ask AI to trace the booking request from session validation to the database write. Ask it to identify the window where two requests can both succeed. Ask it to draft customer messages for the failure states you have defined. Review each change against the behavior you need and run the relevant checks after implementation.

A working prototype is valuable: it makes the idea tangible and lets you learn quickly. The next investment is to make its promises dependable. For this booking app, I would start with permissions, exclusive slot reservation, and duplicate prevention. Those decisions protect the central promise before adding more features: when the customer sees “confirmed,” the reservation exists and belongs to them.

← Back to all posts