Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ db.sqlite3
*.md
!README.md

# Local infrastructure state
infra/.pulumi/

# Test and development files
.coverage
htmlcov/
Expand All @@ -49,6 +52,10 @@ Thumbs.db
# Development tools
.clinerules/
.claude/
node_modules/
**/node_modules/
.turbo/
**/dist/

# Legacy documentation
legacy_documentation/
Expand Down
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff
56 changes: 56 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: test

on:
pull_request:
push:
branches: [llteacher01]

jobs:
web:
name: apps/web — typecheck, migrate, test
runs-on: ubuntu-latest

services:
postgres:
image: pgvector/pgvector:pg16
env:
POSTGRES_USER: llteacher
POSTGRES_PASSWORD: dev
POSTGRES_DB: llteacher
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U llteacher -d llteacher"
--health-interval 5s
--health-timeout 5s
--health-retries 10

env:
DATABASE_URL: postgres://llteacher:dev@localhost:5432/llteacher

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm

- name: Install dependencies
run: npm ci

- name: Install psql
run: sudo apt-get update && sudo apt-get install -y --no-install-recommends postgresql-client

- name: Apply Postgres extensions
run: psql "$DATABASE_URL" -f apps/web/src/db/init/01_extensions.sql

- name: Apply Drizzle migrations
working-directory: apps/web
run: npm run db:migrate

- name: Typecheck
run: npm run typecheck

- name: Test
run: npm test
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ db.sqlite3
db.sqlite3-journal
media/

# Project-specific
*.env
/.claude/
/.agents/

# Python
*.py[cod]
*$py.class
Expand Down Expand Up @@ -115,3 +120,23 @@ cython_debug/

