Ecommerce for a client
In developmentSublime Ecommerce
An online store for a sticker, sublimated T-shirt, DTF, and vinyl business: an admin-managed catalog, orders, custom orders with Custom Lab, and self-hosted deployment on a VPS.
A client project, in development. Features run in staging; the store already lives on the client's domain, in maintenance mode while the real catalog is loaded. It started on Vercel with a managed database, and I migrated it to a self-managed VPS.
Outcome: 298automated tests in the repository, over 18 versioned database migrations.
- Next.js
- TypeScript
- PostgreSQL
- Docker
- Traefik
Architecture
- DomainStore on the client's domain; password-protected stagingDNS
- ProxyAutomatic HTTPS and routing by domain; www redirects to the main domainTraefik
- AppOne container per environment, built with its own configurationNext.js · Docker
- DatabaseOne database per environment, unreachable from the internetPostgreSQL
- BackupsDaily, with an encrypted off-server copy and a tested restorerclone · Drive
Feature status
Implemented in staging
- Catalog managed from an admin panel: categories, images, variants, prices, and stock with auditing.
- Orders with stock reservation and rule-based shipping.
- Sublime Custom Lab: stickers with background removal, outline, and automatic sheet layout; the server generates the PNG and the PSD for the plotter.
- T-shirt Custom Lab: own or catalog design, placement, and size; the server generates the mockup and a 300 dpi print file.
- Customer accounts, points of sale, and a home page editable from the panel.
- Custom orders copied automatically to Google Drive, plus a notification queue.
Production infrastructure
- Migration from Vercel and a managed database to a VPS with Docker Compose.
- Automatic staging deploys on push; the store is deployed by hand.
- Daily backups: 14 days on the server and 60 days encrypted on Google Drive.
- Maintenance mode: the public sees a notice page while the panel stays available.
Pending
- Payments with Mercado Pago, subject to client approval.
- Customer emails and password recovery, once a provider is chosen.
- AI background removal in Custom Lab.
- Opening the store to the public.
Architecture
- Next.js App Router with strict TypeScript, in standalone mode inside Docker.
- PostgreSQL with versioned migrations; each catalog change, its stock movement, and its audit entry are saved in a single SQL statement.
- Files on disk with public and private paths; custom order attachments can only be downloaded from the panel.
- Admin authorization checked on the server for every page and action.
Deployment decisions
- One image per environment: some pages are generated at build time and need that environment's configuration, passed as a secret and never stored in the image.
- Pull-based deploys: the VPS reads GitHub with a read-only key, and GitHub holds no server credentials.
- Traefik shared with other services on the same VPS: each app only adds its labels.
- The database only listens on the server itself; it is never exposed to the internet.
Code sample
# Runs every minute: deploy the watched branch when it has a new commit.
git --git-dir="$REPO" fetch --quiet --prune origin "+refs/heads/$BRANCH:refs/heads/$BRANCH"
SHA=$(git --git-dir="$REPO" rev-parse "refs/heads/$BRANCH")
[ "$SHA" = "$(cat .deployed-sha 2>/dev/null)" ] && exit 0 # already live
[ "$SHA" = "$(cat .last-attempt 2>/dev/null)" ] && exit 0 # failed once, wait for a new commit
echo "$SHA" > .last-attempt
NEW=$(mktemp -d "$ROOT/.src.XXXXXX")
git --git-dir="$REPO" archive "$SHA" | tar -x -C "$NEW"
mv "$ROOT/src" "$ROOT/src.previous" && mv "$NEW" "$ROOT/src"
if bash "$ROOT/src/deploy/deploy-staging.sh"; then
echo "$SHA" > .deployed-sha
else
echo "deploy failed: staging keeps the previous version"
fiCase limits
- The store is not open to the public yet: it is in maintenance mode.
- There are no online payments; they depend on client approval.
- No sales or business data from the client is published.