- Add lib/db (schema, postgres.js client, enums, seed, migrations) on Drizzle
- Rewrite all lib and admin action queries from Prisma to Drizzle
- Keep existing table/column names so no data migration is needed
- Preserve signed-cookie admin auth unchanged
- Map unique-violation handling from Prisma P2002 to SQLSTATE 23505
- Swap deps, scripts, Makefile, and Dockerfile from Prisma to Drizzle
Reduce the "interchangeable cards" monotony flagged in Phase 0 and apply the
warm-premium type scale.
- SectionHeading: use the type scale (eyebrow via .eyebrow with brand tint,
text-h2 title, body-lg description). Propagates to every home section.
- CapabilitiesSection: cleaner cards with a brand-tinted icon tile, type-scale
title/body, soft elevation (drops the AppCard wrapper).
- ProcessSection: reworked into an editorial numbered timeline (large
translucent brand numerals, top rule, no boxes) so it no longer looks
identical to Capabilities.
Verified: eslint clean, no new type errors, tailwind generates the utilities.
The homepage hero had no call to action (Phase 0 finding). Add a live
availability pill and primary/secondary CTAs while keeping the signature title.
- HomeHero: optional availability status pill (pulsing dot) plus primary
(view work) and secondary (contact) CTAs, RTL-aware arrow, using the type
scale. Backward compatible (all new props optional).
- Wire copy + hrefs from the homepage; add heroVisual.primaryCta /
secondaryCta to en/de/ar.
Verified: JSON valid, eslint clean, no new type errors.
The detail page rendered an empty <PageHero /> (blank gradient band) with the
real title buried in a card lower down (Phase 0 finding).
- Populate the detail PageHero with the project category (badge), title and
summary, so the top of the page is a proper header.
- Slim the in-content ProjectHeader to back-link + meta chips + preview button,
removing the now-duplicated title and summary. Applies across all three
detail templates (grid/story/case-study).
Verified: eslint clean, no new type errors.
Bring imagery to the homepage projects block (Phase 3), matching the portfolio
gallery.
- Thread coverImagePath through ProjectCardCopy and the home mapping.
- Rewrite ProjectsSection as image-first cards (reusing PortfolioCover with the
branded placeholder fallback): whole-card link, featured project spans two
columns with a larger cover, type-scale title, meta + stack badges, hover
lift. Replaces the previous text-only cards.
Verified: eslint clean; no new type errors (pre-existing Prisma-gen anys only).
Redesign the portfolio list/category grid into a premium, image-first gallery
(Phase 3), applying the warm-premium tokens.
- Add components/site/portfolio-cover.tsx: renders the stored cover image
(next/image, object-cover, hover zoom) or a restrained branded placeholder
(monogram + category) when none is set. Placeholders are temporary — the
owner will swap in real artwork.
- Rewrite portfolio-project-grid: responsive 1/2/3-col gallery, featured
projects span two columns with a larger cover, cards use the type scale
(text-h2/h3/caption), eyebrow category labels, line-clamped summaries, soft
elevation and hover lift. Directly fixes the "portfolio shows no images"
gap on the list and category pages.
Verified: eslint clean, no new type errors, tailwind generates the utilities.
Add docs/DESIGN_SYSTEM.md capturing Phase 2 visual identity:
- Chosen direction (warm premium, work-forward) and its principles.
- Documents existing color/surface/brand/status/border/hero tokens with
light + dark values and an accent-budget usage rule.
- Fonts (Museo Latin, Dubai Arabic) and a defined type scale + Arabic overrides.
- Radius, elevation, container and spacing-rhythm guidance, motion, component
conventions, and do/don't. Colors and fonts are owner-fixed and unchanged.
Full refactor of the maintenance/coming-soon page for all locales (de/en/ar,
RTL-aware) with a refined, theme-aware (light + dark) premium composition:
glass panel, live status indicator, hero title, description, launch countdown
and CTAs. Reuses the existing hero/motion system; no new dependencies.
- Add components/site/launch-countdown.tsx: hydration-safe client countdown
(days/hours/minutes/seconds), localized labels, Arabic-aware typography,
"launched" fallback when the target passes.
- Rewrite app/[locale]/coming-soon/page.tsx around the countdown and a single
easy-to-edit LAUNCH_DATE_ISO constant (default ~45 days out).
- Add comingSoon i18n keys (status, countdownLabel, unit labels, launched)
to en/de/ar.
- Replace animated blob/wave/noise backdrop with clean static gradient
(radial ellipse highlights + linear fade) in hero-motion-backdrop
- Remove all framer-motion from background layer; delete unused CSS
classes: hero-blob, hero-sheet-glow, hero-sheet-wave, hero-sheet-noise,
hero-title-shift keyframe, and responsive blob media queries
- Add framer-motion stagger entrance to HeroContentMotion, HeroMotionItem,
and HeroTitle (slide-up + fade on mount)
- Refactor coming-soon page to use HeroContentMotion/HeroMotionItem
instead of MotionFade (whileInView unreliable above the fold)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move admin login lockout from client cookie to AppConfig (DB), keyed
by hashed client IP — clearing browser cookies no longer bypasses it
- Replace rate-limit $transaction (TOCTOU) with atomic SQL
INSERT...ON CONFLICT...RETURNING; add stale-entry cleanup on each
submission to prevent table bloat
- Add 5 s module-level cache for middleware runtime state fetch, reducing
per-request DB roundtrips
- Rename middleware.ts → proxy.ts to resolve Next.js 16 deprecation
warning; update test import accordingly
- Require ADMIN_PASSWORD, ADMIN_AUTH_SECRET, ADMIN_BASIC_AUTH_USER, and
ADMIN_BASIC_AUTH_PASS in docker-compose.yml (:? syntax) — startup
fails loudly instead of using placeholder defaults
- Add set -e and informative echo lines to Dockerfile CMD for clearer
startup failure attribution
- Export requireAdminAuth() from lib/admin-auth for centralised use in
admin pages
- Add CLAUDE.md with architecture notes and working rules
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>