Overview
LearnAI is a social e-learning app built around AI conversation. Learners chat with an AI tutor, organise conversations with tags, search their history, export chats and share them with others. Under the hood it's a deliberately split system: a Next.js 14 app that owns the user experience and relational data, and a set of Rust services on AWS Lambda that own the AI conversation engine.
Live at learning-hub-ai.vercel.app.
Architecture
Frontend: Next.js 14 (App Router)
- Auth: NextAuth with a Prisma adapter and two providers: email and password (bcrypt-hashed credentials) and Google OAuth, with 24-hour JWT sessions.
- Data: Prisma on PostgreSQL, modelling users, activity, chats, messages, tags, chat views and chat shares.
- API routes for chats (messages, streaming, share, export, tags), search, profiles and health checks, plus proxy routes that call the Lambda backend.
- Streaming: a Server-Sent Events route streams AI responses into the chat view as they generate.
- UI: Tailwind, shadcn/ui and Radix, Framer Motion, React Hook Form with Zod validation, TanStack Query for server state, and Markdown with KaTeX for maths in answers. Strings are localised in English and Spanish.
Backend: Rust on AWS Lambda
- Two Rust services, a chat service and an agent service built around the ElizaOS framework, about 3,200 lines of Rust, compiled for the
provided.al2custom runtime on ARM64 (Graviton) with X-Ray tracing enabled. - Infrastructure as code: an AWS SAM template defines API Gateway, a Cognito user pool with Google as an identity provider, a DynamoDB
sessionstable (on-demand billing, with a global secondary index ontenant_idfor tenant-scoped queries), an SNS topic for chat events and an S3 bucket. Terraform and LocalStack scripts cover local and alternative provisioning. - Model fallback: the agent service tries OpenAI
gpt-4o-minifirst, falls back to Anthropicclaude-3-haikuif that fails, and finally to a local pattern-matched reply, so a provider outage degrades the experience instead of breaking it. - Tests: unit tests with
mockallin the chat handler and integration tests for the agent service.
Design choices
- Rust on Lambda for the hot path. Rust's fast cold starts and small memory footprint suit pay-per-request compute, and ARM64 Lambdas are cheaper per GB-second than x86.
- Two data stores, each for its job. PostgreSQL holds relational, user-facing data (chats, tags, shares, search), while DynamoDB holds high-churn session state keyed for tenant isolation.
- Graceful degradation over hard dependencies on any single LLM provider.
What I'd change today
Move the CI workflows to the repository root so GitHub actually runs them, add frontend tests (Jest and MSW are configured but unused), and add retrieval over course material: the current tutor is conversational, without embeddings or a vector store.
Built with
- Next.js 14, React 18, TypeScript, Tailwind, shadcn/ui, TanStack Query, Zod
- NextAuth, Prisma, PostgreSQL
- Rust, AWS Lambda (ARM64), API Gateway, Cognito, DynamoDB, SNS, S3, AWS SAM, Terraform, LocalStack
- OpenAI (
gpt-4o-mini), Anthropic (claude-3-haiku)