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.
Automated CMS content seeding, integrated interactive AI Chat into Bento grid, implemented intelligent idle quote logic, and unified editorial styling across all sub-pages.
Centralized UI labels in Directus, integrated AI Chat and Status into Bento grid, created standalone Books page, and redesigned project sub-pages for consistent high-end aesthetic.
Moved profile photo to Hero for immediate visibility. Rewrote DE/EN translations to be more personal and focused on self-hosting/student identity. Refined Bento grid for better content flow.
Refactored About section to use a responsive Bento Grid layout. Redesigned Hero for stronger visual impact. Implemented floating Island navigation. Updated Project cards for cleaner aesthetic.