v4.1.22: Исправлено удаление записей (HOTFIX)

- FIX: DELETE /api/records/:id возвращал 500 (no such column: deleted_by)
- Было: SET deleted_at = CURRENT_TIMESTAMP, deleted_by = ?
- Стало: SET deleted_at = CURRENT_TIMESTAMP, deleted = 1
- Добавлены логи: console.log('[DELETE]...')
- Docker: убран docker-compose.yml из v4.1.21
- Добавлен fix-docker.sh и docker-compose-simple.yml
- Cache version: app.js?v=4.1.22
This commit is contained in:
Deploy Bot
2026-01-14 23:34:00 +02:00
parent 64403d6fd6
commit bf43461559
9 changed files with 239 additions and 27 deletions

View File

@@ -15,16 +15,26 @@ FROM node:20-bookworm-slim
WORKDIR /app WORKDIR /app
ENV NODE_ENV=production \ ENV NODE_ENV=production \
WRANGLER_SEND_METRICS=false WRANGLER_SEND_METRICS=false \
PORT=3000 \
D1_BINDING=aknaproff-db \
PERSIST_PATH=/data
# Copy everything from builder (includes node_modules, dist, migrations, etc.) # Copy everything from builder (includes node_modules, dist, migrations, etc.)
COPY --from=builder /app /app COPY --from=builder /app /app
RUN chmod +x /app/docker-entrypoint.sh # Create data directory
RUN mkdir -p /data
EXPOSE 3000 EXPOSE 3000
# Persist D1 SQLite data and seed marker between restarts # Persist D1 SQLite data between restarts
VOLUME ["/data"] VOLUME ["/data"]
ENTRYPOINT ["/app/docker-entrypoint.sh"] # Start wrangler directly (no bash script needed)
CMD ["npx", "wrangler", "pages", "dev", "dist", \
"--local", \
"--d1=aknaproff-db", \
"--persist-to=/data", \
"--ip=0.0.0.0", \
"--port=3000"]

124
HOTFIX_v4.1.22.md Normal file
View File

@@ -0,0 +1,124 @@
# 🔧 HOTFIX v4.1.22 - ИСПРАВЛЕНО УДАЛЕНИЕ ЗАПИСЕЙ
**Дата**: 2026-01-14
**Версия**: v4.1.22 FINAL
**Приоритет**: HIGH (Критическая функция не работала)
---
## 📋 **ПРОБЛЕМА**
### **Не работало удаление записей**
**Симптомы:**
- Ошибка 500 при попытке удалить запись
- Консоль: `DELETE /api/records/50 [HTTP/1.1 500 Internal Server Error]`
- Ошибка в логах: `D1_ERROR: no such column: deleted_by: SQLITE_ERROR`
**Причина:**
- Backend пытался записать в несуществующую колонку `deleted_by`
- Таблица `production_records` имеет только `deleted_at`, но не `deleted_by`
---
## ✅ **ИСПРАВЛЕНИЕ**
**Файл:** `src/index.tsx`, endpoint `DELETE /api/records/:id`
**Было:**
```typescript
await c.env.DB.prepare(`
UPDATE production_records
SET deleted_at = CURRENT_TIMESTAMP, deleted_by = ?
WHERE id = ?
`).bind(userId || null, id).run()
```
**Стало:**
```typescript
await c.env.DB.prepare(`
UPDATE production_records
SET deleted_at = CURRENT_TIMESTAMP, deleted = 1
WHERE id = ?
`).bind(id).run()
```
**Изменения:**
- ✅ Убрана попытка записи в `deleted_by` (колонки нет в БД)
- ✅ Добавлена установка флага `deleted = 1`
- ✅ Добавлено логирование для отладки
---
## 🧪 **ТЕСТИРОВАНИЕ**
### **Test: Удаление записи ✅**
```bash
# Было записей: 6
DELETE /api/records/49
# Результат: {"success":true}
# Стало записей: 5
```
**Проверка в БД:**
```sql
SELECT id, deleted, deleted_at FROM production_records WHERE id = 49;
-- Результат: 49|1|2026-01-14 20:30:54
```
---
## 📦 **ФАЙЛЫ**
**Изменённые файлы:**
- `src/index.tsx` - endpoint `DELETE /api/records/:id`
**Версия:**
- `public/original.html` - обновлена до v4.1.22
---
## 🚀 **РАЗВЁРТЫВАНИЕ**
### **ARM Synology:**
```bash
# 1. Остановить контейнер
sudo docker-compose down
# 2. Распаковать новый архив
unzip aknaproff_production_v4.1.22_ARM_FINAL.zip
# 3. Запустить с пересборкой
cd backend
sudo docker-compose up -d --build
# 4. Проверить что удаление работает
# Войти как admin → удалить запись → проверить что удалилась
```
---
## ✅ **РЕЗУЛЬТАТ**
- ✅ Удаление записей работает корректно
- ✅ Записи помечаются как удалённые (soft delete)
-`deleted = 1` и `deleted_at` устанавливаются правильно
- ✅ Ошибка "no such column: deleted_by" исправлена
---
## 📊 **ИСТОРИЯ ВЕРСИЙ**
| Версия | Изменения |
|--------|-----------|
| v4.1.20 | Исправлена форма настроек (смена пароля) |
| v4.1.21 | Убрано ограничение длины поля "Värv" |
| **v4.1.22** | **Исправлено удаление записей** |
---
**Статус**: ✅ ГОТОВО
**Тестирование**: ✅ ПРОЙДЕНО
**Развёртывание**: ГОТОВО К ИСПОЛЬЗОВАНИЮ

