Skip to content
Merged
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
6 changes: 4 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
name: ThoughtSwap CI/CD Pipeline

permissions:
contents: write
on:
push:
branches: [main, develop]
branches: [main, develop, 'feat/**']
pull_request:
branches: [main, develop]
branches: [main, develop, 'feat/**']

jobs:
lint-and-format:
Expand Down
53 changes: 43 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,49 @@ ThoughtSwap is a real-time classroom discussion tool that facilitates anonymous

- **Node.js** (v18+ recommended)
- **npm**
- **Docker & Docker Compose** (for the database)
- **Docker & Docker Compose**
- A **Canvas LMS** instance (or a Free-for-Teacher account) for developer keys.

---

## 🛠️ Setup & Installation
## 🚀 Docker Quickstart

The easiest way to build and deploy ThoughtSwap locally is using Docker Compose. This spins up the Postgres database, API server, and Client UI automatically.

1. **Configure Environment:**
Copy the example environment file to `.env`:

```bash
cp env.example .env
```

Open `.env` and populate the **Canvas Configuration** section (Client ID, Secret, URL). You can generally leave the Database and Port configurations at their defaults.

2. **Start the Application:**
Run the following command to build the images and start the services:

```bash
docker-compose up --build
```

_Note: The server container will automatically apply database migrations upon startup._

