An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          

# littlesteps-ai

[![GitHub Repo](https://img.shields.io/badge/GitHub-littlesteps--ai-blue?logo=github)](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

![LittleSteps AI Demo MVS3 Complete](./docs/screenshots/littlesteps-screen-recording-2025-10-21-MVS3-complete.gif)

### 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).