AstroBaaS

Checkout & payments

Terms & Conditions Checkbox

Free — GPL coresize Scommitted · 5

Generated from docs/plan/core/terms-conditions-checkbox/PLAN.md in the project's planning notes, which are not part of the public repository. Nothing described below is implemented — it is the written plan for it.

Committed, number 5 in the build order. Checkout consent to the shop's terms. Small, and a legal expectation in most of the EU. The whole list.

Merchants need customers to accept terms before checkout. This core feature adds a mandatory checkbox and prevents order placement if unchecked.

Partly built (2026-10-26). The core now ships the terms box: src/lib/commerce/checkout-terms.ts, tested in tests/checkout-terms.test.mjs. It records terms_accepted, privacy_accepted and the time of acceptance on the order. A shop setting holds the label and the terms URL, and the storefront starter draws the box. Different from this page: requiring the box is a setting, checkout_terms_required, which is off by default. On a default install an order without acceptance is still created, and staff orders are always exempt. Not built: extra checkboxes the merchant defines (privacy, newsletter and so on). This item stays planned until the rest is built or the plan is narrowed.

The problem

Without terms acceptance, I have no legal protection against disputes. Customers must accept my terms of service and return policy before I process their order.

What it does

  • Checkbox in checkout form: ‘I agree to the Terms & Conditions’
  • Link to full terms (theme-defined URL or inline modal)
  • Validation: order is rejected if checkbox is unchecked
  • Record: store on Order that customer accepted terms (and timestamp, for legal proof)
  • Customizable text: merchant can change the checkbox label via theme settings
  • Multiple checkboxes: allow merchant to add privacy policy, newsletter consent, etc. (per theme)

What it deliberately does NOT do

Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.

  • Legal template generation — merchants are responsible for their own legal terms. AstroBaaS does not provide template terms.
  • Versioning or acceptance history — core just records that terms were accepted, not which version or when they changed.

Data model

Add to Order: terms_accepted (boolean, required; absent on orders created before this feature means accept without recording), privacy_accepted (boolean, optional; for GDPR consent). Both are frozen at checkout; retroactive changes are not possible.

API

  • POST /api/orders — checkout. Request includes terms_accepted: true (or false). If false, order is rejected with code ‘checkout.terms_not_accepted’. Response returns terms_accepted in the confirmation.

Every route added here must also appear in src/pages/openapi.json.ts — a test fails the build if it does not.

Admin

Checkout form has checkbox; no admin interface needed.

The seam — why this is core

Core owns the Order.terms_accepted field and validation at checkout. Theme owns the checkbox HTML, label text, and link to terms.

Core owns the interface + honest checkbox; checkout compliance is infrastructure, not a per-country obligation or credential.

Dependencies

  • shopping-cart → payment-status-tracking

Acceptance checks

Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.

  • Unchecked: POST /api/orders with terms_accepted=false → 400 error, code ‘checkout.terms_not_accepted’
  • Checked: POST /api/orders with terms_accepted=true → 201, order created, terms_accepted=true stored
  • Order detail view shows ‘Customer accepted terms’ or similar confirmation
  • Merchant can customize checkbox label in theme settings (e.g., ‘I agree to the Store Terms’)

Risks

Acceptance without reading: customer checks the box without reading. This is unavoidable and a limitation of legal UX; provide a link to the terms, not just a box. Recording acceptance time: if Order.created_at is the only timestamp, and merchant changes terms later, there’s ambiguity about which version the customer accepted. Solution: store the terms_accepted_at timestamp and optionally a hash of the terms version at that moment (advanced; out of scope for core). Retroactive enforcement: if a customer disputes and says ‘I never saw the terms’, having recorded acceptance is helpful but not foolproof; a lawyer’s advice is needed.

Commercial context

Suggested pricefree (core)
Rival anchorShopify: included (via apps); Magento: included

The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.


Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full catalogue and CONTRIBUTING.md for how to work on this repository.