Skip to content
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
17 changes: 16 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,22 @@
"Bash(npx playwright test:*)",
"Bash(sort:*)",
"Bash(npx playwright install:*)",
"Bash(ls:*)"
"Bash(ls:*)",
"Bash(grep -r '\"\"clean\"\"' --include=\"package.json\" .)",
"Bash(grep -r '\"\"clean\"\"' --include=\"package.json\" . --exclude-dir=node_modules)",
"Bash(find /c/Users/User/Documents/Projects/nimble/apps/portal/app /c/Users/User/Documents/Projects/nimble/apps/portal/lib /c/Users/User/Documents/Projects/nimble/apps/portal/components -type f \\\\\\(-name *.ts -o -name *.tsx \\\\\\))",
"Bash(git:*)",
"Bash(echo \"EXIT:$?\")",
"Bash(docker compose:*)",
"Bash(bash -n /c/Users/User/Documents/Projects/nimble/.devcontainer/setup.sh)",
"Bash(bash -n /c/Users/User/Documents/Projects/nimble/apps/sidekick-api/scripts/start-local-db.sh)",
"Bash(DEVCONTAINER=true bash /c/Users/User/Documents/Projects/nimble/apps/sidekick-api/scripts/start-local-db.sh)",
"Bash(echo \"Exit code: $?\")",
"Bash(docker build:*)",
"Bash(docker rmi:*)",
"Bash(wsl --list --verbose)",
"Bash(wsl:*)",
"Bash(docker ps:*)"
],
"deny": [],
"ask": [],
Expand Down
12 changes: 12 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
node_modules
.next
out
dist
.turbo
.git
.claude
.env
.env.*
!.env.example
test-results
playwright-report
12 changes: 12 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false
18 changes: 18 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Enforce LF line endings for all text files
* text=auto eol=lf

