E-commerce full-stack com Payload CMS
Loja virtual completa com catálogo, carrinho persistente, checkout integrado e painel admin customizado para gestão de produtos e pedidos.
- Next.js 15
- Payload CMS 3
- TypeScript
- Postgres
- Stripe
- Tailwind CSS

Construí essa loja para explorar como Payload CMS 3 lida com collections relacionais complexas (Products → Variants → Inventory → Orders). O Next.js 15 entra no checkout com Server Actions para mutações, e o Stripe Elements para o pagamento real. Tudo tipado end-to-end com TypeScript estrito.
Decisões de arquitetura
Optei por manter o carrinho no servidor (via cookie httpOnly + Postgres) em vez de localStorage. Sacrifica um pouco de performance no primeiro add-to-cart, mas garante que o carrinho sobrevive a logout, troca de dispositivo e tem o estoque checado em tempo real.
Em produção, e-commerce precisa de concorrência real no estoque. Dois clientes comprando a última unidade ao mesmo tempo não pode resultar em oversell. Postgres com SELECT FOR UPDATE resolve isso nativo; SQLite precisaria de lock no nível da aplicação.
1'use server'23import { getPayload } from 'payload'4import config from '@payload-config'5import { cookies } from 'next/headers'67export async function addToCart(productId: string, variantId: string) {8 const cookieStore = await cookies()9 const cartId = cookieStore.get('cart-id')?.value1011 const payload = await getPayload({ config })1213 // Cria o cart se não existir, com transação14 const cart = await payload.db.executeTransaction(async (tx) => {15 // ... lógica com SELECT FOR UPDATE16 })1718 cookieStore.set('cart-id', String(cart.id), { httpOnly: true, sameSite: 'lax' })19 return { success: true, cartId: cart.id }20}

Imagem ilustrativa de exemplo. Substitua no admin em Mídia.
O que vem depois
Próximo passo é adicionar busca facetada no catálogo (por preço, categoria, tags) usando o índice GIN do Postgres, e webhooks do Stripe para reconciliação de pagamento em caso de retry do cliente.