feat: Add Linux deployment scripts and server logs view

- Add deployment/linux/ with deploy.sh for deploying from Claude-Agent LXC to Windows server
- Add ServerLogsView.vue for viewing server logs from frontend
- Add shared/routes/system.py for system health endpoints
- Update CLAUDE.md with quick deploy instructions
- Improve Windows deployment scripts (ROA2WEB-Console.ps1)
- Fix OCR service validation and worker pool improvements
- Update environment config examples
- Various script permission and startup fixes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-01-04 00:26:36 +00:00
parent 495790411f
commit 02a8c8682c
39 changed files with 1939 additions and 80 deletions

View File

@@ -286,6 +286,7 @@ const processOCR = async () => {
const pollJobStatus = async (id) => {
const LONG_POLL_TIMEOUT = 30 // seconds
const MAX_TOTAL_TIME = 120 // 2 minutes max
const MIN_POLL_INTERVAL = 500 // Minimum 500ms between polls (safety net, backend does long-poll)
const startTime = Date.now()
const poll = async () => {
@@ -298,11 +299,15 @@ const pollJobStatus = async (id) => {
return
}
const pollStartTime = Date.now()
try {
// Long-poll with 30s server timeout, 35s axios timeout
// Add cache-busting param to prevent browser/IIS caching
const response = await api.get(`/ocr/jobs/${id}/wait`, {
params: { timeout: LONG_POLL_TIMEOUT },
timeout: (LONG_POLL_TIMEOUT + 5) * 1000
params: { timeout: LONG_POLL_TIMEOUT, _t: Date.now() },
timeout: (LONG_POLL_TIMEOUT + 5) * 1000,
headers: { 'Cache-Control': 'no-cache' }
})
const job = response.data
@@ -310,7 +315,12 @@ const pollJobStatus = async (id) => {
queuePosition.value = job.queue_position
estimatedWait.value = job.estimated_wait_seconds
console.log('📊 OCR Long-Poll:', { status: job.status, position: job.queue_position })
const pollDuration = Date.now() - pollStartTime
console.log('📊 OCR Long-Poll:', {
status: job.status,
position: job.queue_position,
pollDurationMs: pollDuration
})
if (job.status === 'completed') {
processing.value = false
@@ -336,6 +346,13 @@ const pollJobStatus = async (id) => {
// Still pending/processing - long-poll again
if (processing.value) {
// Prevent rapid polling: if response came back too fast, wait before next poll
const pollDuration = Date.now() - pollStartTime
if (pollDuration < MIN_POLL_INTERVAL) {
const waitTime = MIN_POLL_INTERVAL - pollDuration
console.log(`⏳ Waiting ${waitTime}ms before next poll (preventing rapid polling)`)
await new Promise(resolve => setTimeout(resolve, waitTime))
}
await poll()
}
@@ -349,8 +366,18 @@ const pollJobStatus = async (id) => {
return
}
// Real error
// Real error - wait before retry to prevent rapid error loops
console.error('🔴 Poll Error:', err.message)
// Check if we should retry or give up
const elapsed = (Date.now() - startTime) / 1000
if (elapsed < MAX_TOTAL_TIME && processing.value) {
console.log('🔄 Retrying after error...')
await new Promise(resolve => setTimeout(resolve, MIN_POLL_INTERVAL))
await poll()
return
}
processing.value = false
error.value = 'Eroare la verificarea starii job-ului'
emit('error', error.value)

View File

@@ -1,15 +1,7 @@
import axios from 'axios'
// Detect if we're accessing from remote (not localhost)
const isRemoteAccess = !['localhost', '127.0.0.1'].includes(window.location.hostname)
// For remote access, use direct backend URL (same host, port 8000)
// For local access, use proxy through Vite
const baseURL = isRemoteAccess
? `http://${window.location.hostname}:8000/api/data-entry`
: import.meta.env.BASE_URL + 'api/data-entry'
console.log('📡 API Config:', { isRemoteAccess, baseURL, hostname: window.location.hostname })
// Use relative path - works with both Vite dev proxy and IIS production proxy
const baseURL = import.meta.env.BASE_URL + 'api/data-entry'
const api = axios.create({
baseURL,