# Ensure shell scripts always use LF (critical for bash execution)
*.sh text eol=lf
.husky/* text eol=lf

# Binary files
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.webp binary
*.woff binary
*.woff2 binary
*.ttf binary
*.eot binary
87 changes: 87 additions & 0 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,93 @@

This guide will help you set up and run the Sidekick monorepo locally.

There are two ways to set up your development environment:

- **[Native Setup](#prerequisites)** (macOS/Linux) — Install Node.js, Docker, and dependencies directly on your machine
- **[Docker Setup](#docker-development-setup)** (Windows / Cross-platform) — Run everything inside Docker containers with a single command

---

## Docker Development Setup

Use this setup if you're on **Windows** or prefer a containerized environment. All you need is [Docker Desktop](https://www.docker.com/products/docker-desktop/) — no Node.js, PostgreSQL, or other dependencies required on your machine.

### Prerequisites

- [Docker Desktop](https://www.docker.com/products/docker-desktop/) installed and running

### Quick Start

```bash
# Clone the repository
git clone <repository-url>
cd nimble

# Start the development environment (first run takes a few minutes)
npm run docker:up

# Start the web app
npm run docker:dev:sidekick
```

Open http://localhost:3000 in your browser.

The first `docker:up` automatically handles npm install, shared package builds, database creation, and Prisma migrations. Subsequent starts reuse cached dependencies and are much faster.

### Available Docker Commands

| Command | Description |
|---------|-------------|
| `npm run docker:up` | Start containers (runs setup on first boot) |
| `npm run docker:down` | Stop containers |
| `npm run docker:shell` | Open a bash shell inside the container |
| `npm run docker:dev` | Start all apps |
| `npm run docker:dev:sidekick` | Start the web app only (port 3000) |
| `npm run docker:dev:api` | Start the API server only (port 3001) |
| `npm run docker:test` | Run unit tests |
| `npm run docker:lint` | Run ESLint |
| `npm run docker:typecheck` | Run TypeScript type checking |

For any command not listed above, use the shell:

```bash
npm run docker:shell
# Then run any command inside the container, e.g.:
npm run dev:vault
npx turbo run test:e2e --filter=@nimble/sidekick
```

### IDE Support (TypeScript Intellisense)

The Docker setup uses a separate `node_modules` volume inside the container, so your host machine won't have `node_modules` by default. To get TypeScript autocomplete and go-to-definition working in your editor, run `npm install` locally as well:

```bash
npm install
```

This gives your editor access to type definitions. The container and host `node_modules` are independent and don't interfere with each other.

### Resetting the Environment

```bash
# Stop containers and remove all data (node_modules, database)
docker compose down -v

# Start fresh
npm run docker:up
```

### How It Works

- **`docker-compose.yml`** defines two services: a Node.js 20 app container and a PostgreSQL 15 database
- **`docker/entrypoint.sh`** runs automatically on first start: installs dependencies, builds shared packages, copies `.env.example` files, and runs database migrations
- Source code is bind-mounted from your host, so edits are reflected immediately
- The `DEVCONTAINER=true` environment variable tells the existing `start-local-db.sh` script to skip its Docker logic (the database is already provided by Docker Compose)

---

## Native Setup (macOS/Linux)

## Prerequisites

Before you begin, ensure you have the following installed on your system:
Expand Down
6 changes: 6 additions & 0 deletions apps/sidekick-api/scripts/start-local-db.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ if [ "$NODE_ENV" = "production" ] || [ "$CI" = "true" ]; then
exit 0
fi

# In a dev container, PostgreSQL is provided by Docker Compose
if [ "$DEVCONTAINER" = "true" ]; then
echo "✅ Dev container detected — PostgreSQL is managed by Docker Compose"
exit 0
fi

# Check if Docker is running
if ! docker info > /dev/null 2>&1; then
echo "Docker is not running. Please start Docker Desktop."
Expand Down
44 changes: 44 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
services:
app:
build:
context: .
dockerfile: docker/Dockerfile
volumes:
- .:/workspace:cached
- node_modules:/workspace/node_modules
entrypoint: ["/workspace/docker/entrypoint.sh"]
command: ["sleep", "infinity"]
depends_on:
db:
condition: service_healthy
environment:
DEVCONTAINER: "true"
DATABASE_URL: "postgresql://postgres:nimblelocal123@db:5432/nimbledb?schema=public"
SESSION_SECRET: "dev-session-secret-not-for-production-1234567890"
ports:
- "3000:3000"
- "3001:3001"
- "3002:3002"
- "4000:4000"
- "4321:4321"

db:
image: postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: nimblelocal123
POSTGRES_DB: nimbledb
volumes:
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5

volumes:
node_modules:
postgres-data:
8 changes: 8 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM node:20-bookworm-slim

RUN apt-get update && apt-get install -y --no-install-recommends \
git \
curl \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /workspace
63 changes: 63 additions & 0 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/bin/bash
set -e

echo "=== Nimble Dev Environment Setup ==="

# Fix execute bits (Windows checkout strips them)
find /workspace -name "*.sh" -not -path "*/node_modules/*" -exec chmod +x {} \;
chmod +x /workspace/.husky/pre-commit /workspace/.husky/pre-push 2>/dev/null || true

# Copy .env.example files if .env doesn't exist
copy_env() {
local src="$1" dest="$2"
if [ ! -f "$dest" ]; then
echo " Creating $dest from example..."
cp "$src" "$dest"
fi
}

copy_env apps/sidekick-api/.env.example apps/sidekick-api/.env
copy_env apps/sidekick/.env.example apps/sidekick/.env.local
copy_env apps/portal/.env.example apps/portal/.env.local
copy_env apps/vault/.env.example apps/vault/.env
copy_env apps/discord/.env.example apps/discord/.env

# Install dependencies
echo "Installing npm dependencies..."
npm install

# Wait for database to be ready
echo "Waiting for database..."
for i in $(seq 1 30); do
if node -e "
const net = require('net');
const s = net.createConnection({host:'db',port:5432});
s.on('connect',()=>{s.end();process.exit(0)});
s.on('error',()=>process.exit(1));
" 2>/dev/null; then
echo " Database is ready"
break
fi
if [ "$i" -eq 30 ]; then
echo " ERROR: Database not reachable after 30s"
exit 1
fi
sleep 1
done

# Build all shared packages so apps can import them
echo "Building shared packages..."
npx turbo build --filter='./packages/*'

# Generate Prisma client and run migrations
echo "Setting up database..."
cd apps/sidekick-api
npx prisma generate
npx prisma migrate deploy
cd /workspace

echo ""
echo "=== Setup complete! ==="
echo ""

exec "$@"
Loading