A-Grade Docs
Developer

Website Architecture

Technical analysis of the current A-Grade Services app structure and risks.

Website Architecture

apps/web is a Next.js App Router application styled with Tailwind v4 and animated with Framer Motion. The repo is now a Bun workspace with the website in apps/web, docs in apps/docs, and framework-neutral shared code in packages/shared.

Route Map

RouteFileRender modelMain notes
/apps/web/app/page.tsxServer component with client carouselSticky video hero, carousel, service/process/metric sections
/aboutapps/web/app/about/page.tsxAsync server componentCalls getPexelsImages, renders stats/story/values
/servicesapps/web/app/services/page.tsxAsync server componentCalls getPexelsImages, renders six service cards
/teamapps/web/app/team/page.tsxAsync server componentCalls getPexelsImages, renders placeholder team cards
/contactapps/web/app/contact/page.tsxAsync server componentCalls getPexelsImages, renders contact details and presentational form

Shared Layout

apps/web/app/layout.tsx renders:

  • NavBar
  • route content
  • Footer

The layout also loads Google Roboto through next/font/google and sets global metadata.

components/layout/NavBar.tsx is a client component. It owns:

  • The fixed top nav.
  • Overlay menu open/close state.
  • Body scroll locking while the overlay is open.
  • Reduced-motion-aware overlay/nav animation timing.

components/layout/MiddleNav.tsx is also a client component. It uses Framer Motion useScroll, useSpring, and useTransform to collapse the middle route links over the first 180px of scroll. Hydrated localhost screenshots confirm this behavior works on desktop.

Current technical risk: NavBar hard-codes the shell to w-[850px] max-w-[850px], so mobile viewports overflow. The overlay menu uses a horizontal justify-between content row, which also clips the contact/social column on mobile.

Homepage Mechanics

The homepage uses a sticky hero section followed by a content wrapper with matching negative margin and top padding:

  • Hero: sticky top-0, full viewport height.
  • Content wrapper: -mt-[100vh] pt-[100vh].
  • First content section: full-height project carousel.

This creates the effect of the white content scrolling over the fixed video hero. Preserve this mechanic unless the design direction intentionally changes.

The hero has a technical layering issue: the black before: overlay is z-0, while the video is z-10. The overlay is therefore behind the video, not between the video and text. Current footage is dark enough in many frames, but the code does not guarantee text contrast.

components/home/ProjectsShowcase.tsx uses Embla with autoplay:

  • loop: true
  • align: "center"
  • delay: 1500ms
  • stopOnMouseEnter: true

The carousel has a polished hover label driven by motion values. It does not yet expose visible controls, pagination, slide captions, case-study links, or a reduced-motion alternative for autoplay.

Media And Dynamic Images

Homepage project and service images are local files under apps/web/public/projects.

About, Services, Team, and Contact use getPexelsImages from apps/web/lib/pexels.ts. If PEXELS_API_KEY is missing, the helper returns a fixed fallback array of remote Pexels URLs and logs a warning.

Risks:

  • The fallback images are generic and sometimes off-topic.
  • Services asks for six images, but the fallback array has five; the sixth service repeats the first image through images[index] || images[0].
  • Team requests portraits but can receive architecture/nature imagery.
  • Query params are interpolated into a URL string instead of built with URLSearchParams.

For launch, critical pages should prefer curated local assets or route-specific fallback sets.

Contact Form

The Contact page currently renders a form with inputs and a submit button, but it does not submit anywhere.

Missing pieces:

  • action or server action/API route.
  • Input name attributes.
  • Visible labels.
  • Validation.
  • Pending/success/error states.
  • Spam protection.

This is the highest-risk functional gap because it affects lead capture.

Accessibility Notes

Positive:

  • The menu button has aria-expanded, aria-controls, and aria-label.
  • The overlay uses role="dialog" and aria-modal="true".
  • The close button has an aria-label.

Needs work:

  • Overlay focus is not trapped.
  • Escape-to-close behavior is not implemented.
  • Form controls rely on placeholders instead of labels.
  • Social/link-like footer content includes non-functional destinations.
  • Mobile nav overflow blocks access to controls.

Performance Notes

The local hero video is 8.5M, which is reasonable for an early prototype but should still be checked on mobile networks. The strongest performance risk is less about file size and more about remote image dependencies on secondary pages.

Recommended next steps:

  • Use local optimized launch imagery for the first public version.
  • Add poster imagery for the hero video.
  • Confirm next/image remote behavior in the deployment target.
  • Respect reduced motion for carousel autoplay.

Test Targets

Before launch, add coverage or manual checks for:

  • Desktop and mobile nav visibility.
  • Overlay open/close, focus movement, and Escape close.
  • Contact form validation and submit states.
  • Pexels fallback behavior with no API key.
  • Homepage scroll states at hero, carousel, services, CTA, and footer.
  • Build/typecheck for web, docs, and shared packages.