Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
41a80b9
chore: add .gitattributes for consistent line endings and shell scrip…
ukeSJTU Dec 28, 2025
580e335
chore(vscode): add extensions.json for recommended VSCode extensions
ukeSJTU Dec 28, 2025
073d92a
feat(devcontainer): add Dockerfile for development environment setup
ukeSJTU Dec 28, 2025
8c27071
feat(devcontainer): add docker-compose.yml for development environmen…
ukeSJTU Dec 28, 2025
5226ad2
feat(devcontainer): add devcontainer.json for development environment…
ukeSJTU Dec 28, 2025
0164479
feat(devcontainer): add initialization scripts for development enviro…
ukeSJTU Dec 28, 2025
fbca0a4
feat(devcontainer): add GitHub Actions workflow for DevContainer vali…
ukeSJTU Dec 28, 2025
8d422f3
feat(devcontainer): add DevContainer setup guide for development envi…
ukeSJTU Dec 28, 2025
81d1e92
feat(devcontainer): update VSCode extensions and database configurati…
ukeSJTU Dec 28, 2025
d86cd30
feat(devcontainer): update Dockerfile and docker-compose for environm…
ukeSJTU Dec 28, 2025
3fb0b73
fix: add read permission for devcontainer verification workflow
ukeSJTU Dec 28, 2025
b91fb17
feat(devcontainer): enhance CI environment setup for faster initializ…
ukeSJTU Dec 28, 2025
2598c87
feat(devcontainer): enhance validation steps for improved visibility …
ukeSJTU Dec 28, 2025
e556a55
feat(devcontainer): improve CI environment setup for better control a…
ukeSJTU Dec 28, 2025
e1c0060
refactor(ci): remove devcontainer verification workflow script
ukeSJTU Dec 28, 2025
a2a3fd3
fix(devcontainer): update node version to 22 for consistency across c…
ukeSJTU Dec 28, 2025
9731079
fix(devcontainer): switch pnpm installation method to npm for better …
ukeSJTU Dec 28, 2025
1800171
fix(devcontainer): remove unused environment variables for cleaner co…
ukeSJTU Dec 28, 2025
a3b161e
fix(devcontainer): ensure pnpm store directory is created before conf…
ukeSJTU Dec 28, 2025
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
65 changes: 65 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# syntax=docker/dockerfile:1.4

ARG NODE_VERSION=22

FROM node:${NODE_VERSION}-slim

# Install necessary system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
ca-certificates \
curl \
gnupg \
openssh-client \
bash-completion \
# Playwright browser dependencies
libnss3 \
libnspr4 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libcups2 \
libdrm2 \
libxkbcommon0 \
libxcomposite1 \
libxdamage1 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libasound2 \
libpango-1.0-0 \
libcairo2 \
# PostgreSQL client for CLI debugging
postgresql-client \
&& rm -rf /var/lib/apt/lists/*

# Install pnpm via npm (with fallback to Taobao mirror for network issues)
ARG PNPM_VERSION=10.17.1
RUN npm install -g pnpm@${PNPM_VERSION} || \
npm install -g pnpm@${PNPM_VERSION} --registry=https://registry.npmmirror.com

# Configure pnpm
ENV PNPM_HOME=/pnpm
ENV PATH=$PNPM_HOME:$PATH
RUN mkdir -p /pnpm/store && \
pnpm config set store-dir /pnpm/store

# Set working directory
WORKDIR /workspace

# Configure Git safe directory to avoid permission warnings
RUN git config --global --add safe.directory /workspace

# Pre-create directories for volumes and set correct permissions
# This ensures the node user can write to these directories
RUN mkdir -p /workspace/node_modules /workspace/.turbo && \
chown -R node:node /workspace /pnpm
Comment thread
ukeSJTU marked this conversation as resolved.

# Set up shell configuration for node user
USER node
RUN echo 'alias ll="ls -alh"' >> ~/.bashrc && \
echo 'alias pn="pnpm"' >> ~/.bashrc && \
echo 'export PS1="\[\e[32m\]\u@nomad-dev\[\e[m\]:\[\e[34m\]\w\[\e[m\]\$ "' >> ~/.bashrc

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD node --version && pnpm --version || exit 1
130 changes: 130 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{
"name": "Nomad OTA Platform",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",

"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},

"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"biomejs.biome",
"editorconfig.editorconfig",
"dsznajder.es7-react-js-snippets",
"bradlc.vscode-tailwindcss",
"mtxr.sqltools",
"mtxr.sqltools-driver-pg",
"Playwright.playwright",
"ZixuanChen.vitest-explorer",
"eamodio.gitlens",
"usernamehw.errorlens",
"streetsidesoftware.code-spell-checker",
"DavidAnson.vscode-markdownlint",
"ms-azuretools.vscode-docker"
],
Comment on lines +14 to +30

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

此处的 VS Code 扩展列表与 .vscode/extensions.json 中的推荐列表不完全一致。为了提供真正统一的开发体验,建议保持这两个列表同步。例如,eamodio.gitlensstreetsidesoftware.code-spell-checker 存在于 extensions.json 但此处缺失。同时,styled-components.vscode-styled-components 在此列表中,但不在 extensions.json 中。请考虑统一这些配置。


"settings": {
"editor.defaultFormatter": "biomejs.biome",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"quickfix.biome": "explicit",
"source.organizeImports.biome": "explicit"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/**": true,
"**/.next/**": true,
"**/.turbo/**": true,
"**/dist/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/.next": true,
"**/.turbo": true,
"**/dist": true,
"pnpm-lock.yaml": true
},
"sqltools.connections": [
{
"name": "Nomad Development DB",
"driver": "PostgreSQL",
"previewLimit": 50,
"server": "postgres",
"port": 5432,
"database": "${containerEnv:POSTGRES_DB:nomad_dev}",
"username": "${containerEnv:POSTGRES_USER:nomad}",
"password": "${containerEnv:POSTGRES_PASSWORD:nomad_dev_password}"
},
{
"name": "Nomad Test DB",
"driver": "PostgreSQL",
"previewLimit": 50,
"server": "postgres",
"port": 5432,
"database": "nomad_test",
"username": "${containerEnv:POSTGRES_USER:nomad}",
"password": "${containerEnv:POSTGRES_PASSWORD:nomad_dev_password}"
}
]
}
}
},

