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
85 changes: 85 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Use official VS Code devcontainer Node.js image as base (updated to Node 20 for NestJS requirements)
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:20-bullseye

# Install system dependencies and development tools
RUN apt-get update && apt-get install -y \
# Build tools for native dependencies
build-essential \
python3 \
python3-pip \
# Git for version control
git \
# Utilities
curl \
wget \
vim \
nano \
jq \
sudo \
# Docker CLI for integration tests
ca-certificates \
gnupg \
lsb-release \
# Clean up
&& rm -rf /var/lib/apt/lists/*

# Install Docker CLI
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce-cli docker-compose-plugin \
&& rm -rf /var/lib/apt/lists/*

# Install global npm packages for development
RUN npm install -g \
# TypeScript tooling
typescript \
ts-node \
nodemon \
# Testing tools
mocha \
nyc \
# Linting and formatting
eslint \
prettier \
# Development utilities
concurrently \
cross-env \
# Package management
lerna \
# Build tools
gulp-cli

# Set npm configuration for NestJS
RUN npm config set legacy-peer-deps true

# Create non-root user with proper permissions
ARG USERNAME=node
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Ensure node user has the correct UID/GID
RUN groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME

# Add node user to docker group for Docker socket access
RUN groupadd docker || true \
&& usermod -aG docker $USERNAME \
&& echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

# Set working directory
WORKDIR /workspace

# Create node_modules directory with proper permissions as root
RUN mkdir -p /workspace/node_modules \
&& chown -R $USER_UID:$USER_GID /workspace

# Switch to node user for development
USER $USERNAME

# Create directories for development (will be done by post-create script)
RUN mkdir -p /home/$USERNAME/.vscode-server

# Default command (will be overridden by docker-compose)
CMD ["bash"]
138 changes: 138 additions & 0 deletions .devcontainer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# NestJS Development Container

This development container provides a complete, pre-configured environment for NestJS development with all necessary dependencies, services, and VS Code extensions.

## What's Included

### Development Environment
- **Node.js 20 LTS** with npm configured for legacy peer dependencies (meets requirement >= 10.13.0)
- **TypeScript** and related development tools
- **Docker CLI** for containerized services
- **GitHub CLI** for seamless GitHub integration

### VS Code Extensions
- TypeScript and JavaScript language support
- Code formatting with Prettier
- Linting with ESLint
- Testing integration with Mocha
- Docker support for container management
- Git enhancement with GitLens
- Markdown support for documentation

### Integration Services
- **Redis** (port 16379) - Caching and session storage
- **NATS** (ports 14223, 16222, 18222) - Message broker with monitoring
- **MySQL** (port 13306) - Primary database for testing
- **MQTT/Mosquitto** (ports 11883, 19001) - IoT messaging with WebSocket support

## Getting Started

1. **Open in Dev Container**: VS Code will prompt to reopen in container when opening this repository
2. **Wait for Setup**: The container will automatically install dependencies and build packages
3. **Services will start automatically**: Integration services (Redis, NATS, etc.) start during setup
4. **Start Development**: All services will be available and ready for development

**Note**: Integration services start after the main container is ready, not during container creation. This ensures reliable startup.

## Available Commands

### Build and Test
```bash
npm run build # Build all packages
npm run build:prod # Build packages near source files
npm test # Run unit tests
npm run test:integration # Run integration tests
npm run lint # Run ESLint
npm run format # Format code with Prettier
```

### Development
```bash
npm run prepare # Setup development environment
sh scripts/prepare.sh # Alternative: run prepare script directly
npm start # Start sample application
```

### Services
```bash
npm run test:docker:up # Start integration services
npm run test:docker:down # Stop integration services
```

### Integration Testing
```bash
npm run test:integration # Run integration tests
sh scripts/run-integration.sh # Alternative: run integration script directly
```

## Port Forwarding

The following ports are automatically forwarded for easy access:
- **3000-3010**: Sample applications
- **8080-8082**: Additional development servers
- **16379**: Redis
- **14223, 16222, 18222**: NATS services
- **11883, 19001**: MQTT services
- **13306**: MySQL

## Troubleshooting

### Permission Issues
If you encounter permission issues:
```bash
sudo chown -R node:node /workspace
```

### Missing Dependencies
If dependencies are missing:
```bash
npm install --legacy-peer-deps
```

### Services Not Starting
To manually start integration services:
```bash
npm run test:docker:up
```

### Container Creation Issues
If you see errors about mounting files or directories, this usually means:
1. A file/directory referenced in docker-compose.yml doesn't exist
2. VS Code may be trying to mount a non-existent configuration file

To fix:
1. Check that all referenced files exist
2. Rebuild the devcontainer: `Ctrl+Shift+P` → "Dev Containers: Rebuild Container"

## Container Configuration

- **Base Image**: `mcr.microsoft.com/vscode/devcontainers/typescript-node:20-bullseye`
- **User**: `node` (UID 1000)
- **Workspace**: `/workspace`
- **Docker**: Docker-in-Docker enabled for integration testing

## Contributing

This devcontainer is designed to provide a consistent development environment for all contributors. If you need additional tools or services, please update the configuration files and test thoroughly before submitting changes.

### Testing the DevContainer

To validate that the devcontainer works correctly, you can run:

```bash
# Quick smoke test (2-3 minutes)
./.devcontainer/smoke-test.sh

# Full validation test (5-10 minutes)
./.devcontainer/validate-devcontainer.sh
```

These tests verify:
- ✅ Node.js, npm, and TypeScript are working
- ✅ Package installation and building
- ✅ Docker services are running
- ✅ Unit tests can execute
- ✅ Code quality tools (ESLint, Prettier) are functional
- ✅ Integration test setup is ready

For more information about contributing to NestJS, see [CONTRIBUTING.md](../CONTRIBUTING.md).
166 changes: 166 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
{
"name": "NestJS Development Environment",
"dockerComposeFile": ["docker-compose.yml"],
"service": "devcontainer",
"workspaceFolder": "/workspace",
"remoteUser": "node",
"updateRemoteUserUID": true,

"customizations": {
"vscode": {
"extensions": [
"ms-vscode.vscode-typescript-next",
"ms-vscode.vscode-json",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-npm-script",
"christian-kohler.npm-intellisense",
"leizongmin.node-module-intellisense",
"christian-kohler.path-intellisense",
"formulahendry.auto-rename-tag",
"bradlc.vscode-tailwindcss",
"hbenl.vscode-test-explorer",
"hbenl.vscode-mocha-test-adapter",
"ms-azuretools.vscode-docker",
"eamodio.gitlens",
"yzhang.markdown-all-in-one"
],

"settings": {
"typescript.updateImportsOnFileMove.enabled": "always",
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.suggest.autoImports": true,
"typescript.suggest.completeFunctionCalls": true,
"typescript.workspaceSymbols.scope": "allOpenProjects",

"editor.rulers": [100],
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "explicit"
},

"prettier.configPath": ".prettierrc",
"prettier.ignorePath": ".prettierignore",
"prettier.requireConfig": true,

"eslint.workingDirectories": [
"./packages",
"./integration",
"./sample"
],
"eslint.validate": ["javascript", "typescript"],

"files.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/.nyc_output": true,
"**/coverage": true
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/.nyc_output": true,
"**/coverage": true
},