# Django specific
staticfiles/
# pixi environments
.pixi/*
!.pixi/config.toml

# apps/web + apps/admin — un-ignore TS source lib directories the Python `lib/` pattern above matches by accident
!apps/web/src/lib/
!apps/web/src/lib/**
!apps/admin/src/lib/
!apps/admin/src/lib/**
!apps/admin/src/client/lib/
!apps/admin/src/client/lib/**

# Turborepo monorepo
node_modules/
.turbo/
.turbo-cache/

# Pulumi local state and generated environment files
infra/.pulumi/
infra/.env
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
24
35 changes: 35 additions & 0 deletions Dockerfile.aws
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM node:24-alpine AS build

WORKDIR /app
COPY package.json package-lock.json turbo.json ./
COPY apps/web/package.json apps/web/package.json
COPY apps/admin/package.json apps/admin/package.json
COPY packages/ui/package.json packages/ui/package.json
COPY infra/package.json infra/package.json
RUN npm ci

COPY apps/web apps/web
COPY apps/admin apps/admin
COPY packages/ui packages/ui
RUN npm run build

FROM node:24-alpine AS runtime

ENV NODE_ENV=production \
PORT=8080
WORKDIR /app

COPY package.json package-lock.json ./
COPY apps/web/package.json apps/web/package.json
COPY apps/admin/package.json apps/admin/package.json
COPY packages/ui/package.json packages/ui/package.json
COPY infra/package.json infra/package.json
RUN npm ci --omit=dev --ignore-scripts --workspace=llteacher-web --include-workspace-root=false \
&& npm cache clean --force

COPY --from=build /app/apps/web/dist /app/apps/web/dist
COPY --from=build /app/apps/admin/dist /app/apps/admin/dist

USER node
EXPOSE 8080
CMD ["node", "apps/web/dist/node/server.mjs"]
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,50 @@
# LLTeacher v2

> **Turborepo monorepo.** TypeScript / React 19 / Vite / Tailwind 4 / Cloudflare Workers stack.
> Two workspaces today: `apps/web` (student-facing, port 2311) and `apps/admin` (instructor console, port 2312).
> Django legacy (`apps/accounts`, `apps/conversations`, `apps/homeworks`, `apps/llm`, plus `src/`, `services/`)
> remains the source of truth until cutover.
> See `docs/superpowers/plans/2026-06-01-llteacher-fullstack-port.md`.

AI-assisted educational platform for teachers and students.

## Monorepo layout

```
llteacher/
├── package.json # root — npm workspaces + Turborepo task runner
├── turbo.json # task pipeline (build, dev, typecheck, test)
├── pyproject.toml # root — uv workspaces for Django apps
├── apps/
│ ├── web/ # TS workspace: student-facing app (port 2311)
│ ├── admin/ # TS workspace: instructor console (port 2312)
│ ├── accounts/ # Django legacy: user model + auth
│ ├── conversations/ # Django legacy: AI conversation + submission
│ ├── homeworks/ # Django legacy: homework + section CRUD
│ └── llm/ # Django legacy: LLM config + provider
├── src/llteacher/ # Django project root
├── services/ # Django service layer (uv workspace)
└── docs/design-system/ # shared design system docs
```

The two manifest systems coexist in `apps/`: each TS workspace has a `package.json` (npm reads these), each Django workspace has a `pyproject.toml` (uv reads these). Neither tool sees the other's apps.

### Common commands (from repo root)

```bash
npm install # install all TS workspaces
npx turbo dev # boot all dev servers (web on 2311, admin on 2312)
npx turbo build # build all TS workspaces
npx turbo typecheck # tsc -b across all TS workspaces
npx turbo test # run all TS test suites
```

Or scope to one workspace: `npm run dev --workspace=llteacher-web`.

The Django stack still uses its own commands (`uv run python run_tests.py`, `python manage.py runserver`) and is unaffected by Turborepo.

## 🚀 Project Status

**Phase 1 Complete**: Data Models & Testing Infrastructure ✅
Expand Down
12 changes: 12 additions & 0 deletions apps/admin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
node_modules/
dist/
.env
.env.*
!.env.example
*.tsbuildinfo
*.config.d.ts
*.config.js
*.log
.DS_Store
coverage/
.turbo/
41 changes: 41 additions & 0 deletions apps/admin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# llteacher-admin

Instructor-facing console for LLteacher. Sibling workspace to `apps/web/` in the Turborepo.

## Run

From the repo root:

```bash
npm install # installs workspaces
npx turbo dev # boots both web (2311) and admin (2312)
```

Or just this workspace:

```bash
npm run dev --workspace=llteacher-admin # admin only on http://localhost:2312
```

## Scope

This is currently a **minimal scaffold**. It renders the shared UW Purple chrome (top nav + sidebar) with placeholder content. The instructor surfaces it will eventually own:

- Course / homework / section authoring
- Student roster and submission review
- Conversation grading (replaces Django's submission detail view)
- LLM configuration

## Shared design tokens — known duplication

`src/client/styles.css` is currently a **copy** of `apps/web/src/client/styles.css`. The next monorepo task is extracting both copies into a `packages/ui` shared workspace so the design system lives in one place. Until then, any token changes need to be made in both files.

## What admin does NOT have yet (vs. `apps/web/`)

- No Cloudflare Worker — admin is a static SPA in this scaffold. A Hono Worker will be added when admin needs an API.
- No Drizzle / Neon — same reason.
- No WorkOS / AI SDK / Wrangler — added when needed.

## Port

`2312` — sits next to web's `2311`. Both ports use Vite's `strictPort: true` so they fail loudly if taken rather than silently picking another.
30 changes: 30 additions & 0 deletions apps/admin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "llteacher-admin",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview",
"typecheck": "tsc -b",
"test": "vitest run --passWithNoTests",
"test:watch": "vitest"
},
"dependencies": {
"@llteacher/ui": "*",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router": "^7.0.0"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"@vitejs/plugin-react": "^4.3.0",
"tailwindcss": "^4.0.0",
"typescript": "^5.7.0",
"vite": "^6.0.0",
"vitest": "^2.1.0"
}
}
Loading