Folder Structure
Comprehensive guide to Mail Assist's project organization, file structure, and architectural patterns for maintainable and scalable code.
Project Overview
Mail Assist follows Next.js 14 App Router conventions with a clean, organized structure that separates concerns and promotes code reusability.
mail-assist/
├── app/ # Next.js App Router pages
│ ├── (auth)/ # Auth route group
│ │ ├── login/
│ │ │ └── page.tsx
│ │ └── signup/
│ │ └── page.tsx
│ ├── dashboard/ # Protected dashboard routes
│ │ ├── page.tsx
│ │ ├── history/
│ │ │ └── page.tsx
│ │ └── send/
│ │ └── page.tsx
│ ├── api/ # API routes
│ │ ├── send/
│ │ │ └── route.ts
│ │ ├── custom-mail/
│ │ │ └── route.ts
│ │ └── user-mails/
│ │ └── route.ts
│ ├── globals.css # Global styles
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Homepage
│ ├── loading.tsx # Global loading UI
│ └── not-found.tsx # 404 page├── components/ # Reusable components
│ ├── ui/ # ShadCN/UI components
│ │ ├── button.tsx
│ │ ├── input.tsx
│ │ ├── card.tsx
│ │ └── ...
│ ├── auth/ # Authentication components
│ │ ├── login-form.tsx
│ │ ├── signup-form.tsx
│ │ └── auth-provider.tsx
│ ├── email/ # Email-related components
│ │ ├── email-composer.tsx
│ │ ├── email-preview.tsx
│ │ ├── template-selector.tsx
│ │ └── email-history.tsx├── lib/ # Utility libraries
│ ├── supabase/ # Supabase configuration
│ │ ├── client.ts
│ │ ├── server.ts
│ │ └── types.ts
│ ├── resend/ # Resend configuration
│ │ └── client.ts
│ ├── utils.ts # General utilities
│ ├── validations.ts # Form validation schemas
│ └── constants.ts # App constants
├── hooks/ # Custom React hooks
│ ├── use-auth.ts
│ ├── use-credits.ts
│ └── use-email-history.ts├── types/ # TypeScript type definitions
│ ├── auth.ts
│ ├── email.ts
│ └── database.ts
├── templates/ # Email templates
│ ├── welcome.tsx
│ ├── newsletter.tsx
│ └── notification.tsx
├── public/ # Static assets
│ ├── images/
│ ├── icons/
│ └── favicon.ico
├── .env.example # Environment variables template
├── .env.local # Local environment variables
├── next.config.js # Next.js configuration
├── tailwind.config.js # Tailwind CSS configuration
├── tsconfig.json # TypeScript configuration
├── package.json # Dependencies and scripts
└── README.md # Project documentationApp Directory Structure
The app directory contains all pages, layouts, and API routes following Next.js 14 App Router conventions.
Route Groups
(auth) are route groups that organize routes without affecting the URL structure.export default function AuthLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-50">
<div className="max-w-md w-full space-y-8">
{children}
</div>
</div>
)
}API Routes Structure
API routes are organized by functionality with clear naming conventions and consistent response patterns.
app/api/
├── send/
│ └── route.ts # Main email sending endpoint
├── custom-mail/
│ └── route.ts # Custom email handling
├── user-mails/
│ └── route.ts # Email history retrieval├── auth/
│ ├── callback/
│ │ └── route.ts # Auth callback handler
│ └── signout/
│ └── route.ts # Sign out handler
└── credits/
├── balance/
│ └── route.ts # Get credit balance
└── purchase/
└── route.ts # Purchase credits (future)Components Organization
Components are organized by feature and responsibility, promoting reusability and maintainability across the application.
UI Components
The components/ui directory contains all ShadCN/UI components that provide the design system foundation.
components/ui/
├── button.tsx # Button variants and sizes
├── input.tsx # Form input components
├── card.tsx # Card layouts
├── dialog.tsx # Modal dialogs
├── dropdown-menu.tsx # Dropdown menus├── form.tsx # Form components
├── label.tsx # Form labels
├── select.tsx # Select dropdowns
├── textarea.tsx # Text areas
├── toast.tsx # Toast notifications
├── tooltip.tsx # Tooltips
└── ... # Other UI primitivesFeature Components
Feature-specific components are grouped by functionality for better organization and easier maintenance.
Auth Components
components/auth/
├── login-form.tsx
├── signup-form.tsx
├── forgot-password.tsx
├── auth-provider.tsx
└── protected-route.tsxEmail Components
components/email/
├── email-composer.tsx
├── email-preview.tsx
├── template-selector.tsx
├── email-history.tsx
└── credit-indicator.tsxLibrary Directory
The lib directory contains configuration files, utilities, and service integrations that are used throughout the application.
Supabase Configuration
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs'
import type { Database } from './types'
export const createClient = () =>
createClientComponentClient<Database>()import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import type { Database } from './types'
export const createServerClient = () =>
createServerComponentClient<Database>({ cookies })Utility Functions
import { type ClassValue, clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}export function formatDate(date: string | Date) {
return new Intl.DateTimeFormat('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
}).format(new Date(date))
}export function validateEmail(email: string) {
const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/
return emailRegex.test(email)
}export function calculateCreditsNeeded(mailType: 'custom' | 'template') {
return mailType === 'custom' ? 5 : 10
}Custom Hooks
Custom React hooks encapsulate reusable logic and state management for common operations throughout the application.
Authentication Hook
import { useEffect, useState } from 'react'
import { createClient } from '@/lib/supabase/client'
import type { User } from '@supabase/auth-helpers-nextjs'
export function useAuth() {
const [user, setUser] = useState<User | null>(null)
const [loading, setLoading] = useState(true)
const supabase = createClient()useEffect(() => {
const getUser = async () => {
const { data: { session } } = await supabase.auth.getSession()
setUser(session?.user ?? null)
setLoading(false)
}
getUser()const { data: { subscription } } = supabase.auth.onAuthStateChange(
(event, session) => {
setUser(session?.user ?? null)
setLoading(false)
}
)
return () => subscription.unsubscribe()
}, [supabase.auth])
return { user, loading }
}Credits Management Hook
import { useEffect, useState } from 'react'
import { createClient } from '@/lib/supabase/client'
import { useAuth } from './use-auth'
export function useCredits() {
const [credits, setCredits] = useState<number>(0)
const [loading, setLoading] = useState(true)
const { user } = useAuth()
const supabase = createClient()useEffect(() => {
if (!user) return
const fetchCredits = async () => {
const { data, error } = await supabase
.from('profiles')
.select('credits')
.eq('id', user.id)
.single()
if (data && !error) {
setCredits(data.credits)
}
setLoading(false)
}
fetchCredits()
}, [user, supabase])const refreshCredits = async () => {
if (!user) return
const { data, error } = await supabase
.from('profiles')
.select('credits')
.eq('id', user.id)
.single()
if (data && !error) {
setCredits(data.credits)
}
}
return { credits, loading, refreshCredits }
}Type Definitions
TypeScript type definitions are organized by domain to ensure type safety and better developer experience across the application.
Database Types
export interface Database {
public: {
Tables: {
profiles: {
Row: {
id: string
email: string | null
credits: number
created_at: string
updated_at: string
}Insert: {
id: string
email?: string | null
credits?: number
created_at?: string
updated_at?: string
}
Update: {
id?: string
email?: string | null
credits?: number
created_at?: string
updated_at?: string
}
}user_mails: {
Row: {
id: string
user_id: string
recipient_email: string
subject: string
content: string
mail_type: 'custom' | 'template'
credits_used: number
sent_at: string
}Insert: {
id?: string
user_id: string
recipient_email: string
subject: string
content: string
mail_type: 'custom' | 'template'
credits_used: number
sent_at?: string
}
Update: {
id?: string
user_id?: string
recipient_email?: string
subject?: string
content?: string
mail_type?: 'custom' | 'template'
credits_used?: number
sent_at?: string
}
}
}
}
}Email Types
export interface EmailData {
to: string
subject: string
html: string
mailType: 'custom' | 'template'
}
export interface EmailResponse {
success: boolean
messageId?: string
creditsUsed?: number
remainingCredits?: number
error?: string
}export interface EmailHistoryItem {
id: string
recipient_email: string
subject: string
content: string
mail_type: 'custom' | 'template'
credits_used: number
sent_at: string
}
export interface EmailTemplate {
id: string
name: string
description: string
html: string
preview: string
category: 'welcome' | 'newsletter' | 'notification' | 'marketing'
}Email Templates
Email templates are React components that generate HTML for different email types, providing consistent branding and responsive design.
interface WelcomeEmailProps {
userName: string
loginUrl: string
}
export function WelcomeEmail({ userName, loginUrl }: WelcomeEmailProps) {
return (
<div style={{ fontFamily: 'Arial, sans-serif', maxWidth: '600px', margin: '0 auto' }}>
<div style={{ backgroundColor: '#f8f9fa', padding: '40px 20px', textAlign: 'center' }}><h1 style={{ color: '#333', marginBottom: '20px' }}>
Welcome to Mail Assist, {userName}!
</h1>
<p style={{ color: '#666', fontSize: '16px', lineHeight: '1.5' }}>
Thank you for joining Mail Assist. We're excited to help you send
beautiful emails with ease.
</p><a
href={loginUrl}
style={{
display: 'inline-block',
backgroundColor: '#007bff',
color: 'white',
padding: '12px 24px',
textDecoration: 'none',
borderRadius: '6px',
marginTop: '20px'
}}
>
Get Started
</a>
</div>
</div>
)
}Configuration Files
Key configuration files that control the behavior and setup of the Mail Assist application.
Next.js Configuration
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
serverActions: true,
},
images: {
domains: ['images.unsplash.com'],
},
env: {
CUSTOM_KEY: process.env.CUSTOM_KEY,
},
}
module.exports = nextConfigTailwind Configuration
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class"],
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: 0 },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: 0 },
},
},animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [require("tailwindcss-animate")],
}Best Practices
Follow these conventions and best practices when working with the Mail Assist codebase.
Naming Conventions
- Components - PascalCase (e.g.,
EmailComposer.tsx) - Files - kebab-case (e.g.,
email-composer.tsx) - Directories - kebab-case (e.g.,
email-templates/) - Variables - camelCase (e.g.,
emailData) - Constants - UPPER_SNAKE_CASE (e.g.,
MAX_CREDITS)
Import Organization
// 1. React and Next.js imports
import React from 'react'
import { NextRequest, NextResponse } from 'next/server'
// 2. Third-party library imports
import { z } from 'zod'
import { Resend } from 'resend'// 3. Internal imports (absolute paths)
import { createServerClient } from '@/lib/supabase/server'
import { validateEmail } from '@/lib/utils'
import { Button } from '@/components/ui/button'
// 4. Relative imports
import './styles.css'
// 5. Type imports (separate from value imports)
import type { EmailData } from '@/types/email'Development Workflow
Recommended workflow for developing new features and maintaining the Mail Assist codebase.
- Feature Planning - Identify components and files needed
- Type Definitions - Define TypeScript interfaces first
- Component Development - Build UI components with proper props
- API Integration - Connect components to backend services
- Testing - Test functionality and edge cases
- Documentation - Update relevant documentation