Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2df990746 | ||
|
|
77bc174e43 |
@@ -61,7 +61,16 @@ jobs:
|
|||||||
STAGING=".ci/docker/backend"
|
STAGING=".ci/docker/backend"
|
||||||
rm -rf "$STAGING"
|
rm -rf "$STAGING"
|
||||||
mkdir -p "$STAGING/packages/contracts" "$STAGING/backend"
|
mkdir -p "$STAGING/packages/contracts" "$STAGING/backend"
|
||||||
cp package.json package-lock.json "$STAGING/"
|
cp package-lock.json "$STAGING/"
|
||||||
|
node <<'NODE'
|
||||||
|
const fs = require("node:fs")
|
||||||
|
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"))
|
||||||
|
pkg.workspaces = ["packages/*", "backend"]
|
||||||
|
pkg.dependencies = {}
|
||||||
|
pkg.devDependencies = {}
|
||||||
|
delete pkg.scripts
|
||||||
|
fs.writeFileSync(".ci/docker/backend/package.json", `${JSON.stringify(pkg, null, 2)}\n`)
|
||||||
|
NODE
|
||||||
cp packages/contracts/package.json packages/contracts/tsconfig.json "$STAGING/packages/contracts/"
|
cp packages/contracts/package.json packages/contracts/tsconfig.json "$STAGING/packages/contracts/"
|
||||||
cp -R packages/contracts/src "$STAGING/packages/contracts/"
|
cp -R packages/contracts/src "$STAGING/packages/contracts/"
|
||||||
cp backend/package.json backend/tsconfig.json "$STAGING/backend/"
|
cp backend/package.json backend/tsconfig.json "$STAGING/backend/"
|
||||||
@@ -70,6 +79,7 @@ jobs:
|
|||||||
cp -R backend/drizzle "$STAGING/backend/"
|
cp -R backend/drizzle "$STAGING/backend/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ sequenceDiagram
|
|||||||
- **Node.js 22** (как в `Dockerfile.frontend` и `backend/Dockerfile`).
|
- **Node.js 22** (как в `Dockerfile.frontend` и `backend/Dockerfile`).
|
||||||
- **npm** с workspaces; установка из корня: `npm ci` или `npm install`.
|
- **npm** с workspaces; установка из корня: `npm ci` или `npm install`.
|
||||||
- Для нативной сборки `better-sqlite3` на Linux может понадобиться toolchain (`python3`, `make`, `g++`); в Docker-образе backend они уже ставятся.
|
- Для нативной сборки `better-sqlite3` на Linux может понадобиться toolchain (`python3`, `make`, `g++`); в Docker-образе backend они уже ставятся.
|
||||||
|
- Backend Docker-образ ставит только workspaces `backend` + `contracts` (без корневых Next/React deps); в production логи — JSON без `pino-pretty`.
|
||||||
|
|
||||||
### Запуск
|
### Запуск
|
||||||
|
|
||||||
|
|||||||
+19
-2
@@ -5,10 +5,23 @@ RUN apt-get update \
|
|||||||
&& apt-get install -y --no-install-recommends python3 make g++ \
|
&& apt-get install -y --no-install-recommends python3 make g++ \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
# Do not set NODE_ENV=production here — npm would omit typescript needed for the build stage.
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
COPY packages/contracts/package.json packages/contracts/
|
COPY packages/contracts/package.json packages/contracts/
|
||||||
COPY backend/package.json backend/
|
COPY backend/package.json backend/
|
||||||
RUN npm ci --workspace=@mmapp/contracts --workspace=mikrotik-manager-backend --include-workspace-root --ignore-scripts \
|
# Drop root frontend deps (Next/React/UI) so backend image stays lean.
|
||||||
|
RUN node -e "\
|
||||||
|
const fs=require('fs');\
|
||||||
|
const p=JSON.parse(fs.readFileSync('package.json','utf8'));\
|
||||||
|
p.dependencies={};\
|
||||||
|
p.devDependencies={};\
|
||||||
|
delete p.scripts;\
|
||||||
|
p.workspaces=['packages/*','backend'];\
|
||||||
|
fs.writeFileSync('package.json', JSON.stringify(p,null,2)+'\\n');\
|
||||||
|
"
|
||||||
|
# Prefer npm ci; if lockfile rejects stripped root package.json, fall back to install.
|
||||||
|
RUN (npm ci --workspace=@mmapp/contracts --workspace=mikrotik-manager-backend --ignore-scripts \
|
||||||
|
|| npm install --workspace=@mmapp/contracts --workspace=mikrotik-manager-backend --ignore-scripts) \
|
||||||
&& npm rebuild better-sqlite3
|
&& npm rebuild better-sqlite3
|
||||||
|
|
||||||
FROM deps AS build
|
FROM deps AS build
|
||||||
@@ -18,7 +31,9 @@ COPY packages/contracts packages/contracts
|
|||||||
COPY backend backend
|
COPY backend backend
|
||||||
RUN npm run build -w @mmapp/contracts \
|
RUN npm run build -w @mmapp/contracts \
|
||||||
&& npm run build -w mikrotik-manager-backend \
|
&& npm run build -w mikrotik-manager-backend \
|
||||||
&& npm prune --omit=dev
|
&& npm prune --omit=dev \
|
||||||
|
# npm may nest workspace deps (e.g. dotenv) under backend/node_modules — keep dir for COPY
|
||||||
|
&& mkdir -p backend/node_modules
|
||||||
|
|
||||||
FROM node:22-bookworm-slim AS runner
|
FROM node:22-bookworm-slim AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
@@ -32,6 +47,8 @@ COPY --from=build /app/node_modules ./node_modules
|
|||||||
COPY --from=build /app/packages/contracts ./packages/contracts
|
COPY --from=build /app/packages/contracts ./packages/contracts
|
||||||
COPY --from=build /app/backend/dist ./backend/dist
|
COPY --from=build /app/backend/dist ./backend/dist
|
||||||
COPY --from=build /app/backend/package.json ./backend/package.json
|
COPY --from=build /app/backend/package.json ./backend/package.json
|
||||||
|
# Nested install from lockfile (dotenv etc.) — ESM resolves from /app/backend/dist → ../node_modules
|
||||||
|
COPY --from=build /app/backend/node_modules ./backend/node_modules
|
||||||
RUN mkdir -p /app/data
|
RUN mkdir -p /app/data
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
CMD ["node", "backend/dist/index.js"]
|
CMD ["node", "backend/dist/index.js"]
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
"drizzle-orm": "^0.45.2",
|
"drizzle-orm": "^0.45.2",
|
||||||
"fastify": "^5.8.5",
|
"fastify": "^5.8.5",
|
||||||
"fastify-plugin": "^5.1.0",
|
"fastify-plugin": "^5.1.0",
|
||||||
"pino-pretty": "^13.1.3",
|
|
||||||
"undici": "^8.1.0",
|
"undici": "^8.1.0",
|
||||||
"zod": "^4.4.1"
|
"zod": "^4.4.1"
|
||||||
},
|
},
|
||||||
@@ -33,6 +32,7 @@
|
|||||||
"@types/node": "^22.15.3",
|
"@types/node": "^22.15.3",
|
||||||
"drizzle-kit": "^0.31.10",
|
"drizzle-kit": "^0.31.10",
|
||||||
"jose": "^6.2.11",
|
"jose": "^6.2.11",
|
||||||
|
"pino-pretty": "^13.1.3",
|
||||||
"tsx": "^4.19.3",
|
"tsx": "^4.19.3",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-9
@@ -29,22 +29,26 @@ export async function buildApp(opts?: {
|
|||||||
logger?: boolean
|
logger?: boolean
|
||||||
startScheduler?: boolean
|
startScheduler?: boolean
|
||||||
}): Promise<FastifyInstance> {
|
}): Promise<FastifyInstance> {
|
||||||
|
const usePrettyLogger =
|
||||||
|
opts?.logger !== false && process.env.NODE_ENV !== "production"
|
||||||
const app = Fastify({
|
const app = Fastify({
|
||||||
bodyLimit: 512 * 1024 * 1024,
|
bodyLimit: 512 * 1024 * 1024,
|
||||||
requestTimeout: 10 * 60 * 1000,
|
requestTimeout: 10 * 60 * 1000,
|
||||||
logger:
|
logger:
|
||||||
opts?.logger === false
|
opts?.logger === false
|
||||||
? false
|
? false
|
||||||
: {
|
: usePrettyLogger
|
||||||
transport: {
|
? {
|
||||||
target: "pino-pretty",
|
transport: {
|
||||||
options: {
|
target: "pino-pretty",
|
||||||
colorize: true,
|
options: {
|
||||||
translateTime: "HH:MM:ss",
|
colorize: true,
|
||||||
ignore: "pid,hostname",
|
translateTime: "HH:MM:ss",
|
||||||
|
ignore: "pid,hostname",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
},
|
: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
app.setValidatorCompiler(validatorCompiler)
|
app.setValidatorCompiler(validatorCompiler)
|
||||||
|
|||||||
Generated
+73
-1
@@ -58,7 +58,6 @@
|
|||||||
"drizzle-orm": "^0.45.2",
|
"drizzle-orm": "^0.45.2",
|
||||||
"fastify": "^5.8.5",
|
"fastify": "^5.8.5",
|
||||||
"fastify-plugin": "^5.1.0",
|
"fastify-plugin": "^5.1.0",
|
||||||
"pino-pretty": "^13.1.3",
|
|
||||||
"undici": "^8.1.0",
|
"undici": "^8.1.0",
|
||||||
"zod": "^4.4.1"
|
"zod": "^4.4.1"
|
||||||
},
|
},
|
||||||
@@ -67,6 +66,7 @@
|
|||||||
"@types/node": "^22.15.3",
|
"@types/node": "^22.15.3",
|
||||||
"drizzle-kit": "^0.31.10",
|
"drizzle-kit": "^0.31.10",
|
||||||
"jose": "^6.2.11",
|
"jose": "^6.2.11",
|
||||||
|
"pino-pretty": "^13.1.3",
|
||||||
"tsx": "^4.19.3",
|
"tsx": "^4.19.3",
|
||||||
"typescript": "^5.8.3"
|
"typescript": "^5.8.3"
|
||||||
}
|
}
|
||||||
@@ -3951,6 +3951,70 @@
|
|||||||
"node": ">=14.0.0"
|
"node": ">=14.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/wasi-threads": "1.1.0",
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@emnapi/core": "^1.7.1",
|
||||||
|
"@emnapi/runtime": "^1.7.1",
|
||||||
|
"@tybys/wasm-util": "^0.10.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": {
|
||||||
|
"version": "0.10.1",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"dev": true,
|
||||||
|
"inBundle": true,
|
||||||
|
"license": "0BSD",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
|
||||||
"version": "4.2.4",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.4.tgz",
|
||||||
@@ -5741,6 +5805,7 @@
|
|||||||
"version": "2.0.20",
|
"version": "2.0.20",
|
||||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
|
||||||
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/combined-stream": {
|
"node_modules/combined-stream": {
|
||||||
@@ -5967,6 +6032,7 @@
|
|||||||
"version": "4.6.3",
|
"version": "4.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz",
|
||||||
"integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
|
"integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
@@ -7237,6 +7303,7 @@
|
|||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-4.0.3.tgz",
|
||||||
"integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==",
|
"integrity": "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-decode-uri-component": {
|
"node_modules/fast-decode-uri-component": {
|
||||||
@@ -7370,6 +7437,7 @@
|
|||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz",
|
||||||
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
|
"integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/fast-string-truncated-width": {
|
"node_modules/fast-string-truncated-width": {
|
||||||
@@ -8166,6 +8234,7 @@
|
|||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz",
|
||||||
"integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
|
"integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/hermes-estree": {
|
"node_modules/hermes-estree": {
|
||||||
@@ -8977,6 +9046,7 @@
|
|||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz",
|
||||||
"integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==",
|
"integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
@@ -10573,6 +10643,7 @@
|
|||||||
"version": "13.1.3",
|
"version": "13.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-13.1.3.tgz",
|
||||||
"integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==",
|
"integrity": "sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colorette": "^2.0.7",
|
"colorette": "^2.0.7",
|
||||||
@@ -10597,6 +10668,7 @@
|
|||||||
"version": "5.0.3",
|
"version": "5.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.3.tgz",
|
||||||
"integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==",
|
"integrity": "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==",
|
||||||
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.16"
|
"node": ">=14.16"
|
||||||
|
|||||||
Reference in New Issue
Block a user