https://github.com/dileeparanawake/littlesteps-ai
Full-stack LLM app with auth, prompt history, and Docker β for personalised parenting support
https://github.com/dileeparanawake/littlesteps-ai
ai better-auth chatapp containerization docker drizzle full-stack google-oauth llm nextjs openai parenting portfolio postgres react react-query software-engineering typescript vitest zod
Last synced: 30 days ago
JSON representation
Full-stack LLM app with auth, prompt history, and Docker β for personalised parenting support
- Host: GitHub
- URL: https://github.com/dileeparanawake/littlesteps-ai
- Owner: dileeparanawake
- License: mit
- Created: 2025-07-11T16:39:20.000Z (9 months ago)
- Default Branch: main
- Last Pushed: 2026-02-23T09:18:17.000Z (about 1 month ago)
- Last Synced: 2026-02-23T18:07:11.336Z (about 1 month ago)
- Topics: ai, better-auth, chatapp, containerization, docker, drizzle, full-stack, google-oauth, llm, nextjs, openai, parenting, portfolio, postgres, react, react-query, software-engineering, typescript, vitest, zod
- Language: TypeScript
- Homepage: https://littlesteps-ai.com
- Size: 13 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# littlesteps-ai
[](https://github.com/dileeparanawake/littlesteps-ai)
AI guidance for new parents - a full-stack, auth-gated LLM chat, built with **Next.js 15**, **PostgreSQL/Drizzle**, **React Query**, **Vitest**, **Docker**, **OpenAI**. Shipped in tagged minimum viable slices (MVS). [Whatβs an MVS? (Blog)](https://dileeparanawake.com/minimum-viable-slice).
**Keywords:** Next.js, React, TypeScript, PostgreSQL, Drizzle ORM, Docker, React Query, Zod, BetterAuth.js, Google OAuth, OpenAI API, Vitest, Full-stack development, API design, Authentication, Authorization, Database design, Testing, Containerisation, REST APIs
---
- ποΈ [Project Kanban](https://github.com/users/dileeparanawake/projects/4/views/1)
- π·οΈ Release tags: [MVS1](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs1-complete) Β· [MVS2](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs2-complete) Β· [MVS3](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs3-complete) Β· [MVS4](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs4-complete) Β· [MVS5](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs5-complete)
- π [Diff MVS4 β MVS5](https://github.com/dileeparanawake/littlesteps-ai/compare/mvs4-complete...mvs5-complete)
## Demo

### Skills demonstrated
- Built a full-stack, auth-gated chat app using **Next.js**, **React**, **TypeScript**, and **React Query**.
- Modelled and persisted data in **PostgreSQL** with **Drizzle ORM** and **SQL migrations**, containerised via **Docker Compose**.
- Implemented **Google OAuth 2.0** authentication using **BetterAuth** with session-protected endpoints.
- Validated and sanitised inputs using **Zod**; followed RESTful API conventions for predictable error handling.
- Integrated **OpenAI's API** for promptβresponse handling on the server.
- Wrote **DB-backed tests** with **Vitest + Docker Postgres** to verify core actions and data integrity.
- Deployed to **Fly.io** with **Neon** managed PostgreSQL, HTTPS, secrets management, and production-ready configuration.
- Implemented **access controls** and **usage limits** around AI usage, using an adapter pattern for the AI provider and **GitHub Actions** for automated deployment.
- Implemented **GDPR compliance** with a privacy policy page, automated inactive-user cleanup via **GitHub Actions OIDC**, and cascade deletes for data retention.
## Features by Minimum Viable Slice
Each slice represents a tagged, working release β from basic prompt handling to full auth-gated history.
MVS5 β GDPR Compliance & Data Retention
**Goal:** Make LittleSteps GDPR-compliant with transparent privacy practices and automated data retention.
**Key features**
- **Privacy policy page** (`/privacy`) with footer and sign-in modal links.
- **Automated inactive-user deletion** β monthly GitHub Actions workflow deletes accounts inactive for 90+ days.
- **OIDC-secured admin endpoint** (`/api/admin/cleanup`) authenticated via GitHub Actions OIDC tokens.
- **Verification table cleanup** decoupled from user deletion for independent lifecycle management.
- Admin users excluded from auto-deletion; cascade deletes handle all related data.
MVS4 β Production Deployment & Access Controls
**Goal:** Deploy LittleSteps to Fly.io as a production-ready application with safety guardrails and access controls.
**Key features**
- Deployed to **Fly.io** with **Neon** managed PostgreSQL, HTTPS, and secrets management.
- **RBAC on routes** for initial release (admin-only access to chat APIs).
- **Usage limits** enforced for non-admin users.
- **AI provider adapter** with prompt caching (threadId-based).
- **UI improvements**: safety banner, disclaimer, Open Graph image, mobile-responsive layout.
- **Automated CD** via GitHub Actions for production deployment.
MVS3 β Prompt History & Persistence
**Goal:** Persist chat threads and messages so logged-in users can revisit their prompt history.
**Key features**
- PostgreSQL + Drizzle schema for `thread` / `message` (UUIDs, ordered `sequence`).
- Auth-gated APIs (`/api/chat`, `/api/threads`) enforcing ownership.
- Rename & delete threads (β€60 chars, Zod validation, cascade delete).
- React Query caching / invalidation keeps sidebar and thread lists synced.
- DB-backed tests (Vitest + Docker Postgres) verify CRUD and ordering.
MVS2 β User Authentication (Google OAuth)
**Goal:** Secure app access with Google OAuth via BetterAuth.js.
**Key features**
- Google sign-in modal using BetterAuth.js (HttpOnly sessions).
- Auth-gated routes and session-aware UI state.
- Early DB prototype used SQLite (migrated to Postgres in MVS3).
MVS1 β Prompt Interface (No Auth)
**Goal:** Provide a simple OpenAI-powered prompt/response interface.
**Key features**
- Basic chat UI with secure API route to OpenAI.
- Docker Compose setup for containerised local development.
- Established initial minimum viable slice and project structure.
## Tech Stack
- **UI / App:** Next.js (App Router), React, TypeScript
- **Data layer:** React Query (@tanstack/react-query)
- **Database / ORM:** PostgreSQL (Docker, **Neon**) + Drizzle ORM (migrations)
- **Auth:** BetterAuth.js (Google OAuth, HttpOnly sessions)
- **Validation:** Zod
- **LLM:** OpenAI API (SDK)
- **Testing:** Vitest (DB-backed tests)
- **Dev / Infra:** Node 20 (Volta), Docker & Docker Compose, Fly.io (production), **GitHub Actions (CD)**
> Note: SQLite was used in MVS2 only; MVS3 migrated to PostgreSQL.
## Data Model
A small, explicit schema that prioritises **ownership**, **deterministic ordering**, and **clean deletes**.
Data model (expand)
```txt
User (id TEXT PK, email UNIQUE, name, createdAt, updatedAt)
ββ Session (id TEXT PK, token UNIQUE, expiresAt, userId FK β User.id ON DELETE CASCADE)
ββ Account (id TEXT PK, accountId, providerId, userId FK β User.id ON DELETE CASCADE)
ββ Thread (id UUID PK, userId FK β User.id ON DELETE CASCADE, title VARCHAR(60), createdAt, updatedAt)
ββ Message (id UUID PK, threadId FK β Thread.id ON DELETE CASCADE,
sequence INT, role ENUM[system|user|assistant], content TEXT,
createdAt, promptTokens?, completionTokens?, totalTokens?,
UNIQUE(threadId, sequence))
```
### Key decisions (what & why)
- **UUIDs for Thread/Message** β non-guessable, safe in URLs, simpler client routing.
- **Deterministic ordering** β `UNIQUE(thread_id, sequence)` ensures stable message order without relying on timestamps.
- **Ownership enforcement** β `thread.user_id` FK + API session checks (BetterAuth) guarantee users can only access their own threads.
- **Clean deletes** β `ON DELETE CASCADE` on FKs automatically removes dependent messages.
- **Tight title constraint** β `VARCHAR(60)` prevents UI overflow and keeps naming consistent.
- **Role enum** (`system | user | assistant`) β validates message type at the DB layer.
- **Token fields** (`promptTokens`, `completionTokens`, `totalTokens`) β reserved for future analytics and rate-limiting.
### Migration & testing workflow
- Schema changes are managed with **Drizzle migrations**.
- Tests are **DB-backed** (Vitest + Docker Postgres): create thread β append messages β fetch ordered β assert content & order.
## API quick reference
API reference (expand)
Authentication required for all endpoints (BetterAuth session). Usage limits are currently applied to authenticated non-admin users only.
POST /api/chat?threadId=UUID (optional)
- body: { "prompt": string }
- 200: { "threadID": UUID }
- 400 invalid body | 401 unauthenticated | 500 error
- Behavior: appends user prompt, calls OpenAI, appends assistant reply; creates a thread if none provided.
GET /api/chat?threadId=UUID
- 200: Message[] ordered by sequence
- 400 missing threadId | 401 unauthenticated | 403 not owner
GET /api/threads
- 200: Thread[] for the session user
PATCH /api/threads
- body: { "threadId": UUID, "title": string<=60 }
- 200: Thread | 400 invalid | 401 unauth | 403 forbidden
DELETE /api/threads
- body: { "threadId": UUID }
- 200: { "success": true } | 401 unauth | 403 forbidden | 404 not found
## Project structure
Project structure (expand)
```
ββ src/app/ (Next.js App Router)
β ββ page.tsx (landing)
β ββ chat/[threadId]/page.tsx (thread view)
β ββ api/
β ββ auth/[...all]/route.ts (BetterAuth handlers)
β ββ chat/route.ts (POST: send msg, GET: fetch msgs)
β ββ threads/route.ts (GET: list, PATCH: rename, DELETE)
β
ββ src/components/
β ββ chat/
β β ββ ChatSidebar/ (thread list, rename, delete)
β β ββ ChatThread/ (message list, input, submit)
β ββ sign-in/ (Google OAuth modal)
β ββ layout/Header.tsx (nav, session UI)
β
ββ src/lib/
ββ auth.ts (BetterAuth config)
ββ chat/ (DB operations: create, read, update, delete)
ββ db/ (Drizzle schema, migrations)
```
**Data flow:** User β React components β API routes β Drizzle ORM β PostgreSQL
## Architecture at a glance
- **App:** Next.js App Router; server routes for APIs, client components for UI.
- **Auth/Data:** BetterAuth.js + Drizzle ORM β Postgres (UUID, sequence ordering).
- **Client state:** React Query cache; invalidation on rename/delete/post.
- **Deployment:** Dockerised Next.js app on **Fly.io**, connected to **Neon** managed PostgreSQL, deployed via **GitHub Actions**.
## Tests
```bash
pnpm test
```
DB-backed (Vitest + Docker Postgres): create/read/update/delete flows for threads/messages.
## Local Development
See full guide: [`public/docs/local-dev-guide.md`](./docs/local-dev-guide.md)
Quick start:
```bash
docker compose up -d
pnpm migrate
```
## Releases
- 2026-02-24 β MVS5: GDPR compliance & data retention β [Tag](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs5-complete)
- 2025-12-26 β MVS4: Production deployment & access controls β [Tag](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs4-complete)
- 2025-10-21 β MVS3: Prompt history & persistence β [Tag](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs3-complete)
- 2025-07-27 β MVS2: User Authentication β [Tag](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs2-complete)
- 2025-07-20 β MVS1: Prompt Interface β [Tag](https://github.com/dileeparanawake/littlesteps-ai/releases/tag/mvs1-complete)
## License
This project is licensed under the [MIT License](./LICENSE).