"forwardPorts": [3000, 3001, 3002, 5432, 6006, 6007],

"portsAttributes": {
"3000": {
"label": "Web App",
"onAutoForward": "notify"
},
"3001": {
"label": "Documentation",
"onAutoForward": "silent"
},
"3002": {
"label": "Demo (Remotion)",
"onAutoForward": "silent"
},
"5432": {
"label": "PostgreSQL",
"onAutoForward": "silent"
},
"6006": {
"label": "Storybook",
"onAutoForward": "silent"
},
"6007": {
"label": "React Email",
"onAutoForward": "silent"
}
},

"postCreateCommand": "bash .devcontainer/init-scripts/postCreateCommand.sh",
"postStartCommand": "bash .devcontainer/init-scripts/postStartCommand.sh",

"remoteUser": "node",

"containerEnv": {
"NODE_ENV": "development"
},

"mounts": [
"source=nomad-pnpm-store,target=/pnpm/store,type=volume",
"source=nomad-node-modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
]
}
80 changes: 80 additions & 0 deletions .devcontainer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
services:
app:
build:
context: .
dockerfile: Dockerfile
args:
NODE_VERSION: 22
PNPM_VERSION: 10.17.1

volumes:
- ..:/workspace:cached
- nomad-pnpm-store:/pnpm/store
- nomad-node-modules:/workspace/node_modules
- nomad-turbo-cache:/workspace/.turbo

command: sleep infinity

environment:
- NODE_ENV=development
- DATABASE_URL=postgresql://${POSTGRES_USER:-nomad}:${POSTGRES_PASSWORD:-nomad_dev_password}@postgres:5432/${POSTGRES_DB:-nomad_dev}
- DATABASE_URL_TEST=postgresql://${POSTGRES_USER:-nomad}:${POSTGRES_PASSWORD:-nomad_dev_password}@postgres:5432/nomad_test
- BETTER_AUTH_URL=http://localhost:3000
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-dev_secret_key_change_in_production_32_chars_minimum}
- LOG_LEVEL=${LOG_LEVEL:-debug}
- ENABLE_ALIYUN_SMS=${ENABLE_ALIYUN_SMS:-disabled}
- ENABLE_RESEND=${ENABLE_RESEND:-disabled}
- NEXT_PUBLIC_TURNSTILE_SITE_KEY=1x00000000000000000000AA
- TURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA
- RESEND_FROM_EMAIL=onboarding@resend.dev
- DATABASE_SSL=false

depends_on:
postgres:
condition: service_healthy

networks:
- nomad-network

user: node

postgres:
image: postgres:15-alpine
restart: unless-stopped

volumes:
- nomad-postgres-data:/var/lib/postgresql/data
- ./init-scripts/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro

environment:
POSTGRES_USER: ${POSTGRES_USER:-nomad}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-nomad_dev_password}
POSTGRES_DB: ${POSTGRES_DB:-nomad_dev}
POSTGRES_INITDB_ARGS: "--encoding=UTF8 --locale=C"

healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-nomad} -d ${POSTGRES_DB:-nomad_dev}"]
interval: 10s
timeout: 5s
retries: 5

