My first n8n project grew from a payment reminder to a full booking system in less than 3 months. What would you cut?

Hello n8n Community!!

This is my first n8n project. Three months ago, I started with one workflow:
a daily email to my dad listing the supplier and customer payments due, so he could stop tracking them manually (forgetting them).
He runs a small Italian tour operator that organises destination running events in Europe.

What was supposed to be one reminder workflow turned into the rest of the back office: quote requests, pricing, quote emails, a booking form, PDF contracts, payment follow-up, and booking changes. It has been live since April, handling real bookings.

I don’t know if I overbuilt it. I have nothing to compare against, so I’m asking.

What’s actually in there (beyond a basic “form + email” version)

  • The booking link is a one-time token. It expires, can only be used once, and is invalidated server-side as soon as the booking workflow starts.
  • Flights are optional. The operator can add or remove a flight on a booking with one button, and the price recalculates.
  • Bookings can be modified after confirmation. The modification link is tokenised, expiring, and single-use. The operator can also change the stay option or re-price a booking from a button in Airtable.
  • If a booking or modification gets stuck mid-flow, a recovery workflow picks it back up from the last good state.
  • Pricing is a sub-workflow called from three places. A regression harness runs it against 13 hardcoded scenarios and checks every output plus four universal invariants (installments must sum to the total, rounding rule must hold, etc.). It is inactive day-to-day and is run before any pricing change.
  • Every failure goes to a global error handler and into a daily digest, so nothing sits silently.

Stack

Form (Vercel) -> Webhook -> n8n (self-hosted)
                    + Airtable (11 tables, ~450 fields) for DB and operator UI
                    + SMTP / Gmail for emails
                    + Carbone.io for PDF contracts
                    + Google Drive for storage and backups

Scale: 10 to 12 events a year, ~800-900 quote requests a year, ~100-150 bookings. Slowly growing.

Shape: 26 active workflows. Quote intake (4), booking (4), modifications (4), recovery (2), admin (7), error handling (2), operations (3). Plus a dormant pricing test harness.

Two things I’m not sure about

1. Did I overbuild this? 26 workflows for that volume sounds like a lot. Every one solves a real problem that came up during testing, but I don’t know what normal looks like.

For reference, the system replaces an estimated 130-200 hours of manual admin a year for one solo operator; that’s the baseline I’m measuring “overbuilt” against.

2. Is the recovery + error-handling layer proportionate? Four workflows go to “what if something fails”: global error handler, daily error digest, and two recovery workflows that resume crashed bookings or modifications from a persisted state. Mid-flow failures have happened twice so far in production. But one unrecoverable stuck booking means manual cleanup across four tables and a confused customer, so I’d rather have the safety net. At this volume, is that proportionate, over-engineered, or still under-engineered?


Happy to share sanitized workflow JSON for any flow if it helps.

2 Likes

I’m really sorry that I don’t have a better way to say this…

You want to make sure that your systems are modular and not monolithic. eachthingthat you build should do a thing and it should be able to do that thingvery well, but it should also be able to do itwith anythingyou want it done to.

Level 0: If you wanted to make an AI email sorter, for you, a fireman, then you could create a classifier for emails about calendar requests, fundraisers, and exotic dancing, you could do that.

Level 1: You could also create the exact same flow but use variables, and I, not a fireman, could change the set (define) node vars so that the classifier now splits between my things and puts them into my labels, or drafts a reply - with a prompt that is partially hard-coded and partially steered via input in the same set node.

Level 2: You use the gmail node to pull the labels in the account that I have authenticated for this flow, then you populate those into both the classifier and the draft drafter agent prompt.

You now don’t have an email handler for you, and you don’t even just have an email handler that anyone could set up for themselves. You have a modular email handler that you could slap into ANY workflow, for ANY reason, and use the account that you select from a dropdown as sufficient context for it to go to work. Sure include a set node with some default tuning so they can dive deeper if they want, but the fact that they don’t have to means you have done it “right”