mirror of
https://github.com/reconurge/flowsint.git
synced 2026-05-10 15:14:23 -05:00
feat: docker production setup
This commit is contained in:
20
Makefile
20
Makefile
@@ -11,8 +11,7 @@ dev:
|
||||
|
||||
prod:
|
||||
$(MAKE) check-env
|
||||
docker compose up -d
|
||||
$(MAKE) frontend_prod
|
||||
docker compose -f docker-compose.prod.yml up -d --build
|
||||
|
||||
check-env:
|
||||
@echo "🔎 Checking .env files..."
|
||||
@@ -38,12 +37,11 @@ install:
|
||||
fi
|
||||
poetry config virtualenvs.in-project true --local
|
||||
poetry env use python3.12
|
||||
docker compose up -d
|
||||
docker compose up -d postgres redis neo4j
|
||||
poetry install
|
||||
cd $(PROJECT_ROOT)/flowsint-core && poetry install
|
||||
cd $(PROJECT_ROOT)/flowsint-transforms && poetry install
|
||||
cd $(PROJECT_ROOT)/flowsint-api && poetry install && poetry run alembic upgrade head
|
||||
cd $(PROJECT_ROOT)/flowsint-app && yarn install
|
||||
@echo "✅ All modules installed successfully!"
|
||||
|
||||
infra:
|
||||
@@ -53,7 +51,9 @@ api:
|
||||
cd $(PROJECT_ROOT)/flowsint-api && poetry run uvicorn app.main:app --host 0.0.0.0 --port 5001 --reload
|
||||
|
||||
frontend:
|
||||
cd $(PROJECT_ROOT)/flowsint-app && npm run dev
|
||||
@echo "🚀 Starting frontend in Docker and opening browser..."
|
||||
@docker compose up -d flowsint-app
|
||||
@bash -c 'until curl -s http://localhost:5173 > /dev/null 2>&1; do sleep 1; done; open http://localhost:5173 2>/dev/null || xdg-open http://localhost:5173 2>/dev/null || echo "✅ Frontend ready at http://localhost:5173"'
|
||||
|
||||
frontend_prod:
|
||||
cd $(PROJECT_ROOT)/flowsint-app && npm run build
|
||||
@@ -61,8 +61,14 @@ frontend_prod:
|
||||
celery:
|
||||
cd $(PROJECT_ROOT)/flowsint-core && poetry run celery -A flowsint_core.core.celery worker --loglevel=info --pool=solo
|
||||
|
||||
run: infra
|
||||
$(MAKE) -j3 api frontend celery
|
||||
run:
|
||||
@echo "🚀 Starting all services..."
|
||||
docker compose up -d
|
||||
@echo "⏳ Waiting for frontend to be ready..."
|
||||
@bash -c 'until curl -s http://localhost:5173 > /dev/null 2>&1; do sleep 1; done'
|
||||
@echo "🌐 Opening browser..."
|
||||
@open http://localhost:5173 2>/dev/null || xdg-open http://localhost:5173 2>/dev/null || echo "✅ All services ready! Frontend at http://localhost:5173"
|
||||
$(MAKE) -j2 api celery
|
||||
|
||||
stop:
|
||||
@echo "🛑 Stopping all services..."
|
||||
|
||||
@@ -67,6 +67,20 @@ services:
|
||||
networks:
|
||||
- flowsint_network
|
||||
|
||||
# Flowsint frontend app (production)
|
||||
flowsint-app:
|
||||
build:
|
||||
context: ./flowsint-app
|
||||
dockerfile: Dockerfile
|
||||
container_name: flowsint-app
|
||||
ports:
|
||||
- "5173:80"
|
||||
depends_on:
|
||||
- flowsint_api
|
||||
networks:
|
||||
- flowsint_network
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
flowsint_network:
|
||||
name: flowsint_network
|
||||
|
||||
@@ -48,6 +48,24 @@ services:
|
||||
networks:
|
||||
- flowsint_network
|
||||
|
||||
# Flowsint frontend app (development)
|
||||
flowsint-app:
|
||||
build:
|
||||
context: ./flowsint-app
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: flowsint-app
|
||||
ports:
|
||||
- "5173:5173"
|
||||
volumes:
|
||||
- ./flowsint-app:/app
|
||||
- /app/node_modules
|
||||
environment:
|
||||
- VITE_API_URL=http://localhost:5001
|
||||
networks:
|
||||
- flowsint_network
|
||||
stdin_open: true
|
||||
tty: true
|
||||
|
||||
networks:
|
||||
flowsint_network:
|
||||
name: flowsint_network
|
||||
|
||||
@@ -19,8 +19,8 @@ FROM nginx:alpine
|
||||
# Copy built files to nginx
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Copy nginx configuration if needed
|
||||
# COPY nginx.conf /etc/nginx/nginx.conf
|
||||
# Copy nginx configuration
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
|
||||
16
flowsint-app/Dockerfile.dev
Normal file
16
flowsint-app/Dockerfile.dev
Normal file
@@ -0,0 +1,16 @@
|
||||
FROM node:20
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
RUN yarn install
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Expose Vite dev server port
|
||||
EXPOSE 5173
|
||||
|
||||
# Run development server with host flag to make it accessible from outside container
|
||||
CMD ["yarn", "dev", "--host", "0.0.0.0"]
|
||||
38
flowsint-app/nginx.conf
Normal file
38
flowsint-app/nginx.conf
Normal file
@@ -0,0 +1,38 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 10240;
|
||||
gzip_proxied expired no-cache no-store private auth;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;
|
||||
gzip_disable "MSIE [1-6]\.";
|
||||
|
||||
# Proxy API requests to backend
|
||||
location /api {
|
||||
proxy_pass http://flowsint_api:5001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
# Handle SPA routing - serve index.html for all routes
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Cache static assets
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
@@ -200,12 +200,13 @@ export const useGraphSettingsStore = create<GraphGeneralSettingsStore>()(
|
||||
// Core methods
|
||||
updateSetting: (category, key, value) =>
|
||||
set((state) => {
|
||||
const categorySettings = state.settings[category as keyof typeof state.settings] as any
|
||||
const newSettings = {
|
||||
...state.settings,
|
||||
[category]: {
|
||||
...state.settings[category],
|
||||
...categorySettings,
|
||||
[key]: {
|
||||
...state.settings[category][key],
|
||||
...(categorySettings?.[key] || {}),
|
||||
value: value
|
||||
}
|
||||
}
|
||||
@@ -217,7 +218,7 @@ export const useGraphSettingsStore = create<GraphGeneralSettingsStore>()(
|
||||
newForceSettings = {
|
||||
...state.forceSettings,
|
||||
[key]: {
|
||||
...state.forceSettings[key],
|
||||
...(state.forceSettings[key] || {}),
|
||||
value: value
|
||||
}
|
||||
}
|
||||
@@ -249,6 +250,7 @@ export const useGraphSettingsStore = create<GraphGeneralSettingsStore>()(
|
||||
|
||||
getCategorySettings: (category: string) => {
|
||||
const categorySettings: Record<string, any> = {}
|
||||
// @ts-ignore
|
||||
const settings = get().settings[category]
|
||||
if (settings) {
|
||||
Object.entries(settings as Record<string, any>).forEach(([key, setting]) => {
|
||||
@@ -266,8 +268,8 @@ export const useGraphSettingsStore = create<GraphGeneralSettingsStore>()(
|
||||
if (!preset) return
|
||||
|
||||
set((state) => {
|
||||
const newSettings = { ...state.settings }
|
||||
const newForceSettings = { ...state.forceSettings }
|
||||
const newSettings = { ...state.settings } as any
|
||||
const newForceSettings = { ...state.forceSettings } as any
|
||||
|
||||
Object.entries(preset).forEach(([key, value]) => {
|
||||
if (newSettings.graph[key]) {
|
||||
@@ -297,14 +299,25 @@ export const useGraphSettingsStore = create<GraphGeneralSettingsStore>()(
|
||||
setKeyboardShortcutsOpen: (open) => set({ keyboardShortcutsOpen: open }),
|
||||
|
||||
// Helper methods
|
||||
getSettingValue: (category: string, key: string) => get().settings[category]?.[key]?.value,
|
||||
getSettingType: (category: string, key: string) => get().settings[category]?.[key]?.type,
|
||||
getSettingOptions: (category: string, key: string) =>
|
||||
get().settings[category]?.[key]?.options,
|
||||
getSettingDescription: (category: string, key: string) =>
|
||||
get().settings[category]?.[key]?.description,
|
||||
getSettingValue: (category: string, key: string) => {
|
||||
const categorySettings = get().settings[category as keyof typeof DEFAULT_SETTINGS] as any
|
||||
return categorySettings?.[key]?.value
|
||||
},
|
||||
getSettingType: (category: string, key: string) => {
|
||||
const categorySettings = get().settings[category as keyof typeof DEFAULT_SETTINGS] as any
|
||||
return categorySettings?.[key]?.type
|
||||
},
|
||||
getSettingOptions: (category: string, key: string) => {
|
||||
const categorySettings = get().settings[category as keyof typeof DEFAULT_SETTINGS] as any
|
||||
return categorySettings?.[key]?.options
|
||||
},
|
||||
getSettingDescription: (category: string, key: string) => {
|
||||
const categorySettings = get().settings[category as keyof typeof DEFAULT_SETTINGS] as any
|
||||
return categorySettings?.[key]?.description
|
||||
},
|
||||
getSettingConstraints: (category: string, key: string) => {
|
||||
const setting = get().settings[category]?.[key]
|
||||
const categorySettings = get().settings[category as keyof typeof DEFAULT_SETTINGS] as any
|
||||
const setting = categorySettings?.[key]
|
||||
if (setting && 'min' in setting) {
|
||||
return {
|
||||
min: setting.min,
|
||||
|
||||
Reference in New Issue
Block a user