Skip to content
This repository was archived by the owner on Feb 15, 2026. It is now read-only.

Commit cfd01b8

Browse files
committed
Merge remote-tracking branch 'origin/next' into next
2 parents 0d09f7d + 718329e commit cfd01b8

14 files changed

Lines changed: 1854 additions & 1065 deletions

File tree

.dockerignore

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Git
2+
.git
3+
.gitignore
4+
.github
5+
6+
# Dependencies
7+
node_modules
8+
9+
# Build outputs
10+
build
11+
.svelte-kit
12+
dist
13+
14+
# Data directories
15+
pgdata
16+
redis-data
17+
logs
18+
# Environment
19+
.env
20+
.env.*
21+
!.env.example
22+
23+
# Debug logs
24+
npm-debug.log*
25+
yarn-debug.log*
26+
yarn-error.log*
27+
pnpm-debug.log*
28+
29+
# OS
30+
.DS_Store
31+
Thumbs.db
32+
33+
# IDE
34+
.vscode
35+
.idea
36+
*.swp
37+
*.swo
38+
39+
# Docker
40+
Dockerfile
41+
docker-compose*
42+
.dockerignore
43+
44+
# Documentation
45+
README.md
46+
readme.md
47+
LICENSE
48+
licence
49+
50+
# Tests
51+
**/*.test.ts
52+
**/*.spec.ts
53+
**/__tests__
54+
**/__mocks__

.env.example

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,60 @@
1-
SALT=***
2-
SERVER_KEY=***
3-
RATELIMIT_BYPASS_IPS="***,***,***"
4-
RATELIMIT_BYPASS_USERIDS="***,***,***"
1+
# === REQUIRED (Change before running in production) ===
2+
# `SALT`: MUST be changed before deployment. Must be at least 32 characters and generated
3+
# with a cryptographically secure random generator.
4+
# Example: `openssl rand -hex 32`
5+
SALT='CHANGE_ME_SALT_generate_with_openssl_rand_hex_32'
6+
7+
# `SERVER_KEY`: secret key used for server-to-server auth. MUST be changed before deployment.
8+
# Generate a long random value (32+ bytes of hex) with a cryptographically secure generator.
9+
# Example: `openssl rand -hex 32`
10+
SERVER_KEY='CHANGE_ME_SERVER_KEY_generate_with_openssl_rand_hex_32'
11+
12+
# Optional rate-limit bypass lists (comma-separated)
13+
RATELIMIT_BYPASS_IPS=""
14+
RATELIMIT_BYPASS_USERIDS="1"
15+
16+
# === DATABASE (Change for your environment) ===
517
# PostgreSQL DB 설정
6-
POSTGRESQL_HOST=***
7-
POSTGRESQL_PORT=***
8-
POSTGRESQL_USER=***
9-
POSTGRESQL_PASSWORD='***'
10-
POSTGRESQL_NAME=***
11-
POSTGRESQL_MAX_CONNS=***
12-
POSTGRESQL_CONN_MAX_LIFETIME=***
13-
POSTGRESQL_CONN_MAX_IDLE_TIME=***
14-
POSTGRESQL_SSL=require
18+
POSTGRESQL_HOST=postgres
19+
POSTGRESQL_PORT=5432
20+
# `POSTGRESQL_USER`: DB username
21+
POSTGRESQL_USER=postgres
22+
# `POSTGRESQL_PASSWORD`: DB password (REQUIRED if not using trust)
23+
POSTGRESQL_PASSWORD=postgres
24+
# `POSTGRESQL_NAME`: database name
25+
POSTGRESQL_NAME=pjsedb
26+
# `POSTGRESQL_SSL`: set to 'disable' for local docker; use 'require' in production if supported
27+
POSTGRESQL_SSL=disable
28+
1529
# Redis 설정
16-
REDIS_HOST=***
17-
REDIS_PORT=***
18-
REDIS_USERNAME=***
19-
REDIS_PASSWORD='***'
30+
REDIS_HOST=redis
31+
REDIS_PORT=6379
32+
REDIS_USERNAME=default
33+
# `REDIS_PASSWORD`: MUST be set to a strong random value in production if your Redis requires AUTH.
34+
# Example: `openssl rand -hex 32`. Do NOT use any example or default password in production.
35+
REDIS_PASSWORD=""
2036
REDIS_DB=0
21-
REDIS_TLS=true
22-
# 서버 설정
37+
REDIS_TLS=false
38+
39+
# Server settings
40+
# `HOST`/`PORT`: server listen address and port
2341
HOST=0.0.0.0
24-
ORIGIN="http://localhost:5173"
25-
PORT=4000
26-
ID=1
42+
PORT=8000
43+
# `ORIGIN`: application origin used for CSRF/trusted origins
44+
ORIGIN="http://localhost:8000"
2745
CLOUDFLARED_TUNNEL=false
2846
ALLOW_TEST_PAGE=true
29-
ALLOW_REGISTER=true
3047
SYS_LOG=true
3148
SYS_LOG_STDOUT=true
3249
SYS_LOG_LOCATION=./logs
33-
# 이메일 설정
34-
SMTP_HOST=***
35-
SMTP_FROM=***
36-
SMTP_USERNAME=***
37-
SMTP_PASSWORD="***"
50+
51+
# Email (optional): fill these only if you want email features (recovery/confirmations)
52+
SMTP_HOST=
53+
SMTP_FROM=
54+
SMTP_USERNAME=
55+
SMTP_PASSWORD=""
3856
SMTP_SECURITY=force_tls
39-
SMTP_PORT=***
57+
SMTP_PORT=
58+
# 리버스 프록시 설정
59+
#ADDRESS_HEADER=X-Forwarded-For
60+
#XFF_DEPTH=1

