- Multi-layer Security: Server-side middleware + client-side protection
- Social Login: Google OAuth integration
- Session Management: Automatic timeout handling and session recovery
- MFA Support: Optional SMS-based multi-factor authentication
- Smart Redirects: Preserves intended destination after login
- Course Catalog: Browse and enroll in EMDR training courses
- Smart Course Navigation: Auto-expanding sidebar with active chapter detection
- Simple Progress Tracking: Chapter-based completion tracking with visual indicators
- Interactive Dashboard: Personalized learning dashboard with widgets
- Enhanced Quiz System:
- Pass/fail feedback with conditional navigation
- "Next Chapter" button on quiz success
- "Retry Quiz" + "Ask Question" on failure
- Question interaction tracking per chapter
- AI-Powered Help: Tavus conversational video AI for asking questions about chapter content
- Real-time video conversations with AI instructor
- Chapter-specific context injection
- 4-minute sessions with countdown timer
- Camera/microphone controls
- Community Features: Social learning with posts and interactions
- SEO-Friendly URLs: Human-readable slugs with reliable ID references
- Hierarchical Structure: Course β Chapters β Sections with auto-collapse navigation
- Simple Time Estimation: Basic formula for course completion times
totalTime = videoTime + quizTime + learningCheckTime- Default 8-minute chapters with configurable quiz and learning check times
- Progress Calculation: Two simple approaches
- Time-based:
(timeSpent / totalTime) * 100 - Chapter-based:
(completedChapters / totalChapters) * 100
- Time-based:
- Reusable Timer Component:
- Countdown timers for quizzes and learning activities
- Multiple variants (compact, default, large)
- Built with shadcn countdown hook for reliability
- Responsive Design: Mobile-first approach with adaptive layouts
- Consistent Progress Indicators: Reusable ChapterProgress component
- Smart Sidebar: Only active section expanded, others auto-collapsed
- Modal System: Accessible dialogs with proper ARIA support
- Dark/Light Themes: CSS-first theming with next-themes integration
- Accessibility: WCAG compliant components and navigation
- Loading States: Smooth transitions and professional loading indicators
- Interactive Video Player: Next-video with Mux streaming + synchronized WebVTT transcripts
- Auto-highlighting transcript segments during playback
- Click-to-seek: Jump to any part by clicking transcript text
- Callback ref pattern for seamless video-transcript sync
- VTT parser with precise timestamp handling
- Breadcrumb Navigation: Clear hierarchical navigation paths
- Timer Components: Comprehensive timer system for quizzes, AI interactions, and progress tracking
- Content Estimation System: AI-powered time estimation for reading and video content with personalized learning recommendations
| Category | Technology |
|---|---|
| Framework | Next.js 15 (App Router) |
| Language | TypeScript 5.9 |
| Authentication | AWS Amplify Gen2 + Cognito |
| AI Conversations | Tavus CVI (@tavus/cvi-ui) |
| Video Streaming | next-video + Mux |
| Transcripts | WebVTT with custom parser |
| Forms | React Hook Form + Zod |
| State Management | React Context + useState |
| Code Quality | ESLint + TypeScript strict mode |
| Deployment | AWS Amplify Hosting |
The 8P3P LMS follows a hierarchical content structure designed for optimal learning flow:
Course {
id: "1"
title: "EMDR Therapy Fundamentals"
chapters: [
Chapter {
id: "chapter_1"
title: "EMDR Foundations"
sections: [
Section { id: "section_1_1", title: "Introduction", sectionType: "video" }
Section { id: "section_1_2", title: "How EMDR Works", sectionType: "video" }
Section { id: "section_1_3", title: "Trauma and the Body", sectionType: "video" }
Section { id: "section_1_4", title: "Closing", sectionType: "video" }
Section { id: "section_1_5", title: "Learning Check", sectionType: "ai_avatar" }
Section { id: "section_1_6", title: "Knowledge Assessment", sectionType: "quiz" }
]
}
]
}- πΉ Video: Video content with transcript and progress tracking
- π€ AI Avatar: Interactive conversation with AI instructor (Tavus integration)
- π Quiz: Assessment with multiple choice questions and retry logic
- π Learning Check: Interactive review and reinforcement activities
Sections can be reordered dynamically without changing IDs:
- Each section has an
orderfield for flexible sequencing - Content can be reorganized based on learning objectives
- Maintains consistent URLs and progress tracking
- Node.js 18+ and npm
- AWS Account (for authentication)
- Git
- Radix UI components (@radix-ui/react-slider, @radix-ui/react-radio-group)
git clone https://github.com/your-org/8p3p-lms-nextjs.git
cd 8p3p-lms-nextjs
npm install# Start Amplify sandbox (handles auth backend)
npx ampx sandbox# Copy environment template
cp .env.example .env.local
# Edit .env.local and add your Tavus credentials:
# TAVUS_API_KEY=your_tavus_api_key_here
# TAVUS_REPLICA_ID=your_replica_id_here
# TAVUS_PERSONA_ID=your_persona_id_here # Optional
# TAVUS_DEFAULT_CALL_DURATION=240 # Optional (default: 4 minutes)Get Tavus Credentials:
- Sign up at https://www.tavus.io/
- Create a replica (AI avatar) in the Tavus dashboard
- Copy API Key and Replica ID to
.env.local - See Tavus Documentation for details
# In another terminal, start development server
npm run dev
# Optional: Run linting and type checking
npm run lint
npm run type-checkVisit http://localhost:3000
graph TD
A[User Request] --> B[Server Middleware]
B --> C{Authenticated?}
C -->|No| D[Redirect to /login]
C -->|Yes| E[Allow Access]
D --> F[Amplify Authenticator]
F --> G[Google OAuth / Email]
G --> H[Success]
H --> I[Redirect to Intended Page]
- Middleware:
middleware.tsvalidates sessions before page load - API Routes: Protected endpoints with server-side auth checks
- Cannot be bypassed: Works even with JavaScript disabled
- Route Guards:
ProtectedRoutecomponents for smooth UX - Session Handling: Automatic session timeout detection
- Smart Redirects: Preserves user's intended destination
- Conditional Rendering: Auth-aware UI components
- Loading States: Professional loading indicators during auth checks
- Error Boundaries: Graceful error handling and recovery
- Visit protected route (e.g.,
/dashboard) β Redirect to/login - Click "Create Account" β Fill registration form
- Email verification β Account confirmed
- Automatic redirect to originally requested page
- Visit
/loginor click "Login" in navbar - Choose email/password or Google OAuth
- Successful authentication β Redirect to
/dashboard - Session persists across browser sessions
- Session expires β Automatic detection
- User redirected to
/loginwith return path stored - After re-authentication β Return to original page
- Logout β Clear session and redirect to
/login
For rapid MVP development, we prioritize manual Q&A testing over comprehensive unit testing:
Route Protection:
- Visit protected routes without login β Should redirect to
/login - Login and access protected routes β Should work normally
- Logout β Should clear session and redirect appropriately
Course Navigation:
- Browse course catalog β All courses should display correctly
- Navigate through chapters β Progress should update
- Complete quizzes β Should track completion status
Timer Functionality:
- Start quiz timer β Should countdown properly
- Timer expiration β Should trigger appropriate actions
- Different timer variants β Should display correctly
# Run linting (enforced in CI/CD)
npm run lint:strict
# Run type checking
npm run type-check
# Validate build
npm run validateAfter feature completion, we'll implement:
- Comprehensive unit test suite
- Integration tests for key workflows
- End-to-end testing with Playwright
- Performance and accessibility testing
8p3p-lms-nextjs/
βββ π amplify/ # AWS Amplify backend configuration
β βββ auth/resource.ts # Authentication setup
β βββ backend.ts # Backend entry point
βββ π src/
β βββ π app/ # Next.js App Router
β β βββ π (auth)/ # Auth route group
β β β βββ login/ # Login page
β β βββ π dashboard/ # Protected dashboard
β β βββ π courses/ # Protected courses
β β β βββ π [id]/ # Course detail pages
β β β βββ π [chapterId]/ # Chapter pages
β β β βββ π sections/ # Section content
β β β βββ π [sectionId]/ # Individual sections
β β βββ π api/ # API routes
β β β βββ tavus/ # Tavus AI conversation API
β β β β βββ conversation/ # Create conversation endpoint
β β β βββ user/ # Protected user endpoint
β β βββ layout.tsx # Root layout with auth provider
β βββ π components/ # Reusable components
β β βββ π auth/ # Authentication components
β β β βββ AuthProvider.tsx # Amplify provider wrapper
β β β βββ ProtectedRoute.tsx # Client-side route guard
β β β βββ AuthRedirect.tsx # Login page redirect logic
β β β βββ SessionHandler.tsx # Session timeout handler
β β β βββ SignIn.tsx # Amplify authenticator
β β βββ π course/ # Course components
β β β βββ course-sidebar.tsx # Course navigation sidebar
β β β βββ course-overview.tsx # Course overview page
β β β βββ breadcrumb-nav.tsx # Breadcrumb navigation
β β β βββ π chapter-content/ # Chapter components
β β β βββ index.tsx # Main chapter wrapper
β β β βββ video-player.tsx # Video player component
β β β βββ interactive-script.tsx # Transcript component
β β β βββ chapter-quiz.tsx # Quiz component
β β β βββ ask-question.tsx # Question form component
β β βββ π common/ # Common reusable components
β β β βββ π timer/ # Timer component system
β β β βββ Timer.tsx # Main timer component (Client)
β β β βββ TimerDisplay.tsx # Timer display (Server)
β β βββ π cvi/ # Tavus CVI components (auto-generated)
β β β βββ π components/ # CVI UI components
β β β β βββ conversation/ # Conversation component
β β β β βββ cvi-provider/ # CVI provider
β β β β βββ device-select/ # Device management
β β β βββ π hooks/ # CVI hooks
β β β βββ use-cvi-call.tsx # CVI call hook
β β βββ π ui/ # shadcn/ui components
β βββ π hooks/ # Custom React hooks
β β βββ useTimer.ts # Timer hook with state management
β β βββ use-mobile.ts # Mobile detection hook
β β βββ use-params.ts # Next.js 15+ params hook
β βββ π lib/ # Utility functions
β β βββ auth-server.ts # Server-side auth utilities
β β βββ course-utils.ts # Course utility functions
β β βββ mock-data.ts # Mock data for development
β β βββ utils.ts # General utilities
β β βββ π utils/ # Utility modules
β β βββ time-formatting.ts # Time formatting and validation
β βββ π types/ # TypeScript type definitions
β β βββ tavus.ts # Tavus API types
β βββ amplify_outputs.json # Amplify configuration
βββ π context/ # Documentation and context
β βββ course-page-structure.md # Course page structure guide
β βββ url-slugs-guide.md # URL slug implementation guide
βββ middleware.ts # Server-side route protection
βββ eslint.config.mjs # ESLint configuration for Next.js 15+
βββ amplify_outputs.json # Root Amplify config
βββ package.json
# Deploy to AWS Amplify
npx ampx pipeline-deploy --branch main# Lint and type check before building
npm run lint
npm run type-check
# Build for production
npm run build
# Start production server
npm startRun local checks before pushing to prevent CI/CD failures:
# Run all validation checks locally
npm run pre-commit
# Individual checks
npm run lint
npm run type-check
npm run buildAutomated validation on every PR and push:
- ESLint: Code quality and style checking
- TypeScript: Type safety validation
- Build: Production build verification
- Caching: Optimized with Node.js 20 and enhanced caching
- Security: Minimal permissions and concurrency control
# .env.local (auto-generated by Amplify)
NEXT_PUBLIC_AWS_PROJECT_REGION=<your-region>
NEXT_PUBLIC_AWS_COGNITO_REGION=<your-region>
# ... other Amplify-generated variablesThe theme system uses Tailwind CSS v4 with a dual-layer approach for maximum flexibility:
- Define in
@themedirective (required for Tailwind v4):
/* src/app/globals.css */
@theme {
/* Add your new color with both light and dark variants */
--color-success: oklch(67.31% 0.162 144.21);
--color-success-dark: oklch(55% 0.15 144);
--color-success-foreground: oklch(100% 0 0);
--color-success-foreground-dark: oklch(0% 0 0);
}- Reference in CSS custom properties (for runtime theme switching):
:root {
--success: var(--color-success);
--success-foreground: var(--color-success-foreground);
}
.dark {
--success: var(--color-success-dark);
--success-foreground: var(--color-success-foreground-dark);
}- Use in components:
// As Tailwind utility
<div className="bg-success text-success-foreground">Success message</div>
// As CSS variable
<div style={{ backgroundColor: 'var(--success)' }}>Success message</div>Brand colors are pre-defined and available as both utilities and CSS variables:
/* Available brand colors */
--color-brand-blue: oklch(28.08% 0.051 260.2); /* Primary brand */
--color-brand-gold: oklch(76.65% 0.139 91.06); /* Accent/CTA */
--color-brand-gray: oklch(71.37% 0.019 261.32); /* Neutral */
--color-brand-light-blue: oklch(96.53% 0.007 247.9); /* Backgrounds */
--color-brand-green: oklch(67.31% 0.162 144.21); /* Success */
--color-brand-red: oklch(64.27% 0.215 28.81); /* Error/Warning */Usage:
<button className="bg-brand-gold text-brand-blue">CTA Button</button>To customize shadcn/ui component colors:
- Modify the base theme colors in
@themedirective - Components automatically inherit the new colors
- Override specific components using CSS custom properties:
/* Override specific component styling */
@layer components {
.custom-button {
background-color: var(--color-brand-gold);
color: var(--color-brand-blue);
}
}Critical: All theme colors must be defined in the @theme directive for Tailwind v4 production builds:
/* β
CORRECT - Will work in production */
@theme {
--color-custom: oklch(50% 0.1 180);
}
/* β INCORRECT - Will be stripped in production */
:root {
--custom-color: #somecolor;
}Edit amplify/auth/resource.ts to customize:
- User attributes (email, name, custom fields)
- Password policies
- MFA settings
- OAuth providers
- Callback URLs
Required: Configure Google OAuth 2.0 Console with Cognito user pool domains when deploying to new environments:
- Visit Google Cloud Console: console.cloud.google.com
- Navigate to: APIs & Services β Credentials β OAuth 2.0 Client IDs
- Select your OAuth client and click the Edit button
Add your Cognito user pool domains (not your app URLs):
# From amplify_outputs.json - check your actual domains
https://<your-local-user-pool-domain>.auth.<region>.amazoncognito.com #local dev
https://<your-main-user-pool-domain>.auth.<region>.amazoncognito.com #main branch
https://<your-dev-user-pool-domain>.auth.<region>.amazoncognito.com #dev branchAdd your Cognito user pool domains with /oauth2/idpresponse endpoint:
# From amplify_outputs.json - check your actual domains
https://<your-local-user-pool-domain>.auth.<region>.amazoncognito.com/oauth2/idpresponse #local dev
https://<your-main-user-pool-domain>.auth.<region>.amazoncognito.com/oauth2/idpresponse #main branch
https://<your-dev-user-pool-domain>.auth.<region>.amazoncognito.com/oauth2/idpresponse #dev branchMethod 1: From amplify_outputs.json (Local Development)
# Check your amplify_outputs.json file
cat amplify_outputs.json | grep "domain"Method 2: From AWS Amplify Console (Deployed Branches)
For each deployed branch, follow these steps to find the Cognito User Pool domain:
-
Navigate to Branch Deployments:
# Replace with your actual region, app ID, and branch name https://<region>.console.aws.amazon.com/amplify/apps/<your-app-id>/branches/main/deployments https://<region>.console.aws.amazon.com/amplify/apps/<your-app-id>/branches/dev/deployments -
Access Backend Resources:
- Scroll down to find the "Deployed backend Resources" tab
- Click on the tab to expand the resources table
-
Locate User Pool:
- In the search bar, type:
UserPool - Find and click on "AWS::Cognito::UserPool" in the "Type" column
- In the search bar, type:
-
Find Domain Settings:
- A new browser window opens to AWS Cognito Console
- In the left sidebar, click "Domain" under the "Branding" section
- Copy the "Cognito Domain" from the main content area
Example Cognito domains by branch:
# Local Development (from amplify_outputs.json)
https://<local-user-pool-id>.auth.<region>.amazoncognito.com
# Main Branch (from AWS Console)
https://<main-user-pool-id>.auth.<region>.amazoncognito.com
# Dev Branch (from AWS Console)
https://<dev-user-pool-id>.auth.<region>.amazoncognito.comIn AWS Amplify Console β Secrets:
# Replace with your actual region and app ID
https://<region>.console.aws.amazon.com/amplify/apps/<your-app-id>/secrets
Add the following secrets:
GOOGLE_CLIENT_ID: Your Google OAuth client IDGOOGLE_CLIENT_SECRET: Your Google OAuth client secret
Reference: AWS Amplify External Identity Providers Guide
Comprehensive timer functionality for quizzes, AI interactions, and progress tracking:
- Multiple Variants: Countdown, stopwatch, and progress timers
- Accurate Timing: High-resolution timestamps with tab visibility handling
- Accessibility: Full WCAG compliance with screen reader support
- Keyboard Controls: Spacebar/Enter to toggle, Ctrl+R to reset, Escape to pause
- Visual Indicators: Color-coded urgency (green β yellow β red)
- Context Validation: Different time limits for quiz, AI, learning, and general contexts
// Main Timer Component (Client Component)
<Timer
duration={300} // 5 minutes
variant="countdown" // countdown | stopwatch | progress
context="quiz" // quiz | ai | learning | general
showControls // Play/pause/reset buttons
showProgress // Progress bar for progress variant
onComplete={handleSubmit} // Callback when timer completes
onTick={updateState} // Callback every second
/>
// Compact Timer (for navigation/cards)
<CompactTimer
duration={240} // 4 minutes
variant="countdown"
context="ai"
autoStart
/>
// Timer Display Only (Server Component)
<TimerDisplay
time={180} // Current time in seconds
color="warning" // Visual urgency indicator
showLabel // "3 minutes remaining"
size="lg" // sm | md | lg
/>// Custom timer logic with full control
const timer = useTimer(300, {
variant: "countdown",
autoStart: true,
onComplete: () => submitQuiz(),
onTick: (state) => updateProgress(state.progress),
});
// Timer state and controls
const {
time, // Current time (seconds)
isRunning, // Timer running state
isPaused, // Timer paused state
isCompleted, // Timer completed state
progress, // Progress percentage (0-100)
start,
pause,
resume, // Control functions
reset,
toggle, // Control functions
getFormattedTime, // "05:30" format
getTimeWithLabel, // "5 minutes 30 seconds remaining"
getColorTheme, // "success" | "warning" | "danger"
} = timer;// Automatic validation based on context
validateTimerDuration(300, "quiz"); // β
Valid (30s - 1hr)
validateTimerDuration(600, "ai"); // β Too long (1min - 5min)
validateTimerDuration(30, "learning"); // β Too short (1min - 30min)
validateTimerDuration(7200, "general"); // β
Valid (1s - 2hr)formatTime(90); // "01:30"
formatTime(3661, true); // "1:01:01"
formatTimeWithLabel(90, "remaining"); // "1 minute 30 seconds remaining"
calculateProgress(30, 60); // 50 (percent)
getTimerColorTheme(10, 60); // "danger" (< 25% remaining)The 8P3P LMS features a production-ready video player with synchronized WebVTT transcripts, providing an accessible and engaging learning experience.
- πΉ Mux Streaming: Adaptive HLS streaming with automatic quality adjustment
- π Live Transcripts: Real-time synchronized captions with precise timestamps
- π― Auto-Highlighting: Active transcript segment highlights as video plays
- π Click-to-Seek: Jump to any video moment by clicking transcript text
- βΏ Accessibility: Full screen reader support and keyboard navigation
- π Bidirectional Sync: Video controls transcript, transcript controls video
// InteractiveVideoPlayer - Full featured player with transcript
<InteractiveVideoPlayer
src={video_url} // next-video Asset or string URL
showTranscript={true} // Toggle transcript panel
transcript={parsedVTT} // Array of TranscriptSegment[]
layout="default" // default | theater | compact
autoPlay={false}
muted={false}
/>Converts WebVTT format to structured transcript segments:
import { parseVTT } from '@/lib/utils/vtt-parser';
const vttContent = `WEBVTT
1
00:00:00.000 --> 00:00:05.330
Welcome to chapter one of the EMDR course.`;
const segments = parseVTT(vttContent);
// [{ id: "1", startTime: 0, endTime: 5.33, text: "Welcome..." }]Ensures reliable video-transcript synchronization:
// VideoPlayer uses callback ref for event listeners
const setVideoRef = useCallback((element: HTMLVideoElement | null) => {
if (element) {
// Attach listeners immediately when element mounts
element.addEventListener('timeupdate', handleTimeUpdate);
element.addEventListener('durationchange', handleDurationChange);
}
}, []);
<Video ref={setVideoRef} ... />Video β Transcript (Auto-highlight)
const handleTimeUpdate = (currentTime: number) => {
// Find active segment based on current time
const active = transcript.find(
seg => currentTime >= seg.startTime && currentTime < seg.endTime
);
setActiveSegmentId(active?.id);
};Transcript β Video (Click-to-seek)
const handleSegmentClick = (startTime: number) => {
// Seek video to timestamp
videoPlayerRef.seekTo(startTime);
setCurrentTime(startTime);
};Videos are uploaded to Mux and processed automatically:
# Videos stored in /videos directory
videos/
βββ Intro-8p3p-Ch1-Section-1-1.mp4
βββ Intro-8p3p-Ch1-Section-1-1.mp4.json # Auto-generated metadata
βββ ...# Fetch VTT files from Mux (requires playback ID + track ID)
node scripts/fetch-mux-vtt.js
# Script outputs formatted VTT content to console
# Copy the videoVTT snippets directly to mock-data.ts{
id: "section_1_1",
title: "Introduction",
videoUrl: video_1_1, // next-video Asset
videoScript: "...", // Plain text script
videoVTT: `WEBVTT...`, // WebVTT format transcript
sectionType: "video"
}interface InteractiveVideoPlayerProps {
src: Asset | string; // Video source
poster?: string; // Thumbnail image
transcript?: TranscriptSegment[]; // Parsed VTT segments
showTranscript?: boolean; // Show/hide transcript
layout?: "default" | "theater" | "compact";
autoPlay?: boolean;
muted?: boolean;
className?: string;
}interface TranscriptSegment {
id: string; // Unique segment identifier
startTime: number; // Start time in seconds (e.g., 5.33)
endTime: number; // End time in seconds
text: string; // Transcript text content
}import { InteractiveVideoPlayer, parseVTT } from '@/components/video';
export function VideoSection({ section }) {
const transcript = section.videoVTT
? parseVTT(section.videoVTT)
: createTranscriptFromScript(section.videoScript, 90);
return (
<InteractiveVideoPlayer
src={section.videoUrl}
showTranscript={true}
transcript={transcript}
layout="default"
/>
);
}- π Enhanced Learning: Visual + audio + text reinforcement
- βΏ Accessibility: Deaf/hard-of-hearing support, non-native speakers
- π Quick Reference: Click transcript to review specific concepts
- π± Mobile-Friendly: Responsive design with touch support
- β‘ Performance: Lazy-loaded transcripts, optimized rendering
Enhanced tracking capabilities:
// Chapter completion tracking
interface Chapter {
videoCompleted?: boolean;
quizPassed?: boolean;
questionAskedCount?: number;
timeSpent?: number; // Time spent in seconds
quizAttempts?: number; // Number of quiz attempts
}
// Course progress tracking
interface Course {
lastViewedChapter?: string;
completedChapters: string[];
totalTimeSpent?: number; // Total learning time
averageQuizScore?: number; // Average quiz performance
}
// Timer interaction tracking
interface TimerSession {
context: "quiz" | "ai" | "learning";
duration: number; // Configured duration
timeUsed: number; // Actual time used
completed: boolean; // Whether timer completed naturally
pauseCount?: number; // Number of pauses
}We welcome contributions! Please see our Contributing Guide for detailed information on:
- π Getting Started: Setup and development workflow
- π PR Guidelines: Stacked PRs, size limits, and review process
- π§ͺ Testing Standards: Required tests and validation
- π Code Quality: Standards, comments, and best practices
- π Release Process: Sprint-based development and deployment
- Fork the repository
- Create feature branch (
git checkout -b feature/amazing-feature) - Run pre-commit checks (
npm run pre-commit) - Commit changes (
git commit -m 'Add amazing feature') - Push to branch (
git push origin feature/amazing-feature) - Open Pull Request
π For detailed guidelines, see CONTRIBUTING.md
- Next.js 15+ Compliance: Server components first, client only when needed
- Data Schema Compliance: Update mock-data models for new state/properties
- Dependency Compliance: Verify required packages before implementation
- Pre-commit Validation: All checks must pass locally before pushing
- ESLint Rules: Strict enforcement with no unused variables/imports
- Server Components: Default choice for better performance
- Client Components: Only for interactivity (useState, event handlers, browser APIs)
- Link Navigation: Use Next.js Link instead of useRouter when possible
- Route Parameters:
- Server Components: Use
await paramsdirectly - Client Components: Use
useParamshook from@/hooks/use-params - NEVER: Use React.use() directly - always use established patterns
- Server Components: Use
- Component Reuse: Leverage existing components (ChapterProgress, etc.)
- TypeScript Compliance: Layout props must use Promise-only params type for Next.js 15+
The Content Estimation System provides intelligent time estimation for mixed educational content (text + video) with personalized learning recommendations. Built following our component reusability protocol using existing timer infrastructure and shadcn/ui components.
- Text Analysis: Word count, reading speed calculation (150-250 WPM), complexity assessment
- Video Analysis: Duration parsing, type classification (lecture/demo/interactive), engagement factors
- Mixed Content: Combined analysis with interaction time calculation
- Complexity Detection: Simple/Moderate/Complex classification based on technical terms and structure
- User Profiles: Reading speed tracking, completion rate history, learning pace preferences
- Adaptive Estimates: Personalized time calculations based on user performance
- Confidence Scoring: Reliability assessment for time estimates (0-1 scale)
- Profile Updates: Automatic learning from actual completion times
- Session Planning: Optimal session length and break frequency suggestions
- Pace Recommendations: Fast/Moderate/Slow based on content complexity and user profile
- Progress Tracking: Real-time progress monitoring with remaining time calculations
// Text analysis with complexity detection
import { analyzeTextContent } from "@/lib/content-analysis";
const analysis = analyzeTextContent(content);
// Video analysis with engagement factors
import { analyzeVideoContent } from "@/lib/content-analysis";
const videoAnalysis = analyzeVideoContent(metadata);
// Complete time estimation
import { calculateTimeEstimate } from "@/lib/content-analysis";
const estimate = calculateTimeEstimate(mixedContent, userProfile);// Time estimate display (multiple variants)
import { TimeEstimate } from '@/components/common/content-estimation';
<TimeEstimate
estimate={estimate}
variant="detailed"
showBreakdown={true}
complexity="moderate"
/>
// Content estimator with analysis
import { ContentEstimator } from '@/components/common/content-estimation';
<ContentEstimator
content={mixedContent}
userProfile={userProfile}
onEstimateReady={(estimate) => console.log(estimate)}
trackProgress={true}
/>
// Progress tracking
import { ProgressIndicator } from '@/components/common/progress';
<ProgressIndicator
progress={45}
estimatedTime={1800}
elapsedTime={810}
variant="linear"
/>// Content estimation with caching
import { useContentEstimation } from "@/hooks/useContentEstimation";
const { estimate, isLoading, error, analyze } = useContentEstimation({
content: mixedContent,
userProfile: userProfile,
autoAnalyze: true,
});
// Progress tracking
import { useProgressTracking } from "@/hooks/useContentEstimation";
const { elapsedTime, remainingTime, progress, startTracking, stopTracking } =
useProgressTracking(estimatedTime);import { ContentEstimator } from '@/components/common/content-estimation';
function LessonPage({ lesson }) {
const handleEstimateReady = (estimate) => {
console.log(`Estimated time: ${estimate.total} seconds`);
console.log(`Confidence: ${estimate.confidence * 100}%`);
};
return (
<div>
<ContentEstimator
content={{
text: lesson.content,
videos: lesson.videos,
contentType: "lesson"
}}
userProfile={user.learningProfile}
onEstimateReady={handleEstimateReady}
variant="card"
showBreakdown={true}
/>
</div>
);
}import { useContentEstimation, useProgressTracking } from '@/hooks/useContentEstimation';
function InteractiveLearningSession({ content, userProfile }) {
const { estimate, isLoading } = useContentEstimation({
content,
userProfile,
autoAnalyze: true
});
const {
progress,
elapsedTime,
remainingTime,
startTracking,
stopTracking,
updateProgress
} = useProgressTracking(estimate?.total || 0);
const handleStartLearning = () => {
startTracking();
};
const handleProgressUpdate = (completionPercentage) => {
updateProgress(completionPercentage);
};
return (
<div>
{estimate && (
<ProgressIndicator
progress={progress}
estimatedTime={estimate.total}
elapsedTime={elapsedTime}
variant="linear"
showTimeRemaining={true}
/>
)}
</div>
);
}The MVP system focuses on simple, reliable functionality:
- Basic time calculations using configurable constants
- Reusable timer component with multiple variants
- Simple progress tracking based on chapter completion
- Q&A testing approach for rapid iteration
# Validate code quality
npm run validate
# Run development server
npm run devComprehensive mock data available for development and testing:
import {
mockLessons,
mockUserProfiles,
mockTimeEstimates,
} from "@/lib/mock-data/content-estimation";
// Use in development
const estimate = mockTimeEstimates.mediumLesson;
const userProfile = mockUserProfiles.fastReader;
const content = mockLessons.comprehensiveChapter;# Fix TypeScript errors
npm run type-check
# Fix linting issues
npm run lint:fix
# Clean build
rm -rf .next && npm run build# CSS variable recognition errors in production
# Root cause: Custom CSS variables not integrated with Tailwind v4 theme system
# Solution: Define colors in @theme directive using --color-* namespace
# Check for CSS variable issues
grep -r "var(--" src/ --include="*.css"
# Verify Tailwind v4 theme configuration
# Ensure colors are defined in @theme { --color-* } format
# Reference: docs/design-system-rules.md#tailwind-v4-production-build-issues# Common issue: Layout params type incompatible with Next.js 15+
# Solution: Use Promise<{ id: string }> instead of union types
# Client components: Use useParams hook from @/hooks/use-params
# Server components: Use await params directly# Install shadcn/ui components
npx shadcn@latest add dialog
npx shadcn@latest add progress
# Verify package.json dependencies
npm ci# Restart Amplify sandbox
npx ampx sandbox --delete
npx ampx sandboxMIT License - see LICENSE file for details.
- π§ Email: [email protected]
- π Documentation (coming soon): docs.8p3p.io
- π Issues: GitHub Issues
- π¬ Discussions: GitHub Discussions
Built with β€οΈ by Rhyan Vargas and 8P3P
Β© 2025 8P3P
