v4.1.26: Docker hotfix — рабочие конфиги для Synology ARM
- FIX: Dockerfile — правильный multi-stage build - FIX: docker-compose.yml — убраны нерабочие конфиги - FIX: docker-entrypoint.sh — добавлен правильный entrypoint - FIX: D1_BINDING=aknaproff-db во всех конфигах - wrangler.jsonc: исправлен D1_BINDING - public/original.html: cache version update - Удалён HOTFIX_v4.1.24.md, добавлен HOTFIX_v4.1.26.md
This commit is contained in:
58
Dockerfile
58
Dockerfile
@@ -1,58 +1,30 @@
|
||||
# Multi-stage build для оптимизации размера образа
|
||||
|
||||
# Stage 1: Build
|
||||
FROM node:20-alpine AS builder
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# ---------- Build stage ----------
|
||||
FROM node:20-bookworm-slim AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Копировать package files
|
||||
COPY package*.json ./
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm install
|
||||
|
||||
# Установить зависимости
|
||||
RUN npm ci --only=production
|
||||
|
||||
# Копировать исходники
|
||||
COPY . .
|
||||
|
||||
# Собрать проект
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Runtime
|
||||
FROM node:20-alpine
|
||||
|
||||
# ---------- Runtime stage ----------
|
||||
FROM node:20-bookworm-slim
|
||||
WORKDIR /app
|
||||
|
||||
# Установить dumb-init для правильной обработки сигналов
|
||||
RUN apk add --no-cache dumb-init
|
||||
ENV NODE_ENV=production \
|
||||
WRANGLER_SEND_METRICS=false
|
||||
|
||||
# Создать пользователя без root
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S nodejs -u 1001
|
||||
# Copy everything from builder (includes node_modules, dist, migrations, etc.)
|
||||
COPY --from=builder /app /app
|
||||
|
||||
# Копировать зависимости из builder
|
||||
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
|
||||
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
|
||||
COPY --from=builder --chown=nodejs:nodejs /app/package.json ./
|
||||
COPY --from=builder --chown=nodejs:nodejs /app/wrangler.jsonc ./
|
||||
COPY --from=builder --chown=nodejs:nodejs /app/migrations ./migrations
|
||||
COPY --from=builder --chown=nodejs:nodejs /app/seed.sql ./
|
||||
RUN chmod +x /app/docker-entrypoint.sh
|
||||
|
||||
# Создать директорию для локальной БД
|
||||
RUN mkdir -p .wrangler/state/v3/d1 && \
|
||||
chown -R nodejs:nodejs .wrangler
|
||||
|
||||
# Переключиться на непривилегированного пользователя
|
||||
USER nodejs
|
||||
|
||||
# Открыть порт
|
||||
EXPOSE 3000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
CMD wget --quiet --tries=1 --spider http://localhost:3000 || exit 1
|
||||
# Persist D1 SQLite data and seed marker between restarts
|
||||
VOLUME ["/data"]
|
||||
|
||||
# Запуск с dumb-init
|
||||
ENTRYPOINT ["dumb-init", "--"]
|
||||
|
||||
# Команда запуска
|
||||
CMD ["sh", "-c", "npm run db:reset && npx wrangler pages dev dist --d1=webapp-production --local --ip 0.0.0.0 --port 3000"]
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
# 🔥 HOTFIX v4.1.24 - ARVE ПОЛЯ НЕ СОХРАНЯЛИСЬ
|
||||
|
||||
**Дата**: 2026-01-15
|
||||
**Версия**: v4.1.24 FINAL
|
||||
**Приоритет**: CRITICAL 🔥
|
||||
|
||||
---
|
||||
|
||||
## 🚨 **КРИТИЧНАЯ ПРОБЛЕМА**
|
||||
|
||||
### **Симптомы:**
|
||||
- ❌ Бухгалтер не может добавить номер счёта (arve_makstud)
|
||||
- ❌ Не работает галочка "Arve makstud" (arve_checked)
|
||||
- ❌ При создании/редактировании записей эти поля просто не сохраняются
|
||||
|
||||
### **Причина:**
|
||||
**Backend не включал поля `arve_checked` и `arve_makstud` в SQL запросы!**
|
||||
|
||||
Поля были в форме, отправлялись с фронтенда, но backend **игнорировал их полностью**.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **РЕШЕНИЕ**
|
||||
|
||||
### **Файл:** `src/index.tsx`
|
||||
|
||||
#### **1. POST /api/records - добавление записи**
|
||||
|
||||
**Было (строка 196-207):**
|
||||
```typescript
|
||||
const result = await c.env.DB.prepare(`
|
||||
INSERT INTO production_records (
|
||||
month, year, client_name, type, offer_number, work_number,
|
||||
quantity, color, notes, problems, installer, price,
|
||||
created_by, updated_by
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).bind(
|
||||
data.month, data.year, data.client_name, data.type || null,
|
||||
data.offer_number, data.work_number, quantity, data.color || null,
|
||||
data.notes || null, data.problems || null, data.installer || null,
|
||||
price, userId, userId
|
||||
).run()
|
||||
```
|
||||
|
||||
**Стало:**
|
||||
```typescript
|
||||
const arveChecked = data.arve_checked ? parseInt(data.arve_checked, 10) : 0
|
||||
|
||||
const result = await c.env.DB.prepare(`
|
||||
INSERT INTO production_records (
|
||||
month, year, client_name, type, offer_number, work_number,
|
||||
quantity, color, notes, problems, installer, price,
|
||||
arve_checked, arve_makstud,
|
||||
created_by, updated_by
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`).bind(
|
||||
data.month, data.year, data.client_name, data.type || null,
|
||||
data.offer_number, data.work_number, quantity, data.color || null,
|
||||
data.notes || null, data.problems || null, data.installer || null,
|
||||
price, arveChecked, data.arve_makstud || null,
|
||||
userId, userId
|
||||
).run()
|
||||
```
|
||||
|
||||
#### **2. PUT /api/records/:id - обновление записи**
|
||||
|
||||
**Было (строка 238-248):**
|
||||
```typescript
|
||||
await c.env.DB.prepare(`
|
||||
UPDATE production_records
|
||||
SET client_name = ?, type = ?, offer_number = ?, work_number = ?,
|
||||
quantity = ?, color = ?, notes = ?, problems = ?, installer = ?, price = ?,
|
||||
updated_by = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ? AND deleted_at IS NULL
|
||||
`).bind(
|
||||
data.client_name, data.type || null, data.offer_number, data.work_number,
|
||||
quantity, data.color || null, data.notes || null, data.problems || null,
|
||||
data.installer || null, price, userId, id
|
||||
).run()
|
||||
```
|
||||
|
||||
**Стало:**
|
||||
```typescript
|
||||
const arveChecked = data.arve_checked ? parseInt(data.arve_checked, 10) : 0
|
||||
|
||||
await c.env.DB.prepare(`
|
||||
UPDATE production_records
|
||||
SET client_name = ?, type = ?, offer_number = ?, work_number = ?,
|
||||
quantity = ?, color = ?, notes = ?, problems = ?, installer = ?, price = ?,
|
||||
arve_checked = ?, arve_makstud = ?,
|
||||
updated_by = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ? AND deleted_at IS NULL
|
||||
`).bind(
|
||||
data.client_name, data.type || null, data.offer_number, data.work_number,
|
||||
quantity, data.color || null, data.notes || null, data.problems || null,
|
||||
data.installer || null, price, arveChecked, data.arve_makstud || null,
|
||||
userId, id
|
||||
).run()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 **ТЕСТИРОВАНИЕ**
|
||||
|
||||
### **Test 1: Создать запись с arve полями ✅**
|
||||
|
||||
```bash
|
||||
POST /api/records
|
||||
{
|
||||
"arve_checked": 1,
|
||||
"arve_makstud": "INV-2025-001"
|
||||
}
|
||||
|
||||
Результат:
|
||||
✅ id: 56
|
||||
✅ arve_checked: 1
|
||||
✅ arve_makstud: INV-2025-001
|
||||
```
|
||||
|
||||
### **Test 2: Обновить arve поля ✅**
|
||||
|
||||
```bash
|
||||
PUT /api/records/56
|
||||
{
|
||||
"arve_checked": 0,
|
||||
"arve_makstud": "INV-2025-002"
|
||||
}
|
||||
|
||||
Результат:
|
||||
✅ arve_checked: 0 → обновилось
|
||||
✅ arve_makstud: INV-2025-002 → обновилось
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 **ФАЙЛЫ**
|
||||
|
||||
**Изменённые файлы:**
|
||||
- `src/index.tsx` - endpoint POST /api/records (строки 196-207)
|
||||
- `src/index.tsx` - endpoint PUT /api/records/:id (строки 238-248)
|
||||
|
||||
**Версия:**
|
||||
- `public/original.html` - v4.1.24
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **РАЗВЁРТЫВАНИЕ**
|
||||
|
||||
### **ARM Synology:**
|
||||
|
||||
```bash
|
||||
# 1. Остановить контейнер
|
||||
sudo docker-compose down
|
||||
|
||||
# 2. Распаковать новый архив
|
||||
unzip aknaproff_production_v4.1.24_ARM_FINAL.zip
|
||||
|
||||
# 3. Запустить с пересборкой
|
||||
cd backend
|
||||
sudo docker-compose up -d --build
|
||||
|
||||
# 4. Проверить
|
||||
# - Создать новый ряд
|
||||
# - Ввести номер счёта в "Arve Nr"
|
||||
# - Поставить галочку "Arve makstud"
|
||||
# - Сохранить
|
||||
# - ✅ Поля должны сохраниться!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ **РЕЗУЛЬТАТ**
|
||||
|
||||
- ✅ arve_checked сохраняется при создании
|
||||
- ✅ arve_makstud сохраняется при создании
|
||||
- ✅ arve_checked обновляется при редактировании
|
||||
- ✅ arve_makstud обновляется при редактировании
|
||||
- ✅ Бухгалтер может работать с полями счёта!
|
||||
|
||||
---
|
||||
|
||||
## 📊 **ИСТОРИЯ ВЕРСИЙ**
|
||||
|
||||
| Версия | Изменения |
|
||||
|--------|-----------|
|
||||
| v4.1.23 | Цена с запятой + проверка дат |
|
||||
| **v4.1.24** | **ИСПРАВЛЕНЫ ПОЛЯ СЧЁТА (arve)** 🔥 |
|
||||
|
||||
---
|
||||
|
||||
**Статус**: ✅ ГОТОВО
|
||||
**Тестирование**: ✅ ПРОЙДЕНО
|
||||
**Критичность**: 🔥 ВЫСОКАЯ
|
||||
**Развёртывание**: СРОЧНО РЕКОМЕНДУЕТСЯ
|
||||
103
HOTFIX_v4.1.26.md
Normal file
103
HOTFIX_v4.1.26.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# 🔧 HOTFIX v4.1.26 - PRODUCTION FILES & DB
|
||||
|
||||
**Дата**: 2026-01-18
|
||||
**Версия**: v4.1.26 FINAL
|
||||
**Приоритет**: CRITICAL 🔥
|
||||
|
||||
---
|
||||
|
||||
## 🚨 **КРИТИЧНЫЕ ИЗМЕНЕНИЯ**
|
||||
|
||||
### **1. Рабочие файлы Docker**
|
||||
Использованы ПРОВЕРЕННЫЕ рабочие файлы:
|
||||
- ✅ `Dockerfile` - рабочий multi-stage build
|
||||
- ✅ `docker-compose.yml` - рабочая конфигурация
|
||||
- ✅ `docker-entrypoint.sh` - правильный entrypoint script
|
||||
|
||||
### **2. Правильное имя БД**
|
||||
Во ВСЕХ конфигурациях установлено:
|
||||
```
|
||||
D1_BINDING=aknaproff-db
|
||||
```
|
||||
|
||||
### **3. Production БД**
|
||||
Включена рабочая БД:
|
||||
- **Файл**: `data/aknaproff-db.sqlite`
|
||||
- **Записей**: 67 production records
|
||||
- **Размер**: 212 KB
|
||||
|
||||
---
|
||||
|
||||
## 📦 **СТРУКТУРА АРХИВА**
|
||||
|
||||
```
|
||||
backend/
|
||||
├── Dockerfile # Multi-stage build (рабочий)
|
||||
├── docker-compose.yml # Конфигурация (рабочая)
|
||||
├── docker-entrypoint.sh # Entrypoint script (рабочий)
|
||||
├── wrangler.jsonc # D1_BINDING=aknaproff-db
|
||||
├── package.json # NPM скрипты
|
||||
├── src/ # Backend код
|
||||
├── public/ # Frontend
|
||||
├── dist/ # Built files
|
||||
├── migrations/ # D1 миграции
|
||||
├── seed.sql # Seed данные
|
||||
└── data/
|
||||
└── aknaproff-db.sqlite # PRODUCTION БД (67 записей)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 **РАЗВЁРТЫВАНИЕ НА SYNOLOGY**
|
||||
|
||||
```bash
|
||||
# 1. Остановить контейнер
|
||||
sudo docker-compose down
|
||||
|
||||
# 2. Распаковать архив
|
||||
unzip aknaproff_production_v4.1.26_ARM_FINAL.zip
|
||||
|
||||
# 3. Перейти в backend
|
||||
cd backend
|
||||
|
||||
# 4. ВАЖНО: Проверить что БД на месте
|
||||
ls -lh data/aknaproff-db.sqlite
|
||||
# Должно быть: 212K
|
||||
|
||||
# 5. Запустить с пересборкой
|
||||
sudo docker-compose up -d --build
|
||||
|
||||
# 6. Проверить логи
|
||||
sudo docker-compose logs -f
|
||||
|
||||
# 7. Проверить БД
|
||||
curl http://localhost:8180/api/records?month=1&year=2025
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ **ЧТО ИСПРАВЛЕНО**
|
||||
|
||||
1. ✅ Использованы РАБОЧИЕ Docker файлы
|
||||
2. ✅ Имя БД = `aknaproff-db` во всех конфигах
|
||||
3. ✅ Включена production БД (67 записей)
|
||||
4. ✅ Удалены `.env` файлы (не нужны)
|
||||
5. ✅ Поля arve работают (v4.1.24)
|
||||
6. ✅ Все предыдущие исправления сохранены
|
||||
|
||||
---
|
||||
|
||||
## 📊 **ИСТОРИЯ ВЕРСИЙ**
|
||||
|
||||
| Версия | Изменения |
|
||||
|--------|-----------|
|
||||
| v4.1.24 | Исправлены поля счёта (arve) |
|
||||
| v4.1.25 | Попытка обратной совместимости |
|
||||
| **v4.1.26** | **PRODUCTION FILES + DB** 🔥 |
|
||||
|
||||
---
|
||||
|
||||
**Статус**: ✅ ГОТОВО
|
||||
**Тестирование**: ✅ ПРОВЕРЕНО
|
||||
**Критичность**: 🔥 ВЫСОКАЯ
|
||||
**Развёртывание**: ИСПОЛЬЗУЙТЕ ТОЛЬКО ЭТУ ВЕРСИЮ
|
||||
2
dist/original.html
vendored
2
dist/original.html
vendored
@@ -1225,7 +1225,7 @@
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script>
|
||||
<script src="/static/app.js?v=4.1.24"></script>
|
||||
<script src="/static/app.js?v=4.1.26"></script>
|
||||
|
||||
|
||||
</body></html>
|
||||
@@ -1,55 +1,23 @@
|
||||
version: '3.8'
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
webapp:
|
||||
image: node:20-alpine
|
||||
container_name: aknaproff-webapp
|
||||
working_dir: /app
|
||||
|
||||
# Bind mount - все файлы проекта включая БД
|
||||
volumes:
|
||||
# Весь проект монтируется в /app
|
||||
- ./:/app
|
||||
# node_modules остаются в контейнере для производительности
|
||||
- /app/node_modules
|
||||
|
||||
# Переменные окружения
|
||||
environment:
|
||||
- NODE_ENV=development
|
||||
- PORT=3000
|
||||
# Cloudflare Workers local mode
|
||||
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:-}
|
||||
|
||||
# Открыть порт 3000
|
||||
aknaproff-backend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: aknaproff-backend
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
# Команда запуска
|
||||
command: >
|
||||
sh -c "
|
||||
echo '🚀 Starting AKNAPROFF Tootmine...' &&
|
||||
echo '📦 Installing dependencies...' &&
|
||||
npm install &&
|
||||
echo '🗄️ Setting up local database...' &&
|
||||
npm run db:reset &&
|
||||
echo '🔨 Building project...' &&
|
||||
npm run build &&
|
||||
echo '✅ Starting development server...' &&
|
||||
npx wrangler pages dev dist --d1=webapp-production --local --ip 0.0.0.0 --port 3000
|
||||
"
|
||||
|
||||
# Перезапуск при падении
|
||||
- "8180:3000"
|
||||
environment:
|
||||
PORT: 3000
|
||||
D1_BINDING: aknaproff-db
|
||||
PERSIST_PATH: /data
|
||||
SEED_DATA: "false" # Set to "true" on first run to load seed.sql automatically
|
||||
WRANGLER_SEND_METRICS: "false"
|
||||
volumes:
|
||||
- ./data:/data
|
||||
restart: unless-stopped
|
||||
|
||||
# Health check
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
# Сеть (необязательно, но полезно для будущего расширения)
|
||||
networks:
|
||||
default:
|
||||
name: aknaproff-network
|
||||
volumes:
|
||||
d1-data:
|
||||
driver: local
|
||||
|
||||
54
docker-entrypoint.sh
Executable file
54
docker-entrypoint.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
PORT="${PORT:-3000}"
|
||||
D1_BINDING="${D1_BINDING:-aknaproff-db}"
|
||||
PERSIST_PATH="${PERSIST_PATH:-/data}"
|
||||
SEED_DATA="${SEED_DATA:-false}"
|
||||
SEED_SENTINEL="${PERSIST_PATH}/.seeded"
|
||||
|
||||
mkdir -p "${PERSIST_PATH}"
|
||||
export WRANGLER_SEND_METRICS="${WRANGLER_SEND_METRICS:-false}"
|
||||
|
||||
apply_migrations() {
|
||||
echo "[entrypoint] Applying D1 migrations (binding: ${D1_BINDING}, persist: ${PERSIST_PATH})"
|
||||
npx wrangler d1 migrations apply "${D1_BINDING}" \
|
||||
--local \
|
||||
--persist-to "${PERSIST_PATH}"
|
||||
}
|
||||
|
||||
maybe_seed_data() {
|
||||
if [[ "${SEED_DATA,,}" != "true" ]]; then
|
||||
echo "[entrypoint] Seed step disabled (set SEED_DATA=true to enable)"
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -f "${SEED_SENTINEL}" ]]; then
|
||||
echo "[entrypoint] Seed data already applied (skipping)"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "[entrypoint] Seeding local database from seed.sql"
|
||||
if npx wrangler d1 execute "${D1_BINDING}" \
|
||||
--local \
|
||||
--persist-to "${PERSIST_PATH}" \
|
||||
--file ./seed.sql; then
|
||||
touch "${SEED_SENTINEL}"
|
||||
else
|
||||
echo "[entrypoint] Seed step failed but container will continue" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
start_server() {
|
||||
echo "[entrypoint] Starting Wrangler dev server on port ${PORT}"
|
||||
exec npx wrangler pages dev dist \
|
||||
--local \
|
||||
--d1="${D1_BINDING}" \
|
||||
--persist-to "${PERSIST_PATH}" \
|
||||
--ip 0.0.0.0 \
|
||||
--port "${PORT}"
|
||||
}
|
||||
|
||||
apply_migrations
|
||||
maybe_seed_data
|
||||
start_server
|
||||
@@ -1225,7 +1225,7 @@
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script>
|
||||
<script src="/static/app.js?v=4.1.24"></script>
|
||||
<script src="/static/app.js?v=4.1.26"></script>
|
||||
|
||||
|
||||
</body></html>
|
||||
@@ -6,10 +6,11 @@
|
||||
"pages_build_output_dir": "./dist",
|
||||
|
||||
// D1 Database configuration
|
||||
// ВАЖНО: Имя БД ВСЕГДА aknaproff-db (используется в docker-entrypoint.sh)
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "webapp-production",
|
||||
"database_name": "aknaproff-db",
|
||||
"database_id": "local"
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user