When your friend needs a solution, you don't just recommend tools - you build them.
My friend's Canadian PR timeline was tight. Existing French learning platforms were either expensive or poorly architected. So I did what any dev would do: built a better one from scratch.
β‘ The Technical Challenge
Create a production-ready French learning platform optimized for Canadian immigration with modern web technologies.
The Stack:
Frontend: Next.js 15 + TypeScript + Tailwind CSS
Backend: Firebase (Firestore + Auth)
Deployment: Vercel
Styling: shadcn/ui + Radix UI
Performance: Server Components + Bundle Optimization
Technical Achievements
Performance Optimization:
β’ 60% bundle size reduction through strategic code splitting
β’ Server Components for optimal hydration
β’ 95+ Lighthouse scores across all metrics
β’ Sub-2s initial page load
Architecture Decisions:
β’ React Server Components for SEO-critical pages
β’ Client Components only where interactivity is needed
β’ Real-time progress sync with Firestore
β’ Optimistic UI updates for smooth UX
Developer Experience:
β’ Full TypeScript coverage with strict typing
β’ Component-based architecture with shadcn/ui
β’ Reusable UI system with Tailwind CSS
β’ Accessibility-first design patterns
Interesting Implementation Details
Web Speech API Integration:
Built custom audio controls using the Web Speech API for pronunciation practice. Users can click any French text to hear native pronunciation:
const speakText = async () => {
if ('speechSynthesis' in window) {
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = 'fr-FR';
utterance.rate = 0.8;
utterance.pitch = 1;
utterance.volume = 0.8;
speechSynthesis.speak(utterance);
}
};
Progress Tracking System:
Real-time sync between client and Firestore with comprehensive progress tracking:
interface UserStats {
userId: string;
totalLessonsCompleted: number;
totalXP: number;
currentStreak: number;
longestStreak: number;
averageScore: number;
timeSpent: number;
}
Express Entry Integration:
Built custom calculators for Canadian immigration requirements:
// CLB Calculator for language proficiency
const CLB_CONVERSION = {
'Reading': {
0: { clb: 0, level: 'No proficiency', color: 'bg-red-500' },
181: { clb: 4, level: 'Basic', color: 'bg-orange-500' },
// ... more thresholds
}
};
π― Core Features & Architecture
Smart Content Delivery:
- Dynamic lesson routing with Next.js App Router
- Lazy-loaded components with custom hooks
- Progressive image loading for lesson illustrations
- Structured learning modules with XP rewards
Real-time Learning Engine:
- Firebase Firestore for real-time progress sync
- Optimistic updates with conflict resolution
- Custom state management with React Context
- Offline-first architecture considerations
Performance Patterns:
// Server Component for SEO + Client Component for interactivity
export default async function LessonPage({ params }) {
const lesson = await fetchLesson(params.id); // Server-side
return <InteractiveLessonClient initialData={lesson} />;
}
π₯ Technical Highlights
Bundle Optimization:
- Dynamic imports for lesson components:
React.lazy(() => import('./AudioLesson'))
- Tree-shaking Tailwind with custom config
- Next.js 15 Turbopack for faster builds
- Critical CSS extraction for above-the-fold content
Audio Engineering:
- Web Speech API for pronunciation practice
- Custom audio button component with loading states
- Error handling for unsupported browsers
- Mobile-optimized audio controls
Developer Experience:
# One command setup
npm install && npm run dev
# Type-safe development with TypeScript
npm run type-check
π Learning Features
Structured Curriculum:
- 13 learning modules covering foundations to advanced
- XP reward system (50-150 XP per lesson)
- Progress tracking with streaks
- Difficulty-based lesson categorization
Interactive Elements:
- Click-to-hear pronunciation for any French text
- Real-time progress visualization
- Module completion tracking
- Responsive design for all devices
Immigration Focus:
- Express Entry CRS score calculator
- CLB (Canadian Language Benchmarks) calculator
- Immigration-specific vocabulary
- Test preparation resources
π Why This Matters for Devs
This isn't just another CRUD app. It's a production-ready example of:
- Modern React patterns in real-world application
- Performance optimization techniques that actually work
- Accessibility implementation beyond basic compliance
- Clean architecture that scales
- Real-world Firebase integration patterns
Key Learning Points:
- Server Components vs Client Components strategy
- Web Speech API integration patterns
- Firebase real-time data synchronization
- TypeScript interfaces for complex data structures
- Component composition with shadcn/ui
Project Structure & Architecture
Next.js 15 App Router Architecture
src/
βββ app/ # Next.js App Router (File-based routing)
β βββ (auth)/ # Route groups for authentication
β βββ admin/ # Admin dashboard routes
β βββ learn/[moduleId]/[lessonId]/ # Dynamic learning routes
β βββ layout.tsx # Root layout with providers
β βββ page.tsx # Home page
β βββ globals.css # Global styles
β βββ manifest.ts # PWA manifest
β βββ robots.ts # SEO robots.txt
β βββ sitemap.ts # Dynamic sitemap generation
βββ components/ # Component library
β βββ ui/ # shadcn/ui components
β β βββ audio-button.tsx # Web Speech API integration
β β βββ auth-modal.tsx # Authentication modals
β β βββ enhanced-button.tsx # Custom button variants
β β βββ ... # 20+ reusable UI components
β βββ calculators/ # Immigration calculators
β β βββ clb-calculator.tsx # Canadian Language Benchmarks
β β βββ express-entry-calculator.tsx # CRS score calculator
β βββ content/ # Page-specific content components
β β βββ alphabet-content.tsx
β β βββ grammar-content.tsx
β β βββ ... # 15+ content modules
β βββ layout/ # Layout components
β β βββ header.tsx # Navigation header
β β βββ main-layout.tsx # Three-column layout
β β βββ admin-layout.tsx # Admin dashboard layout
β βββ shared/ # Shared interactive components
βββ contexts/ # React Context providers
β βββ AuthContext.tsx # Authentication state management
β βββ FavoritesContext.tsx # User favorites management
β βββ AdminContext.tsx # Admin panel state
β βββ search-context.tsx # Global search state
βββ data/ # Static content & JSON data
β βββ learning-content.ts # Structured lesson data
β βββ alphabet.json # French alphabet data
β βββ grammar.json # Grammar rules & examples
β βββ vocabulary.json # Vocabulary lists
β βββ ... # 15+ JSON content files
βββ hooks/ # Custom React hooks
β βββ useProgress.ts # Progress tracking hook
β βββ useLoadingState.ts # Loading state management
βββ lib/ # Utility libraries
β βββ firebase/ # Firebase configuration
β β βββ config.ts # Firebase initialization
β β βββ auth.ts # Authentication functions
β β βββ progress.ts # Progress tracking functions
β β βββ ... # 8+ Firebase modules
β βββ utils/ # Utility functions
βββ types/ # TypeScript definitions
βββ index.ts # Main type definitions
βββ data-types.ts # Data structure types
π¨ Design System & Architecture Patterns
1. Component Architecture:
- Atomic Design: UI components follow atomic design principles
- Compound Components: Complex components like modals use compound patterns
- Render Props: Flexible components that accept render functions
- Custom Hooks: Business logic separated into reusable hooks
2. State Management Strategy:
// Context-based state management with custom hooks
const AuthContext = createContext<AuthContextType | undefined>(undefined);
// Custom hook for type-safe context usage
export function useAuth() {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within an AuthProvider');
return ctx;
}
3. Layout Architecture:
- Three-Column Layout: Left sidebar (navigation) + Main content + Right sidebar (quick access)
- Responsive Design: Mobile-first approach with breakpoint-specific layouts
- Sticky Navigation: Fixed header with smooth scrolling
- Progressive Enhancement: Works without JavaScript, enhanced with it
4. Data Flow Architecture:
User Action β Custom Hook β Firebase Service β Context Update β UI Re-render
β β β β
Component β useProgress β progress.ts β AuthContext β Real-time UI
π§ Technical Implementation Patterns
1. Server/Client Component Strategy:
// Server Component for SEO-critical pages
export default async function LessonPage({ params }) {
const lesson = await fetchLesson(params.id); // Server-side data fetching
return <InteractiveLessonClient initialData={lesson} />; // Client component
}
2. Custom Hook Pattern:
// Progress tracking with real-time updates
export function useProgress() {
const { user, isAuthenticated } = useAuth();
const [progress, setProgress] = useState<UserProgress | null>(null);
// Real-time Firebase integration
const loadProgress = useCallback(async () => {
if (!isAuthenticated || !user) return;
const userProgress = await getUserProgress(user.uid);
setProgress(userProgress);
}, [isAuthenticated, user]);
return { progress, loading, error, updateLesson };
}
3. Context Provider Composition:
// Nested context providers for different concerns
<AuthProvider>
<UserStorageProvider>
<AdminProvider>
<FavoritesProvider>
<SearchProvider>
{children}
</SearchProvider>
</FavoritesProvider>
</AdminProvider>
</UserStorageProvider>
</AuthProvider>
π Performance Architecture
1. Code Splitting Strategy:
- Route-based splitting: Each page loads only necessary code
- Component-based splitting: Heavy components loaded on demand
-
Dynamic imports:
React.lazy()
for non-critical components
2. Bundle Optimization:
- Tree shaking: Unused code eliminated at build time
- Turbopack: Next.js 15's fast bundler for development
- Image optimization: Next.js automatic image optimization
3. Caching Strategy:
- Static generation: Pre-built pages for better performance
- ISR (Incremental Static Regeneration): Dynamic content with static benefits
- Client-side caching: React Query for API response caching
π Security & Authentication Architecture
1. Firebase Authentication:
// Centralized auth state management
interface AuthContextType {
user: AppUser | null;
isLoading: boolean;
login: (email: string, password: string) => Promise<boolean>;
signup: (name: string, email: string, password: string) => Promise<boolean>;
loginWithGoogle: () => Promise<boolean>;
logout: () => void;
isAuthenticated: boolean;
}
2. Route Protection:
- AuthGuard component: Protects authenticated routes
- Role-based access: Admin vs user permissions
- Client-side validation: Immediate feedback for auth errors
Mobile-First Architecture
1. Responsive Design System:
- Breakpoint strategy: Mobile-first with progressive enhancement
- Touch optimization: Mobile-friendly interactions
- PWA capabilities: Service worker for offline functionality
2. Performance on Mobile:
- Critical CSS: Above-the-fold styles inlined
- Lazy loading: Images and components loaded on demand
- Bundle size: Optimized for slower mobile connections
Live Demo: Frenchpro.ca
Source Code: Open source on GitHub
Question for the community: What's your go-to pattern for handling real-time data in educational apps? Always curious about different approaches to state synchronization!
Building solutions for real problems hits different. Sometimes the best side projects come from helping friends.
Top comments (0)