.github/workflows/workflow.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: workflow.yml
2+
3+
on:
4+
push:
5+
branches:
6+
- next
7+
- feat/**
8+
- release/**
9+
paths-ignore:
10+
- 'readme.md'
11+
- 'readme.*'
12+
- 'docker-compose*'
13+
- 'docs/**'
14+
- 'licence'
15+
16+
jobs:
17+
build-and-push:
18+
runs-on: ubuntu-latest
19+
permissions:
20+
contents: read
21+
packages: write
22+
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
27+
- name: Set up QEMU
28+
uses: docker/setup-qemu-action@v3
29+
30+
- name: Set up Docker Buildx
31+
uses: docker/setup-buildx-action@v3
32+
33+
- name: Login to GHCR
34+
uses: docker/login-action@v3
35+
with:
36+
registry: ghcr.io
37+
username: ${{ github.actor }}
38+
password: ${{ secrets.GITHUB_TOKEN }}
39+
40+
- name: Build and Push Docker Image
41+
uses: docker/build-push-action@v6
42+
with:
43+
context: .
44+
platforms: linux/amd64
45+
target: runtime
46+
push: true
47+
tags: |
48+
ghcr.io/${{ github.repository_owner }}/pjs2:latest
49+
ghcr.io/${{ github.repository_owner }}/pjs2:${{ github.sha }}
50+
cache-from: type=gha
51+
cache-to: type=gha,mode=max

Dockerfile

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
FROM node:25.2.1-alpine AS builder
2+
WORKDIR /usr/src/app
3+
4+
RUN apk update && apk upgrade --no-cache
5+
6+
RUN apk add --no-cache \
7+
ca-certificates \
8+
postgresql-client \
9+
python3 \
10+
make \
11+
g++ \
12+
gcc \
13+
musl-dev \
14+
openssl-dev \
15+
pkgconfig
16+
17+
COPY package.json package-lock.json* ./
18+
RUN --mount=type=cache,target=/root/.npm \
19+
if [ -f package-lock.json ]; then npm ci --no-audit --prefer-offline; \
20+
else npm install --no-audit --prefer-offline; fi
21+
22+
COPY . .
23+
24+
ENV POSTGRESQL_HOST=127.0.0.1
25+
ENV POSTGRESQL_PORT=5432
26+
ENV POSTGRESQL_USER=postgres
27+
ENV POSTGRESQL_PASSWORD=postgres
28+
ENV POSTGRESQL_NAME=pjsedb
29+
ENV POSTGRESQL_SSL=disable
30+
ENV SALT='super-secret-salt-at-least-32-characters-long-0000'
31+
ENV SERVER_KEY='super-secret-server-key-000000000000'
32+
33+
ENV NODE_ENV=production
34+
RUN npm run prepare || true
35+
RUN npm run drizzle:generate
36+
RUN npm run build
37+
38+
FROM node:25.2.1-alpine AS runtime
39+
WORKDIR /usr/src/app
40+
41+
RUN apk update && apk upgrade --no-cache
42+
43+
RUN apk add --no-cache \
44+
ca-certificates \
45+
libstdc++ \
46+
postgresql-client \
47+
su-exec
48+
49+
COPY --from=builder /usr/src/app/package.json ./
50+
COPY --from=builder /usr/src/app/package-lock.json ./
51+
52+
RUN apk add --no-cache --virtual .build-deps make g++ gcc musl-dev openssl-dev python3 \
53+
&& if [ -f package-lock.json ]; then npm ci --omit=dev --no-audit --no-fund; \
54+
else npm install --production --no-audit --no-fund; fi \
55+
&& npm cache clean --force \
56+
&& rm -rf /tmp/* /root/.npm \
57+
&& apk del .build-deps
58+
59+
COPY --from=builder --chown=node:node /usr/src/app/build ./build
60+
COPY --from=builder --chown=node:node /usr/src/app/docker-entrypoint.sh ./docker-entrypoint.sh
61+
COPY --from=builder --chown=node:node /usr/src/app/.env.example ./.env.example
62+
COPY --from=builder --chown=node:node /usr/src/app/exchanges ./exchanges
63+
COPY --from=builder --chown=node:node /usr/src/app/drizzle ./drizzle
64+
65+
RUN chmod +x /usr/src/app/docker-entrypoint.sh
66+
67+
EXPOSE 8000
68+
69+
RUN mkdir -p /usr/src/app/logs && chown -R node:node /usr/src/app/logs
70+
71+
ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh"]
72+
CMD ["node", "build"]

FixList

Lines changed: 0 additions & 1 deletion
This file was deleted.

docker-entrypoint.sh

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/bin/sh
2+
3+
set -e
4+
5+
if [ "$(id -u)" = "0" ]; then
6+
echo "Running as root, fixing volume permissions..."
7+
8+
if [ -d /usr/src/app/logs ]; then
9+
echo "Fixing permissions for /usr/src/app/logs"
10+
if ! chown -R node:node /usr/src/app/logs; then
11+
echo "Warning: Could not change ownership of /usr/src/app/logs" >&2
12+
fi
13+
fi
14+
15+
if [ -d /var/lib/postgresql/data ]; then
16+
echo "Fixing permissions for /var/lib/postgresql/data"
17+
if ! chown -R node:node /var/lib/postgresql/data; then
18+
echo "Warning: Could not change ownership of /var/lib/postgresql/data" >&2
19+
fi
20+
fi
21+
22+
if [ -d /data/redis ]; then
23+
echo "Fixing permissions for /data/redis"
24+
if ! chown -R node:node /data/redis; then
25+
echo "Warning: Could not change ownership of /data/redis" >&2
26+
fi
27+
fi
28+
29+
echo "Switching to node user with su-exec..."
30+
if command -v su-exec >/dev/null 2>&1; then
31+
exec su-exec node "$0" "$@"
32+
else
33+
echo "ERROR: su-exec not found! Falling back to su"
34+
# shellcheck disable=SC2016
35+
exec su node -s /bin/sh -c 'exec "$0" "$@"' -- "$0" "$@"
36+
fi
37+
fi
38+
39+
# 이하 node 유저로 실행
40+
echo "Running as $(whoami) (UID: $(id -u))"
41+
42+
# PJSe.json 자동 다운로드
43+
PJSe_FILE="/usr/src/app/exchanges/PJSe.json"
44+
DEFAULT_PJSe_URL="https://raw.githubusercontent.com/0ghost0-dev/PJS2/refs/heads/next/exchanges/PJSe.json"
45+
46+
if [ ! -f "$PJSe_FILE" ]; then
47+
echo "PJSe.json not found. Downloading from GitHub..."
48+
mkdir -p /usr/src/app/exchanges
49+
PJSe_URL="${PJSe_CONFIG_URL:-$DEFAULT_PJSe_URL}"
50+
51+
if command -v wget >/dev/null 2>&1; then
52+
wget -q "$PJSe_URL" -O "$PJSe_FILE" || {
53+
echo "Error: Failed to download PJSe.json from $PJSe_URL"
54+
exit 1
55+
}
56+
elif command -v curl >/dev/null 2>&1; then
57+
curl -fsSL "$PJSe_URL" -o "$PJSe_FILE" || {
58+
echo "Error: Failed to download PJSe.json from $PJSe_URL"
59+
exit 1
60+
}
61+
else
62+
echo "Error: Neither wget nor curl available"
63+
exit 1
64+
fi
65+
66+
echo "Successfully downloaded PJSe.json from $PJSe_URL"
67+
else
68+
echo "PJSe.json already exists at $PJSe_FILE"
69+
fi
70+
71+
echo "Waiting for Postgres at ${POSTGRESQL_HOST:-postgres}:${POSTGRESQL_PORT:-5432}..."
72+
until pg_isready -h "${POSTGRESQL_HOST:-postgres}" -p "${POSTGRESQL_PORT:-5432}" -U "${POSTGRESQL_USER:-postgres}" >/dev/null 2>&1; do
73+
sleep 1
74+
done
75+
76+
echo "Postgres is available. Starting app..."
77+
exec "$@"

exchanges/PJSe.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
"logo": "https://example.com/logo.png",
1616
"description": "Project. Stock Exchange is a fictional stock exchange used for demonstration purposes.",
1717
"pre_market_sessions": {
18-
"Monday": { "open": "08:30", "close": "09:00" },
19-
"Tuesday": { "open": "08:30", "close": "09:00" },
20-
"Wednesday": { "open": "08:30", "close": "09:00" },
21-
"Thursday": { "open": "08:30", "close": "09:00" },
22-
"Friday": { "open": "08:30", "close": "09:00" },
23-
"Saturday": { "open": null, "close": null },
18+
"Monday": { "open": "02:00", "close": "09:00" },
19+
"Tuesday": { "open": "02:00", "close": "09:00" },
20+
"Wednesday": { "open": "02:00", "close": "09:00" },
21+
"Thursday": { "open": "02:00", "close": "09:00" },
22+
"Friday": { "open": "02:00", "close": "09:00" },
23+
"Saturday": { "open": "02:00", "close": "10:00" },
2424
"Sunday": { "open": null, "close": null }
2525
},
2626
"regular_trading_sessions": {
@@ -29,16 +29,16 @@
2929
"Wednesday": { "open": "09:00", "close": "15:30" },
3030
"Thursday": { "open": "09:00", "close": "15:30" },
3131
"Friday": { "open": "09:00", "close": "15:30" },
32-
"Saturday": { "open": null, "close": null },
32+
"Saturday": { "open": "10:00", "close": "14:00" },
3333
"Sunday": { "open": null, "close": null }
3434
},
3535
"post_market_sessions": {
36-
"Monday": { "open": "15:30", "close": "16:00" },
37-
"Tuesday": { "open": "15:30", "close": "16:00" },
38-
"Wednesday": { "open": "15:30", "close": "16:00" },
39-
"Thursday": { "open": "15:30", "close": "16:00" },
40-
"Friday": { "open": "15:30", "close": "16:00" },
41-
"Saturday": { "open": null, "close": null },
36+
"Monday": { "open": "15:30", "close": "00:00" },
37+
"Tuesday": { "open": "15:30", "close": "00:00" },
38+
"Wednesday": { "open": "15:30", "close": "00:00" },
39+
"Thursday": { "open": "15:30", "close": "00:00" },
40+
"Friday": { "open": "15:30", "close": "00:00" },
41+
"Saturday": { "open": "14:00", "close": "20:00" },
4242
"Sunday": { "open": null, "close": null }
4343
},
4444
"anniversaries": [{

0 commit comments

Comments
 (0)