diff --git a/smart-app-city/docker-compose.yml b/smart-app-city/docker-compose.yml index 9d29c3ea..201a5df9 100644 --- a/smart-app-city/docker-compose.yml +++ b/smart-app-city/docker-compose.yml @@ -1,9 +1,32 @@ -# Smart App City — Docker Compose +# Smart App City — Docker Compose (Web + Backend) version: "3.8" +networks: + smartcity-shared: + external: true + traefik-public: + external: true + services: - # API Gateway + # ─── Web Frontend (Expo React Native Web) ─── + smartapp-web: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: smartapp-web + networks: + - smartcity-shared + - traefik-public + restart: unless-stopped + labels: + - "traefik.enable=true" + - "traefik.http.routers.smartapp-web.rule=Host(`smartapp.digitribe.fr`)" + - "traefik.http.routers.smartapp-web.entrypoints=websecure" + - "traefik.http.routers.smartapp-web.tls.certresolver=letsencrypt" + - "traefik.http.services.smartapp-web.loadbalancer.server.port=80" + + # ─── API Gateway ─── api-gateway: build: ./backend/api-gateway container_name: smartapp-gateway @@ -12,13 +35,19 @@ services: environment: - KEYCLOAK_URL=http://openremote-keycloak:8080/auth - LOCALAI_URL=http://localai-api:8080 - - QDRANT_URL=http://qdrant:*** + - QDRANT_URL=http://qdrant:6333 - REDIS_URL=redis://redis:6379 networks: - smartcity-shared - restart: always + restart: unless-stopped + labels: + - "traefik.enable=true" + - "traefik.http.routers.smartapp-api.rule=Host(`api-smartapp.digitribe.fr`)" + - "traefik.http.routers.smartapp-api.entrypoints=websecure" + - "traefik.http.routers.smartapp-api.tls.certresolver=letsencrypt" + - "traefik.http.services.smartapp-api.loadbalancer.server.port=8000" - # RAG Service + # ─── RAG Service ─── rag-service: build: ./ai/rag-service container_name: smartapp-rag @@ -26,15 +55,15 @@ services: - "8001:8001" environment: - LOCALAI_URL=http://localai-api:8080 - - QDRANT_URL=http://qdrant:*** + - QDRANT_URL=http://qdrant:6333 - EMBEDDING_MODEL=intfloat/multilingual-e5-large networks: - smartcity-shared depends_on: - api-gateway - restart: always + restart: unless-stopped - # Agent Service + # ─── Agent Service ─── agent-service: build: ./ai/agent-service container_name: smartapp-agent @@ -47,9 +76,9 @@ services: - smartcity-shared depends_on: - rag-service - restart: always + restart: unless-stopped - # Qdrant (if not existing) + # ─── Qdrant Vector DB ─── qdrant: image: qdrant/qdrant:v1.9.0 container_name: smartapp-qdrant @@ -59,9 +88,9 @@ services: - qdrant_data:/qdrant/storage networks: - smartcity-shared - restart: always + restart: unless-stopped - # Meilisearch (if not existing) + # ─── Meilisearch ─── meilisearch: image: getmeili/meilisearch:v1.7 container_name: smartapp-search @@ -71,11 +100,7 @@ services: - meilisearch_data:/meili_data networks: - smartcity-shared - restart: always - -networks: - smartcity-shared: - external: true + restart: unless-stopped volumes: qdrant_data: diff --git a/smart-app-city/frontend/Dockerfile b/smart-app-city/frontend/Dockerfile new file mode 100644 index 00000000..dd34005b --- /dev/null +++ b/smart-app-city/frontend/Dockerfile @@ -0,0 +1,42 @@ +# Smart App City — Web build (Expo/React Native Web) +# Build stage +FROM node:20-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package.json package-lock.json ./ + +# Install dependencies +RUN npm ci --legacy-peer-deps + +# Copy source +COPY . . + +# Build web version +RUN npx expo export --platform web --output-dir dist + +# Serve stage — lightweight nginx +FROM nginx:alpine + +# Copy built assets +COPY --from=builder /app/dist /usr/share/nginx/html + +# Nginx config for SPA routing +RUN echo 'server { \ + listen 80; \ + server_name _; \ + root /usr/share/nginx/html; \ + index index.html; \ + location / { \ + try_files $uri $uri/ /index.html; \ + } \ + location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff|woff2|ttf|eot)$ { \ + expires 1y; \ + add_header Cache-Control "public, immutable"; \ + } \ +}' > /etc/nginx/conf.d/default.conf + +EXPOSE 80 + +CMD ["nginx", "-g", "daemon off;"]