addToCart() compared item.variantId === selectedVariant where
selectedVariant is null but saved items store variantId: undefined.
null !== undefined caused findIndex to never match, always inserting
a duplicate instead of incrementing quantity. Normalised with || undefined.
Cart page checked localStorage.getItem('user') which is never set by
the cookie-based auth system. Replaced with useUser() context and
corrected redirect target from /cart to /checkout.
20 component tests covering Button (variants, disabled state, event handlers) and
ProductCard (rendering, price formatting, sale badge, image fallback). README
documents the full suite: 151 tests across 10 files, how to run, mock patterns,
and what's missing by priority (checkout flow, admin routes, more components).
27 tests covering POST /api/auth/login (9), POST /api/auth/register (9), and
POST /api/webhooks/stripe (11). Routes are tested by importing handlers directly
as functions, no HTTP server needed. Stripe false-positive fixed: thrown error
message now differs from the hardcoded 400 response to verify sanitization.
49 tests for all 10 Zod schemas in validate.ts, 26 tests for auth (hashPassword,
verifyPassword, createSession, getSession, getCurrentUser, deleteSession), 11 for
storage (magic-byte validation, saveImage, deleteImageFile), 9 for email (sendMail
scenarios), and 6 for rate limiting logic.
Adds test harness for the suite:
- vitest.config.ts: happy-dom env, @/* alias, v8 coverage with 70% thresholds
- setup.ts: env vars, global next/headers and next/navigation mocks
- tsconfig.json: IDE alias resolution for test/
- __mocks__/prisma.ts: centralised Prisma mock auto-registered via vi.mock
- fixtures/users.ts, fixtures/orders.ts: typed test data
Added Italian communication requirement, error-first workflow (report then wait),
and missing Prisma models: ProductVariant, PasswordResetToken, Page/PageSection,
SiteSettings, AuditLog. Added app/coverage/ to .gitignore.
- Add public /api/settings endpoint (force-dynamic, no auth) exposing
site_name, site_description, footer_copyright, footer_links
- Navbar, login, register pages fetch site_name via useEffect
- Homepage hero and footer read site_name and site_description from DB
- Fix admin settings form silently ignoring API errors on save
Bind-mounting ./data/uploads caused EACCES errors because Docker creates
the host directory as root, while the container runs as nextjs (UID 1001).
A named volume is initialized from the image where chown is already set correctly.
- Stripe webhook: log only error.message instead of full error objects
to avoid exposing stack traces in aggregated logs
- Admin products POST: return only first Zod error message instead of
the full error array which reveals internal schema structure
- .env.example: replace weak default INITIAL_ADMIN_PASSWORD and
AUTH_SECRET with instructive placeholders requiring manual generation
- docker-compose.yml: parameterize POSTGRES_USER, POSTGRES_PASSWORD,
POSTGRES_DB and DATABASE_URL via environment variables with local fallbacks
Add VALID_TRANSITIONS map and validate each status change before updating
the database. Prevents skipping payment (e.g. PENDING→FULFILLED) or
reopening closed orders.
- Add LoginAttempt model to Prisma schema with migration
- Create rate-limit.ts utility (10 attempts / 15 min window, DB-backed)
- Apply rate limiting to login endpoint (replaces in-memory Map)
- Apply rate limiting to change-password endpoint (previously unprotected)
- Rate limit state survives server restarts and works across multiple instances
- Add GET /api/auth/me endpoint returning current user from httpOnly cookie
- Add UserContext + useUser() hook that fetches from /api/auth/me on mount
- Wrap root layout with UserProvider
- Remove all localStorage.setItem/getItem('user') calls from login, register,
navbar, account pages, change-password, and checkout
- mustChangePassword redirect now reads from refreshed server session
- Add validateImageMagicBytes() to storage.ts reading first 12 bytes
to verify JPEG/PNG/WebP/ICO signatures regardless of declared MIME type
- Remove image/svg+xml from favicon upload whitelist (SVG can embed scripts)
- Apply magic bytes check in product image and favicon upload endpoints
Sezione dedicata alle porte con distinzione tra porte pubbliche (80,
443), interne Docker (3000, 5432, 1025) e solo sviluppo (8025).
Include comandi UFW pronti per Ubuntu/Debian.
Aggiunta documentazione campo per campo per tutte le sezioni: Product
Types, Categorie, Admin Users, Impostazioni (generale, footer, favicon).
Corretto Base Price da centesimi a euro dopo la fix del form.
Lo slug viene calcolato automaticamente dal nome senza che l'utente
debba compilarlo — il campo è rimosso dal form ma continua ad essere
inviato nel payload e visibile nella tabella.
Il campo prezzo del form admin ora accetta valori in unità (es. 19.99)
invece di centesimi (1999). La conversione *100 avviene al submit,
il DB e Stripe continuano a ricevere centesimi.
- docker-compose.yml: sostituisce pgdata/uploads/caddy_data/caddy_config con bind mount su ./data/
- app/public/.gitkeep: crea cartella richiesta dal Dockerfile durante il build
- scripts/backup.sh: backup automatico di DB (pg_dump) e uploads con rotazione 30 giorni
- docs/BACKUP.md: guida completa backup, ripristino e setup cron
- .gitignore: aggiorna con data/ e backups/
- Admin settings page now has sections for general settings, footer, and favicon
- Footer component reads footer_copyright and footer_links from DB
- New API route POST /api/admin/upload/favicon saves uploaded image and updates favicon_url in DB
- Textarea support added for footer_links JSON field
- Add icon.png as default favicon (cropped to remove transparent padding)
- Fix layout.tsx to use icon.png as fallback when favicon_url is not set in DB
- Move ADMIN_GUIDE.md to docs/ folder
- Add docs/CUSTOMIZATION.md with guide on how to customize icon, title, footer
- Add new section summarising the 4 differences between local dev and
production: domain/HTTPS, env vars, server requirements, backups
- Update production Caddyfile example to include /uploads/* static
file handler (required for image serving)
Covers all admin sections with step-by-step instructions:
login, dashboard, products (detailed field reference including image
upload with aspect ratio guidance), product types, categories,
orders, customers, reviews, admin users, settings, and recommended
onboarding flow.
- Add storage.ts utility (saveImage, deleteImageFile) for local disk operations
- Add POST /api/admin/products/[id]/images: validates MIME type and 5MB limit, saves file, creates MediaAsset record
- Add DELETE /api/admin/products/[id]/images?imageId=: removes file and DB record
- Add Images section to product edit form (hidden for new products until saved)
- Display images in square aspect-ratio grid matching storefront display
- Support multi-file upload; hover to reveal delete button
- Add named Docker volume `uploads` mounted at /app/public/uploads in app container
- Share same volume with Caddy at /srv/uploads for direct static file serving
- Add Caddy `handle /uploads/*` block so images bypass Next.js (standalone mode does not serve runtime public files)
- Create uploads directory with correct nextjs:nodejs ownership in Dockerfile
- Add mkdir safeguard in entrypoint.sh