deploy: canlı veri backend'ini container'a ekle (nginx /api → Node :3001)
- Dockerfile: nginx + Node tek container; backend arka planda, nginx ön planda - nginx.conf: /api → 127.0.0.1:3001 proxy - dt-store: node:sqlite guard (yoksa DT devre dışı, açık ihaleler yine canlı) - Açık ihale canlı verisi sıfır npm bağımlılığıyla deploy'da çalışır
This commit is contained in:
+17
-5
@@ -1,4 +1,4 @@
|
|||||||
# Stage 1: Build Vite SPA
|
# Stage 1: Vite SPA build
|
||||||
FROM node:22-alpine AS build
|
FROM node:22-alpine AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
@@ -6,9 +6,21 @@ RUN npm ci
|
|||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# Stage 2: Production Nginx Server
|
# Stage 2: nginx (frontend) + node (canlı veri backend) tek container'da
|
||||||
FROM nginx:alpine
|
FROM node:22-alpine
|
||||||
|
RUN apk add --no-cache nginx
|
||||||
|
|
||||||
|
# Frontend
|
||||||
COPY --from=build /app/dist /usr/share/nginx/html
|
COPY --from=build /app/dist /usr/share/nginx/html
|
||||||
COPY --from=build /app/nginx.conf /etc/nginx/conf.d/default.conf
|
COPY --from=build /app/nginx.conf /etc/nginx/http.d/default.conf
|
||||||
|
|
||||||
|
# Backend (yalnızca Node builtin'leri kullanır — npm bağımlılığı yok)
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=build /app/server ./server
|
||||||
|
|
||||||
|
# Başlangıç: Node backend'i (3001) arka planda + nginx ön planda
|
||||||
|
RUN printf '#!/bin/sh\nset -e\nnode /app/server/index.js &\nexec nginx -g "daemon off;"\n' > /start.sh \
|
||||||
|
&& chmod +x /start.sh
|
||||||
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["/start.sh"]
|
||||||
|
|||||||
+12
-3
@@ -5,10 +5,19 @@ server {
|
|||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
# Ensure proper MIME types for JavaScript, CSS, etc.
|
|
||||||
include /etc/nginx/mime.types;
|
include /etc/nginx/mime.types;
|
||||||
|
|
||||||
# Serve static assets directly
|
# Canlı veri backend'i (aynı container'da Node, port 3001)
|
||||||
|
location /api/ {
|
||||||
|
proxy_pass http://127.0.0.1:3001;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_read_timeout 60s;
|
||||||
|
proxy_connect_timeout 10s;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Statik varlıklar
|
||||||
location /assets/ {
|
location /assets/ {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
@@ -16,7 +25,7 @@ server {
|
|||||||
add_header Cache-Control "public, no-transform";
|
add_header Cache-Control "public, no-transform";
|
||||||
}
|
}
|
||||||
|
|
||||||
# SPA routing fallback for app routes
|
# SPA yönlendirmesi
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -3,11 +3,19 @@
|
|||||||
* Veritabanı yoksa (worker hiç koşmadıysa) sessizce boş liste döner.
|
* Veritabanı yoksa (worker hiç koşmadıysa) sessizce boş liste döner.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { DatabaseSync } from 'node:sqlite';
|
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
|
// node:sqlite bazı Node sürümlerinde deneysel/flag'li. Yoksa DT devre dışı kalır,
|
||||||
|
// ilan.gov.tr canlı verisi yine de çalışır.
|
||||||
|
let DatabaseSync = null;
|
||||||
|
try {
|
||||||
|
({ DatabaseSync } = await import('node:sqlite'));
|
||||||
|
} catch {
|
||||||
|
console.warn('[dt-store] node:sqlite yok — doğrudan temin devre dışı (açık ihaleler etkilenmez)');
|
||||||
|
}
|
||||||
|
|
||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||||
const DB_PATH = path.join(__dirname, 'data', 'dt.sqlite');
|
const DB_PATH = path.join(__dirname, 'data', 'dt.sqlite');
|
||||||
|
|
||||||
@@ -92,7 +100,7 @@ function mapDtRow(row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function readDtTenders(limit = 300) {
|
export function readDtTenders(limit = 300) {
|
||||||
if (!fs.existsSync(DB_PATH)) return { tenders: [], totalCount: 0, available: false };
|
if (!DatabaseSync || !fs.existsSync(DB_PATH)) return { tenders: [], totalCount: 0, available: false };
|
||||||
const db = new DatabaseSync(DB_PATH, { readOnly: true });
|
const db = new DatabaseSync(DB_PATH, { readOnly: true });
|
||||||
try {
|
try {
|
||||||
const total = db.prepare('SELECT COUNT(*) c FROM dt_tenders').get().c;
|
const total = db.prepare('SELECT COUNT(*) c FROM dt_tenders').get().c;
|
||||||
|
|||||||
Reference in New Issue
Block a user