8
dist/_worker.js vendored

File diff suppressed because one or more lines are too long

2
dist/original.html vendored
View File

@@ -1225,7 +1225,7 @@
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script>
<script src="/static/app.js?v=4.1.21"></script> <script src="/static/app.js?v=4.1.22"></script>
</body></html> </body></html>

20
docker-compose-simple.yml Normal file
View File

@@ -0,0 +1,20 @@
version: "3.8"
services:
aknaproff-backend:
build:
context: .
dockerfile: Dockerfile
container_name: aknaproff-backend
ports:
- "8180:3000"
environment:
PORT: 3000
D1_BINDING: aknaproff-db
PERSIST_PATH: /data
SEED_DATA: "false"
SKIP_MIGRATIONS: "true"
WRANGLER_SEND_METRICS: "false"
volumes:
- ./data:/data
restart: unless-stopped

View File

@@ -5,24 +5,9 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
platforms:
- linux/amd64
- linux/arm64/v8
platform: linux/arm64/v8 # Explicit for ARM Synology
container_name: aknaproff-backend container_name: aknaproff-backend
ports: ports:
- "8180: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
SKIP_MIGRATIONS: "true" # ⚠️ Skip migrations to use existing database
WRANGLER_SEND_METRICS: "false"
volumes: volumes:
- ./data:/data - ./data:/data
restart: unless-stopped restart: unless-stopped
volumes:
d1-data:
driver: local

69
fix-docker.sh Executable file
View File

@@ -0,0 +1,69 @@
#!/bin/bash
# Quick fix script for Synology Docker "lease not found" error
echo "=== AKNAPROFF Docker Fix Script ==="
echo ""
# Stop and remove old containers
echo "1. Stopping and removing old containers..."
sudo docker-compose down -v 2>/dev/null || true
# Prune containers
echo "2. Cleaning orphan containers..."
sudo docker container prune -f
# Prune build cache
echo "3. Cleaning build cache..."
sudo docker builder prune -f
# Remove old image if exists
echo "4. Removing old image..."
sudo docker rmi tootmine-aknaproff-backend:latest 2>/dev/null || true
sudo docker rmi aknaproff-backend:latest 2>/dev/null || true
# System prune
echo "5. System cleanup..."
sudo docker system prune -f
echo ""
echo "=== Cleanup complete ==="
echo ""
echo "Choose build method:"
echo "1) Use docker-compose.yml (with platform support)"
echo "2) Use docker-compose-simple.yml (without platform - RECOMMENDED for Synology)"
echo ""
read -p "Enter choice [1 or 2]: " choice
case $choice in
1)
echo "Building with docker-compose.yml..."
sudo docker-compose build --no-cache
sudo docker-compose up -d --force-recreate
;;
2)
echo "Building with docker-compose-simple.yml..."
sudo docker-compose -f docker-compose-simple.yml build --no-cache
sudo docker-compose -f docker-compose-simple.yml up -d --force-recreate
;;
*)
echo "Invalid choice. Please run script again."
exit 1
;;
esac
echo ""
echo "=== Checking status ==="
sudo docker ps | grep aknaproff
echo ""
echo "=== Checking logs (last 20 lines) ==="
sudo docker logs aknaproff-backend --tail=20
echo ""
echo "=== Testing API ==="
sleep 3
curl -s http://localhost:8180/api/years | head -20
echo ""
echo "=== Done ==="
echo "If container is running, access at: http://synology-ip:8180"

View File

@@ -1225,7 +1225,7 @@
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios@1.6.0/dist/axios.min.js"></script>
<script src="/static/app.js?v=4.1.21"></script> <script src="/static/app.js?v=4.1.22"></script>
</body></html> </body></html>

View File

@@ -291,11 +291,15 @@ app.delete('/api/records/:id', optionalAuthMiddleware, async (c) => {
const id = c.req.param('id') const id = c.req.param('id')
const userId = c.get('userId') const userId = c.get('userId')
console.log('[DELETE] Deleting record:', id, 'by user:', userId)
await c.env.DB.prepare(` await c.env.DB.prepare(`
UPDATE production_records UPDATE production_records
SET deleted_at = CURRENT_TIMESTAMP, deleted_by = ? SET deleted_at = CURRENT_TIMESTAMP, deleted = 1
WHERE id = ? WHERE id = ?
`).bind(userId || null, id).run() `).bind(id).run()
console.log('[DELETE] Record deleted successfully:', id)
return c.json({ success: true }) return c.json({ success: true })
} catch (error) { } catch (error) {