networks:
- nomad-network

ports:
- "5432:5432"

volumes:
nomad-pnpm-store:
name: nomad-pnpm-store
nomad-node-modules:
name: nomad-node-modules
nomad-turbo-cache:
name: nomad-turbo-cache
nomad-postgres-data:
name: nomad-postgres-data

networks:
nomad-network:
name: nomad-network
driver: bridge
10 changes: 10 additions & 0 deletions .devcontainer/init-scripts/init-db.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash
set -e

# Create test database
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
CREATE DATABASE nomad_test;
GRANT ALL PRIVILEGES ON DATABASE nomad_test TO $POSTGRES_USER;
EOSQL

echo "Test database 'nomad_test' created successfully"
106 changes: 106 additions & 0 deletions .devcontainer/init-scripts/postCreateCommand.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/bash
set -e

echo "Initializing Nomad development environment..."

# Display environment information
echo "Node.js version: $(node --version)"
echo "pnpm version: $(pnpm --version)"

# ============================================================================
# CI Environment Detection
# ============================================================================
# In CI environments (like GitHub Actions), we completely skip postCreateCommand
# to avoid timeout issues during container startup. The devcontainers/ci tool
# expects postCreateCommand to complete quickly, but even a basic "pnpm install"
# can take several minutes on first run.
#
# Solution:
# - In CI: postCreateCommand does nothing (instant return)
# - All setup steps (including dependency installation) are handled explicitly
# in the GitHub workflow's runCmd section for better control and visibility
#
# Benefits:
# - Reliable container startup in CI (no timeouts)
# - Complete visibility of all validation steps in workflow logs
# - Fine-grained control over each step's execution
# ============================================================================
if [ "$CI" = "true" ]; then
echo "CI environment detected - Skipping postCreateCommand"
echo "All setup steps will be handled by the CI workflow's runCmd"
exit 0
fi

# ============================================================================
# Full Development Environment Setup (Local Development Only)
# ============================================================================
# The following steps are only executed in local development environments
# to provide a complete, ready-to-use setup.
# ============================================================================

# Install dependencies
echo "Installing dependencies..."
pnpm install --frozen-lockfile

# Wait for database to be ready
echo "Waiting for PostgreSQL to be ready..."
until pg_isready -h postgres -U nomad -d nomad_dev > /dev/null 2>&1; do
echo "Waiting for database..."
sleep 2
done
echo "Database is ready!"

# Initialize development database
echo "Initializing development database..."
cd /workspace/apps/web
pnpm db:push

# Seed development database (optional)
echo "Seeding development database..."
pnpm db:seed || echo "Warning: Seeding failed or skipped"

# Initialize test database
echo "Initializing test database..."
export NODE_ENV=test
export DATABASE_URL=postgresql://nomad:nomad_dev_password@postgres:5432/nomad_test
pnpm db:push || echo "Warning: Test DB initialization failed"

# Install Playwright browsers
echo "Installing Playwright browsers..."
cd /workspace/apps/web
Comment thread
ukeSJTU marked this conversation as resolved.
pnpm exec playwright install chromium --with-deps || echo "Warning: Playwright installation failed"

# Create local environment variable file if it doesn't exist
cd /workspace/apps/web
Comment thread
ukeSJTU marked this conversation as resolved.
if [ ! -f .env.local ]; then
echo "Creating .env.local for development..."
cat > .env.local << 'EOF'
# Local development overrides
# This file is automatically created by devcontainer

# Database (managed by Docker Compose)
DATABASE_URL=postgresql://nomad:nomad_dev_password@postgres:5432/nomad_dev

# Auth (development defaults)
BETTER_AUTH_SECRET=dev_secret_key_change_in_production_32_chars_minimum

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

此处为 BETTER_AUTH_SECRET 设置的默认值与 docker-compose.yml 文件中的默认值 (dev_secret_key_change_in_production_32_chars_min) 不一致。为了避免潜在的混淆和错误,建议保持两者一致。

Suggested change
BETTER_AUTH_SECRET=dev_secret_key_change_in_production_32_chars_minimum
BETTER_AUTH_SECRET=dev_secret_key_change_in_production_32_chars_min

BETTER_AUTH_URL=http://localhost:3000

# Features (disabled by default in dev)
ENABLE_ALIYUN_SMS=disabled
ENABLE_RESEND=disabled

# Logging
LOG_LEVEL=debug
EOF
fi

# Return to workspace root
cd /workspace

echo ""
echo "Setup complete! You can now:"
echo " - Run 'pnpm dev' to start all applications"
echo " - Run 'pnpm web:dev' to start only the web app"
echo " - Run 'pnpm web:test' to run tests"
echo " - Open http://localhost:3000 to view the app"
echo ""
Loading
Loading