3. **Access:**
- **Client:** [http://localhost:5173](http://localhost:5173)
- **Server:** [http://localhost:8000](http://localhost:8000)

4. **Optional: Seed Data**
To create the "Dev Teacher" account without a real Canvas login, run the seed command inside the running server container:

```bash
docker-compose exec server npx prisma db seed
```

---

## 🛠️ Manual Setup & Development

If you prefer to run the Node applications directly on your host machine (while using Docker for the database), follow these steps.

1. **Clone the repository:**

Expand Down Expand Up @@ -49,19 +86,15 @@ ThoughtSwap is a real-time classroom discussion tool that facilitates anonymous
CANVAS_REDIRECT_URI="http://localhost:8000/accounts/canvas/login/callback/"
```

---

## Local Development

### 1. Start the Database
### 4. Start the Database

Use Docker to spin up the PostgreSQL database defined in `docker-compose.yml`.

```bash
docker-compose up -d
docker-compose up -d postgres
```

### 2. Run Migrations & Seed
### 5. Run Migrations & Seed

Apply the Prisma schema to your database and seed the initial dev user.

Expand All @@ -76,7 +109,7 @@ npx prisma db seed

The seed command creates a "Dev Teacher" account (teacher@dev.com) which allows you to test teacher features without a real Canvas login.

### 3. Start the Application
### 6. Start the Application

Run both the client and server concurrently from the root directory.

Expand Down
46 changes: 42 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,53 @@
services:
postgres:
image: postgres:15-alpine
restart: always
container_name: thoughtswap_db
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: thoughtswap
POSTGRES_USER: ${POSTGRES_USER:-user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-password}
POSTGRES_DB: ${POSTGRES_DB:-thoughtswap}
ports:
- '5432:5432'
- '${POSTGRES_HOST_PORT:-5432}:5432'
volumes:
- pgdata:/var/lib/postgresql/data

server:
build:
context: .
dockerfile: packages/server/Dockerfile
args:
DATABASE_URL: ${DATABASE_URL:-postgresql://user:password@postgres:5432/thoughtswap}
PORT: ${SERVER_PORT:-3001}
restart: always
command: sh -c "npx prisma migrate deploy && npm start"
ports:
- '${SERVER_HOST_PORT:-8000}:${SERVER_PORT:-3001}'
environment:
DATABASE_URL: ${DATABASE_URL:-postgresql://user:password@postgres:5432/thoughtswap}
PORT: ${SERVER_PORT:-3001}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:${CLIENT_HOST_PORT:-5173}}
CANVAS_BASE_URL: ${CANVAS_BASE_URL}
CANVAS_CLIENT_ID: ${CANVAS_CLIENT_ID}
CANVAS_CLIENT_SECRET: ${CANVAS_CLIENT_SECRET}
CANVAS_REDIRECT_URI: ${CANVAS_REDIRECT_URI}
depends_on:
- postgres

client:
build:
context: .
dockerfile: packages/client/Dockerfile
args:
PORT: ${CLIENT_PORT:-5173}
restart: always
ports:
- '${CLIENT_HOST_PORT:-5173}:${CLIENT_PORT:-5173}'
environment:
SERVER_URL: ${SERVER_URL:-http://server:${SERVER_PORT:-3001}}
PORT: ${CLIENT_PORT:-5173}
depends_on:
- server

volumes:
pgdata:
33 changes: 33 additions & 0 deletions env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Canvas Configuration
CANVAS_CLIENT_ID=
CANVAS_CLIENT_SECRET=
CANVAS_BASE_URL=
CANVAS_REDIRECT_URI=

# Database Configuration
POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_DB=thoughtswap
# Port exposed on the host machine for direct database access
POSTGRES_HOST_PORT=5432

# Server (Backend) Configuration
# Port the Node.js server listens on inside the container
SERVER_PORT=3001
# Port exposed on the host machine to access the API
SERVER_HOST_PORT=8000
# Connection string for Prisma.
DATABASE_URL=postgresql://user:password@postgres:5432/thoughtswap

# Client (Frontend) Configuration
# Port the Vite server listens on inside the container
CLIENT_PORT=5173
# Port exposed on the host machine to access the UI
CLIENT_HOST_PORT=5173
# URL of the backend server for API requests (used by Vite proxy)
SERVER_URL=http://server:3001

# Shared Configuration
# URL where the frontend is accessible (used for CORS on the server)
# Should match http://localhost:${CLIENT_HOST_PORT}
FRONTEND_URL=http://localhost:5173
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions packages/client/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM node:22-alpine

WORKDIR /app

# Copy root configuration
COPY package.json package-lock.json ./

# Copy package definitions to satisfy workspace requirements
COPY packages/server/package.json ./packages/server/
COPY packages/client/package.json ./packages/client/

# Install dependencies
RUN npm ci

# Copy client source code
COPY packages/client ./packages/client

# Set working directory to client package
WORKDIR /app/packages/client

ARG PORT=5173
ENV PORT=$PORT

# Expose the application port
EXPOSE $PORT

# Start the application
CMD ["npm", "run", "dev"]
2 changes: 1 addition & 1 deletion packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function App() {
const [showTour, setShowTour] = useState(false);

// TODO: Change the following to the correct Canvas Auth URL
const CANVAS_AUTH_URL = 'http://localhost:8000/accounts/canvas/login/';
const CANVAS_AUTH_URL = '/accounts/canvas/login/';

const updateAuth = (newState: AuthState) => {
setAuthState(newState);
Expand Down
14 changes: 12 additions & 2 deletions packages/client/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

const SERVER_URL = process.env.SERVER_URL || 'http://localhost:8000';
const PORT = Number(process.env.PORT) || 5173;

export default defineConfig({
plugins: [react()],
server: {
host: true,
port: PORT,
proxy: {
'/api': {
// Proxy all /api requests to the server
target: 'http://localhost:8000',
target: SERVER_URL,
changeOrigin: true,
secure: false,
},
'/accounts': {
target: SERVER_URL,
changeOrigin: true,
secure: false,
},
'/socket.io': {
target: 'http://localhost:8000',
target: SERVER_URL,
ws: true,
},
},
Expand Down
9 changes: 0 additions & 9 deletions packages/server/.env.example

This file was deleted.

36 changes: 36 additions & 0 deletions packages/server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
FROM node:22-alpine

WORKDIR /app

# Copy root configuration
COPY package.json package-lock.json ./

# Copy package definitions to satisfy workspace requirements
COPY packages/server/package.json ./packages/server/
COPY packages/client/package.json ./packages/client/

# Install dependencies (including devDependencies for building)
RUN npm ci

# Copy server source code
COPY packages/server ./packages/server

# Set working directory to server package
WORKDIR /app/packages/server

# environment variables
ARG DATABASE_URL
ARG PORT=3001
ENV PORT=$PORT

# Generate Prisma Client
RUN npx prisma generate

# Build the TypeScript code
RUN npm run build

# Expose the application port
EXPOSE $PORT

# Start the application
CMD ["npm", "start"]
2 changes: 1 addition & 1 deletion packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { PrismaClient } from '@prisma/client';

dotenv.config();

const { FRONTEND_URL } = process.env;
const FRONTEND_URL = process.env.FRONTEND_URL || 'http://localhost:5173';

const app = express();
const prisma = new PrismaClient();
Expand Down
5 changes: 3 additions & 2 deletions packages/server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Visit https://aka.ms/tsconfig to read more about this file
"compilerOptions": {
// File Layout
"rootDir": ".",
"rootDir": "./src",
"outDir": "./dist",

// Environment Settings
Expand Down Expand Up @@ -42,5 +42,6 @@
"moduleDetection": "force",
"skipLibCheck": true,
"esModuleInterop": true
}
},
"include": ["src"]
}