- HeroSection: 3-col layout (copy | concentric circles+dashboard | display headline) - 'use client' + framer-motion entrance animations (slide in from sides, scale centre) - DashboardPreview inline component (compact portal mockup) - Two floating stat mini-cards (Avg Tax Saved, Response Time) - Mobile: stacked layout, right headline column hidden, H1 in left column - ContainerScroll: simplified — removed 72rem scroll container and scroll transforms; now plain layout wrapper with CSS fadeInUp entrance - Header: logo size increased h-10 → h-13 (40px → 52px) - fix: escape apostrophes in ProcessSection, SolutionSection, TestimonialsSection - fix: remove unused customSize param from SpotlightCard - docs: update CONTEXT_HANDOVER.md with session 4 changes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
932 lines
40 KiB
Markdown
932 lines
40 KiB
Markdown
# Axil Accountants — Implementation Plan
|
||
|
||
> Based on: `Concept.md` v1.0
|
||
> Stack: Next.js 15 · TypeScript · Tailwind CSS v4 · Payload CMS 3 · PostgreSQL (Neon) · Vercel
|
||
> Each feature is isolated and can be developed, tested, and reviewed independently.
|
||
|
||
---
|
||
|
||
## Legend
|
||
|
||
- `[ ]` — Not started
|
||
- `[x]` — Complete
|
||
- `[~]` — In progress
|
||
- `[!]` — Blocked / needs decision
|
||
|
||
---
|
||
|
||
## Feature 1 — Project Setup & Repository
|
||
|
||
- [x] Scaffold Next.js 16.1.6 project with App Router and TypeScript (`create-next-app`)
|
||
- [x] Configure TypeScript (`tsconfig.json`): strict mode, path aliases (`@/*`)
|
||
- [x] Install and configure **Tailwind CSS v4**
|
||
- [x] Install and configure **ESLint 9** (Next.js preset)
|
||
- [x] Install and configure **Prettier** with Tailwind class sorting plugin
|
||
- [x] Set up **Husky 9** + **lint-staged 16** (pre-commit: lint + format)
|
||
- [x] Define `.env.local` structure and `.env.example` template
|
||
- [x] Create `src/` directory structure (app, components/ui/layout/sections/three/cms, lib, hooks, types, payload)
|
||
- [x] Initialise Git repository, create `main` and `develop` branches
|
||
- [x] **Docker**: multi-stage Dockerfile (dev/build/production) + docker-compose.yml (app + PostgreSQL 17)
|
||
- [x] ~~Create **Vercel** project~~ — **N/A: self-hosted on Ubuntu**
|
||
- [x] ~~Configure Vercel environment variables~~ — **N/A: `.env.local` on server**
|
||
|
||
---
|
||
|
||
## Feature 2 — Database & Infrastructure
|
||
|
||
- [x] **Docker PostgreSQL 17** — сервис `db` в `docker-compose.yml` (user: axil, db: axil)
|
||
- [x] `DATABASE_URI` прописан в `.env.local` → `postgresql://axil:axil_dev@db:5432/axil`
|
||
- [x] Verify database connectivity — healthcheck в docker-compose (`pg_isready`)
|
||
- [ ] **Media storage** — Payload local disk storage (`/public/media`) — без внешних сервисов
|
||
- [ ] **Email (Resend)** — настроить позже (Feature 19, когда нужны реальные письма)
|
||
|
||
---
|
||
|
||
## Feature 3 — Payload CMS — Core Installation ✅
|
||
|
||
- [x] Install Payload CMS 3 into the Next.js project
|
||
- [x] Configure `payload.config.ts` (serverURL, secret, db, editor, admin)
|
||
- [x] Mount Payload API handler at `src/app/(payload)/api/[...slug]/route.ts`
|
||
- [x] Mount admin panel at `src/app/(payload)/admin/[[...segments]]/page.tsx`
|
||
- [x] Add `layout.tsx` with `RootLayout` from `@payloadcms/next/layouts` (provides ConfigProvider)
|
||
- [x] Configure **local disk storage** for Payload media (`/public/media`)
|
||
- [x] Email adapter — deferred (Feature 19, Resend)
|
||
- [x] Verify admin panel loads at `/admin` — **confirmed ✅**
|
||
- [x] Install **Payload Form Builder plugin** (`@payloadcms/plugin-form-builder`) — installed, re-enabled in Feature 4
|
||
- [x] Downgrade Next.js 16.1.6 → 15.4.11 (peer dep compatibility with Payload 3.77)
|
||
- [x] Upgrade Docker Node.js 20 → 22 (undici/tsx compatibility)
|
||
|
||
---
|
||
|
||
## Feature 4 — CMS Collections Schema ✅
|
||
|
||
Define all Payload collections and globals. Each collection = one content type the client manages.
|
||
|
||
### 4.1 — Media Collection
|
||
|
||
- [x] `Media` collection с локальным хранилищем (`/public/media`)
|
||
- Fields: `alt` (text, required), `caption` (text, optional)
|
||
- Image sizes: `thumbnail` (400×300), `card` (800×600), `hero` (1920×1080)
|
||
|
||
### 4.2 — Users Collection
|
||
|
||
- [x] `Users` collection (extends Payload default)
|
||
- Fields: `name`, `email`, `role` (select: admin | editor)
|
||
- Role-based access control: editors can manage content, not settings
|
||
|
||
### 4.3 — Services Collection
|
||
|
||
- [x] `Services` collection
|
||
- `title` (text, required)
|
||
- `slug` (slug, auto from title, unique)
|
||
- `icon` (select: bookkeeping | tax | payroll | vat)
|
||
- `tagline` (text — short subtitle)
|
||
- `description` (rich text — full description)
|
||
- `whatsIncluded` (array of bullet strings)
|
||
- `whoItsFor` (array: `{ audience: select, description: text }`)
|
||
- `howItWorks` (array of 3: `{ step: number, title: text, description: text }`)
|
||
- `faq` (array: `{ question: text, answer: rich text }`)
|
||
- `relatedTestimonials` (relationship → Testimonials, many)
|
||
- `seo` group: `{ metaTitle, metaDescription, ogImage → Media }`
|
||
- `publishedAt` (date), `status` (select: draft | published)
|
||
|
||
### 4.4 — Blog Posts Collection
|
||
|
||
- [x] `Posts` collection
|
||
- `title` (text, required)
|
||
- `slug` (slug, unique)
|
||
- `author` (relationship → Users)
|
||
- `category` (relationship → Categories)
|
||
- `coverImage` (upload → Media)
|
||
- `excerpt` (textarea, 150 chars max)
|
||
- `content` (rich text — Lexical with full feature set)
|
||
- `readingTime` (number, auto-calculated on save via hook)
|
||
- `publishedAt` (date)
|
||
- `status` (select: draft | published | scheduled)
|
||
- `tags` (array of text)
|
||
- `seo` group: `{ metaTitle, metaDescription, ogImage → Media }`
|
||
|
||
### 4.5 — Categories Collection
|
||
|
||
- [x] `Categories` collection
|
||
- `name` (text, required)
|
||
- `slug` (slug)
|
||
- `colour` (text — hex, for tag colour)
|
||
|
||
### 4.6 — Team Members Collection
|
||
|
||
- [x] `TeamMembers` collection
|
||
- `name` (text, required)
|
||
- `role` (text)
|
||
- `qualifications` (text — e.g. "ACCA, MAAT")
|
||
- `bio` (textarea)
|
||
- `photo` (upload → Media)
|
||
- `linkedIn` (text — URL)
|
||
- `order` (number — display order)
|
||
|
||
### 4.7 — Testimonials Collection
|
||
|
||
- [x] `Testimonials` collection
|
||
- `clientName` (text, required)
|
||
- `businessName` (text)
|
||
- `businessType` (select: sole-trader | limited-company | startup | other)
|
||
- `rating` (select: 1–5)
|
||
- `quote` (textarea, required)
|
||
- `photo` (upload → Media, optional)
|
||
- `source` (select: google | manual)
|
||
- `service` (relationship → Services, optional — for filtering)
|
||
- `featured` (checkbox — show in homepage carousel)
|
||
- `publishedAt` (date)
|
||
|
||
### 4.8 — FAQs Collection
|
||
|
||
- [x] `FAQs` collection (global FAQ bank)
|
||
- `question` (text, required)
|
||
- `answer` (rich text)
|
||
- `service` (relationship → Services, optional)
|
||
- `global` (checkbox — show on generic FAQ sections)
|
||
- `order` (number)
|
||
|
||
### 4.9 — Form Builder (Payload Plugin Collections)
|
||
|
||
- [x] Enable `@payloadcms/plugin-form-builder` — provides:
|
||
- `Forms` collection (drag-and-drop field builder in admin)
|
||
- `FormSubmissions` collection (stores all submissions)
|
||
- [x] Configure supported field types: `text`, `email`, `phone`, `select`, `checkbox`, `textarea`
|
||
- [ ] Configure submission handlers:
|
||
- Email notification (to: configurable per form)
|
||
- Webhook trigger (URL: from webhook registry in Site Settings)
|
||
- Redirect URL or confirmation message (per form)
|
||
|
||
### 4.10 — Navigation Global
|
||
|
||
- [x] `Navigation` global
|
||
- `items` (array):
|
||
- `label` (text)
|
||
- `href` (text, optional — for simple links)
|
||
- `isDropdown` (checkbox)
|
||
- `children` (array, conditional): `{ label, href, icon, description }`
|
||
|
||
### 4.11 — Footer Global
|
||
|
||
- [x] `Footer` global
|
||
- `columns` (array of 4):
|
||
- `heading` (text)
|
||
- `links` (array: `{ label, href }`)
|
||
- `contactInfo` group: `{ address, phone, email }`
|
||
- `socialLinks` group: `{ linkedIn, facebook, instagram }`
|
||
- `legalLinks` (array: `{ label, href }`)
|
||
- `copyrightText` (text)
|
||
|
||
### 4.12 — Site Settings Global
|
||
|
||
- [x] `SiteSettings` global
|
||
- **Brand**: `siteName`, `tagline`, `logo → Media`, `logoDark → Media`, `favicon → Media`
|
||
- **Contact**: `address`, `phone`, `email`, `officeHours`
|
||
- **Social**: `linkedIn`, `facebook`, `instagram`
|
||
- **Analytics**: `googleAnalyticsId`, `googleTagManagerId`, `facebookPixelId`
|
||
- **Booking**: `calendlyUrl`, `calendlyInline` (checkbox)
|
||
- **Chat Bot**: `chatBotMode` (select: disabled | ai | livechat | leadcapture), `chatBotCustomCode` (code field — for Tawk.to etc.)
|
||
- **Webhooks Registry**: `webhooks` (array: `{ name, url, active }`)
|
||
- **Email**: `notificationEmail` (default recipient for form submissions)
|
||
- **SEO Defaults**: `defaultMetaTitle`, `defaultMetaDescription`, `defaultOgImage → Media`
|
||
- **Scripts**: `headerScripts` (code), `footerScripts` (code) — for third-party embeds
|
||
|
||
---
|
||
|
||
## Feature 5 — Design System & Base UI Components ✅
|
||
|
||
- [x] Configure Tailwind CSS with custom design tokens:
|
||
```js
|
||
// globals.css (@theme inline)
|
||
colors: {
|
||
emerald: {
|
||
DEFAULT: '#3CC68A', // primary — CTA кнопки, иконки, border
|
||
dark: '#27A870', // hover / active
|
||
deeper: '#1A8C5B', // тёмные секции
|
||
light: '#7DDCB0', // tints
|
||
mist: '#E8F8F1', // светлые фоны секций
|
||
},
|
||
blue: {
|
||
DEFAULT: '#1B9AD6', // secondary — заголовки, trust, links
|
||
dark: '#1480B8', // hover
|
||
light: '#6CC4E8', // tints
|
||
mist: '#E8F5FC', // светлые фоны
|
||
},
|
||
charcoal: '#162520', // основной текст
|
||
muted: '#6B7280', // второстепенный текст
|
||
bg: '#F5FEFA', // фоновый off-white
|
||
}
|
||
borderRadius: { card: '16px', hero: '24px', pill: '999px' }
|
||
fontFamily: {
|
||
sans: ['Inter', 'sans-serif'],
|
||
display: ['Satoshi', 'sans-serif'],
|
||
mono: ['DM Mono', 'monospace'],
|
||
}
|
||
```
|
||
- [x] Set up fonts:
|
||
- `Satoshi` (variable font) — Fontshare CDN (`<link>` in layout.tsx, CSS var reference in @theme)
|
||
- `Inter` — `next/font/google` → `--font-inter` → `--font-sans`
|
||
- `DM Mono` — `next/font/google` → `--font-dm-mono` → `--font-mono`
|
||
- [x] Create CSS variables in `globals.css` for all design tokens (enables runtime theming)
|
||
- [x] **Button** component (`src/components/ui/Button.tsx`):
|
||
- Variants: `primary` (green fill), `secondary` (outline), `ghost` (text only)
|
||
- Sizes: `sm`, `md`, `lg`
|
||
- States: hover (scale + colour shift), focus (ring), loading (spinner), disabled
|
||
- Optional: trailing arrow icon, leading icon
|
||
- [x] **Icon system** (`src/components/ui/icons/`):
|
||
- Custom SVG line icons for each service (Bookkeeping, Tax, Payroll, VAT)
|
||
- Shared icons: ArrowRight, CheckCircle, Star, Menu, X, ChevronDown
|
||
- All exported as React components with `size` and `color` props
|
||
- [x] **Heading** component — `h1`–`h4` with correct size + weight from design system
|
||
- [x] **Tag/Badge** component — pill with colour variant (green, grey, blue)
|
||
- [x] **StarRating** component — 1–5 filled star SVGs
|
||
- [x] **GlassCard** component — frosted glass base with emerald border, hover glow (light + dark variants)
|
||
- [x] **Section** layout wrapper — `max-w-[1440px]`, horizontal padding
|
||
- [x] **Divider** component — subtle emerald gradient horizontal rule
|
||
- [x] **Spinner** component — loading state for forms and async content
|
||
|
||
---
|
||
|
||
## Feature 6 — Animation Infrastructure
|
||
|
||
- [ ] Install dependencies: `gsap`, `@gsap/react`, `lenis`, `framer-motion`, `@react-three/fiber`, `three`
|
||
- [ ] **Lenis smooth scroll** provider (`src/lib/lenis.tsx`):
|
||
- `LenisProvider` wraps the app in root layout
|
||
- Integrates with GSAP ticker for synchronized animations
|
||
- Disabled on mobile if causing performance issues
|
||
- [ ] **GSAP context provider** (`src/lib/gsap.ts`):
|
||
- Registers ScrollTrigger plugin
|
||
- Exports `gsap` instance with plugins pre-registered
|
||
- Custom hook `useGSAP` for component-level animation cleanup
|
||
- [ ] **`useAnimateOnScroll` hook** (`src/hooks/useAnimateOnScroll.ts`):
|
||
- Accepts `ref`, `animation type` (fadeUp, fadeIn, slideLeft, etc.), `delay`, `stagger`
|
||
- Returns trigger state
|
||
- Uses ScrollTrigger under the hood
|
||
- [ ] **`useCountUp` hook** (`src/hooks/useCountUp.ts`):
|
||
- Accepts `target` (number), `duration`, `prefix` (`£`, `+`), `suffix` (`%`, `+`)
|
||
- Triggers animation when element enters viewport
|
||
- Returns current display value (string)
|
||
- [ ] **`AnimatedText` component** (`src/components/ui/AnimatedText.tsx`):
|
||
- Splits text into words or lines
|
||
- Each word/line slides up on a stagger delay
|
||
- GSAP-driven, respects `prefers-reduced-motion`
|
||
- [ ] **`FadeInSection` component** (`src/components/ui/FadeInSection.tsx`):
|
||
- Wraps any content
|
||
- Fades + translates up when enters viewport
|
||
- Accepts `delay` and `duration` props
|
||
- [ ] **Framer Motion page transition** (`src/components/layout/PageTransition.tsx`):
|
||
- Wraps each page with `AnimatePresence`
|
||
- Default: fade + subtle Y translate
|
||
- Used in root layout
|
||
- [ ] **`prefers-reduced-motion` utility** — all animation components check and skip if enabled
|
||
|
||
---
|
||
|
||
## Feature 7 — Header & Navigation
|
||
|
||
- [ ] **`Header` component** (`src/components/layout/Header.tsx`):
|
||
- Fixed/sticky at top, `z-50`
|
||
- On scroll: applies `backdrop-blur` + white/85% opacity background (Framer Motion)
|
||
- Transparent when at top of page
|
||
- Max-width container, flex layout: logo | nav | CTA
|
||
- [ ] **Logo component** — renders logo image from CMS Site Settings, supports light/dark variant
|
||
- [ ] **Desktop navigation** (`src/components/layout/DesktopNav.tsx`):
|
||
- Renders items from CMS Navigation global
|
||
- Simple links: hover underline slide-in animation
|
||
- Dropdown trigger: `Services ▾` — renders `ServicesDropdown`
|
||
- [ ] **`ServicesDropdown` component**:
|
||
- Opens on hover/focus, closes on blur/outside click
|
||
- Grid of service cards: icon + name + short description
|
||
- Framer Motion: animate-in (scale + fade from top)
|
||
- [ ] **Header CTA button** — "Book a Free Consultation" → opens booking modal
|
||
- [ ] **`MobileMenu` component** (`src/components/layout/MobileMenu.tsx`):
|
||
- Hamburger icon button (animated → X on open)
|
||
- Full-screen overlay, `fixed inset-0`, dark green tint background
|
||
- Framer Motion: slide-in from right or fade-in
|
||
- Staggered nav item reveal
|
||
- Large CTA button at bottom
|
||
- Closes on link click or backdrop click
|
||
- [ ] Fetch navigation data from Payload at build/request time (cached)
|
||
|
||
---
|
||
|
||
## Feature 8 — Footer
|
||
|
||
- [ ] **`Footer` component** (`src/components/layout/Footer.tsx`):
|
||
- 4-column grid (collapses to 2×2 on tablet, 1 column on mobile)
|
||
- Column 1: Logo, tagline, social icon links
|
||
- Column 2: Services links
|
||
- Column 3: Company links (About, Blog, Contact)
|
||
- Column 4: Contact info (address, phone, email) + ICAEW/ACCA badges
|
||
- [ ] Social icon links (LinkedIn, Facebook, Instagram) — SVG icons, hover colour transition
|
||
- [ ] ICAEW / ACCA badge images (stored in media, linked from Site Settings)
|
||
- [ ] **Bottom bar**: copyright text | Privacy Policy | Cookie Policy
|
||
- [ ] Data fetched from CMS Footer global + Site Settings global
|
||
|
||
---
|
||
|
||
## Feature 9 — 3D Hero Scene (Three.js / R3F)
|
||
|
||
- [ ] Install: `@react-three/fiber`, `@react-three/drei`, `three`
|
||
- [ ] **`GlobeScene` component** (`src/components/three/GlobeScene.tsx`):
|
||
- Canvas with `@react-three/fiber`
|
||
- Camera position, fog, ambient + directional lighting (soft green tint)
|
||
- [ ] **`Globe` mesh**:
|
||
- `SphereGeometry` with high segment count
|
||
- Custom `PointsMaterial` shader: dot-matrix surface pattern
|
||
- Colour: sage green `#6BAF7D` on near-white background
|
||
- Slow auto-rotation around Y axis (`useFrame`)
|
||
- [ ] **`ParticleNetwork`**:
|
||
- 150–300 floating particle nodes (reduced on mobile: 60–80)
|
||
- Lines connecting nearby particles (`LineSegments`)
|
||
- Nodes float with subtle Perlin noise movement
|
||
- Colour: soft mint with 40% opacity
|
||
- [ ] **Mouse parallax interaction**:
|
||
- Track `mousemove` on hero section
|
||
- Globe and particle network shift slightly (opposite to mouse direction)
|
||
- `useSpring` (React Spring or Framer Motion) for smooth interpolation
|
||
- [ ] **Device-adaptive performance**:
|
||
- Detect mobile / low-power device
|
||
- Reduce particle count, disable post-processing effects
|
||
- `React.Suspense` boundary with skeleton loader during WebGL init
|
||
- [ ] **Mobile fallback** (`src/components/three/GlobeFallback.tsx`):
|
||
- 2D SVG animated globe (CSS animation, no WebGL)
|
||
- Shown when WebGL unavailable or `prefers-reduced-motion` is set
|
||
- [ ] **`useWebGLSupport` hook** — detects WebGL availability, returns boolean
|
||
|
||
---
|
||
|
||
## Feature 10 — Home Page: Hero Section
|
||
|
||
- [ ] **`HeroSection` component** (`src/components/sections/home/HeroSection.tsx`)
|
||
- [ ] Full-viewport height (`min-h-screen`), flex / grid split layout
|
||
- [ ] Left column:
|
||
- Eyebrow tag (e.g. "Trusted by 500+ UK Businesses") — Badge component, fade-in
|
||
- `AnimatedText` H1: "Smart Accounting for Growing British Businesses" — word stagger
|
||
- Subheadline paragraph — fade-in with delay
|
||
- Button group: Primary CTA + Secondary CTA (with arrow icon)
|
||
- Trust strip: star rating + "4.9 Google Rating" · "ICAEW Certified" · "500+ Clients Served"
|
||
- [ ] Right column: `GlobeScene` (or `GlobeFallback` on mobile/no WebGL)
|
||
- [ ] Mobile layout: stacked, 3D scene below text, reduced height
|
||
- [ ] Content driven from CMS Pages collection (hero fields)
|
||
|
||
---
|
||
|
||
## Feature 11 — Home Page: Pain Points Section
|
||
|
||
- [ ] **`PainPointsSection` component**
|
||
- [ ] Dark green background (`#1A2E1F`), full-width
|
||
- [ ] Headline + subtext — `AnimatedText` reveal
|
||
- [ ] 3 `GlassCard` components (frosted glass on dark background):
|
||
- Card 1: "Missed deadlines & HMRC penalties"
|
||
- Card 2: "Confused by tax rules that keep changing"
|
||
- Card 3: "Hours wasted on bookkeeping instead of growing"
|
||
- [ ] ScrollTrigger staggered reveal: cards slide up 100ms apart
|
||
- [ ] Subtle parallax: background shifts 20px on scroll
|
||
|
||
---
|
||
|
||
## Feature 12 — Home Page: Services Overview Section
|
||
|
||
- [ ] **`ServicesSection` component**
|
||
- [ ] Section header: headline + subheadline
|
||
- [ ] 2×2 `GlassCard` grid (CSS Grid, responsive)
|
||
- [ ] Each card:
|
||
- Custom SVG icon (from icon system)
|
||
- Service name (heading)
|
||
- Short description (from CMS)
|
||
- "Learn More →" link to `/services/[slug]`
|
||
- Hover: `translateY(-4px)` + sage green border glow (`box-shadow`)
|
||
- [ ] ScrollTrigger staggered card reveal
|
||
- [ ] CTA block below grid: "Not sure which service you need? → Let's Talk"
|
||
- [ ] Data: fetch all Services from Payload
|
||
|
||
---
|
||
|
||
## Feature 13 — Home Page: Why Choose Axil Section
|
||
|
||
- [ ] **`WhyAxilSection` component**
|
||
- [ ] Section headline: "Why Businesses Choose Axil"
|
||
- [ ] **Stat counter row** (4 stats):
|
||
- `500+` Businesses Served
|
||
- `98%` Client Retention Rate
|
||
- `£2M+` Tax Saved for Our Clients
|
||
- `12+` Years of Experience
|
||
- Each uses `useCountUp` hook, triggers on ScrollTrigger enter
|
||
- Numbers in `DM Mono` font
|
||
- [ ] **4 USP blocks** (icon + heading + description):
|
||
- ICAEW & ACCA Qualified
|
||
- Fixed Monthly Engagement
|
||
- Dedicated Account Manager
|
||
- Cloud-Based & Paper-Free
|
||
- [ ] `FadeInSection` wrapper per block, staggered
|
||
|
||
---
|
||
|
||
## Feature 14 — Home Page: Testimonials Section
|
||
|
||
- [ ] **`TestimonialsSection` component**
|
||
- [ ] Auto-scrolling marquee carousel (infinite horizontal scroll, CSS animation)
|
||
- Pause on hover
|
||
- Two rows scrolling in opposite directions (optional premium touch)
|
||
- [ ] **`TestimonialCard`** component:
|
||
- Client name + business type
|
||
- `StarRating` (1–5)
|
||
- Quote text (truncated at 3 lines, expand on click)
|
||
- Optional client avatar (from Media, fallback to initials)
|
||
- [ ] Google Reviews badge (static badge image or API widget)
|
||
- [ ] ICAEW / ACCA certification badge display
|
||
- [ ] CTA below: "Join hundreds of satisfied UK businesses → Book Your Free Consultation"
|
||
- [ ] Data: fetch featured testimonials from Payload (where `featured = true`)
|
||
|
||
---
|
||
|
||
## Feature 15 — Home Page: Who We Work With Section
|
||
|
||
- [ ] **`AudienceSection` component**
|
||
- [ ] 3 audience cards:
|
||
- Sole Traders — illustrated icon, description, "Learn More →"
|
||
- Limited Companies — illustrated icon, description, "Learn More →"
|
||
- Startups — illustrated icon, description, "Learn More →"
|
||
- [ ] Illustrated icons: custom SVG per audience type
|
||
- [ ] Cards: `GlassCard`, hover lift effect
|
||
- [ ] FadeIn reveal on scroll
|
||
|
||
---
|
||
|
||
## Feature 16 — Home Page: How It Works Section
|
||
|
||
- [ ] **`HowItWorksSection` component**
|
||
- [ ] 3-step horizontal layout (flex row on desktop, vertical stack on mobile)
|
||
- [ ] Each step: numbered circle + title + description
|
||
- [ ] **Animated connecting line**:
|
||
- SVG path between steps
|
||
- GSAP `DrawSVGPlugin` or stroke `dashoffset` animation
|
||
- Draws left-to-right as section scrolls into view
|
||
- [ ] Step data driven from CMS (global or hardcoded — TBD with client)
|
||
|
||
---
|
||
|
||
## Feature 17 — Home Page: Blog Preview Section
|
||
|
||
- [ ] **`BlogPreviewSection` component**
|
||
- [ ] Section headline + "Visit Our Blog →" link
|
||
- [ ] Fetch 3 most recent published posts from Payload
|
||
- [ ] **`BlogCard`** component (reused on blog index):
|
||
- Cover image (`next/image`, lazy-loaded)
|
||
- Category tag badge
|
||
- Title (heading)
|
||
- Excerpt (truncated)
|
||
- Author name + date + read time
|
||
- Hover: image subtle zoom, card lift
|
||
- [ ] Grid: 3 columns desktop, 1 column mobile
|
||
|
||
---
|
||
|
||
## Feature 18 — Home Page: Final CTA Section
|
||
|
||
- [ ] **`FinalCTASection` component**
|
||
- [ ] Full-width, deep forest green background (`#1A2E1F` or `#2E7D52`)
|
||
- [ ] Centred content:
|
||
- Large headline: "Ready to take the stress out of your finances?"
|
||
- Subheadline
|
||
- Large primary CTA button (white on green): "Book a Free Consultation"
|
||
- Trust reassurance: "★ 4.9/5 on Google · ICAEW Certified · No lock-in contracts"
|
||
- [ ] Optional: subtle animated background (particle drift or gradient shift)
|
||
|
||
---
|
||
|
||
## Feature 19 — Consultation Booking Modal & Form
|
||
|
||
This is the primary conversion mechanism. Opens from every CTA across the site.
|
||
|
||
- [ ] **`BookingModal` component** (`src/components/BookingModal.tsx`):
|
||
- Global state: `useBookingModal()` Zustand store or React Context
|
||
- Triggered by `openBookingModal()` from any component
|
||
- `AnimatePresence` + Framer Motion: fade-in backdrop, slide-up modal
|
||
- Close on backdrop click, Escape key, close button
|
||
- Accessible: focus trap, `role="dialog"`, `aria-modal`
|
||
- [ ] **Two modes** (configurable in CMS Site Settings):
|
||
- **Mode A — Calendly**: renders `<iframe>` from `calendlyUrl` setting
|
||
- **Mode B — Custom Form**: renders the consultation form
|
||
- [ ] **Consultation form fields**:
|
||
- Full name (text, required)
|
||
- Email address (email, required)
|
||
- Phone number (text, optional)
|
||
- Business type (select: sole trader / limited company / startup / other)
|
||
- What do you need help with? (select: bookkeeping / tax / payroll / VAT / not sure)
|
||
- Message (textarea, optional)
|
||
- [ ] Form validation: client-side (React Hook Form + Zod schema)
|
||
- [ ] Submit handler (API route `POST /api/contact`):
|
||
- Save to Payload FormSubmissions collection
|
||
- Send notification email via Resend to admin email (from Site Settings)
|
||
- Trigger webhook if configured (from webhooks registry)
|
||
- Return success/error response
|
||
- [ ] Success state: animated checkmark + "We'll be in touch within 1 business day" message
|
||
- [ ] Error state: clear error messages per field + general error fallback
|
||
|
||
---
|
||
|
||
## Feature 20 — Services Pages
|
||
|
||
### 20.1 — Services Overview Page (`/services`)
|
||
|
||
- [ ] Grid of all 4 service cards (large format)
|
||
- [ ] Each card links to individual service page
|
||
- [ ] Intro section: headline + subheadline
|
||
- [ ] CTA at bottom
|
||
|
||
### 20.2 — Individual Service Pages (`/services/[slug]`)
|
||
|
||
- [ ] Dynamic route with `generateStaticParams` (ISR)
|
||
- [ ] Fetch service data by slug from Payload at build/revalidate time
|
||
- [ ] **Hero section**: service name, bold tagline, illustration/icon, CTA button
|
||
- [ ] **What's Included section**: bullet list of deliverables (from CMS `whatsIncluded`)
|
||
- [ ] **Who It's For section**: audience cards filtered to relevant segments
|
||
- [ ] **How It Works section**: 3-step process (service-specific, from CMS)
|
||
- [ ] **FAQ section**: accordion component
|
||
- Fetch FAQs related to this service from Payload
|
||
- Animated expand/collapse (Framer Motion `AnimatePresence` + height animation)
|
||
- JSON-LD `FAQPage` schema injected via `generateMetadata`
|
||
- [ ] **Testimonials section**: filtered by service (from Payload relationship)
|
||
- [ ] **Final CTA section**
|
||
- [ ] `generateMetadata`: SEO title, description, OG image from CMS `seo` group
|
||
|
||
---
|
||
|
||
## Feature 21 — About Page (`/about`)
|
||
|
||
- [ ] Fetch team members, site settings from Payload
|
||
- [ ] **Hero section**: large headline + team group photo (from Media)
|
||
- [ ] **Our Story section**: rich text from CMS (Lexical renderer)
|
||
- [ ] **Team grid section**:
|
||
- `TeamMemberCard` component: photo, name, role, qualifications, LinkedIn link
|
||
- Responsive grid: 3 col desktop, 2 col tablet, 1 col mobile
|
||
- Hover: subtle overlay with LinkedIn button
|
||
- Data from Payload TeamMembers collection (ordered by `order` field)
|
||
- [ ] **Core Values section**: 4 value blocks (icon + title + description)
|
||
- [ ] **Certifications section**: ICAEW + ACCA logo badges with descriptions
|
||
- [ ] **Final CTA section**
|
||
|
||
---
|
||
|
||
## Feature 22 — Blog System
|
||
|
||
### 22.1 — Blog Index Page (`/blog`)
|
||
|
||
- [ ] Fetch all published posts (ISR, revalidate: 3600s)
|
||
- [ ] **Search input**: client-side filter by title/excerpt
|
||
- [ ] **Category filter tabs**: "All" + each category — filters post grid
|
||
- [ ] Blog post card grid (3 columns desktop, 1 mobile) — `BlogCard` component
|
||
- [ ] Pagination (10 posts per page, Payload `limit`/`page` query)
|
||
- [ ] SEO metadata for blog index
|
||
|
||
### 22.2 — Individual Blog Post Page (`/blog/[slug]`)
|
||
|
||
- [ ] `generateStaticParams` + ISR (revalidate: 3600s)
|
||
- [ ] Fetch post by slug from Payload
|
||
- [ ] **Lexical rich text renderer** (`src/lib/lexical-renderer.tsx`):
|
||
- Renders all Lexical nodes: headings, paragraphs, lists, blockquotes, images, code blocks
|
||
- Custom component for pull quotes (green left border, large text)
|
||
- Syntax highlighting for code blocks (`shiki` or `prism`)
|
||
- [ ] **Article layout**: hero image (full-width), title, author + date + read time + category tag
|
||
- [ ] **Table of Contents** (auto-generated from H2/H3 headings):
|
||
- Sticky sidebar on desktop
|
||
- Active heading highlight on scroll (Intersection Observer)
|
||
- [ ] **Social share buttons**: copy link, Twitter/X, LinkedIn
|
||
- [ ] **Related posts section**: 2–3 posts from same category
|
||
- [ ] `generateMetadata`: full SEO + Open Graph from CMS seo group
|
||
|
||
---
|
||
|
||
## Feature 23 — Contact Page (`/contact`)
|
||
|
||
- [ ] Hero: "Get in Touch" + brief description
|
||
- [ ] **Contact form** (renders a Payload Form via form builder):
|
||
- Fields: name, email, phone, subject, message
|
||
- Submission saves to Payload FormSubmissions + email notification
|
||
- [ ] **Contact info panel**: address, phone, email, office hours
|
||
- [ ] **Google Maps embed** (iframe, optional — lazy-loaded)
|
||
- [ ] Office hours block
|
||
|
||
---
|
||
|
||
## Feature 24 — Legal Pages (`/privacy-policy`, `/cookie-policy`)
|
||
|
||
- [ ] Static page routes
|
||
- [ ] Content editable via CMS Pages collection (rich text fields)
|
||
- [ ] Standard typography layout: table of contents sidebar + main content
|
||
- [ ] Last updated date (from CMS)
|
||
|
||
---
|
||
|
||
## Feature 25 — Chat Bot Module
|
||
|
||
- [ ] **`ChatWidget` component** (`src/components/chat/ChatWidget.tsx`):
|
||
- Floating button (bottom-right), "Chat with us" label
|
||
- Slide-up panel animation (Framer Motion)
|
||
- Reads `chatBotMode` from Site Settings global
|
||
- [ ] **Mode: disabled** — component renders nothing
|
||
- [ ] **Mode: livechat** (Tawk.to or custom):
|
||
- Reads `chatBotCustomCode` from Site Settings
|
||
- Injects script via `useEffect` (no SSR)
|
||
- Custom button hidden; Tawk.to button shown instead
|
||
- [ ] **Mode: ai** — AI Chat:
|
||
- Pre-chat form: collect visitor name + email
|
||
- Chat messages UI: user + bot bubbles, loading dots
|
||
- API route `POST /api/chat`:
|
||
- Sends message to OpenAI/Claude with system prompt
|
||
- System prompt: company info, services, FAQs — fetched from Payload
|
||
- Streams response back (SSE or JSON)
|
||
- Escalation: if bot confidence low → "Let me connect you with our team" → email notification
|
||
- Conversation log saved to Payload (custom `ChatLogs` collection or email)
|
||
- [ ] **Mode: leadcapture** — Scripted Bot:
|
||
- Step 1: "Hi! What's your name?"
|
||
- Step 2: "Great, {name}! What's your email address?"
|
||
- Step 3: "Are you a sole trader, limited company, or startup?"
|
||
- Step 4: "What's your main concern? (tax / bookkeeping / payroll / other)"
|
||
- Step 5: "Thanks! Our team will be in touch shortly."
|
||
- On completion: POST lead to `/api/contact` → email + webhook
|
||
|
||
---
|
||
|
||
## Feature 26 — SEO & Metadata System
|
||
|
||
- [ ] **`generateMetadata` function** utility (`src/lib/metadata.ts`):
|
||
- Accepts CMS seo object + fallback to Site Settings defaults
|
||
- Returns Next.js `Metadata` object
|
||
- Handles: title, description, OG image, canonical URL
|
||
- [ ] **Open Graph image generation** (`src/app/og/route.tsx`):
|
||
- Dynamic OG images for blog posts using `@vercel/og`
|
||
- Template: Axil logo + post title + sage green background
|
||
- [ ] **Structured data helpers** (`src/lib/structured-data.ts`):
|
||
- `LocalBusiness` schema (name, address, phone, opening hours)
|
||
- `AccountingService` schema
|
||
- `FAQPage` schema (for service pages)
|
||
- `BlogPosting` schema (for blog articles)
|
||
- Injected via `<script type="application/ld+json">` in page `<head>`
|
||
- [ ] **`sitemap.ts`** (`src/app/sitemap.ts`):
|
||
- Fetches all published blog posts + service slugs from Payload
|
||
- Returns `MetadataRoute.Sitemap` array
|
||
- Revalidates on ISR
|
||
- [ ] **`robots.ts`** (`src/app/robots.ts`):
|
||
- Allow all crawlers
|
||
- Point to sitemap
|
||
- Block `/admin/*`
|
||
- [ ] Verify all pages have correct `<title>` tags in browser devtools
|
||
|
||
---
|
||
|
||
## Feature 27 — Analytics, Tracking & Cookie Consent
|
||
|
||
- [ ] **`AnalyticsProvider` component** (`src/components/AnalyticsProvider.tsx`):
|
||
- Reads GA ID, GTM ID, FB Pixel ID from CMS Site Settings
|
||
- Conditionally loads scripts only after cookie consent granted
|
||
- [ ] **Google Tag Manager** integration:
|
||
- `<Script>` in `<head>` and `<noscript>` in `<body>`
|
||
- Only loads after consent
|
||
- [ ] **Cookie consent banner** (`src/components/CookieBanner.tsx`):
|
||
- GDPR / UK GDPR compliant
|
||
- Framer Motion: slides up from bottom on first visit
|
||
- Buttons: "Accept All" | "Reject Non-Essential" | "Manage Preferences"
|
||
- Stores consent in `localStorage`
|
||
- Triggers analytics scripts on accept
|
||
- [ ] **`useConsent` hook** — reads/writes consent state, exposes `hasConsent(category)`
|
||
- [ ] **Custom code injection** from CMS Site Settings:
|
||
- `headerScripts` — injected in `<head>` via Next.js root layout
|
||
- `footerScripts` — injected before `</body>`
|
||
|
||
---
|
||
|
||
## Feature 28 — Form Builder Frontend Renderer
|
||
|
||
Allows any Payload-built form to be rendered on the frontend.
|
||
|
||
- [ ] **`FormRenderer` component** (`src/components/cms/FormRenderer.tsx`):
|
||
- Accepts `formId` prop (Payload form document ID or slug)
|
||
- Fetches form schema from Payload API
|
||
- Dynamically renders all field types:
|
||
- `text`, `email`, `phone`, `textarea` → `<input>` / `<textarea>`
|
||
- `select` → `<select>` or custom dropdown
|
||
- `checkbox` → styled checkbox
|
||
- React Hook Form + Zod validation from field config (required, type)
|
||
- [ ] **`FormField` component** — renders individual field with label, input, error message
|
||
- [ ] **Submit handler**: `POST /api/form-submissions`
|
||
- Saves to Payload FormSubmissions
|
||
- Triggers email + webhook from form config
|
||
- [ ] Success / error UI states
|
||
- [ ] Usage: embed `<FormRenderer formId="..." />` anywhere on any CMS-managed page
|
||
|
||
---
|
||
|
||
## Feature 29 — Performance Optimisation
|
||
|
||
- [ ] All images use `next/image` with correct `sizes` prop and `priority` for LCP images
|
||
- [ ] `next/font` for Inter + DM Mono (eliminates layout shift from font load)
|
||
- [ ] **Dynamic imports** for heavy components:
|
||
- `GlobeScene` — `dynamic(() => import(...), { ssr: false })`
|
||
- `ChatWidget` — `dynamic(() => import(...), { ssr: false })`
|
||
- Lexical renderer — `dynamic` import
|
||
- [ ] **ISR** (Incremental Static Regeneration):
|
||
- Service pages: `revalidate = 86400` (24h)
|
||
- Blog posts: `revalidate = 3600` (1h)
|
||
- Homepage: `revalidate = 3600`
|
||
- [ ] Install `@next/bundle-analyzer`, run bundle analysis, eliminate large dependencies
|
||
- [ ] Lazy-load all sections below fold (Intersection Observer or Next.js `loading="lazy"`)
|
||
- [ ] Verify no unused CSS (Tailwind PurgeCSS is automatic)
|
||
- [ ] Run Lighthouse on all key pages — target: Performance 95+, SEO 100, Accessibility 95+
|
||
- [ ] Fix any Lighthouse findings before delivery
|
||
|
||
---
|
||
|
||
## Feature 30 — Accessibility Audit & Fixes
|
||
|
||
- [ ] Add `<a href="#main-content">Skip to content</a>` as first focusable element
|
||
- [ ] Verify all interactive elements are keyboard-navigable (Tab, Enter, Escape)
|
||
- [ ] All images have meaningful `alt` text (enforced by Payload Media collection)
|
||
- [ ] All form fields have associated `<label>` elements
|
||
- [ ] All icon-only buttons have `aria-label`
|
||
- [ ] Modals: focus trap, `role="dialog"`, `aria-modal`, return focus on close
|
||
- [ ] Navigation dropdowns: `aria-expanded`, `aria-haspopup`
|
||
- [ ] Colour contrast: check all text/background combos meet WCAG AA (4.5:1 body, 3:1 large text)
|
||
- [ ] Test with screen reader (VoiceOver / NVDA)
|
||
- [ ] Verify `prefers-reduced-motion` disables all non-essential animations
|
||
|
||
---
|
||
|
||
## Feature 31 — Responsive Design QA
|
||
|
||
- [ ] Test every page at: `320px`, `375px`, `414px`, `768px`, `1024px`, `1280px`, `1440px`, `1920px`
|
||
- [ ] Verify 3D scene: WebGL on desktop, SVG fallback on mobile
|
||
- [ ] Verify hamburger menu: opens, nav links work, closes correctly
|
||
- [ ] Verify booking modal: fills screen on mobile, scrollable content
|
||
- [ ] Verify all form fields usable with touch keyboard (no content hidden behind keyboard)
|
||
- [ ] Verify testimonials marquee / carousel: touch-swipeable on mobile
|
||
- [ ] Verify blog grid: 1-column on mobile, readable font sizes
|
||
- [ ] Verify footer: stacks correctly on mobile
|
||
|
||
---
|
||
|
||
## Feature 32 — Error Handling & Monitoring
|
||
|
||
- [ ] **Sentry** setup (`@sentry/nextjs`):
|
||
- Install and configure with `SENTRY_DSN`
|
||
- Client + server + edge error capture
|
||
- Source maps upload on build
|
||
- [ ] **Custom 404 page** (`src/app/not-found.tsx`):
|
||
- Brand-styled, helpful message
|
||
- Links back to home + contact
|
||
- [ ] **Custom 500 page** (`src/app/error.tsx`):
|
||
- Brand-styled error page
|
||
- Reports error to Sentry
|
||
- [ ] All API routes return proper HTTP status codes + JSON error bodies
|
||
- [ ] Form submission error states: clear per-field errors + general fallback
|
||
- [ ] Payload API fetch failures: graceful degradation (show fallback content, not crash)
|
||
|
||
---
|
||
|
||
## Feature 33 — Deployment (Ubuntu VPS + Docker)
|
||
|
||
Stack: Ubuntu server · Docker + Docker Compose · Nginx reverse proxy · Let's Encrypt SSL
|
||
|
||
### 33.1 — Server preparation
|
||
|
||
- [ ] Install Docker + Docker Compose on Ubuntu:
|
||
```bash
|
||
curl -fsSL https://get.docker.com | sh
|
||
sudo usermod -aG docker $USER
|
||
```
|
||
- [ ] Install Nginx + Certbot:
|
||
```bash
|
||
sudo apt install nginx certbot python3-certbot-nginx -y
|
||
```
|
||
- [ ] Clone repository on server:
|
||
```bash
|
||
git clone git@github.com:YOUR_ORG/axil-accountants.git /opt/axil
|
||
cd /opt/axil && git checkout main
|
||
```
|
||
- [ ] Create production `.env.local` on server (manually — never commit):
|
||
- `DATABASE_URI=postgresql://axil:STRONG_PASS@db:5432/axil`
|
||
- `PAYLOAD_SECRET=STRONG_SECRET_32_CHARS`
|
||
- `NEXT_PUBLIC_SITE_URL=https://axilaccountants.co.uk`
|
||
|
||
### 33.2 — Docker Compose production override
|
||
|
||
- [ ] Create `docker-compose.prod.yml` (production overrides):
|
||
- App: `NODE_ENV=production`, `restart: always`, no port 3000 exposed externally (only via Nginx)
|
||
- DB: named volume for persistence, `restart: always`
|
||
- Remove dev-only volume mounts
|
||
|
||
### 33.3 — Nginx reverse proxy
|
||
|
||
- [ ] Create `/etc/nginx/sites-available/axil` config:
|
||
- `server_name axilaccountants.co.uk www.axilaccountants.co.uk`
|
||
- `proxy_pass http://127.0.0.1:3000`
|
||
- Gzip, proxy headers, timeouts
|
||
- [ ] Enable site: `sudo ln -s /etc/nginx/sites-available/axil /etc/nginx/sites-enabled/`
|
||
- [ ] Obtain SSL certificate: `sudo certbot --nginx -d axilaccountants.co.uk -d www.axilaccountants.co.uk`
|
||
- [ ] Verify auto-renewal: `sudo certbot renew --dry-run`
|
||
- [ ] Configure `www` → apex redirect in Nginx (301)
|
||
|
||
### 33.4 — Deploy script
|
||
|
||
- [ ] Create `scripts/deploy.sh` at repo root:
|
||
```bash
|
||
#!/bin/bash
|
||
set -e
|
||
cd /opt/axil
|
||
git pull origin main
|
||
docker compose -f docker-compose.yml -f docker-compose.prod.yml build app
|
||
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps app
|
||
docker image prune -f
|
||
echo "Deploy complete: $(date)"
|
||
```
|
||
- [ ] Make executable: `chmod +x scripts/deploy.sh`
|
||
- [ ] Test deploy: `./scripts/deploy.sh` — verify site responds after restart
|
||
|
||
### 33.5 — Verification
|
||
|
||
- [ ] Run production build locally first: `docker compose build && docker compose up` — no errors
|
||
- [ ] Verify HTTPS works: `curl -I https://axilaccountants.co.uk`
|
||
- [ ] Run Lighthouse on production URL — confirm scores meet targets
|
||
- [ ] Verify DB volume survives container restart (data not lost)
|
||
|
||
---
|
||
|
||
## Feature 34 — Content Seeding & CMS Setup
|
||
|
||
- [ ] Create seed script (`src/payload/seed.ts`):
|
||
- Site Settings: company name, logo, contact details, placeholder social URLs
|
||
- 4 Services: Bookkeeping, Tax Returns, Payroll, VAT Returns (full content per service)
|
||
- 3 Sample Testimonials (marked as featured)
|
||
- 3 FAQs per service
|
||
- Blog Categories: "Tax Tips", "Business Advice", "HMRC Updates", "Payroll Guide"
|
||
- Navigation: full nav structure from concept
|
||
- Footer: all columns with links
|
||
- [ ] Run seed script against production database
|
||
- [ ] Verify all seeded content displays correctly on frontend
|
||
- [ ] Create CMS editor user account for client
|
||
|
||
---
|
||
|
||
## Feature 35 — Client Handover & Documentation
|
||
|
||
- [ ] **CMS User Guide** (`docs/cms-guide.md`):
|
||
- How to log into the admin panel
|
||
- How to edit page content (services, hero text, etc.)
|
||
- How to write and publish a blog post
|
||
- How to add a testimonial
|
||
- How to add a team member
|
||
- How to create a contact form
|
||
- How to set up a webhook on a form
|
||
- How to change the chat bot mode
|
||
- How to update integration settings (GA, GTM, Calendly URL)
|
||
- [ ] **Handover checklist**:
|
||
- [ ] Client has admin login credentials
|
||
- [ ] Client has SSH access to server (or handover to sysadmin)
|
||
- [ ] Client has Resend account access (for email settings)
|
||
- [ ] DNS properly pointing to Vercel
|
||
- [ ] Google Analytics connected and receiving data
|
||
- [ ] Booking form submissions arriving in CMS + email
|
||
- [ ] Mobile tested on real device (iPhone + Android)
|
||
- [ ] Lighthouse scores confirmed ≥ 95 Performance
|
||
|
||
---
|
||
|
||
## Summary: Feature Dependency Order
|
||
|
||
```
|
||
Feature 1 (Project Setup)
|
||
└── Feature 2 (Database)
|
||
└── Feature 3 (Payload CMS Core)
|
||
└── Feature 4 (CMS Collections Schema)
|
||
├── Feature 5 (Design System) ← parallel from here
|
||
├── Feature 6 (Animation Infrastructure)
|
||
└── Feature 7 + 8 (Header + Footer)
|
||
└── Feature 9 (3D Scene)
|
||
└── Feature 10 (Hero Section)
|
||
└── Features 11–18 (Home Page Sections)
|
||
└── Feature 19 (Booking Modal) ← needed by all CTAs
|
||
├── Feature 20 (Services Pages)
|
||
├── Feature 21 (About Page)
|
||
├── Feature 22 (Blog)
|
||
├── Feature 23 (Contact Page)
|
||
└── Feature 24 (Legal Pages)
|
||
├── Feature 25 (Chat Bot)
|
||
├── Feature 26 (SEO)
|
||
├── Feature 27 (Analytics)
|
||
├── Feature 28 (Form Renderer)
|
||
├── Feature 29 (Performance)
|
||
├── Feature 30 (Accessibility)
|
||
├── Feature 31 (Responsive QA)
|
||
├── Feature 32 (Error Handling)
|
||
└── Feature 33 (Deployment)
|
||
├── Feature 34 (Content Seed)
|
||
└── Feature 35 (Handover)
|
||
```
|
||
|
||
---
|
||
|
||
_Total features: 35 | Estimated tasks: ~220_
|
||
_Last updated: February 2026_
|