System Design
How I build websites as complete systems
I start with the customer’s action and the business’s next action—not a page list or a preferred stack. The architecture should carry that workflow reliably, without owning more than it needs to.
A “website” can be a document, a protected intake boundary, a booking operation, or a commerce system. Systems thinking means telling those apart early.
The word “website” hides the engineering problem
A public interface is only the visible edge of a business workflow. A visitor clicks Send, Book, or Order; after that, the system still has to validate intent, place the resulting work somewhere authoritative, notify the right person, expose a useful operational state, and recover if one of those steps fails.
I learned to treat those downstream responsibilities as part of the website decision. That does not mean giving every client a database, admin dashboard, or custom backend. Kora Studio’s own inquiry flow intentionally sends one validated owner notification and stores nothing. Zube’s Grub needs a very different boundary because payments, kitchen work, fulfillment, and provider reconciliation continue long after checkout.
This article explains the method that recurs across the systems I have built. It is not a fixed process or a universal stack. Each example is here because its checked-in implementation makes a different tradeoff visible.
The first question
Trace the work in both directions
I begin with a concrete customer action and follow it until the business can respond. Then I trace backward: what must be true before the interface is allowed to offer that action?
Text equivalent
- A customer arrives with an intent: ask, book, or buy.
- The public interface collects only what the workflow needs.
- The server validates the request and enforces the trust boundary.
- One authoritative system accepts the work.
- The owner receives a state they can act on.
- The customer receives an honest confirmation; recovery reconnects any failed step to the authority.
The user action, the owner’s next action, the facts each side needs, the system allowed to accept the work, and the evidence required before the customer sees “success.”
For an inquiry, this might end with one email accepted by Resend. For a booking, “success” may require a held slot but not yet an owner-approved appointment. For an order, it may require server-calculated totals and a captured payment before staff can begin fulfillment. The words on the button are simple; their contracts are not interchangeable.
The visible system
Shape information and interaction around decisions
Information architecture answers what a person needs to understand before acting. Interaction design answers what the system must reveal while that action is underway: prerequisites, price, availability, privacy boundaries, progress, errors, and a recovery path.
I map the happy path and the hesitant path. A customer who already knows what they want should move quickly. Someone who is unsure should be able to compare options without opening a second site or calling for basic information. That is why a useful architecture includes content ownership and state design, not only routes.
| System | Customer decision | Interface responsibility | Deliberate limit |
|---|---|---|---|
| Kora Studio | Is this studio relevant to my problem? | Explain the work, collect a focused inquiry, preserve a non-JavaScript submit path. | No CRM or scheduling system on the public site. |
| Divine Care | Which non-emergency contact path fits? | Route people by inquiry type and make the no-PHI boundary visible before submission. | No clinical intake, diagnosis, DOB, medication, or insurance-member data. |
| Elevate | Which consultation time can I request? | Show current availability, collect non-clinical logistics, hold a slot, and explain owner confirmation. | Payment does not silently become a confirmed appointment. |
Responsive behavior, keyboard access, readable focus, reduced motion, and honest loading states belong here too. They are not a final accessibility pass. They decide whether the workflow can be completed at all.
The central design decision
Give each important fact one owner
Most expensive system mistakes begin when two parts of the product believe they own the same fact. The browser should not decide a commercial price. A database projection should not overrule a payment provider. A webhook should not be treated as a once-only message. An admin panel should not expose controls the underlying authority cannot honor.
Text equivalent
- Browser: temporary input and presentation state; never privileged commercial or operational authority.
- Server: validation, authorization, and workflow policy.
- Specialized provider: payment, order, email, calendar, or CRM truth when that service is present.
- Operational store: durable workflow state and provider projections needed by the business.
- Owner interface: only the actions the authority model permits.
Zube’s Grub makes this distinction especially concrete: Square owns payments, orders, and the operational catalog; Supabase holds application workflow and projections; the browser carries cart intent; staff controls move through protected server boundaries. By contrast, Kora Studio intentionally has no lead database. Its successful terminal state is an accepted owner email notification, so adding persistence would create a second responsibility without improving the workflow.
Scope control
Choose the smallest architecture that completes the workflow
“Smallest” does not mean the fewest files. It means no subsystem exists without a responsibility, and no required responsibility is left to a manual accident. I escalate architecture only when the business workflow introduces a new kind of state, authority, or recovery obligation.
Text equivalent
- If the click needs no server work, use static delivery or an external handoff.
- If the server only validates and notifies, build a narrow server boundary and fail visibly when delivery fails.
- If state must survive the request, add a durable store with a clear schema and retention boundary.
- If an owner must operate that state, add authenticated tools for the actual decisions they make.
- If a provider owns money, orders, calendar, or CRM state, define synchronization and recovery before treating the integration as complete.
Five systems, five justified shapes
Text equivalent
- Kora Studio: schema validation, honeypot, rate limit, one server-side email notification, and no lead persistence.
- Divine Care: multiple inquiry types, allow-listed fields, explicit consent, and rejection of clinical-data keys before email delivery.
- Elevate: non-clinical lead persistence, live availability, held slots, payment state, protected owner confirmation, and customer notification.
- Zube’s Grub: storefront, protected staff application, Square-owned commerce, operational projections, webhooks, queues, and reconciliation.
- Aboh: a native booking model plus queued workflow items and provider-alignment records for Salesforce and calendar handoffs.
The implementation seam
Build the public interface against a narrow server contract
The browser is untrusted and disposable. It can help someone assemble intent, but the server must reload or validate every fact that affects money, permission, availability, privacy, or durable state. I keep that boundary legible: a route or server action accepts a bounded input, enforces the contract, calls one domain operation, and returns a user-safe result.
request
→ normalize and allow-list fields
→ reject unsafe or incomplete input
→ enforce authorization and abuse limits
→ ask the authoritative service to perform the work
→ persist only the workflow state the business owns
→ return an honest success, conflict, or recovery path
The shape is visible in real differences. Kora Studio uses a Server Action so the contact form can still submit when JavaScript fails; the server validates, rate-limits, sends one notification, and reports failure rather than claiming the message arrived. Divine Care’s Cloudflare function removes forbidden clinical keys and accepts only allow-listed scheduling and administrative fields. Elevate reloads availability before reserving a slot and removes an orphan lead if the hold loses a race.
Integrations live behind the same boundary. Secrets never enter browser bundles. Money stays in integer cents. External identifiers are treated as references, not proof that an operation succeeded. User-facing success waits for the level of evidence promised by the interface.
The business-facing product
Build operational tooling only around real decisions
An admin interface is justified when someone repeatedly needs to review state, resolve exceptions, or change information without a code deployment. It is not justified because “professional websites have dashboards.”
Content
Give owners control when information changes frequently and publishing state matters. Elevate separates draft and published blog content and exposes selected site settings without making every sentence database-driven.
Scheduling
Expose availability, holds, payment state, and confirmation as distinct states. The owner should see what action remains instead of inferring it from email.
Fulfillment
Use a workflow vocabulary that matches the work. Zube’s Grub translates paid orders into kitchen states while withholding unconfirmed provider intent from public tracking.
Exceptions
Surface the cases automation cannot safely close: a failed notification, a provider mismatch, an expired hold, or a record awaiting owner approval.
Which real decision does this control let the owner make, what authority accepts that decision, and what evidence proves the change took effect?
Trust boundaries
Privacy and security change the product surface
Security is not only middleware around an already-decided form. It changes what the form is allowed to ask, where records may live, who can act on them, and what the system says when a dependency is unavailable.
Divine Care is the clearest example. The public site is intentionally zero-PHI. Its endpoint strips forbidden keys including diagnosis, medications, DOB, insurance identifiers, and clinical messages; it does not simply add a warning and hope people comply. The interface routes users toward scheduling and administrative callbacks while preserving phone and office contact paths for anything outside that boundary.
Other recurring controls include server-derived staff authorization, authenticated owner routes, row-level database rules, request size limits, origin checks, honeypots, rate limits, and provider signature verification. I choose controls in proportion to the data and action—not from a generic “security checklist”—but privileged state always stays behind the server.
The non-happy path
Design recovery as part of the workflow
Distributed work is not finished when an API returns 200 once. Providers retry webhooks, networks time out after accepting work, two people claim the same slot, credentials expire, and an email can fail after the underlying state changed. The system needs enough durable identity to determine what happened without repeating a side effect.
My recovery design depends on the consequence:
- Human inquiry: fail visibly and provide a direct alternative contact path.
- Competing booking: return a conflict, remove orphan state, and ask the customer to choose again.
- Payment or order: use idempotency, monotonic provider projections, signed webhooks, retryable claims, and reconciliation.
- Owner confirmation: make the transition explicit and make follow-up delivery retryable without repeating the decision.
This is why Zube’s Grub’s architecture contains durable webhook claims and reconciliation while Kora Studio’s contact form does not. The cost of ambiguity and the amount of state to repair are fundamentally different.
Release confidence
Verify the story from interface to owner outcome
I treat build success as one signal, not the release gate. Verification follows the responsibilities introduced by the architecture: schema and unit tests for domain contracts, integration tests for persistence and providers, browser checks for complete user paths, and deployment checks for routing, headers, configuration, and recovery.
Text equivalent
- Verify domain contracts and schemas locally.
- Verify persistence and third-party adapters at their real boundaries.
- Complete the workflow in a browser, including error and reduced-motion states.
- Build the production-shaped artifact with the intended environment contract.
- Verify live routes, headers, delivery, and recovery; keep the previous healthy deployment available for rollback.
Handoff completes the operational story. The owner needs to know what they can change, what failure looks like, where work appears, and which external accounts the system depends on. Documentation should describe the current system rather than preserve every abandoned plan.
What I carry forward
Five working principles
- Trace the customer action into the business.
The page is not complete until the resulting work reaches a state someone can act on.
- Name the owner of every important fact.
Browser intent, application policy, provider truth, and operator state must not compete silently.
- Add architecture only when responsibility requires it.
A database, dashboard, queue, or custom integration has to close a real workflow gap.
- Make failure states honest and recoverable.
Success copy should reflect accepted work, not optimistic intent.
- Verify the same path the customer and owner use.
Tests, deployment checks, and operational handoff should prove the system as a connected whole.
A good website is not the architecture with the most parts. It is the smallest complete system that lets a customer act, lets a business respond, and makes both sides’ state trustworthy.