Skip to content

Commit 00334e5

Browse files
authored
feat(ci): socket realtime image for hosting (#565)
* feat: socket server for self/local deployment * ci: memory limit and redundant dependency install * chore: update readme, devcontainer, cli package * chore: add new dev scripts and update README for full development setup
1 parent 0049644 commit 00334e5

10 files changed

Lines changed: 187 additions & 4 deletions

File tree

.devcontainer/Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,5 @@ WORKDIR /workspace
3838

3939
# Expose the ports we're interested in
4040
EXPOSE 3000
41-
EXPOSE 3001
41+
EXPOSE 3001
42+
EXPOSE 3002

.devcontainer/docker-compose.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ services:
1717
depends_on:
1818
db:
1919
condition: service_healthy
20+
realtime:
21+
condition: service_healthy
2022
migrations:
2123
condition: service_completed_successfully
2224
ports:
@@ -30,6 +32,29 @@ services:
3032
retries: 3
3133
start_period: 10s
3234

35+
realtime:
36+
build:
37+
context: ..
38+
dockerfile: .devcontainer/Dockerfile
39+
command: sleep infinity
40+
environment:
41+
- NODE_ENV=development
42+
- DATABASE_URL=postgresql://postgres:postgres@db:5432/simstudio
43+
- BETTER_AUTH_URL=http://localhost:3000
44+
- NEXT_PUBLIC_APP_URL=http://localhost:3000
45+
depends_on:
46+
db:
47+
condition: service_healthy
48+
ports:
49+
- "3002:3002"
50+
working_dir: /workspace
51+
healthcheck:
52+
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3002']
53+
interval: 90s
54+
timeout: 5s
55+
retries: 3
56+
start_period: 10s
57+
3358
migrations:
3459
build:
3560
context: ..

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ jobs:
1616
image: ghcr.io/simstudioai/simstudio
1717
- dockerfile: ./docker/db.Dockerfile
1818
image: ghcr.io/simstudioai/migrations
19+
- dockerfile: ./docker/realtime.Dockerfile
20+
image: ghcr.io/simstudioai/realtime
1921
permissions:
2022
contents: read
2123
packages: write

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ docker compose -f docker-compose.prod.yml up -d
8686

8787
1. Open VS Code with the [Remote - Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers)
8888
2. Open the project and click "Reopen in Container" when prompted
89-
3. Run `bun run dev` in the terminal or use the `sim-start` alias
89+
3. Run `bun run dev:full` in the terminal or use the `sim-start` alias
9090

9191
### Option 4: Manual Setup
9292

@@ -111,12 +111,26 @@ cp .env.example .env # Configure with required variables (DATABASE_URL, BETTER_
111111
bunx drizzle-kit push
112112
```
113113

114-
4. Start the development server:
114+
4. Start the development servers:
115+
116+
Next.js app:
115117

116118
```bash
117119
bun run dev
118120
```
119121

122+
Start the realtime server:
123+
124+
```bash
125+
bun run dev:sockets
126+
```
127+
128+
Run both together (recommended):
129+
130+
```bash
131+
bun run dev:full
132+
```
133+
120134
## Tech Stack
121135

122136
- **Framework**: [Next.js](https://nextjs.org/) (App Router)
@@ -128,6 +142,7 @@ bun run dev
128142
- **Flow Editor**: [ReactFlow](https://reactflow.dev/)
129143
- **Docs**: [Fumadocs](https://fumadocs.vercel.app/)
130144
- **Monorepo**: [Turborepo](https://turborepo.org/)
145+
- **Realtime**: [Socket.io](https://socket.io/)
131146

132147
## Contributing
133148

apps/sim/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"dev": "next dev --turbo --port 3000",
1313
"dev:classic": "next dev",
1414
"dev:sockets": "bun run socket-server/index.ts",
15-
"dev:full": "concurrently \"bun run dev\" \"bun run dev:sockets\"",
15+
"dev:full": "concurrently -n \"NextJS,Realtime\" -c \"cyan,magenta\" \"bun run dev\" \"bun run dev:sockets\"",
1616
"build": "next build",
1717
"start": "next start",
1818
"prepare": "cd ../.. && bun husky",

docker-compose.local.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,47 @@ services:
2222
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-placeholder}
2323
- RESEND_API_KEY=${RESEND_API_KEY:-placeholder}
2424
- OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434}
25+
- SOCKET_SERVER_URL=${SOCKET_SERVER_URL:-http://localhost:3002}
2526
depends_on:
2627
db:
2728
condition: service_healthy
2829
migrations:
2930
condition: service_completed_successfully
31+
realtime:
32+
condition: service_healthy
3033
healthcheck:
3134
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3000']
3235
interval: 90s
3336
timeout: 5s
3437
retries: 3
3538
start_period: 10s
3639

40+
realtime:
41+
build:
42+
context: .
43+
dockerfile: docker/realtime.Dockerfile
44+
environment:
45+
- DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-simstudio}
46+
- NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
47+
- BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:3000}
48+
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-your_auth_secret_here}
49+
depends_on:
50+
db:
51+
condition: service_healthy
52+
restart: unless-stopped
53+
ports:
54+
- '3002:3002'
55+
deploy:
56+
resources:
57+
limits:
58+
memory: 8G
59+
healthcheck:
60+
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3002']
61+
interval: 90s
62+
timeout: 5s
63+
retries: 3
64+
start_period: 10s
65+
3766
migrations:
3867
build:
3968
context: .

docker-compose.prod.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,45 @@ services:
2121
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-placeholder}
2222
- RESEND_API_KEY=${RESEND_API_KEY:-placeholder}
2323
- OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434}
24+
- SOCKET_SERVER_URL=${SOCKET_SERVER_URL:-http://localhost:3002}
2425
depends_on:
2526
db:
2627
condition: service_healthy
2728
migrations:
2829
condition: service_completed_successfully
30+
realtime:
31+
condition: service_healthy
2932
healthcheck:
3033
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3000']
3134
interval: 90s
3235
timeout: 5s
3336
retries: 3
3437
start_period: 10s
3538

39+
realtime:
40+
image: ghcr.io/simstudioai/realtime:latest
41+
restart: unless-stopped
42+
ports:
43+
- '3002:3002'
44+
deploy:
45+
resources:
46+
limits:
47+
memory: 4G
48+
environment:
49+
- DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-simstudio}
50+
- NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
51+
- BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:3000}
52+
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-your_auth_secret_here}
53+
depends_on:
54+
db:
55+
condition: service_healthy
56+
healthcheck:
57+
test: ['CMD', 'wget', '--spider', '--quiet', 'http://127.0.0.1:3002']
58+
interval: 90s
59+
timeout: 5s
60+
retries: 3
61+
start_period: 10s
62+
3663
migrations:
3764
image: ghcr.io/simstudioai/migrations:latest
3865
environment:

docker/realtime.Dockerfile

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# ========================================
2+
# Base Stage: Alpine Linux with Bun
3+
# ========================================
4+
FROM oven/bun:alpine AS base
5+
6+
# ========================================
7+
# Dependencies Stage: Install Dependencies
8+
# ========================================
9+
FROM base AS deps
10+
RUN apk add --no-cache libc6-compat
11+
WORKDIR /app
12+
13+
# Install turbo globally
14+
RUN bun install -g turbo
15+
16+
COPY package.json bun.lock ./
17+
RUN mkdir -p apps
18+
COPY apps/sim/package.json ./apps/sim/package.json
19+
20+
RUN bun install --omit dev --ignore-scripts
21+
22+
# ========================================
23+
# Builder Stage: Build the Application
24+
# ========================================
25+
FROM base AS builder
26+
WORKDIR /app
27+
28+
COPY --from=deps /app/node_modules ./node_modules
29+
COPY . .
30+
31+
# ========================================
32+
# Runner Stage: Run the Socket Server
33+
# ========================================
34+
FROM base AS runner
35+
WORKDIR /app
36+
37+
ENV NODE_ENV=production
38+
39+
# Copy the entire sim app since socket-server has dependencies on other modules
40+
COPY --from=builder /app/apps/sim ./apps/sim
41+
COPY --from=builder /app/node_modules ./node_modules
42+
COPY --from=builder /app/package.json ./package.json
43+
44+
# Expose socket server port (default 3002, but configurable via PORT env var)
45+
EXPOSE 3002
46+
ENV PORT=3002 \
47+
SOCKET_PORT=3002 \
48+
HOSTNAME="0.0.0.0"
49+
50+
# Run the socket server directly
51+
CMD ["bun", "apps/sim/socket-server/index.ts"]

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"scripts": {
1212
"build": "turbo run build",
1313
"dev": "turbo run dev",
14+
"dev:sockets": "cd apps/sim && bun run dev:sockets",
15+
"dev:full": "cd apps/sim && bun run dev:full",
1416
"test": "turbo run test",
1517
"format": "bunx biome format --write .",
1618
"format:check": "bunx biome format .",

packages/cli/src/index.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Command } from 'commander'
1111
const NETWORK_NAME = 'simstudio-network'
1212
const DB_CONTAINER = 'simstudio-db'
1313
const MIGRATIONS_CONTAINER = 'simstudio-migrations'
14+
const REALTIME_CONTAINER = 'simstudio-realtime'
1415
const APP_CONTAINER = 'simstudio-app'
1516
const DEFAULT_PORT = '3000'
1617

@@ -78,6 +79,7 @@ async function cleanupExistingContainers(): Promise<void> {
7879
await stopAndRemoveContainer(APP_CONTAINER)
7980
await stopAndRemoveContainer(DB_CONTAINER)
8081
await stopAndRemoveContainer(MIGRATIONS_CONTAINER)
82+
await stopAndRemoveContainer(REALTIME_CONTAINER)
8183
}
8284

8385
async function main() {
@@ -101,6 +103,7 @@ async function main() {
101103
if (options.pull) {
102104
await pullImage('ghcr.io/simstudioai/simstudio:latest')
103105
await pullImage('ghcr.io/simstudioai/migrations:latest')
106+
await pullImage('ghcr.io/simstudioai/realtime:latest')
104107
await pullImage('pgvector/pgvector:pg17')
105108
}
106109

@@ -193,6 +196,34 @@ async function main() {
193196
process.exit(1)
194197
}
195198

199+
// Start the realtime server
200+
console.log(chalk.blue('🔄 Starting Realtime Server...'))
201+
const realtimeSuccess = await runCommand([
202+
'docker',
203+
'run',
204+
'-d',
205+
'--name',
206+
REALTIME_CONTAINER,
207+
'--network',
208+
NETWORK_NAME,
209+
'-p',
210+
'3002:3002',
211+
'-e',
212+
`DATABASE_URL=postgresql://postgres:postgres@${DB_CONTAINER}:5432/simstudio`,
213+
'-e',
214+
`BETTER_AUTH_URL=http://localhost:${port}`,
215+
'-e',
216+
`NEXT_PUBLIC_APP_URL=http://localhost:${port}`,
217+
'-e',
218+
'BETTER_AUTH_SECRET=your_auth_secret_here',
219+
'ghcr.io/simstudioai/realtime:latest',
220+
])
221+
222+
if (!realtimeSuccess) {
223+
console.error(chalk.red('❌ Failed to start Realtime Server'))
224+
process.exit(1)
225+
}
226+
196227
// Start the main application
197228
console.log(chalk.blue('🔄 Starting Sim Studio...'))
198229
const appSuccess = await runCommand([

0 commit comments

Comments
 (0)