Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ItsJhonAlex/Ecommerce/llms.txt

Use this file to discover all available pages before exploring further.

Avanzar In Time Shop uses a province-based lookup table for shipping costs, designed around Cuba’s geographic and administrative structure. Rather than a complex real-time carrier integration, each combination of destination province and billing currency maps to a flat rate stored in the shipping_rates table. At checkout, the backend resolves the correct rate automatically from the recipient’s declared province and the order currency.

Shipping Rate Fields

The shipping_rates table has a unique constraint on (province, currency) — there can only be one active rate per province-currency pair at any time.
ColumnTypeNotes
idUUIDPrimary key, generated by the database
provincetextDestination province name (must match exactly the value supplied at checkout)
currencytextISO 4217 currency code (e.g., "USD", "CUP")
amountMinorintegerShipping cost in the currency’s minor units (cents)
activeboolean (default true)Only active = true rates are used during checkout; set to false to temporarily suspend a rate without deleting it

Order Recipient vs. Buyer

Avanzar explicitly separates the buyer from the recipient, a distinction that reflects how overseas customers commonly shop for family members in Cuba.

Buyer

The person paying for the order. May be located abroad (e.g., sending USD via Zelle from the United States). Captured as a snapshot on the order via buyerName, buyerEmail, and buyerPhone.

Recipient

The person receiving the shipment in Cuba. Captured as a full address snapshot on the order. This is the address used to calculate the shipping rate.
The recipient address is stored directly on the orders row as a snapshot, not as a foreign key to the addresses table. This means the delivery details are permanently frozen at the moment of purchase — if the customer later edits their address book, past order history is unaffected. Recipient fields on the orders table:
FieldDescription
shipRecipientFull name of the recipient
shipPhoneContact phone number for the recipient
shipProvinceDestination province (used for shipping rate lookup)
shipMunicipalityDestination municipality
shipAddressLineStreet address and house number
shipReferenceOptional delivery landmark or gate reference

Checkout Shipping Resolution

1

Checkout payload includes recipient province and currency

The storefront sends a CheckoutInput payload containing recipient.province and currency (validated as a 3-character ISO 4217 code via Zod schema).
// packages/shared/src/checkout.ts
export const checkoutSchema = z.object({
  currency: z.string().length(3), // e.g. "USD" or "CUP"
  recipient: z.object({
    province:     z.string().min(1),
    municipality: z.string().min(1),
    addressLine:  z.string().min(1),
    // ...
  }),
  // ...
});
2

Backend queries shipping_rates

The checkout service performs a lookup:
SELECT amount_minor
FROM   shipping_rates
WHERE  province = :province
AND    currency = :currency
AND    active   = true
LIMIT  1;
3

Missing rate → 422 error

If no matching active rate is found, the checkout is aborted immediately with HTTP 422 Unprocessable Entity and error code SHIPPING_NOT_SUPPORTED. The order is not created.
4

shippingMinor added to order totals

The resolved amountMinor from shipping_rates becomes the shippingMinor value used in the order total calculation via computeOrderTotals.

Order Totals

Order totals are computed server-side by computeOrderTotals from the backend checkout service and stored as four integer fields on the orders row:
// apps/backend/src/services/checkout.ts
export function computeOrderTotals(
  lines: CheckoutLine[],
  shippingMinor: number,
) {
  const subtotalMinor = lines.reduce((acc, l) => acc + l.lineTotalMinor, 0);
  const discountMinor = 0; // Reserved — no discount codes in V1
  const totalMinor    = subtotalMinor + shippingMinor - discountMinor;
  return { subtotalMinor, shippingMinor, discountMinor, totalMinor };
}
FieldDescription
subtotalMinorSum of all line totals: unitAmountMinor × quantity for every item
shippingMinorShipping cost resolved from the shipping_rates lookup
discountMinorReserved for future discount/coupon codes; always 0 in V1
totalMinorFinal amount: subtotal + shipping − discount
All order totals are calculated server-side from prices stored in the database. The checkout endpoint ignores any price or total values that the client may include in the request body — only productId, quantity, currency, and recipient/buyer details are accepted from the client. This prevents price-tampering attacks.

Address Book

Authenticated customers can maintain a personal address book using the addresses table. These saved addresses are independent from order snapshots and can be managed via the addresses API:
EndpointAction
GET /api/v1/addressesList all addresses for the authenticated user
POST /api/v1/addressesCreate a new saved address
PATCH /api/v1/addresses/:idUpdate an existing saved address
DELETE /api/v1/addresses/:idDelete a saved address
The addresses table is scoped to userId with a CASCADE delete — all saved addresses are removed if the user account is deleted. Guest checkouts (where userId is null on the order) do not create address book entries.
Admin staff can view, create, update, and deactivate shipping rates via GET, POST, PATCH, and DELETE on /api/v1/admin/shipping-rates. To temporarily disable shipping to a province without losing the rate configuration, set active: false via PATCH rather than deleting the row.

Build docs developers (and LLMs) love