Skip to content

Instantly share code, notes, and snippets.

@matheusps
Created March 2, 2026 14:51
Show Gist options
  • Select an option

  • Save matheusps/57d7f943c53c724949d027f3f807c459 to your computer and use it in GitHub Desktop.

Select an option

Save matheusps/57d7f943c53c724949d027f3f807c459 to your computer and use it in GitHub Desktop.
---
name: FastCheckout to FastStore Migration
overview: Migrate the entire FastCheckout application (NestJS BFF + Next.js/Relay client + UI libraries) into a set of FastStore pages, sections, API extensions, and custom components, preserving all checkout features (cart, delivery, payment, review, order placed, sign-in, payment loading).
todos:
- id: bff-typedefs
content: Create all GraphQL type definitions (.graphql files) in src/graphql/vtex/typeDefs/ for each checkout domain (cart, auth, payment, shipping, order, summary, coupon, customer, delivery, pickup, simulation, account-settings, store-preferences, custom-fields, dynamic-fields, one-click-checkout, budget, permissions)
status: pending
- id: bff-clients
content: "Create VTEX API client modules for services not covered by FastStore's native clients: VtexIdentityClient, VtexPaymentsClient, VtexWalletHubClient, VtexMasterDataClient, VtexBudgetClient, GoogleMapsClient"
status: pending
- id: bff-resolvers
content: Convert all 25 NestJS resolver classes to plain GraphQL resolver objects in src/graphql/vtex/resolvers/, wiring them to the new client modules and FastStore's existing ctx.clients
status: pending
- id: api-route
content: Modify FastStore's /api/graphql route to forward checkout-specific headers (x-order-form-id, x-fastcheckout-user-date-time) and handle checkout cookie management
status: pending
- id: checkout-pages
content: Create all checkout pages under pages/checkout/ (index, cart, delivery, payment, review, order-placed/[orderId], payment-loading, sign-in) using getServerSideProps and RenderSections
status: pending
- id: sdk-hooks
content: Create SWR-based checkout hooks in src/sdk/checkout/ (useCheckoutCart, useCheckoutShipping, useCheckoutPayment, useCheckoutOrder, useCheckoutAuth, useCheckoutSummary, useCheckoutCoupon, useCheckoutCustomer) replacing Relay queries/mutations
status: pending
- id: shared-components
content: Build shared checkout components (Summary, Breadcrumb/StepIndicator, AddressForm, CardForm, PaymentOptionIcon) using FastStore UI components and SCSS modules
status: pending
- id: cart-screen
content: "Migrate Cart screen: convert Cart.tsx and subcomponents to FastStore section, replacing FC UI components with FastStore equivalents, Vanilla Extract with SCSS modules"
status: pending
- id: delivery-screen
content: "Migrate Delivery screen: convert to FastStore section with address forms, shipping SLA selectors, pickup point search, using FastStore components"
status: pending
- id: payment-screen
content: "Migrate Payment screen: convert payment option selector, credit card form, saved cards, gift cards, installments to FastStore sections"
status: pending
- id: review-screen
content: "Migrate Review screen: convert order review display with delivery, payment, and cart summaries to FastStore section"
status: pending
- id: order-placed-screen
content: "Migrate OrderPlaced screen: convert order confirmation page to FastStore section"
status: pending
- id: remaining-screens
content: "Migrate remaining screens: SignIn, PaymentLoading, CartPunchout (B2B) to FastStore sections"
status: pending
- id: form-libs
content: "Migrate address-form and card-ui libraries: create react-hook-form wrapper components that integrate with FastStore InputField, SelectField, CheckboxField"
status: pending
- id: utils-migration
content: Copy utility libraries (validators, input-mask, constants, i18n) into src/customizations/src/utils/
status: pending
- id: styling-migration
content: Convert all Vanilla Extract styles (*.css.ts) to SCSS modules (*.module.scss) using FastStore design tokens (--fs-*) and component data attributes
status: pending
- id: config-update
content: Update discovery.config to point checkoutUrl to /checkout/cart, update redirectToCheckout to use internal navigation, and add checkout-specific configuration
status: pending
- id: cms-sections
content: Create CMS section definitions in cms/faststore/sections.json for all checkout sections and sync with Headless CMS
status: pending
isProject: false
---
# FastCheckout to FastStore Full Migration
## Architecture Overview
The FastCheckout app is a standalone checkout with a **NestJS BFF** (GraphQL via Mercurius, ~25 resolver modules, ~10 VTEX API clients) and a **Next.js/Relay client** (8 checkout screens, 20+ UI components, Vanilla Extract styling). It must become a native part of FastStore using FastStore's extension points.
```mermaid
flowchart TB
subgraph currentArch [Current Architecture]
FC_Client["FastCheckout Client\n(Next.js + Relay)"]
FC_BFF["FastCheckout BFF\n(NestJS + Mercurius)"]
VTEX["VTEX APIs"]
FC_Client -->|"GraphQL\n/api/checkout-bff/graphql"| FC_BFF
FC_BFF --> VTEX
end
subgraph targetArch [Target Architecture]
FS_Pages["FastStore Checkout Pages\n(/checkout/cart, /delivery, etc.)"]
FS_BFF["FastStore API Route\n(/api/graphql)"]
FS_Resolvers["VTEX Extension Resolvers\n(src/graphql/vtex/)"]
VTEX2["VTEX APIs"]
FS_Pages -->|"SWR + GraphQL\n/api/graphql"| FS_BFF
FS_BFF --> FS_Resolvers
FS_Resolvers --> VTEX2
end
currentArch -.->|"Migration"| targetArch
```
## 1. BFF Migration Strategy
The NestJS BFF (`fastcheckout/packages/apps/server/`) must be converted to FastStore's VTEX API extension system. FastStore supports extending its GraphQL schema via:
- **TypeDefs**: `.graphql` files in `src/graphql/vtex/typeDefs/`
- **Resolvers**: `.ts` files in `src/graphql/vtex/resolvers/`
### 1.1 TypeDefs Migration
Create `.graphql` files in `[faststore/packages/core/src/customizations/src/graphql/vtex/typeDefs/](faststore/packages/core/src/customizations/src/graphql/vtex/typeDefs/)` for each domain:
| FastCheckout Module | New TypeDef File | Key Types |
| ------------------- | ------------------------------------ | ------------------------------------------------------------------------------ |
| Cart | `checkout-cart.graphql` | `CheckoutCart`, `CheckoutCartItem`, mutations for add/remove/update items |
| Auth | `checkout-auth.graphql` | `CheckoutAuth`, `AuthProvider`, login/logout mutations |
| Payment | `checkout-payment.graphql` | `CheckoutPayment`, `PaymentOption`, `SavedCard`, `GiftCard`, installment types |
| Shipping | `checkout-shipping.graphql` | `CheckoutShipping`, `DeliveryOption`, `PickupPoint`, address types |
| Order | `checkout-order.graphql` | `CheckoutOrder`, place order mutations, transaction types |
| Summary | `checkout-summary.graphql` | `CheckoutSummary`, totals |
| Coupon | `checkout-coupon.graphql` | `CheckoutCoupon`, add/remove coupon mutations |
| Customer | `checkout-customer.graphql` | `CheckoutCustomer`, profile data |
| Delivery | `checkout-delivery.graphql` | Delivery-specific types, SLA selection |
| Pickup | `checkout-pickup.graphql` | Pickup point search, selection |
| Simulation | `checkout-simulation.graphql` | Shipping simulation types |
| AccountSettings | `checkout-account-settings.graphql` | Store checkout settings |
| StorePreferences | `checkout-store-preferences.graphql` | Store preferences |
| CustomFields | `checkout-custom-fields.graphql` | Custom field definitions and values |
| DynamicFields | `checkout-dynamic-fields.graphql` | Dynamic fields |
| OneClickCheckout | `checkout-one-click.graphql` | One-click checkout options |
| GiftCard | (in payment) | Gift card add/remove |
| Budget | `checkout-budget.graphql` | Budget allocation (B2B) |
| Permissions | `checkout-permissions.graphql` | Permission checks (B2B) |
All new types should be prefixed with `Checkout` to avoid collisions with existing FastStore types. Extend `Query` and `Mutation` with new root fields prefixed with `checkout_` (e.g., `checkout_cart`, `checkout_placeOrder`).
### 1.2 Resolvers Migration
Create resolver files in `[faststore/packages/core/src/customizations/src/graphql/vtex/resolvers/](faststore/packages/core/src/customizations/src/graphql/vtex/resolvers/)`:
**VTEX API Clients**: The NestJS client services (`[fastcheckout/packages/apps/server/src/client/](fastcheckout/packages/apps/server/src/client/)`) must be rewritten as plain functions or classes that can be instantiated within FastStore resolver context. FastStore resolvers receive a `ctx` with `ctx.clients.commerce` (which has `checkout`, `session`, `profile`, `oms` sub-clients). For APIs not covered by FastStore's native clients (e.g., Payments, WalletHub, MasterData, Identity, LicenseManager), create new client modules.
**Resolver structure**: Each NestJS resolver class becomes a plain resolver object:
```typescript
// src/graphql/vtex/resolvers/checkoutCart.ts
const checkoutCartResolver = {
Query: {
checkout_cart: async (_, args, ctx) => { /* ... */ },
},
Mutation: {
checkout_addProduct: async (_, args, ctx) => { /* ... */ },
checkout_removeProduct: async (_, args, ctx) => { /* ... */ },
checkout_changeQuantity: async (_, args, ctx) => { /* ... */ },
},
}
export default checkoutCartResolver
```
**Key client mappings**:
| NestJS Client | FastStore Equivalent |
| ------------------------------ | ------------------------------------------------------------------------------------- |
| `CheckoutClientService` | `ctx.clients.commerce.checkout` (partial) + new custom client for remaining endpoints |
| `SessionClientService` | `ctx.clients.commerce.session` |
| `CatalogClientService` | `ctx.clients.commerce.catalog` |
| `IdentityClientService` | New `VtexIdentityClient` |
| `PaymentsClientService` | New `VtexPaymentsClient` |
| `WalletHubClientService` | New `VtexWalletHubClient` |
| `MasterDataClientService` | New `VtexMasterDataClient` |
| `AccountSettingsClientService` | New custom client |
| `LicenseManagerClientService` | `ctx.clients.commerce.licenseManager` (if available) or new client |
| `BudgetClientService` | New `VtexBudgetClient` |
| `GoogleMapsClientService` | New `GoogleMapsClient` |
**Context handling**: The NestJS BFF extracts `accountName`, `orderFormId`, `requestId`, `userDateTime` from request headers/cookies. In FastStore, this context must be extracted in the API route handler (`[faststore/packages/core/src/pages/api/graphql.ts](faststore/packages/core/src/pages/api/graphql.ts)`) and passed through the GraphQL context. The API route will need modifications to forward checkout-specific headers.
### 1.3 Cookie and Authentication Handling
The FastCheckout BFF manages VTEX auth cookies (`VtexIdclientAutCookie`, `checkout.vtex.com`, `vtex_session`, etc.). In FastStore, the API route at `/api/graphql` already handles session cookies. Checkout-specific cookie management (especially for Identity login flows) will need to be added to the API route or handled via a middleware.
## 2. Page Structure
Create the following pages under `[faststore/packages/core/src/pages/checkout/](faststore/packages/core/src/pages/checkout/)`:
| Route | File | Purpose |
| ---------------------------------- | ---------------------------- | ------------------------------------------------- |
| `/checkout` | `index.tsx` | Redirects to `/checkout/cart` |
| `/checkout/cart` | `cart.tsx` | Cart with items, summary, coupons |
| `/checkout/delivery` | `delivery.tsx` | Address selection, shipping options |
| `/checkout/payment` | `payment.tsx` | Payment method selection, credit card, gift cards |
| `/checkout/review` | `review.tsx` | Order review before placing |
| `/checkout/order-placed/[orderId]` | `order-placed/[orderId].tsx` | Order confirmation |
| `/checkout/payment-loading` | `payment-loading.tsx` | Payment processing status |
| `/checkout/sign-in` | `sign-in.tsx` | Authentication for checkout |
Each page will:
- Use `getServerSideProps` (not `getStaticProps`) since checkout is dynamic/personalized
- Render global sections (header/footer) via `RenderSections`
- Render checkout-specific sections as custom components
## 3. Component Migration
### 3.1 Direct Mappings (use FastStore components)
| FastCheckout | FastStore | Import |
| --------------------- | ------------------ | --------------- |
| `Button` | `Button` | `@faststore/ui` |
| `TextInput` | `InputField` | `@faststore/ui` |
| `Checkbox` | `CheckboxField` | `@faststore/ui` |
| `SelectInput` | `SelectField` | `@faststore/ui` |
| `IconButton` | `IconButton` | `@faststore/ui` |
| `Tag` | `Tag` | `@faststore/ui` |
| `Link` | `Link` | `@faststore/ui` |
| `Spinner` | `Loader` | `@faststore/ui` |
| `Breadcrumb` | `Breadcrumb` | `@faststore/ui` |
| `SearchInput` | `SearchInputField` | `@faststore/ui` |
| `Modal` (various) | `Modal` | `@faststore/ui` |
| `Accordion` (if used) | `Accordion` | `@faststore/ui` |
| `Skeleton` | `Skeleton` | `@faststore/ui` |
| `Table` | `Table` | `@faststore/ui` |
### 3.2 Custom Components (must be built as new FastStore sections/components)
These have no FastStore equivalent and must be created in `[faststore/packages/core/src/customizations/src/components/](faststore/packages/core/src/customizations/src/components/)`:
- **CheckoutCart** - Cart item list with quantity controls, item removal
- **CheckoutSummary** - Order summary with totals, discounts
- **CheckoutCoupon** - Coupon input and applied coupons
- **AddressForm** - Address form with country-specific fields (BRA, USA)
- **CardForm** - Credit card form with masking, Luhn validation
- **PaymentOptions** - Payment method selector with saved cards, gift cards
- **DeliveryOptions** - Shipping SLA selector, delivery windows
- **PickupPointSelector** - Pickup point search and selection
- **ReviewOrder** - Order review display
- **OrderPlacedConfirmation** - Order confirmation with details
- **PaymentLoadingScreen** - Payment processing indicator
- **CheckoutBreadcrumb** - Step progress indicator
- **CheckoutSignIn** - Login form with VTEX Identity integration
- **OneClickCheckout** - One-click purchase flow
### 3.3 Checkout Sections for CMS
Create CMS section definitions in `cms/faststore/sections.json` for each checkout section so they can be managed in Headless CMS:
```json
[
{ "name": "CheckoutCart", "schema": { ... } },
{ "name": "CheckoutDelivery", "schema": { ... } },
{ "name": "CheckoutPayment", "schema": { ... } },
{ "name": "CheckoutReview", "schema": { ... } },
{ "name": "CheckoutOrderPlaced", "schema": { ... } },
{ "name": "CheckoutSummary", "schema": { ... } }
]
```
## 4. State Management Migration
| FastCheckout | FastStore |
| ------------------- | ---------------------------------------------------------- |
| Relay Environment | SWR + custom GraphQL `request()` function |
| `usePreloadedQuery` | `useQuery` (SWR-based, from `src/sdk/graphql/useQuery.ts`) |
| `useFragment` | Inline field selection in queries (no fragments needed) |
| `useMutation` | Custom `useMutation` hook using `fetch` to `/api/graphql` |
| Relay Store | Zustand stores + SWR cache |
| `loadQuery` | SWR `prefetch` or `getServerSideProps` data |
Create new SDK hooks in `src/sdk/checkout/`:
- `useCheckoutCart()` - fetches and manages cart state
- `useCheckoutShipping()` - shipping/delivery state
- `useCheckoutPayment()` - payment state
- `useCheckoutOrder()` - order placement
- `useCheckoutAuth()` - authentication state
- `useCheckoutSummary()` - order summary
- `useCheckoutCoupon()` - coupon management
- `useCheckoutCustomer()` - customer data
Each hook will use SWR for queries and a custom mutation helper for mutations, all hitting `/api/graphql`.
## 5. Styling Migration
- **From**: Vanilla Extract (`*.css.ts`, `styleVariants`, `sprinkles`, `assignInlineVars`)
- **To**: SCSS Modules (`*.module.scss`) with FastStore design tokens (`var(--fs-*)`)
**Strategy**: For each screen component, create a `.module.scss` file that:
1. Imports relevant `@faststore/ui` component styles
2. Maps FastCheckout theme tokens to FastStore CSS custom properties
3. Preserves the layout and visual design
**Token mapping** (FastCheckout theme -> FastStore tokens):
- `theme.colors.`* -> `var(--fs-color-*)`
- `theme.spacers.`* -> `var(--fs-spacing-*)`
- `theme.typography.`* -> `var(--fs-text-size-*)`
- `theme.border.`* -> `var(--fs-border-*)`
## 6. i18n Migration
FastCheckout uses `react-intl` with locales `en-US`, `es-MX`, `pt-BR` (`[fastcheckout/packages/libs/i18n/](fastcheckout/packages/libs/i18n/)`). FastStore doesn't have built-in i18n for custom sections. Options:
- Keep `react-intl` as a dependency and wrap checkout pages with `IntlProvider`
- This is the pragmatic approach since the translation files and `FormattedMessage` usage throughout the checkout are extensive
## 7. Form Libraries Migration
The `[address-form](fastcheckout/packages/libs/address-form/)` and `[card-ui](fastcheckout/packages/libs/card-ui/)` libraries use `react-hook-form`. Since FastStore components are uncontrolled by default, create wrapper components that integrate `react-hook-form` with FastStore form fields (`InputField`, `SelectField`, `CheckboxField`).
## 8. Utility Libraries Migration
- `[validators](fastcheckout/packages/libs/validators/)` - Copy as-is into `src/customizations/src/utils/validators/`
- `[input-mask](fastcheckout/packages/libs/input-mask/)` - Copy as-is into `src/customizations/src/utils/input-mask/`
- `[constants](fastcheckout/packages/libs/constants/)` - Copy as-is into `src/customizations/src/utils/constants/`
## 9. Configuration Changes
Update `[discovery.config.default.js](faststore/packages/core/discovery.config.default.js)`:
- Change `checkoutUrl` to `/checkout/cart` (internal route instead of external redirect)
- Add checkout-specific configuration (payment options, address formats, etc.)
Update the `redirectToCheckout` function in `[faststore/packages/core/src/sdk/cart/redirectToCheckout.ts](faststore/packages/core/src/sdk/cart/redirectToCheckout.ts)` to navigate to `/checkout/cart` instead of an external URL.
## 10. API Route Modifications
Modify `[faststore/packages/core/src/pages/api/graphql.ts](faststore/packages/core/src/pages/api/graphql.ts)` to:
- Forward checkout-specific headers (`x-order-form-id`, `x-fastcheckout-user-date-time`)
- Handle checkout cookie management (auth cookies, session cookies)
- Support the additional checkout mutations (place order, payment, etc.)
## File Structure (Target)
```
faststore/packages/core/src/
├── customizations/src/
│ ├── components/
│ │ ├── checkout/
│ │ │ ├── Cart/
│ │ │ ├── Delivery/
│ │ │ ├── Payment/
│ │ │ ├── Review/
│ │ │ ├── OrderPlaced/
│ │ │ ├── SignIn/
│ │ │ ├── PaymentLoading/
│ │ │ ├── shared/ (Summary, Breadcrumb, AddressForm, CardForm, etc.)
│ │ │ └── index.tsx
│ │ └── index.tsx
│ ├── graphql/vtex/
│ │ ├── typeDefs/
│ │ │ ├── checkout-cart.graphql
│ │ │ ├── checkout-auth.graphql
│ │ │ ├── checkout-payment.graphql
│ │ │ ├── checkout-shipping.graphql
│ │ │ ├── checkout-order.graphql
│ │ │ ├── checkout-summary.graphql
│ │ │ ├── checkout-coupon.graphql
│ │ │ ├── checkout-customer.graphql
│ │ │ └── ... (remaining domains)
│ │ └── resolvers/
│ │ ├── index.ts
│ │ ├── checkoutCart.ts
│ │ ├── checkoutAuth.ts
│ │ ├── checkoutPayment.ts
│ │ ├── checkoutShipping.ts
│ │ ├── checkoutOrder.ts
│ │ └── ... (remaining resolvers)
│ └── utils/
│ ├── validators/
│ ├── input-mask/
│ ├── constants/
│ └── i18n/
├── pages/
│ └── checkout/
│ ├── index.tsx
│ ├── cart.tsx
│ ├── delivery.tsx
│ ├── payment.tsx
│ ├── review.tsx
│ ├── payment-loading.tsx
│ ├── sign-in.tsx
│ └── order-placed/
│ └── [orderId].tsx
└── sdk/
└── checkout/
├── useCheckoutCart.ts
├── useCheckoutShipping.ts
├── useCheckoutPayment.ts
├── useCheckoutOrder.ts
├── useCheckoutAuth.ts
├── useCheckoutSummary.ts
├── useCheckoutCoupon.ts
├── useCheckoutCustomer.ts
└── clients/
├── VtexIdentityClient.ts
├── VtexPaymentsClient.ts
├── VtexWalletHubClient.ts
├── VtexMasterDataClient.ts
└── VtexBudgetClient.ts
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment