feat: project setup & repository (Feature 1)

- Next.js 16.1.6 with App Router, TypeScript strict, Tailwind CSS v4
- ESLint 9, Prettier with Tailwind class sorting plugin
- Husky + lint-staged pre-commit hooks
- Multi-stage Dockerfile (dev/build/production) with pnpm + Node 20
- docker-compose.yml with hot reload + PostgreSQL 17
- src/ directory structure (components, lib, hooks, types, payload)
- .env.example template with all required variables
- standalone output mode for production Docker builds

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-02-21 22:43:53 +00:00
commit e373c2b46c
48 changed files with 6821 additions and 0 deletions

View file

@ -0,0 +1,160 @@
---
name: design-guidelines
description: Generate, update, or audit frontend design guidelines for Axil Accountants. Use this skill to create/maintain the design system documentation, review component consistency, or produce a design guidelines document.
---
You are a senior frontend design systems engineer working on **Axil Accountants** — a premium British accounting firm website.
## Your Role
When invoked, you produce or update the **Frontend Design Guidelines** document for the project. This document is the single source of truth for all visual and interaction decisions on the site.
## Project Context (Always Apply)
**Stack:** Next.js 15 · TypeScript · Tailwind CSS v4 · Framer Motion · GSAP · Three.js / R3F
**Design Philosophy:**
- Premium, airy, light — predominantly white/near-white backgrounds
- Sage green as an **accent**, not the dominant colour
- Generous whitespace — every element has room to breathe
- Glassmorphism cards for interactive surfaces
- Soft shadows only — no harsh drop shadows
- Every animation has a purpose — no decoration for its own sake
- British English throughout all copy
---
## Design Guidelines Structure
When asked to generate or update design guidelines, produce a document covering:
### 1. Colour System
- Full palette with hex values and usage rules
- Which colours are safe on dark backgrounds vs light
- Colour combinations to **avoid** (contrast failures)
- Overlay and tint values for interactive states (hover, focus, pressed)
- Green tints: `#6BAF7D`, `#A8C5A0`, `#F4FAF5`, `#2E7D52`, `#1A2E1F`
### 2. Typography Rules
- Font families and when to use each (Satoshi for display, Inter for body, DM Mono for numbers)
- Type scale: specific sizes for H1H6, body, small, caption
- Line height and letter spacing rules per scale
- Forbidden: Arial, Roboto, system-ui as display fonts
- Max line length: 70 characters for body text
### 3. Spacing & Layout
- 8px base grid — all spacing multiples of 4px or 8px
- Section padding rules (desktop vs mobile)
- Container max-width (1440px) and gutter rules
- Card internal padding standards
### 4. Component Patterns
For each component, specify:
- Default state
- Hover / focus state
- Active / pressed state
- Disabled state
- Dark background variant
- Mobile variant
**Components to document:**
- Button (primary, secondary, ghost)
- Card (glass, solid, feature)
- Navigation (desktop, mobile, dropdown)
- Form fields (input, select, checkbox, textarea)
- Badge / Tag
- Testimonial card
- Blog card
- Service card
- Modal / Overlay
- Accordion / FAQ
### 5. Animation Principles
- **Timing functions:** ease-out for entrances, ease-in for exits, ease-in-out for loops
- **Duration rules:**
- Micro-interactions (button hover): 150200ms
- Element reveals (fade in): 300500ms
- Page transitions: 400600ms
- 3D loop animations: 820s
- **Stagger:** 80120ms between sibling elements
- **ScrollTrigger start:** `top 80%` (element enters when 80% down viewport)
- **`prefers-reduced-motion`:** all animations must be wrapped in a media query check — skip or reduce motion for users who request it
- GSAP for scroll-driven + complex sequences
- Framer Motion for page transitions + React state-driven animations
- CSS transitions for simple hover states
### 6. Iconography
- Style: line icons, 1.5px stroke, rounded caps
- Size: 16px (small), 20px (default), 24px (large), 32px (feature)
- Colour: inherits text colour or explicit sage green
- Never use filled icons mixed with line icons in the same context
- Custom SVG components — no icon font libraries
### 7. Imagery Guidelines
- Photography: real people, authentic UK business settings, natural light
- Never use: stock photo clichés, handshake photos, generic office scenes
- All images: `next/image` with correct `alt` text
- Cover images: 16:9 ratio for blog, 4:3 for cards
- Hero images: full-width, overlaid with dark tint if text is on top
- Alt text: descriptive, contextual, British English
### 8. Accessibility Standards
- All text: WCAG AA (4.5:1 body, 3:1 large text) minimum
- Focus styles: `ring-2 ring-sage ring-offset-2` — never `outline: none` without replacement
- Interactive elements: minimum 44×44px touch target
- Form fields: always have a visible `<label>`
- Modals: focus trap required, Escape key closes
- Keyboard: all functionality available without mouse
### 9. Responsive Breakpoints
| Name | Min width | Tailwind prefix |
| ------- | --------- | --------------- |
| Mobile | 0px | (default) |
| Small | 640px | `sm:` |
| Tablet | 768px | `md:` |
| Desktop | 1024px | `lg:` |
| Wide | 1280px | `xl:` |
| Max | 1440px | `2xl:` |
Mobile-first: always write base styles for mobile, then override at breakpoints.
### 10. Do / Don't Checklist
**Do:**
- Use CSS variables for all colours
- Use `next/image` for all images
- Wrap all animations in `prefers-reduced-motion` check
- Use `font-display` for headlines, `font-sans` for body
- Apply `focus-visible:` for keyboard styles, not `focus:`
**Don't:**
- Hardcode hex values in JSX (use Tailwind tokens)
- Use `!important` in CSS
- Nest more than 3 levels of layout components
- Use `px` for font sizes (use `rem` via Tailwind scale)
- Animate `width`, `height`, or `top/left` (use `transform` instead)
---
## Output Format
When generating or updating guidelines:
1. Output the full guidelines document in Markdown
2. Include code examples for each pattern (Tailwind class strings or JSX)
3. Flag any existing components that violate guidelines
4. Suggest `CLAUDE.md` entries to enforce the most critical rules automatically

View file

@ -0,0 +1,99 @@
---
name: tailwind-design-system
description: Generate, audit, or extend the Tailwind CSS design system for Axil Accountants. Use this skill when working on design tokens, component styles, theme configuration, or Tailwind utility patterns.
---
You are a Tailwind CSS design system expert working on the **Axil Accountants** website.
## Project Design System Context
**Brand colours:**
| Token | Hex | Tailwind class |
|---|---|---|
| Primary (Sage Green) | `#6BAF7D` | `sage` |
| Primary Light (Soft Mint) | `#A8C5A0` | `sage-light` |
| Background (Near-White) | `#F4FAF5` | `mint` |
| Accent / Dark (Deep Forest) | `#2E7D52` | `forest` |
| Text Dark (Charcoal) | `#1A2E1F` | `charcoal` |
| Text Muted (Slate Grey) | `#6B7280` | `muted` |
| Dark BG (Forest Night) | `#1A2E1F` | `forest-dark` |
**Typography scale:**
- Display / H1H2: `font-display` (Satoshi) — `text-5xl``text-7xl`, `font-bold`
- H3H4: `font-display``text-2xl``text-4xl`, `font-semibold`
- Body: `font-sans` (Inter) — `text-base``text-lg`, `font-normal`
- Numbers / Stats: `font-mono` (DM Mono) — `text-4xl``text-6xl`, `font-bold`
**Spacing & layout:**
- Section vertical padding: `py-20 md:py-32`
- Container: `max-w-[1440px] mx-auto px-4 sm:px-6 lg:px-8`
- Card border radius: `rounded-2xl` (16px)
- Hero card radius: `rounded-3xl` (24px)
- Button radius: `rounded-full` (pill)
**Shadows (custom):**
- Card: `shadow-[0_4px_24px_rgba(107,175,125,0.08)]`
- Card hover: `shadow-[0_8px_40px_rgba(107,175,125,0.18)]`
- Button: `shadow-[0_2px_12px_rgba(46,125,82,0.25)]`
**Glass morphism pattern:**
```css
backdrop-blur-md bg-white/70 border border-sage/20 rounded-2xl
```
## What You Can Do
When the user asks to:
### 1. Generate / extend `tailwind.config.ts`
Produce a fully typed Tailwind v4 config with all Axil tokens registered as CSS variables and Tailwind utilities. Include:
- Custom `colors` (sage, forest, mint, charcoal, muted)
- Custom `fontFamily` (display → Satoshi, sans → Inter, mono → DM Mono)
- Custom `borderRadius` (card, hero, pill)
- Custom `boxShadow` (card, card-hover, button, glow)
- Custom `animation` and `keyframes` (float, pulse-glow, draw-line)
### 2. Audit existing component styles
Review a component for:
- Consistency with the Axil design system
- Correct use of design tokens (no hardcoded hex values)
- WCAG AA contrast compliance
- Mobile-first responsive patterns
- Proper use of `transition` and `hover:` states
### 3. Create utility class patterns
Define reusable Tailwind patterns for:
- `.btn-primary`, `.btn-secondary`, `.btn-ghost`
- `.card-glass`, `.card-solid`
- `.section-dark`, `.section-light`
- `.heading-display`, `.heading-section`
- `.tag-badge`
### 4. Generate component styles
When asked to style a specific component, output:
- Full Tailwind class strings (no inline CSS)
- Responsive variants (`sm:`, `md:`, `lg:`)
- State variants (`hover:`, `focus:`, `active:`, `disabled:`)
- Dark-section variants (styles for when component sits on `#1A2E1F` background)
## Output Format
Always output:
1. The Tailwind classes / config code (in a code block)
2. A brief note on design decisions made
3. Any accessibility considerations
Never use arbitrary values when a design token exists. Prefer `text-sage` over `text-[#6BAF7D]`.

6
.claude/settings.json Normal file
View file

@ -0,0 +1,6 @@
{
"enabledPlugins": {
"frontend-design@claude-code-plugins": false,
"feature-dev@claude-code-plugins": false
}
}

View file

@ -0,0 +1,23 @@
{
"permissions": {
"allow": [
"WebFetch(domain:axil1.local)",
"Bash(claude plugins install:*)",
"Bash(pnpm --version:*)",
"Bash(node --version:*)",
"Bash(npx --version:*)",
"Bash(docker:*)",
"Bash(docker compose:*)",
"Bash(git init:*)",
"Bash(git remote add:*)",
"WebFetch(domain:medium.com)",
"WebFetch(domain:htalbot.dev)",
"WebFetch(domain:charlie2code.com)",
"Bash(chmod:*)",
"Bash(for dir in src/components/ui src/components/layout src/components/sections src/components/three src/components/cms src/lib src/hooks src/types src/payload)",
"Bash(do touch \"$dir/.gitkeep\")",
"Bash(done)",
"Bash(git add:*)"
]
}
}

10
.dockerignore Normal file
View file

@ -0,0 +1,10 @@
node_modules
.next
.git
.env.local
.DS_Store
Logo
Concept.md
implementation_plan.md
docs
*.docx

21
.env.example Normal file
View file

@ -0,0 +1,21 @@
# Database (Neon PostgreSQL)
DATABASE_URI=postgresql://user:password@localhost:5432/axil
# Payload CMS
PAYLOAD_SECRET=your-payload-secret-min-32-chars-here
# Email (Resend)
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Site
NEXT_PUBLIC_SITE_URL=http://localhost:3000
# Media Storage (Uploadthing)
UPLOADTHING_SECRET=sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
UPLOADTHING_APP_ID=your-app-id
# AI Chat Bot (optional)
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Error Monitoring
SENTRY_DSN=https://xxxx@sentry.io/xxxx

43
.gitignore vendored Normal file
View file

@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnpm-store
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files
.env.local
.env.*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

1
.husky/pre-commit Executable file
View file

@ -0,0 +1 @@
pnpm exec lint-staged

4
.lintstagedrc Normal file
View file

@ -0,0 +1,4 @@
{
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,css}": ["prettier --write"]
}

4
.prettierignore Normal file
View file

@ -0,0 +1,4 @@
node_modules
.next
.pnpm-store
pnpm-lock.yaml

8
.prettierrc Normal file
View file

@ -0,0 +1,8 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 100,
"plugins": ["prettier-plugin-tailwindcss"]
}

620
Concept.md Normal file
View file

@ -0,0 +1,620 @@
# Axil Accountants — Website Concept
> **Language:** All website content is in British English.
> **Status:** Concept v1.0 — February 2026
> **Type:** Modern marketing website with headless CMS
---
## 1. Project Overview
**Client:** Axil Accountants
**Goal:** A high-converting, premium marketing website that positions Axil Accountants as the go-to accounting firm for sole traders, limited companies, and startups in the UK. The site functions as a professional sales funnel — driving visitors to book a free consultation.
**Core Principle:** No pricing on the site. Every CTA leads to a consultation request. The funnel is designed to build trust first, then convert.
---
## 2. Brand & Visual Identity
### Logo
- Existing logo — provided by client
- Logo used in header (light version on dark backgrounds, dark version on white)
### Colour Palette
| Role | Colour | Hex |
| ------------- | --------------- | ------------------------ |
| Primary | Sage Green | `#6BAF7D` |
| Primary Light | Soft Mint | `#A8C5A0` |
| Background | Near-White | `#F4FAF5` |
| Accent / Dark | Deep Forest | `#2E7D52` |
| Text Dark | Charcoal | `#1A2E1F` |
| Text Muted | Slate Grey | `#6B7280` |
| White | Pure White | `#FFFFFF` |
| Overlay | Dark Green Tint | `rgba(30, 60, 40, 0.85)` |
### Typography
- **Headlines:** `Satoshi` or `Cabinet Grotesk` — geometric, modern, confident
- **Body:** `Inter` — clean, readable, professional
- **Accent / Numbers:** `DM Mono` — for stats, figures, financial data
### Design Language
- Light, airy, predominantly white/near-white backgrounds
- Sage green as accent — not dominant, used for highlights, borders, CTAs
- Generous whitespace — premium feel
- Subtle grain texture overlays on hero sections
- Glassmorphism cards (frosted glass with green tint) for service blocks
- Soft shadows — no harsh drop shadows
- Rounded corners: `16px` standard, `24px` hero cards, `999px` buttons
---
## 3. Technology Stack
### Frontend
| Technology | Purpose |
| -------------------------------- | ---------------------------------------- |
| **Next.js 15** (App Router) | Core framework — SSR, SSG, ISR |
| **TypeScript** | Type safety across the entire codebase |
| **Tailwind CSS v4** | Utility-first styling |
| **Framer Motion** | Page transitions, element animations |
| **GSAP + ScrollTrigger** | Scroll-driven animations, reveal effects |
| **Three.js / React Three Fiber** | 3D hero scene (globe, particles) |
| **Lenis** | Smooth scrolling |
### CMS & Backend
| Technology | Purpose |
| ----------------------- | ------------------------------------------------------ |
| **Payload CMS 3** | Headless CMS — runs natively inside Next.js |
| **PostgreSQL** | Primary database (via Neon or Supabase) |
| **Payload Admin Panel** | Full content management UI |
| **Resend** | Transactional emails (form submissions, notifications) |
### Infrastructure
| Technology | Purpose |
| ----------------------------- | ----------------------------------- |
| **Vercel** | Hosting & deployment (Edge Network) |
| **Cloudinary or Uploadthing** | Image/media management via CMS |
| **Sentry** | Error monitoring |
### Why This Stack
- **Payload CMS** runs inside the same Next.js codebase — no separate server needed, zero friction
- Admin panel is fully customisable and extensible
- Webhooks, custom fields, form builders all built-in
- Performance: Lighthouse score target 95+
---
## 4. Site Architecture
### Pages
```
/ → Home (main funnel page)
/services → Services overview
/services/bookkeeping → Bookkeeping detail page
/services/tax-returns → Self Assessment & Corporation Tax
/services/payroll → Payroll Management
/services/vat-returns → VAT Returns
/about → About the company & team
/blog → Blog index
/blog/[slug] → Individual blog post
/contact → Contact page (consultation form)
/privacy-policy → Legal
/cookie-policy → Legal
```
### Navigation Structure
```
Logo | Services ▾ | About | Blog | Contact [Book a Free Consultation →]
```
- Sticky header with blur backdrop on scroll
- Mobile: hamburger menu with full-screen overlay, animated slide-in
- Services dropdown with icon cards for each service
---
## 5. Home Page — Sales Funnel Design
The homepage is structured as a sequential sales funnel. Each section is designed to move the visitor one step closer to booking a consultation.
---
### Section 1 — Hero (Above the Fold)
**Purpose:** Capture attention, establish premium positioning, deliver core value proposition.
**Layout:**
- Full-viewport height
- Split layout: left — text content; right — 3D animated scene
**3D Scene (Three.js / React Three Fiber):**
- Interactive 3D globe with soft green particle network
- Globe rotates slowly, responds to mouse/cursor movement (parallax)
- Floating financial data nodes (dots connected by lines, like a network graph)
- Subtle green particle field in the background
- On mobile: simplified 2D animated version (performance-first)
**Content:**
```
[EYEBROW TAG] Trusted by 500+ UK Businesses
[HEADLINE H1]
Smart Accounting
for Growing
British Businesses
[SUBHEADLINE]
From sole traders to limited companies — Axil Accountants handles
your numbers so you can focus on what you do best.
[CTA PRIMARY] → Book a Free Consultation
[CTA SECONDARY] → See Our Services
[TRUST STRIP] ★ 4.9 Google Rating | ICAEW Certified | 500+ Clients Served
```
**Animation:**
- Headline words appear with staggered slide-up (GSAP)
- CTAs fade in after headline
- Trust strip slides in from bottom
- 3D globe loads with scale-in and rotation ease
---
### Section 2 — Pain Points / "We Understand"
**Purpose:** Create empathy. Show we understand client problems.
**Layout:** Full-width section, dark green background (`#1A2E1F`), white text
**Content:**
```
[HEADLINE]
Running a business is hard enough.
Tax deadlines shouldn't keep you up at night.
[SUBTEXT]
Whether you're a freelancer juggling invoices or a director managing
payroll and VAT — the financial admin never stops.
[3-column pain point cards — frosted glass on dark green]
📋 Missed deadlines & HMRC penalties
🧮 Confused by tax rules that keep changing
⏰ Hours wasted on bookkeeping instead of growing your business
```
**Animation:**
- Cards appear on scroll with staggered reveal (ScrollTrigger)
- Section uses subtle parallax background movement
---
### Section 3 — Services Overview
**Purpose:** Present services clearly. Each service links to its own detail page.
**Layout:** Light background, 2×2 grid of service cards (desktop), vertical stack (mobile)
**Services:**
1. **Bookkeeping** — Accurate, up-to-date records. Monthly reports. Peace of mind.
2. **Tax Returns** — Self Assessment & Corporation Tax prepared and filed on time, every time.
3. **Payroll** — Compliant payroll for your team. RTI submissions to HMRC. Payslips handled.
4. **VAT Returns** — MTD-compliant VAT preparation, filing, and advice.
**Card Design:**
- Frosted glass with sage green border
- Icon (custom SVG, line-style)
- Service name + short description
- "Learn More →" link
- Hover: subtle lift effect + green glow border
**CTA below grid:**
```
Not sure which service you need?
[→ Let's Talk — Book a Free Consultation]
```
---
### Section 4 — Why Choose Axil Accountants
**Purpose:** Build trust and differentiate from competitors.
**Layout:** Alternating left/right layout with animated stat counters
**Content:**
```
[HEADLINE] Why Businesses Choose Axil
[STAT COUNTERS — animate on scroll]
500+ Businesses Served
98% Client Retention Rate
£2M+ Tax Saved for Our Clients
12+ Years of Experience
[3 USP blocks]
✓ ICAEW & ACCA Qualified
Our accountants hold the UK's most respected professional qualifications.
✓ Fixed Monthly Engagement
No surprise bills. You always know what you're paying for.
✓ Dedicated Account Manager
One point of contact who knows your business inside-out.
✓ Cloud-Based & Paper-Free
We work with Xero, QuickBooks, and FreeAgent — wherever you are.
```
---
### Section 5 — Testimonials / Social Proof
**Purpose:** Validate trust with real client voices.
**Layout:** Carousel / marquee with client cards
**Sources:**
- Google Reviews (embedded widget or scraped/cached in CMS)
- Manual reviews added via Payload CMS admin panel
- ICAEW / ACCA badge display
**Card Design:**
- Client name + business type
- Star rating (5 stars)
- Quote (23 sentences)
- Optional: client photo or avatar
**CTA below:**
```
Join hundreds of satisfied UK businesses.
[→ Book Your Free Consultation Today]
```
---
### Section 6 — Who We Work With
**Purpose:** Help visitors self-identify. Reinforces audience segmentation.
**Layout:** 3 illustrated cards with icons
```
[Sole Traders] [Limited Companies] [Startups]
Self-employed? Running an Ltd? Just launched?
We handle your We manage your We'll set you up
Self Assessment, annual accounts, right from day one —
bookkeeping, and payroll, VAT, and HMRC registration,
more. Corp Tax. bookkeeping, payroll.
[→ Learn More] [→ Learn More] [→ Learn More]
```
---
### Section 7 — How It Works
**Purpose:** Remove friction. Show how easy it is to get started.
**Layout:** Horizontal step-by-step process (3 steps), animated connecting line
```
Step 1 → Step 2 → Step 3
Book a Free We Review You Focus on
Consultation Your Needs Your Business
15-minute call, We propose a We handle everything
no commitment. tailored plan. — you get reports.
```
---
### Section 8 — Blog Preview
**Purpose:** SEO value + content authority. Show expertise.
**Layout:** 3 latest blog post cards in a row
- Managed entirely through Payload CMS
- Cards: cover image, category tag, headline, excerpt, date, read time
- CTA: "Visit Our Blog →"
---
### Section 9 — Final CTA Section
**Purpose:** Last chance to convert before footer. High-urgency design.
**Layout:** Full-width, deep green background, centred content
```
[HEADLINE]
Ready to take the stress out of your finances?
[SUBHEADLINE]
Book a free 15-minute consultation with our team today.
No commitment. No jargon. Just clear, honest advice.
[CTA BUTTON — large, white on green]
→ Book a Free Consultation
[Trust reassurance below]
★ 4.9/5 on Google · ICAEW Certified · No lock-in contracts
```
---
### Footer
**4-column layout:**
1. Logo + tagline + social icons (LinkedIn, Facebook, Instagram)
2. Services links
3. Company links (About, Blog, Contact, Careers)
4. Contact info (address, phone, email) + ICAEW/ACCA badge
**Bottom bar:** Copyright · Privacy Policy · Cookie Policy
---
## 6. Individual Service Pages
Each service has a dedicated landing page, structured as a mini-funnel:
1. **Hero** — Service name, bold headline, CTA ("Get a Quote" → consultation form)
2. **What's Included** — Bullet list of deliverables
3. **Who It's For** — Targeted at sole traders / Ltd / startups as relevant
4. **How It Works** — 3-step process specific to this service
5. **FAQ** — 57 questions, managed in CMS
6. **Testimonials** — Filtered by service tag from CMS
7. **CTA** — Book consultation
---
## 7. About Page
**Sections:**
1. **Hero** — Company story headline + team photo
2. **Our Story** — Founding, mission, values
3. **Team** — Staff profiles (photo, name, role, qualification) — managed in CMS
4. **Our Values** — 4 core values (integrity, clarity, reliability, growth)
5. **Certifications** — ICAEW / ACCA logos + descriptions
6. **CTA** — Meet us for a free consultation
---
## 8. Blog
**Features:**
- Blog index with search + category filter
- Articles managed entirely in Payload CMS
- Rich text editor with image upload, code blocks, pull quotes
- Author, publish date, reading time, category tags
- Open Graph / SEO metadata per post (editable in CMS)
- Related posts section on each article
**Content Strategy:** Articles targeting UK accounting SEO terms (e.g., "How to file a Self Assessment tax return", "What expenses can I claim as a sole trader UK", "MTD for VAT explained")
---
## 9. CMS Admin Panel (Payload CMS)
The Payload CMS admin panel is available at `/admin` and allows the client to manage all website content without touching code.
### Collections (Manageable Content)
| Collection | What you can manage |
| ----------------- | ----------------------------------------------- |
| **Pages** | Edit text, headings, CTAs on any page |
| **Services** | Add/edit service pages, descriptions, FAQs |
| **Blog Posts** | Create, edit, schedule, publish articles |
| **Team Members** | Add/remove staff profiles, photos, bios |
| **Testimonials** | Add client reviews manually |
| **FAQs** | Global FAQ entries, tagged by service |
| **Media Library** | Upload images, PDFs, videos |
| **Forms** | Create contact forms, newsletter sign-ups |
| **Navigation** | Edit menu items, dropdown links |
| **Footer** | Edit footer links, contact details, social URLs |
| **Site Settings** | Global settings — phone, email, address, logo |
### Form Builder
- Drag-and-drop form fields (text, email, phone, dropdown, checkbox, file upload)
- Per-form settings:
- **Email notification** — send submissions to any email address
- **Webhook** — send payload to external URL (CRM, Slack, Zapier, etc.)
- **Redirect** — after submission, redirect to thank-you page
- **Confirmation message** — custom success message shown to user
- All form submissions stored in CMS admin panel
### Integration Settings (Admin-Configurable)
- **Calendly URL** — booking widget embed URL
- **Google Analytics ID**
- **Google Tag Manager ID**
- **Facebook Pixel ID**
- **Tawk.to / chat widget** — paste widget code in admin
- **Webhook endpoints** — add named webhooks, assign to forms
- **SMTP / Email provider** — configure Resend API key
- **Social media URLs** — LinkedIn, Facebook, Instagram
---
## 10. Chat Bot
**Recommended approach:** Configurable in admin panel — client can activate one of:
### Option A — AI Chat (recommended)
- Custom-built chat widget powered by OpenAI GPT-4o or Claude API
- Trained on company services, FAQs, pricing guidance
- Collects visitor name + email before chat
- Escalates to human (email notification) when it cannot answer
- Conversation logs stored in CMS / sent to email
### Option B — Live Chat Widget
- Tawk.to embed — free, supports operators going online/offline
- Chat widget code paste-able in admin settings
### Option C — Lead Capture Bot
- Scripted flow: asks 34 qualifying questions
- Collects name, email, business type, main concern
- Sends lead to email + optional webhook to CRM
**Admin can switch between options or disable chat entirely from settings panel.**
---
## 11. Animations & Visual Effects
### Hero — 3D Scene (Three.js / R3F)
- Slowly rotating 3D sphere with dot-matrix surface
- Particle network floats above globe — financial data visualisation metaphor
- Mouse parallax: globe and particles shift slightly with cursor movement
- Colour palette: sage green particles on near-white background
- Performance: reduced particle count on mobile, falls back gracefully
### Scroll Animations (GSAP + ScrollTrigger)
- Headlines: word-by-word or line-by-line slide-up reveal
- Section entries: fade-in + translate-up on scroll
- Stat counters: number count-up animation when entering viewport
- Service cards: staggered reveal with 100ms delay between cards
- "How It Works" timeline: animated line draws left-to-right as user scrolls
### Page Transitions (Framer Motion)
- Page-level: smooth fade + slight vertical slide between routes
- Overlay: green full-screen wipe on navigation (optional — client preference)
### Micro-Interactions
- Buttons: subtle scale + colour shift on hover
- Nav links: underline slides in from left on hover
- Cards: lift + border glow on hover
- Form fields: smooth focus state with green border transition
- CTA button: gentle pulse animation when idle (draws attention)
### Smooth Scrolling
- Lenis for buttery-smooth scroll physics across all sections
---
## 12. Performance & SEO
### Performance Targets
- Lighthouse Performance: **95+**
- First Contentful Paint: **< 1.2s**
- Largest Contentful Paint: **< 2.5s**
- Cumulative Layout Shift: **< 0.1**
### SEO
- Next.js App Router with built-in metadata API
- Per-page SEO title, description, Open Graph image — all editable in CMS
- Structured data (JSON-LD): LocalBusiness, AccountingService, FAQPage schemas
- Sitemap auto-generated (`/sitemap.xml`)
- Robots.txt configurable
- Blog articles optimised for UK accounting search terms
### Accessibility
- WCAG 2.1 AA compliant
- Keyboard navigation throughout
- Proper ARIA labels on interactive elements
- Sufficient colour contrast for all text
---
## 13. Responsive Design
| Breakpoint | Behaviour |
| ------------------- | ------------------------------------------- |
| Mobile (< 640px) | Single column, 3D simplified, hamburger nav |
| Tablet (6401024px) | 2-column grids, condensed nav |
| Desktop (> 1024px) | Full layout, all animations active |
| Large (> 1440px) | Max-width container `1440px`, centred |
---
## 14. Key Conversion Points (CTA Map)
Every CTA across the site leads to the consultation booking form.
| Location | CTA Text | Action |
| ---------------------- | -------------------------- | ----------------------------------- |
| Hero | "Book a Free Consultation" | Opens booking form / Calendly modal |
| Hero | "See Our Services" | Smooth scroll to services section |
| Services section | "Let's Talk" | Opens booking form |
| Each service page hero | "Get Started Today" | Opens booking form |
| Testimonials section | "Join Our Clients" | Opens booking form |
| Final CTA section | "Book a Free Consultation" | Opens booking form |
| Header (sticky) | "Book a Consultation" | Opens booking form |
| Chat bot | Collect name + email | Sends lead to CRM / email |
---
## 15. Project Deliverables
- [ ] Full Next.js 15 codebase (TypeScript)
- [ ] Payload CMS configured with all collections
- [ ] Admin panel at `/admin`
- [ ] All pages: Home, Services (5 pages), About, Blog, Contact
- [ ] 3D animated hero scene (Three.js / R3F)
- [ ] GSAP scroll animations
- [ ] Framer Motion page transitions
- [ ] Consultation booking form (with email notifications + webhook support)
- [ ] Responsive design (mobile-first)
- [ ] SEO metadata system
- [ ] Google Analytics / GTM integration
- [ ] Chat bot integration (configurable in admin)
- [ ] Deployment to Vercel
- [ ] CMS training documentation for client
---
## 16. Out of Scope (v1)
- Client portal / login area
- Online payment processing
- Accounting software integration (Xero API, etc.)
- Multi-language support
- A/B testing framework
_These can be considered for v2 based on business needs._
---
_Document maintained by development team. Last updated: February 2026._

46
Dockerfile Normal file
View file

@ -0,0 +1,46 @@
FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable && corepack prepare pnpm@latest --activate
WORKDIR /app
# --- Dependencies ---
FROM base AS deps
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile
# --- Development ---
FROM base AS dev
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NODE_ENV=development
ENV WATCHPACK_POLLING=true
EXPOSE 3000
CMD ["pnpm", "dev"]
# --- Build ---
FROM base AS build
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN pnpm build
# --- Production ---
FROM node:20-slim AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY --from=build /app/public ./public
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
Logo/Axil Accounting.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

36
README.md Normal file
View file

@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

41
docker-compose.yml Normal file
View file

@ -0,0 +1,41 @@
services:
app:
build:
context: .
target: dev
ports:
- '3000:3000'
volumes:
- ./src:/app/src
- ./public:/app/public
- ./next.config.ts:/app/next.config.ts
- ./tailwind.config.ts:/app/tailwind.config.ts
- ./tsconfig.json:/app/tsconfig.json
- ./postcss.config.mjs:/app/postcss.config.mjs
environment:
- NODE_ENV=development
- WATCHPACK_POLLING=true
env_file:
- .env.local
depends_on:
db:
condition: service_healthy
db:
image: postgres:17-alpine
ports:
- '5432:5432'
environment:
POSTGRES_USER: axil
POSTGRES_PASSWORD: axil_dev
POSTGRES_DB: axil
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U axil']
interval: 5s
timeout: 5s
retries: 5
volumes:
pgdata:

View file

@ -0,0 +1,199 @@
# Next.js + Docker Setup Guide
## Principle
Run Next.js 16 in Docker using multi-stage builds with pnpm standalone output for minimal production images, and volume-mounted source code with filesystem polling for fast development hot reload.
## Architecture
### Multi-Stage Build Flow
```
+------------------+ +------------------+ +------------------+
| Stage: deps | | Stage: build | | Stage: runner |
| | | | | |
| node:20-slim | | node:20-slim | | node:20-slim |
| | | | | |
| - corepack | --> | - Copy deps from | --> | - Copy standalone|
| enable pnpm | | deps stage | | from build |
| - pnpm install | | - Copy src | | - Copy static |
| --frozen- | | - next build | | assets |
| lockfile | | (standalone) | | - Run server.js |
+------------------+ +------------------+ +------------------+
~600 MB ~900 MB ~200 MB
(cached between (discarded after (final image)
builds) build completes)
```
### Docker Compose Topology (Development)
```
+---------------------------------------------------+
| docker-compose.yml |
| |
| +-------------+ +-------------------+ |
| | app | | db | |
| | :3000 | -------> | :5432 | |
| | | depends | | |
| | Next.js dev | on | PostgreSQL 17 | |
| | (webpack) | healthy | pgdata volume | |
| +------+------+ +-------------------+ |
| | |
| bind mount |
| ./src -> /app/src |
| ./public -> /app/public |
+---------------------------------------------------+
```
## Patterns
| Do | Don't | When |
| -------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------ |
| Use `output: "standalone"` in next.config.ts | Ship full `node_modules` in production image | Always in production |
| Use `corepack enable pnpm` in Dockerfile | Install pnpm globally with `npm i -g pnpm` | pnpm projects (respects version pinning in package.json) |
| Use `pnpm install --frozen-lockfile` | Use `pnpm install` without lockfile flag | CI and Docker builds (ensures reproducibility) |
| Use `WATCHPACK_POLLING=true` for dev hot reload | Rely on native filesystem events in Docker | Development on macOS/Windows hosts |
| Use `--turbopack` flag with `next dev` only when not in Docker | Use Turbopack in Docker dev containers | Docker dev (Turbopack ignores polled fs events) |
| Mount only `./src` and `./public` as bind mounts | Mount the entire project root as a bind mount | Docker dev (avoids overwriting container node_modules) |
| Use named volumes for `node_modules` and `.next` | Let bind mounts shadow container-built directories | Docker dev (prevents host/container version mismatches) |
| Run as non-root user (`nextjs:nodejs`) in runner stage | Run as root in production containers | Always in production (limits blast radius) |
| Copy only `standalone`, `static`, and `public` to runner | Copy the entire `.next` folder to runner | Production builds (minimizes image size) |
| Set `HOSTNAME=0.0.0.0` in runner stage | Omit hostname binding | Docker networking (allows external access to container) |
| Use `depends_on` with `condition: service_healthy` | Start app before database is ready | When app needs database at startup (e.g., Prisma migrations) |
| Use `.dockerignore` to exclude `node_modules`, `.next`, `.git` | Let Docker context include everything | Always (speeds up builds, prevents leaking secrets) |
## Configuration
### next.config.ts
| Option | Value | Why |
| -------- | -------------- | ---------------------------------------------------------------------------------------------------------- |
| `output` | `"standalone"` | Produces self-contained build with only required `node_modules` files; reduces image from ~1 GB to ~200 MB |
### Environment Variables
| Variable | Value | Stage | Why |
| ------------------------- | ------------------ | ------------- | ---------------------------------------------------------- |
| `PNPM_HOME` | `/pnpm` | deps, build | Ensures pnpm store is in a known location for caching |
| `PATH` | `$PNPM_HOME:$PATH` | deps, build | Makes pnpm binary available on PATH |
| `NEXT_TELEMETRY_DISABLED` | `1` | build, runner | Disables Vercel telemetry in CI/production |
| `NODE_ENV` | `production` | build, runner | Enables production optimizations in Next.js and React |
| `HOSTNAME` | `0.0.0.0` | runner | Binds server to all interfaces so Docker can route traffic |
| `PORT` | `3000` | runner | Explicit port for `server.js` (matches EXPOSE) |
| `WATCHPACK_POLLING` | `true` | dev only | Forces webpack to poll for file changes in Docker volumes |
### .dockerignore
| Entry | Why |
| --------------------- | ----------------------------------------------------------- |
| `node_modules` | Prevent host dependencies from overriding container install |
| `.next` | Prevent stale build artifacts from entering build context |
| `.git` | Reduce context size; not needed for builds |
| `*.md` | Documentation not needed in image |
| `.env*.local` | Prevent secrets from leaking into image layers |
| `docker-compose*.yml` | Not needed inside the image |
## Dockerfile Stages
### Production (Multi-Stage)
| Stage | Base Image | Purpose | Key Actions |
| -------- | -------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `deps` | `node:20-slim` | Install dependencies | `corepack enable pnpm`, copy `package.json` + `pnpm-lock.yaml`, run `pnpm install --frozen-lockfile` |
| `build` | `node:20-slim` | Compile application | Copy `node_modules` from deps, copy source code, run `pnpm build` (triggers `next build` with standalone output) |
| `runner` | `node:20-slim` | Run production server | Create `nextjs` user/group, copy `.next/standalone`, copy `.next/static` to `.next/standalone/.next/static`, copy `public` to `.next/standalone/public`, run `node server.js` |
### Stage Details
| Concern | Implementation | Notes |
| ------------- | ------------------------------------------------------------ | ------------------------------------------------------ |
| Layer caching | Copy lockfile before source code | Dependency layer is rebuilt only when lockfile changes |
| Security | `RUN addgroup --system nodejs && adduser --system nextjs` | Non-root user in runner stage |
| Permissions | `RUN chown -R nextjs:nodejs /app/.next` | Ensures Next.js can write cache at runtime |
| Final size | Only `standalone` + `static` + `public` in runner | No `node_modules` directory, no build tools |
| Health check | `HEALTHCHECK CMD curl -f http://localhost:3000/ \|\| exit 1` | Optional; useful for orchestrators |
### Base Image Comparison
| Image | Size | Pros | Cons | Recommendation |
| ------------------------------------- | ------ | ----------------------------------------- | -------------------------------------------------------- | --------------------------- |
| `node:20-alpine` | ~50 MB | Smallest, popular | Uses musl libc; can break native modules (bcrypt, sharp) | Use if no native deps |
| `node:20-slim` | ~80 MB | Debian-based (glibc), broad compatibility | Slightly larger than Alpine | Default choice for Next.js |
| `node:20-bookworm-slim` | ~80 MB | Same as slim, pinned Debian release | None significant | Equivalent to slim |
| `gcr.io/distroless/nodejs20-debian12` | ~40 MB | Minimal attack surface, no shell | No shell for debugging, no package manager | Advanced: runner stage only |
## Docker Compose Services
### Development
| Service | Image / Build | Ports | Volumes | Environment | Purpose |
| ------- | ------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | -------------------------- |
| `app` | `build: .` (dev Dockerfile or target) | `3000:3000` | `./src:/app/src`, `./public:/app/public`, `node_modules:/app/node_modules`, `next-cache:/app/.next` | `NODE_ENV=development`, `WATCHPACK_POLLING=true`, `DATABASE_URL=postgres://...` | Dev server with hot reload |
| `db` | `postgres:17-alpine` | `5432:5432` | `pgdata:/var/lib/postgresql/data` | `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` | Development database |
### Production
| Service | Image / Build | Ports | Volumes | Environment | Purpose |
| ------- | --------------------------------------- | -------------------------- | --------------------------------- | ---------------------------------------------------- | ------------------- |
| `app` | `build: .` (multi-stage, runner target) | `3000:3000` | None (stateless) | `NODE_ENV=production`, `DATABASE_URL=postgres://...` | Production server |
| `db` | `postgres:17-alpine` | `5432:5432` (or unexposed) | `pgdata:/var/lib/postgresql/data` | `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` | Production database |
### PostgreSQL Health Check
| Parameter | Value | Why |
| ---------- | ----------------------------------------- | --------------------------------------------------- |
| `test` | `["CMD-SHELL", "pg_isready -U postgres"]` | Lightweight check that Postgres accepts connections |
| `interval` | `5s` | Check every 5 seconds |
| `timeout` | `3s` | Fail check if no response in 3 seconds |
| `retries` | `10` | Mark unhealthy after 10 consecutive failures |
### Named Volumes
| Volume | Mount Point | Why |
| -------------- | -------------------------- | --------------------------------------------------------------- |
| `pgdata` | `/var/lib/postgresql/data` | Persist database between container restarts |
| `node_modules` | `/app/node_modules` | Prevent host bind mount from shadowing container-installed deps |
| `next-cache` | `/app/.next` | Preserve build cache between dev restarts |
## Hot Reload Checklist (Development)
| Step | Detail |
| --------------------------------------- | ---------------------------------------------------------------- |
| 1. Set `WATCHPACK_POLLING=true` | Forces webpack to poll for changes instead of relying on inotify |
| 2. Bind mount only source directories | `./src:/app/src` and `./public:/app/public` (not entire project) |
| 3. Use named volume for `node_modules` | Prevents host `node_modules` from overwriting container deps |
| 4. Use named volume for `.next` | Prevents stale build cache conflicts |
| 5. Use `next dev` without `--turbopack` | Turbopack does not detect polled filesystem events in Docker |
| 6. Expose WebSocket port if needed | HMR uses WebSocket; ensure port 3000 is forwarded |
## Common Issues
| Problem | Cause | Fix |
| ---------------------------------------------- | ---------------------------------------------------- | ---------------------------------------------------------------------- |
| Hot reload not working in Docker | Missing `WATCHPACK_POLLING=true` or using Turbopack | Set env var; use webpack for dev in Docker |
| `pnpm: not found` in Dockerfile | Corepack not enabled | Add `RUN corepack enable pnpm` before pnpm commands |
| Image is 1+ GB | Not using standalone output | Set `output: "standalone"` in next.config.ts |
| App crashes with EACCES | Running as non-root without proper ownership | `chown nextjs:nodejs /app/.next` before switching user |
| Container can't reach database | Using `localhost` instead of service name | Use `db` (service name) as PostgreSQL host in `DATABASE_URL` |
| `sharp` module fails on Alpine | musl libc incompatibility | Use `node:20-slim` (Debian) or install `sharp` platform-specific build |
| Corepack signature verification error | Outdated corepack in base image | Add `RUN corepack prepare pnpm@<version> --activate` |
| Static assets (CSS/images) missing after build | Forgot to copy `public` and `.next/static` to runner | Copy both directories alongside `standalone` in final stage |
## Sources
- [Next.js Official Deployment Docs](https://nextjs.org/docs/app/getting-started/deploying) - 2025
- [Next.js output: standalone Configuration](https://nextjs.org/docs/app/api-reference/config/next-config-js/output) - 2025
- [Next.js 16 Release Blog Post](https://nextjs.org/blog/next-16) - October 2025
- [Next.js 16.1 Release Blog Post](https://nextjs.org/blog/next-16-1) - December 2025
- [Optimizing Next.js Docker Builds with PNPM, Corepack, and Standalone Mode](https://htalbot.dev/posts/build-nextjs-standalone-docker) - 2025
- [Dockerizing Next.js 15 with pnpm for Production](https://medium.com/@she11fish/dockerizing-next-js-15-application-with-pnpm-for-production-39c841ce8323) - 2025
- [Best Next.js Docker Compose Hot-Reload Setup](https://medium.com/@elifront/best-next-js-docker-compose-hot-reload-production-ready-docker-setup-28a9125ba1dc) - 2025
- [How to Configure Next.js with Docker](https://oneuptime.com/blog/post/2026-01-24-nextjs-docker-configuration/view) - January 2026
- [pnpm Docker Documentation](https://pnpm.io/next/docker) - 2025
- [How to use Prisma in Docker](https://www.prisma.io/docs/guides/docker) - 2025
- [Security Advice for Self-Hosting Next.js in Docker](https://blog.arcjet.com/security-advice-for-self-hosting-next-js-in-docker/) - 2025
- [Node.js Docker Optimization 2025: Multi-Stage Builds](https://markaicode.com/nodejs-docker-optimization-2025/) - 2025
- [Container Images Guide: Alpine, Slim, Distroless](https://www.ykira.com/blog/container-images-guide) - 2025
- [Choosing the Best Node.js Docker Image (Snyk)](https://snyk.io/blog/choosing-the-best-node-js-docker-image/) - 2025
- [Turbopack Polling Feature Issue #80665](https://github.com/vercel/next.js/issues/80665) - 2025
- [Docker Compose Watch + Turbopack Issue #12827](https://github.com/docker/compose/issues/12827) - 2025

18
eslint.config.mjs Normal file
View file

@ -0,0 +1,18 @@
import { defineConfig, globalIgnores } from 'eslint/config';
import nextVitals from 'eslint-config-next/core-web-vitals';
import nextTs from 'eslint-config-next/typescript';
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
// Override default ignores of eslint-config-next.
globalIgnores([
// Default ignores of eslint-config-next:
'.next/**',
'out/**',
'build/**',
'next-env.d.ts',
]),
]);
export default eslintConfig;

898
implementation_plan.md Normal file
View file

@ -0,0 +1,898 @@
# 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
- [ ] Scaffold Next.js 15 project with App Router and TypeScript (`create-next-app`)
- [ ] Configure TypeScript (`tsconfig.json`): strict mode, path aliases (`@/*`, `@/components/*`, `@/lib/*`, `@/types/*`)
- [ ] Install and configure **Tailwind CSS v4**
- [ ] Install and configure **ESLint** (Next.js preset + custom rules)
- [ ] Install and configure **Prettier** with Tailwind class sorting plugin
- [ ] Set up **Husky** + **lint-staged** (pre-commit: lint + format)
- [ ] Define `.env.local` structure and `.env.example` template:
- `DATABASE_URI` (Neon PostgreSQL)
- `PAYLOAD_SECRET`
- `RESEND_API_KEY`
- `NEXT_PUBLIC_SITE_URL`
- `UPLOADTHING_SECRET` / `UPLOADTHING_APP_ID`
- `OPENAI_API_KEY` (for AI chat bot, optional)
- `SENTRY_DSN`
- [ ] Create `src/` directory structure:
```
src/
├── app/ # Next.js App Router pages
├── components/
│ ├── ui/ # Primitive components
│ ├── layout/ # Header, Footer, Nav
│ ├── sections/ # Page sections (Hero, Services, etc.)
│ ├── three/ # Three.js / R3F components
│ └── cms/ # CMS-driven components
├── lib/ # Utilities, helpers
├── hooks/ # Custom React hooks
├── types/ # Shared TypeScript types
└── payload/ # Payload CMS config & collections
```
- [ ] Initialise Git repository, create `main` and `develop` branches
- [ ] Create **Vercel** project, connect to Git repository
- [ ] Configure Vercel environment variables (production + preview)
---
## Feature 2 — Database & Cloud Infrastructure
- [ ] Create **Neon PostgreSQL** project (serverless, auto-scaling)
- [ ] Copy connection string to `DATABASE_URI` environment variable
- [ ] Verify database connectivity from local environment
- [ ] Set up **Uploadthing** account for media storage
- Create app, get `UPLOADTHING_SECRET` and `UPLOADTHING_APP_ID`
- Configure allowed file types: images (jpg, png, webp, svg), documents (pdf)
- [ ] Set up **Resend** account for transactional emails
- Create API key, add to `RESEND_API_KEY`
- Verify sending domain
---
## Feature 3 — Payload CMS — Core Installation
- [ ] Install Payload CMS 3 into the Next.js project (`npx create-payload-app` or manual)
- [ ] Configure `payload.config.ts`:
- `serverURL` from `NEXT_PUBLIC_SITE_URL`
- `secret` from `PAYLOAD_SECRET`
- `db`: PostgreSQL adapter pointing to `DATABASE_URI`
- `editor`: Lexical rich text editor
- `admin` panel configuration
- [ ] Mount Payload API handler at `src/app/(payload)/api/[...slug]/route.ts`
- [ ] Mount admin panel at `src/app/(payload)/admin/[[...segments]]/page.tsx`
- [ ] Configure **Uploadthing storage adapter** for Payload media
- [ ] Configure **Resend email adapter** for Payload email notifications
- [ ] Create initial admin superuser (seed script or first-run prompt)
- [ ] Verify admin panel loads at `/admin`
- [ ] Install **Payload Form Builder plugin** (`@payloadcms/plugin-form-builder`)
---
## Feature 4 — CMS Collections Schema
Define all Payload collections and globals. Each collection = one content type the client manages.
### 4.1 — Media Collection
- [ ] `Media` collection with Uploadthing adapter
- Fields: `alt` (text, required), `caption` (text, optional)
- Image sizes: `thumbnail` (400×300), `card` (800×600), `hero` (1920×1080)
### 4.2 — Users Collection
- [ ] `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
- [ ] `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
- [ ] `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
- [ ] `Categories` collection
- `name` (text, required)
- `slug` (slug)
- `colour` (text — hex, for tag colour)
### 4.6 — Team Members Collection
- [ ] `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
- [ ] `Testimonials` collection
- `clientName` (text, required)
- `businessName` (text)
- `businessType` (select: sole-trader | limited-company | startup | other)
- `rating` (select: 15)
- `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
- [ ] `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)
- [ ] Enable `@payloadcms/plugin-form-builder` — provides:
- `Forms` collection (drag-and-drop field builder in admin)
- `FormSubmissions` collection (stores all submissions)
- [ ] 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
- [ ] `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
- [ ] `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
- [ ] `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
- [ ] Configure Tailwind CSS with custom design tokens:
```js
// tailwind.config.ts
colors: {
sage: { DEFAULT: '#6BAF7D', light: '#A8C5A0' },
forest: { DEFAULT: '#2E7D52', dark: '#1A2E1F' },
mint: '#F4FAF5',
charcoal: '#1A2E1F',
muted: '#6B7280',
}
borderRadius: { card: '16px', hero: '24px', pill: '999px' }
fontFamily: {
sans: ['Inter', 'sans-serif'],
display: ['Satoshi', 'sans-serif'],
mono: ['DM Mono', 'monospace'],
}
```
- [ ] Set up fonts:
- `Satoshi` (variable font) — self-hosted via `@font-face` or Fontshare CDN
- `Inter` — Google Fonts / `next/font`
- `DM Mono` — Google Fonts / `next/font`
- [ ] Create CSS variables in `globals.css` for all design tokens (enables runtime theming)
- [ ] **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
- [ ] **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
- [ ] **Heading** component — `h1``h4` with correct size + weight from design system
- [ ] **Tag/Badge** component — pill with colour variant (green, grey)
- [ ] **StarRating** component — 15 filled star SVGs
- [ ] **GlassCard** component — frosted glass base with sage green border, hover glow
- [ ] **Section** layout wrapper — `max-w-[1440px]`, horizontal padding, `py` spacing
- [ ] **Divider** component — subtle sage green horizontal rule
- [ ] **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`**:
- 150300 floating particle nodes (reduced on mobile: 6080)
- 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` (15)
- 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**: 23 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 & CI/CD
- [ ] Configure Vercel project settings:
- Build command: `pnpm build`
- Output directory: `.next`
- Node.js version: 20.x
- [ ] Add all production environment variables to Vercel dashboard
- [ ] Configure **preview deployments**: auto-deploy on every PR to `develop`
- [ ] Configure **production deployment**: auto-deploy on merge to `main`
- [ ] Set up custom domain (e.g. `axilaccountants.co.uk`) in Vercel
- [ ] Verify SSL/HTTPS certificate
- [ ] Configure `www` → apex redirect (or vice versa)
- [ ] Run production build locally (`pnpm build && pnpm start`) — verify no build errors
- [ ] Run Lighthouse on production URL — confirm scores meet targets
- [ ] Set up Vercel Speed Insights (optional)
---
## 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 Vercel access (viewer role)
- [ ] 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 1118 (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_

7
next.config.ts Normal file
View file

@ -0,0 +1,7 @@
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
output: 'standalone',
};
export default nextConfig;

32
package.json Normal file
View file

@ -0,0 +1,32 @@
{
"name": "axil-accountants",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint",
"format": "prettier --write .",
"prepare": "husky"
},
"dependencies": {
"next": "16.1.6",
"react": "19.2.3",
"react-dom": "19.2.3"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"husky": "^9.1.7",
"lint-staged": "^16.2.7",
"prettier": "^3.8.1",
"prettier-plugin-tailwindcss": "^0.7.2",
"tailwindcss": "^4",
"typescript": "^5"
}
}

4375
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load diff

3
pnpm-workspace.yaml Normal file
View file

@ -0,0 +1,3 @@
ignoredBuiltDependencies:
- sharp
- unrs-resolver

7
postcss.config.mjs Normal file
View file

@ -0,0 +1,7 @@
const config = {
plugins: {
'@tailwindcss/postcss': {},
},
};
export default config;

1
public/file.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 391 B

1
public/globe.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1 KiB

1
public/next.svg Normal file
View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

1
public/vercel.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 128 B

1
public/window.svg Normal file
View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>

After

Width:  |  Height:  |  Size: 385 B

BIN
src/app/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

26
src/app/globals.css Normal file
View file

@ -0,0 +1,26 @@
@import 'tailwindcss';
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}

30
src/app/layout.tsx Normal file
View file

@ -0,0 +1,30 @@
import type { Metadata } from 'next';
import { Geist, Geist_Mono } from 'next/font/google';
import './globals.css';
const geistSans = Geist({
variable: '--font-geist-sans',
subsets: ['latin'],
});
const geistMono = Geist_Mono({
variable: '--font-geist-mono',
subsets: ['latin'],
});
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>{children}</body>
</html>
);
}

65
src/app/page.tsx Normal file
View file

@ -0,0 +1,65 @@
import Image from 'next/image';
export default function Home() {
return (
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between bg-white px-16 py-32 sm:items-start dark:bg-black">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl leading-10 font-semibold tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{' '}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{' '}
or the{' '}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{' '}
center.
</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="bg-foreground text-background flex h-12 w-full items-center justify-center gap-2 rounded-full px-5 transition-colors hover:bg-[#383838] md:w-[158px] dark:hover:bg-[#ccc]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] md:w-[158px] dark:border-white/[.145] dark:hover:bg-[#1a1a1a]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Documentation
</a>
</div>
</main>
</div>
);
}

View file

View file

View file

View file

View file

0
src/hooks/.gitkeep Normal file
View file

0
src/lib/.gitkeep Normal file
View file

0
src/payload/.gitkeep Normal file
View file

0
src/types/.gitkeep Normal file
View file

34
tsconfig.json Normal file
View file

@ -0,0 +1,34 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "react-jsx",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
".next/dev/types/**/*.ts",
"**/*.mts"
],
"exclude": ["node_modules"]
}