This is the main frontend application for GrantFlow.AI, built with Next.js 15, TypeScript, and shadcn/ui components.
For prerequisites, environment setup, and general development workflow, see the Contributing Guide.
This README covers frontend-specific architecture and development details.
GrantFlow uses a monorepo with two frontend applications:
frontend/- Main Next.js application (this directory)editor/- Standalone rich text editor built with Vite + React + TipTap
Both applications share dependencies through the pnpm workspace and follow aligned development patterns.
The frontend follows a modern Next.js App Router architecture:
/src
/actions # Server actions for API communication
/app # Next.js app router pages and layouts
/components # React components
/ui # shadcn/ui components
/landing-page # Components for landing page
/sign-in # Authentication components
/projects # Project related components
/lib # Shared utilities and schemas
/styles # Global styles
/types # TypeScript type definitions
/utils # Helper functions
- Next.js 15: React framework with App Router and server components
- React 19: UI library
- TypeScript: Type-safe JavaScript
- shadcn/ui: Component library based on Radix UI primitives
- Tailwind CSS: Utility-first CSS framework
- Storybook: UI component development and documentation
- Vitest: Testing framework
- Firebase: Authentication
- React Hook Form: Form validation and handling
- Zod: Schema validation
- ky: Fetch API wrapper
- Node.js 22 or higher
- pnpm (package manager)
- Google Cloud SDK (gcloud CLI)
- Firebase CLI
For local development, the frontend uses environment variables from the root .env file. No frontend-specific configuration is needed as Next.js automatically loads the root .env file.
For production deployments, environment variables are managed using Google Secret Manager and Firebase App Hosting:
# Adding a new environment variable to Secret Manager
gcloud secrets create SECRET_NAME --data-file=- <<< "secret-value"
# Granting Firebase App Hosting access to the secret
firebase apphosting:secrets:grantaccess SECRET_NAME --backend monorepo# Development
pnpm dev # Start Next.js development server
pnpm build # Build for production
pnpm start # Start production server
# Testing
pnpm test # Run unit tests
pnpm test:watch # Run tests in watch mode
pnpm test:coverage # Run tests with coverage
pnpm test:e2e # Run E2E tests with Playwright
pnpm test:e2e:ui # Run E2E tests with Playwright UI
# Linting & Formatting
pnpm lint # Run Biome + ESLint with auto-fix
pnpm format # Format code with Biome
pnpm typecheck # Type check with TypeScript
pnpm check # Run Biome check + ESLint
# Storybook
pnpm storybook # Start Storybook dev server
pnpm build-storybook # Build Storybook for production
# UI Components
pnpm ui add <name> # Add shadcn/ui componentFrom the repository root, you can use Taskfile commands that work across both frontend applications:
# Development
task frontend:dev # Start main frontend dev server
task editor:dev # Start editor dev server
# Installation & Updates
task frontend:install # Install dependencies for both apps
task frontend:update # Update dependencies for both apps
# Building
task frontend:build # Build both applications
task frontend:main:build # Build main frontend only
task editor:build # Build editor only
# Testing
task frontend:test # Run tests for both apps
task frontend:main:test # Run main frontend tests only
task editor:test # Run editor tests only
# Linting (runs on both frontend apps concurrently)
task lint:frontend # Run all frontend linters
task lint:typescript # TypeScript check for both apps
task lint:biome # Biome linting for both apps
task lint:eslint # ESLint for both apps/components/ui: shadcn/ui components/components: Application-specific components/app: Page components using the Next.js App Router
The project uses shadcn/ui components with the "New York" style preset. To add a new component:
pnpm ui add <component-name>Example:
pnpm ui add button
pnpm ui add dialog
pnpm ui add dropdown-menuThis will add the component to the /components/ui directory with the project's styling configuration.
- React Context: Used for state that spans multiple components
- React Hook Form: Used for form state management
Prefer using server components where possible to reduce client-side JavaScript.
The project uses Vitest for testing with React Testing Library. Test files are co-located with the code they test with a .spec.tsx extension.
- Testing Framework: Vitest
- Test Environment: jsdom
- Testing Libraries: React Testing Library, Jest DOM matchers
- Test Files: Located alongside the components they test
Run all tests:
pnpm testRun tests with coverage:
pnpm test:coverageRun tests in watch mode:
pnpm test:watchThe frontend communicates with the backend API using server actions. API types are defined in /src/types/api-types.ts.
Storybook is used for developing and documenting UI components in isolation.
Start the Storybook development server:
pnpm storybookBuild Storybook for static deployment:
pnpm build-storybookStory files are co-located with their respective components using the .stories.tsx extension:
/components
/my-component
my-component.tsx
my-component.spec.tsx
my-component.stories.tsx
Basic story structure:
import type { Meta, StoryObj } from "@storybook/react";
import { MyComponent } from "./my-component";
const meta: Meta<typeof MyComponent> = {
title: "Components/MyComponent",
component: MyComponent,
parameters: {
layout: "centered",
},
tags: ["autodocs"],
};
export default meta;
type Story = StoryObj<typeof MyComponent>;
export const Default: Story = {
args: {
// Component props here
},
};
export const Variant: Story = {
args: {
// Variant props here
},
};- Create multiple stories for different component states
- Use args to make stories interactive
- Provide documentation using JSDoc comments
- Use controls to demonstrate component flexibility
- Add relevant design information in the component's docs
- TypeScript: Use proper type definitions for all components and functions
- Server Components: Prefer server components where possible to reduce client-side JavaScript
- Component Structure: Keep components focused and composable
- Testing: Write tests for critical functionality and components
- Directory Structure: Follow the established directory structure for consistency
- Styling: Use Tailwind CSS classes for styling, maintaining theme consistency
- Storybook: Create stories for all reusable components to document usage and variants