The dev-deploy workflow was trying to spin up separate portfolio_postgres_dev
and portfolio_redis_dev containers, which don't exist on the server. Now it
reuses the existing production portfolio-postgres and portfolio-redis on
the portfolio_net network.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Mount .next/cache as a BuildKit cache volume during build to persist
the Next.js build cache across Docker rebuilds. Eliminates the
'No build cache found' warning and speeds up subsequent builds.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make prisma migrate deploy failure non-fatal in start-with-migrate.js.
Previously, migration failure caused process.exit() which killed the
container, triggering an infinite restart loop. Now logs a warning
and starts the Next.js server anyway (app has DB fallbacks).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove @sentry/nextjs and all related files since it was never actively used.
- Delete sentry.server.config.ts, sentry.edge.config.ts
- Delete sentry-example-page and sentry-example-api routes
- Clean up instrumentation.ts, global-error.tsx, middleware.ts
- Remove Sentry env vars from env.example and docs
- Update CLAUDE.md, copilot-instructions.md, PRODUCTION_READINESS.md
Middleware bundle reduced from 86KB to 34.8KB (-51KB).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove framer-motion from Hero.tsx and HeaderClient.tsx, replace with CSS animations/transitions
- Replace lucide-react icons (Menu, X, Mail) with inline SVGs in HeaderClient.tsx
- Lazy-load About, Projects, Contact, Footer via dynamic() imports in ClientWrappers.tsx
- Defer ShaderGradient/BackgroundBlobs loading via requestIdleCallback in ClientProviders.tsx
- Remove AnimatePresence page wrapper that caused full re-renders
- Enable experimental.optimizeCss (critters) for critical CSS inlining
- Add fadeIn keyframe to Tailwind config for CSS-based animations
Homepage JS reduced from 563KB to 438KB (-125KB).
Eliminates ~39s main thread work from WebGL init and layout thrashing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add WebGL support detection in ShaderGradientBackground to prevent console errors
- Add .catch() fallback to ShaderGradientBackground dynamic import
- Remove hardcoded aria-label from consent banner minimize button (fixes label-content-name-mismatch)
- Use rewrite instead of redirect for root locale routing (eliminates one redirect hop)
- Change n8n API cache headers from no-store to no-cache (enables bfcache)
- Add three and @react-three/fiber to optimizePackageImports for better tree-shaking
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Disable Sentry in all 3 configs (client/server/edge) - replayIntegration
was recording every DOM mutation causing overhead in Chrome
- Remove grain-overlay div and its CSS (SVG feTurbulence + mix-blend-mode:overlay
forces software compositing in Chrome on every frame)
- Remove mix-blend-multiply from BackgroundBlobs (prevents Chrome GPU compositing)
- Delete unused Grain.tsx, ShaderGradientBackground.tsx and its client wrapper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ShaderGradientBackground used 3 full-screen Three.js WebGL canvases
with a blur(150px) CSS filter, crashing Lighthouse and causing severe
lag in Chrome. BackgroundBlobs also had 7 elements with blur(100-120px)
and per-frame mouse spring tracking compounding the issue.
- Remove ShaderGradientBackground from layout (WebGL not needed for a blur effect)
- Reduce BackgroundBlobs blur from 100-120px to 60px
- Remove mouse tracking spring animations from BackgroundBlobs
- Reduce to 4 blobs (remove 3 least visible)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
next/dynamic with ssr:false is not allowed in Server Components.
Follows existing BackgroundBlobsClient pattern.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add `prefix` param to checkRateLimit/getRateLimitHeaders so each endpoint
has its own bucket (previously all shared `admin_${ip}`, causing 429s when
analytics/track incremented past n8n endpoints' lower limits)
- n8n/hardcover/currently-reading → prefix 'n8n-reading'
- n8n/status → prefix 'n8n-status'
- analytics/track → prefix 'analytics-track'
- Remove custom analytics system (AnalyticsProvider, lib/analytics,
lib/useWebVitals, all /api/analytics/* routes) — was causing 500s in
production due to missing PostgreSQL PageView table
- Remove analytics consent toggle from ConsentBanner/ConsentProvider
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove hardcoded Dennis Konkol idle quote from rotation
- Double quote pool (5 → 12 quotes per locale)
- Start at a random quote on page load
- Cycle to a random non-repeating quote every 10s instead of sequential
- Fix dev-deploy.yml: postgres:15-alpine → postgres:16-alpine
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@shadergradient/react imports these at runtime even though they are not
declared as peer dependencies in its package.json.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove @react-three/drei, @react-three/fiber, three, @types/three
(replaced by @shadergradient/react), plus gray-matter, zod,
react-responsive-masonry and related @types packages that are
not imported anywhere in the codebase.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Docker Compose refused to adopt the existing portfolio_net network because
it lacked the expected com.docker.compose.network label (created outside
Compose). Mark it as external (matching the dev setup) and pre-create it
in the deployment workflow to ensure it always exists before compose up.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The portfolio_dev network was created manually by the pipeline, causing
docker-compose to fail with label mismatch errors. Now:
- Network is marked as external in compose (compose doesn't try to own it)
- Network creation moved before compose up in the pipeline
- Redundant network check later in pipeline removed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- start-with-migrate.js now waits for the database TCP port to be
reachable before running Prisma migrations (15 retries, 2s interval).
Prevents the container from crashing and restarting in a loop when
postgres is still starting up.
- Add explicit 'name:' to both production and dev compose networks
to prevent docker-compose project prefix mismatch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Docker Compose prefixes network names with the project name by default.
The app container (started via docker run) was connecting to 'portfolio_dev'
while postgres/redis were on '<project>_portfolio_dev' - different networks.
Setting 'name: portfolio_dev' forces the exact name so all containers
share the same network.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Postgres and Redis only need to be reachable via the internal Docker
network (portfolio_dev). Removing host port bindings prevents conflicts
with production or other services and reduces attack surface.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Change dev PostgreSQL host port from 5432 to 5433 and dev Redis from
6379 to 6380 to avoid conflicts with production containers or other
services on the host. Internal Docker network ports remain unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Hero: smoother font scaling (text-[2.75rem] -> sm -> md -> lg), smaller
photo on mobile, reduced gaps and padding
- About: responsive bento grid with smaller border-radius, compact hobbies
grid (2-col on mobile), hidden descriptions on small screens
- Projects: wider aspect ratio on mobile (16/10), show tags from sm:,
smoother title scaling
- Contact: compact form inputs, responsive connect links, smaller gaps
- Footer: reduced top padding and gap on mobile
- HomePage: smaller wave separators (h-12 on mobile)
- 404: compact card padding and button sizing
- ActivityFeed: smaller quote text and min-height on mobile
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove unused imports, replace `any` types with proper interfaces in directus.ts
and i18n-loader.ts, exclude scripts/ and coverage/ from ESLint, and fix
unused variable warnings across the codebase.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixed map parentheses syntax errors, resolved missing ActivityFeedClient imports, and corrected ActivityFeed prop types for idleQuote support. All systems green.
Added a shimmering Skeleton component. Integrated loading states for Hero, About (Bento Grid), Reading Log, Projects Archive, and Library pages for a premium UX.
Removed aggressive background text in footer. Implemented intelligent back button for projects. Redesigned project archive page. Stabilized idle quote logic in activity feed.