"docker.composeCommand": "docker-compose",
"docker.dockerComposeDetached": true,
"docker.environment": {},
"docker.dockerPath": "docker",
"docker.explorerRefreshInterval": 2000,
"docker.showExplorer": false,

"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.env.linux": {
"NODE_ENV": "development"
},

"mochaExplorer.files": [
"packages/**/*.spec.ts",
"integration/**/*.spec.ts"
],
"mochaExplorer.env": {
"NODE_ENV": "test"
},

"git.confirmSync": false,
"git.enableSmartCommit": true,
"git.autofetch": true,

"npm.enableRunFromFolder": true,
"npm.packageManager": "npm",
"emmet.includeLanguages": {
"typescript": "html",
"javascript": "html"
}
}
}
},

"forwardPorts": [
3000, 3001, 3002, 3003, 3004, 3005, 3006, 3007, 3008, 3009, 3010, 8080,
8081, 8082, 14223, 16222, 18222, 16379, 11883, 19001, 13306
],

"portsAttributes": {
"3000": {
"label": "Main Application",
"onAutoForward": "notify"
},
"14223": {
"label": "NATS",
"onAutoForward": "silent"
},
"16222": {
"label": "NATS Cluster",
"onAutoForward": "silent"
},
"18222": {
"label": "NATS HTTP",
"onAutoForward": "silent"
},
"16379": {
"label": "Redis",
"onAutoForward": "silent"
},
"11883": {
"label": "MQTT",
"onAutoForward": "silent"
},
"19001": {
"label": "MQTT WebSocket",
"onAutoForward": "silent"
},
"13306": {
"label": "MySQL",
"onAutoForward": "silent"
}
},

"postCreateCommand": "bash .devcontainer/scripts/post-create.sh",

"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"enableNonRootDocker": "true"
},
"ghcr.io/devcontainers/features/github-cli:1": {
"version": "latest"
}
},

"mounts": [
"source=/var/run/docker.sock,target=/var/run/docker-host.sock,type=bind"
],

"containerEnv": {
"NODE_ENV": "development",
"npm_config_legacy_peer_deps": "true",
"DOCKER_HOST": "unix:///var/run/docker-host.sock"
}
}
Loading