Přeskočit obsah

CITYA Local Deployment Guide

Kompletní návod pro nasazení CITYA aplikace (Backend + Dispatcher) v lokálním prostředí.

Obsah

  1. Předpoklady
  2. Struktura projektu
  3. Klonování repozitářů
  4. Databáze PostgreSQL s PostGIS
  5. Migrace dat z GCP
  6. Redis cache
  7. Backend konfigurace
  8. Dispatcher konfigurace
  9. Traefik reverse proxy
  10. Docker Compose nasazení
  11. Vytvoření uživatele
  12. Google Maps API klíč
  13. GCP CORS konfigurace
  14. Ověření nasazení
  15. Troubleshooting

1. Předpoklady

Hardware

  • Server s minimálně 4GB RAM (testováno na Raspberry Pi 5 s 8GB)
  • 50GB volného místa na disku

Software

  • Docker a Docker Compose v2+
  • Git
  • gcloud CLI (pro migraci dat z GCP)
  • psql klient (pro práci s databází)

Přístupy

  • Přístup k Azure DevOps repozitářům CITYA
  • Přístup ke GCP projektu citya-development nebo citya-production
  • Doména s možností konfigurace DNS (volitelné, pro HTTPS)

Instalace Docker (Debian/Ubuntu)

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Odhlásit se a znovu přihlásit

Instalace gcloud CLI

curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud init
gcloud auth application-default login

2. Struktura projektu

Vytvořte adresářovou strukturu:

mkdir -p ~/projects/citya-local/{repos,docker,backups}
cd ~/projects/citya-local

Výsledná struktura:

~/projects/citya-local/
├── repos/
│   ├── backend/          # .NET Backend API
│   └── dispatcher/       # Vue.js/Quasar Frontend
├── docker/
│   ├── docker-compose.yml
│   ├── .env.backend
│   └── nginx.conf
└── backups/
    └── db/               # Databázové exporty


3. Klonování repozitářů

Z Azure DevOps

cd ~/projects/citya-local/repos

# Backend
git clone https://dev.azure.com/citya-team/Citya/_git/Backend backend

# Dispatcher
git clone https://dev.azure.com/citya-team/Citya/_git/Dispatcher dispatcher

Alternativně z lokálního Gitea (pokud máte mirror)

git clone git@gitea:citya/backend.git backend
git clone git@gitea:citya/dispatcher.git dispatcher

4. Databáze PostgreSQL s PostGIS

4.1 Vytvoření PostGIS Docker image

CITYA vyžaduje PostgreSQL s rozšířením PostGIS pro práci s geografickými daty.

mkdir -p ~/projects/citya-local/docker/postgres
cat > ~/projects/citya-local/docker/postgres/Dockerfile << 'EOF'
FROM postgres:13

# Instalace PostGIS
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
       postgresql-13-postgis-3 \
       postgresql-13-postgis-3-scripts \
    && rm -rf /var/lib/apt/lists/*

# Inicializační skript pro vytvoření rozšíření
RUN mkdir -p /docker-entrypoint-initdb.d
COPY init-postgis.sh /docker-entrypoint-initdb.d/
EOF
cat > ~/projects/citya-local/docker/postgres/init-postgis.sh << 'EOF'
#!/bin/bash
set -e

psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
    CREATE EXTENSION IF NOT EXISTS postgis;
    CREATE EXTENSION IF NOT EXISTS postgis_topology;
    CREATE EXTENSION IF NOT EXISTS fuzzystrmatch;
    CREATE EXTENSION IF NOT EXISTS postgis_tiger_geocoder;
EOSQL
EOF
chmod +x ~/projects/citya-local/docker/postgres/init-postgis.sh

4.2 Build PostGIS image

cd ~/projects/citya-local/docker/postgres
docker build -t citya-postgis:13 .

5. Migrace dat z GCP

5.1 Export dat z GCP Cloud SQL

Nejprve se připojte k GCP a zjistěte dostupné instance:

# Přihlášení do GCP
gcloud auth login
gcloud config set project citya-development

# Seznam Cloud SQL instancí
gcloud sql instances list

5.2 Export databáze

# Vytvořte export bucket (pokud neexistuje)
gsutil mb gs://citya-local-backup

# Export databáze do GCS
gcloud sql export sql INSTANCE_NAME gs://citya-local-backup/citya-export.sql \
    --database=citya \
    --offload

# Stažení exportu
mkdir -p ~/projects/citya-local/backups/db
gsutil cp gs://citya-local-backup/citya-export.sql ~/projects/citya-local/backups/db/

5.3 Alternativní metoda - pg_dump přes Cloud SQL Proxy

# Instalace Cloud SQL Proxy
curl -o cloud-sql-proxy https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.8.0/cloud-sql-proxy.linux.amd64
chmod +x cloud-sql-proxy

# Spuštění proxy (v novém terminálu)
./cloud-sql-proxy --port 5432 citya-development:europe-west1:citya-stage &

# Export pomocí pg_dump
PGPASSWORD='your_password' pg_dump -h 127.0.0.1 -U postgres -d citya \
    --no-owner --no-acl \
    -f ~/projects/citya-local/backups/db/citya-export.sql

5.4 Import do lokální databáze

Nejprve spusťte PostgreSQL kontejner:

docker run -d \
    --name citya-postgres-temp \
    -e POSTGRES_USER=postgres \
    -e POSTGRES_PASSWORD=postgres \
    -e POSTGRES_DB=citya \
    -p 5433:5432 \
    -v citya_db_data:/var/lib/postgresql/data \
    citya-postgis:13

# Počkejte na inicializaci
sleep 10

Import dat:

# Import SQL dumpu
PGPASSWORD=postgres psql -h localhost -p 5433 -U postgres -d citya \
    -f ~/projects/citya-local/backups/db/citya-export.sql

# Ověření importu
PGPASSWORD=postgres psql -h localhost -p 5433 -U postgres -d citya -c "
SELECT table_name,
       (SELECT COUNT(*) FROM information_schema.columns WHERE table_name = t.table_name) as columns
FROM information_schema.tables t
WHERE table_schema = 'public'
ORDER BY table_name;
"

Zastavte dočasný kontejner:

docker stop citya-postgres-temp
docker rm citya-postgres-temp

6. Redis cache

Redis je použit pro caching a session management. Konfigurace je součástí docker-compose.yml.


7. Backend konfigurace

7.1 Úprava Dockerfile

Backend vyžaduje curl pro health check. Upravte Dockerfile:

cat > ~/projects/citya-local/repos/backend/src/ApiEntrypoint/Dockerfile << 'EOF'
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 8080

# Instalace curl pro health check a nastavení timezone
RUN apt-get update && \
    apt-get install -y --no-install-recommends tzdata curl && \
    rm -rf /var/lib/apt/lists/*

ENV TZ=Europe/Prague

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["src/ApiEntrypoint/ApiEntrypoint.csproj", "src/ApiEntrypoint/"]
COPY ["Citya.Backend/Citya.Backend.csproj", "Citya.Backend/"]
COPY ["Citya.Core/Citya.Core.csproj", "Citya.Core/"]
RUN dotnet restore "src/ApiEntrypoint/ApiEntrypoint.csproj"
COPY . .
WORKDIR "/src/src/ApiEntrypoint"
RUN dotnet build "ApiEntrypoint.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ApiEntrypoint.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
    CMD curl -f http://localhost:8080/health || exit 1

ENTRYPOINT ["dotnet", "ApiEntrypoint.dll"]
EOF

7.2 Environment variables

Vytvořte soubor s proměnnými prostředí:

cat > ~/projects/citya-local/docker/.env.backend << 'EOF'
# Database
POSTGRES_CONNECTION_STRING=Host=database;Port=5432;Database=citya;Username=postgres;Password=postgres
POSTGRES_CONNECTION_STRING_READONLY=Host=database;Port=5432;Database=citya;Username=postgres;Password=postgres

# Redis
REDIS_CONNECTION_STRING=redis:6379

# URLs
BACKEND_URL=https://citya-local-api.mberanek.cz

# Google Maps API Keys (získat z GCP Secret Manager)
DISPATCHER_GOOGLE_MAPS_API_KEY=YOUR_DISPATCHER_MAPS_API_KEY
PAS_GOOGLE_MAPS_API_KEY=YOUR_PAS_MAPS_API_KEY

# External Services (placeholders pro lokální vývoj)
CEDA_ACCESS_TOKEN=placeholder-ceda-token
STRIPE_API_KEY=sk_test_placeholder
VONAGE_API_KEY=placeholder-vonage-key
VONAGE_API_SECRET=placeholder-vonage-secret
GO_SMS_CLIENT_ID=placeholder-gosms-id
GO_SMS_CLIENT_SECRET=placeholder-gosms-secret
GO_SMS_CHANNEL_ID=1

# Environment
ASPNETCORE_ENVIRONMENT=Development
TENANT=citya-local
EOF

8. Dispatcher konfigurace

8.1 Úprava Dockerfile

Dispatcher je Vue.js/Quasar SPA. Upravte Dockerfile pro podporu konfigurovatelných proměnných:

cat > ~/projects/citya-local/repos/dispatcher/Dockerfile << 'EOF'
# Build stage
FROM node:20-alpine AS builder

WORKDIR /app

# Install yarn
RUN corepack enable && corepack prepare yarn@1.22.22 --activate

# Copy all source files first (Quasar needs project context)
COPY . .

# Install dependencies (postinstall runs quasar prepare)
RUN yarn install --frozen-lockfile

# Build arguments for environment configuration
ARG VITE_API_URL=http://localhost:8085
ARG VITE_TENANT=citya-local
ARG VITE_ENV=development
ARG VITE_CDN_BUCKET=citya-local-cdn
ARG VITE_CDN_URL=

# Set environment variables for build
ENV VITE_API_URL=$VITE_API_URL
ENV VITE_TENANT=$VITE_TENANT
ENV VITE_ENV=$VITE_ENV
ENV VITE_CDN_BUCKET=$VITE_CDN_BUCKET
ENV VITE_CDN_URL=$VITE_CDN_URL

# Build the application
RUN yarn build

# Production stage
FROM nginx:alpine AS production

# Copy custom nginx config
COPY nginx.conf /etc/nginx/conf.d/default.conf

# Copy built assets from builder stage
COPY --from=builder /app/dist/spa /usr/share/nginx/html

# Add healthcheck
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:80/ || exit 1

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
EOF

8.2 Nginx konfigurace

cat > ~/projects/citya-local/repos/dispatcher/nginx.conf << 'EOF'
server {
    listen 80;
    server_name localhost;
    root /usr/share/nginx/html;
    index index.html;

    # Gzip compression
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # SPA routing - all routes go to index.html
    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";
    }

    # Health check endpoint
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }

    # CDN proxy (optional - for local CDN files)
    location /cdn/ {
        alias /usr/share/nginx/html/cdn/;
    }
}
EOF

8.3 Úprava CDN store (volitelné)

Pro podporu lokálního CDN upravte src/stores/cdn.store.ts:

// Změňte řádek s cdnUrl na:
const cdnUrl = import.meta.env.VITE_CDN_URL || `https://storage.googleapis.com/${import.meta.env.VITE_CDN_BUCKET}`

9. Traefik reverse proxy

9.1 Traefik konfigurace

Pro HTTPS přístup s automatickými certifikáty použijte Traefik:

cat > ~/projects/citya-local/docker/traefik.yml << 'EOF'
api:
  dashboard: true
  insecure: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: your-email@example.com
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web

providers:
  docker:
    exposedByDefault: false
    network: citya-network

log:
  level: INFO
EOF

10. Docker Compose nasazení

10.1 Hlavní docker-compose.yml

cat > ~/projects/citya-local/docker/docker-compose.yml << 'EOF'
services:
  traefik:
    image: traefik:v3.0
    container_name: citya-traefik
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - traefik_letsencrypt:/letsencrypt
    networks:
      - citya-network
    restart: unless-stopped

  database:
    container_name: citya-postgres
    image: citya-postgis:13
    ports:
      - "5433:5432"
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: citya
    volumes:
      - citya_db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -d citya"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - citya-network

  redis:
    container_name: citya-redis
    image: redis:7-alpine
    ports:
      - "6380:6379"
    volumes:
      - citya_redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped
    networks:
      - citya-network

  backend:
    container_name: citya-backend
    build:
      context: ../repos/backend
      dockerfile: src/ApiEntrypoint/Dockerfile
    image: citya-backend:latest
    ports:
      - "8085:8080"
    env_file:
      - .env.backend
    environment:
      ASPNETCORE_ENVIRONMENT: Development
      ASPNETCORE_URLS: http://+:8080
    depends_on:
      database:
        condition: service_healthy
      redis:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
    restart: unless-stopped
    networks:
      - citya-network
    labels:
      - "traefik.enable=true"
      # HTTPS Router
      - "traefik.http.routers.citya-local-api.rule=Host(`citya-local-api.mberanek.cz`)"
      - "traefik.http.routers.citya-local-api.entrypoints=websecure"
      - "traefik.http.routers.citya-local-api.tls=true"
      - "traefik.http.routers.citya-local-api.tls.certresolver=letsencrypt"
      - "traefik.http.routers.citya-local-api.middlewares=citya-local-api-cors"
      - "traefik.http.services.citya-local-api.loadbalancer.server.port=8080"
      # CORS Middleware
      - "traefik.http.middlewares.citya-local-api-cors.headers.accesscontrolallowmethods=GET,POST,PUT,DELETE,PATCH,OPTIONS"
      - "traefik.http.middlewares.citya-local-api-cors.headers.accesscontrolallowheaders=Content-Type,Authorization,X-Requested-With,Area,area,App,app"
      - "traefik.http.middlewares.citya-local-api-cors.headers.accesscontrolalloworiginlist=https://citya-local.mberanek.cz"
      - "traefik.http.middlewares.citya-local-api-cors.headers.accesscontrolallowcredentials=true"
      - "traefik.http.middlewares.citya-local-api-cors.headers.accesscontrolmaxage=100"

  dispatcher:
    container_name: citya-dispatcher
    build:
      context: ../repos/dispatcher
      dockerfile: Dockerfile
      args:
        VITE_API_URL: https://citya-local-api.mberanek.cz
        VITE_TENANT: citya-local
        VITE_ENV: development
        VITE_CDN_URL: https://citya-local.mberanek.cz/cdn
    image: citya-dispatcher:latest
    ports:
      - "8086:80"
    depends_on:
      backend:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:80/"]
      interval: 30s
      timeout: 10s
      retries: 3
    restart: unless-stopped
    networks:
      - citya-network
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.citya-local-dispatcher.rule=Host(`citya-local.mberanek.cz`)"
      - "traefik.http.routers.citya-local-dispatcher.entrypoints=websecure"
      - "traefik.http.routers.citya-local-dispatcher.tls=true"
      - "traefik.http.routers.citya-local-dispatcher.tls.certresolver=letsencrypt"
      - "traefik.http.services.citya-local-dispatcher.loadbalancer.server.port=80"

networks:
  citya-network:
    name: citya-network
    driver: bridge

volumes:
  citya_db_data:
  citya_redis_data:
  traefik_letsencrypt:
EOF

10.2 Spuštění služeb

cd ~/projects/citya-local/docker

# Build a spuštění
docker compose up -d --build

# Sledování logů
docker compose logs -f

# Kontrola stavu
docker compose ps

10.3 Vytvoření CDN souborů

Po spuštění dispatcheru vytvořte potřebné CDN soubory:

docker exec citya-dispatcher sh -c "mkdir -p /usr/share/nginx/html/cdn && echo '{\"release\":{\"from\":null,\"to\":null},\"versions\":{\"minSupported\":{\"passApp\":\"1.0.0\"}}}' > /usr/share/nginx/html/cdn/remote-config.json"

11. Vytvoření uživatele

11.1 Vytvoření admin uživatele

Pro přihlášení do dispatcheru potřebujete vytvořit uživatele v databázi:

# Generování BCrypt hashe pro heslo (např. "admin123")
# Můžete použít online nástroj nebo tento příkaz v Node.js:
# node -e "console.log(require('bcryptjs').hashSync('admin123', 10))"

# Hash pro heslo "admin123": $2a$10$N9qo8uLOickgx2ZMRZoMy.MqrqVqzBqVj1v6F9qKjqKjqKjqKjqKj

PGPASSWORD=postgres psql -h localhost -p 5433 -U postgres -d citya << 'EOF'
INSERT INTO "User" (
    "Id",
    "Email",
    "NormalizedEmail",
    "PasswordHash",
    "FirstName",
    "LastName",
    "PhoneNumber",
    "Role",
    "Status",
    "CreatedAt",
    "UpdatedAt"
) VALUES (
    gen_random_uuid(),
    'localadmin@citya.local',
    'LOCALADMIN@CITYA.LOCAL',
    '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi',
    'Local',
    'Admin',
    '+420000000000',
    'Admin',
    0,
    NOW(),
    NOW()
);
EOF

Poznámka: Hash $2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi odpovídá heslu password. Pro produkci použijte silnější heslo.

11.2 Přiřazení uživatele k oblastem

Uživatel musí být přiřazen k oblastem (areas) pro zobrazení dat:

PGPASSWORD=postgres psql -h localhost -p 5433 -U postgres -d citya << 'EOF'
-- Najít ID uživatele
DO $$
DECLARE
    user_id UUID;
BEGIN
    SELECT "Id" INTO user_id FROM "User" WHERE "Email" = 'localadmin@citya.local';

    -- Přiřadit ke všem oblastem
    INSERT INTO "GeoAreaUser" ("GeoAreasId", "UsersId")
    SELECT "Id", user_id FROM "GeoArea"
    ON CONFLICT DO NOTHING;
END $$;
EOF

11.3 Ověření uživatele

PGPASSWORD=postgres psql -h localhost -p 5433 -U postgres -d citya -c "
SELECT u.\"Email\", u.\"Role\", u.\"Status\", COUNT(gau.\"GeoAreasId\") as areas
FROM \"User\" u
LEFT JOIN \"GeoAreaUser\" gau ON u.\"Id\" = gau.\"UsersId\"
WHERE u.\"Email\" = 'localadmin@citya.local'
GROUP BY u.\"Id\";
"

12. Google Maps API klíč

12.1 Získání klíče z GCP Secret Manager

# Přihlášení do GCP
gcloud auth login
gcloud config set project citya-development

# Výpis dostupných secrets
gcloud secrets list

# Získání Maps API klíče
gcloud secrets versions access latest --secret=citya-development-main-secrets | grep DISPATCHER_GOOGLE_MAPS_API_KEY

12.2 Aktualizace konfigurace

Aktualizujte .env.backend s reálným API klíčem:

sed -i 's/DISPATCHER_GOOGLE_MAPS_API_KEY=.*/DISPATCHER_GOOGLE_MAPS_API_KEY=YOUR_ACTUAL_API_KEY/' ~/projects/citya-local/docker/.env.backend

12.3 Restart backendu

cd ~/projects/citya-local/docker
docker compose up -d backend

13. GCP CORS konfigurace

13.1 Revgeo Storage bucket

Dispatcher přistupuje k cachovaným geocoding datům v GCS bucket citya-revgeo-storage. Pro přístup z vaší domény je potřeba nastavit CORS:

# Aktuální CORS nastavení
gsutil cors get gs://citya-revgeo-storage

# Vytvoření CORS konfigurace
cat > /tmp/cors.json << 'EOF'
[
  {
    "origin": [
      "https://citya-local.mberanek.cz",
      "http://localhost:9000",
      "http://localhost:9200"
    ],
    "method": ["GET"],
    "maxAgeSeconds": 3600
  }
]
EOF

# Aplikace CORS
gsutil cors set /tmp/cors.json gs://citya-revgeo-storage

Poznámka: Pokud nemáte přístup k GCS bucket, revgeo cache nebude fungovat. Aplikace bude zobrazovat souřadnice místo adres, což je akceptovatelné pro lokální vývoj.


14. Ověření nasazení

14.1 Kontrola služeb

docker compose ps

Očekávaný výstup:

NAME               STATUS                    PORTS
citya-backend      Up X minutes (healthy)    0.0.0.0:8085->8080/tcp
citya-dispatcher   Up X minutes (healthy)    0.0.0.0:8086->80/tcp
citya-postgres     Up X minutes (healthy)    0.0.0.0:5433->5432/tcp
citya-redis        Up X minutes (healthy)    0.0.0.0:6380->6379/tcp
citya-traefik      Up X minutes              0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp

14.2 Test API

# Health check
curl -s http://localhost:8085/health

# CORS test
curl -s -I -X OPTIONS \
  -H "Origin: https://citya-local.mberanek.cz" \
  -H "Access-Control-Request-Method: GET" \
  -H "Access-Control-Request-Headers: Authorization,area" \
  https://citya-local-api.mberanek.cz/api/areas

Očekávané CORS hlavičky:

access-control-allow-credentials: true
access-control-allow-headers: Content-Type,Authorization,X-Requested-With,Area,area,App,app
access-control-allow-methods: GET,POST,PUT,DELETE,PATCH,OPTIONS
access-control-allow-origin: https://citya-local.mberanek.cz

14.3 Test přihlášení

  1. Otevřete https://citya-local.mberanek.cz
  2. Přihlaste se jako localadmin@citya.local / password
  3. Ověřte, že vidíte data v aplikaci

15. Troubleshooting

Problém: Backend nenaběhne - chybějící env proměnné

Symptom: Backend kontejner se restartuje s chybou o chybějících proměnných.

Řešení:

# Zkontrolujte logy
docker logs citya-backend

# Ověřte, že .env.backend existuje a je správně načten
docker compose config | grep -A20 backend

Problém: CORS chyby v konzoli

Symptom: Access-Control-Allow-Origin chyby v browser konzoli.

Řešení: 1. Ověřte Traefik labels v docker-compose.yml 2. Zkontrolujte, že origin URL přesně odpovídá (včetně https://) 3. Restart služeb: docker compose up -d backend

Problém: Health check failing - IPv6

Symptom: Dispatcher health check selhává s connection refused.

Řešení: Použijte 127.0.0.1 místo localhost v health check:

healthcheck:
  test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:80/"]

Problém: Přihlášení nefunguje

Symptom: Login vrací chybu i se správnými údaji.

Řešení: 1. Zkontrolujte hash hesla (musí začínat $2a$, ne $2b$) 2. Ověřte Status uživatele (musí být 0 = Active):

UPDATE "User" SET "Status" = 0 WHERE "Email" = 'localadmin@citya.local';

Problém: Žádná data v dispatcheru

Symptom: Po přihlášení nejsou vidět žádné rides, areas, companies.

Řešení: Uživatel musí být přiřazen k oblastem:

-- Zkontrolujte přiřazení
SELECT * FROM "GeoAreaUser" WHERE "UsersId" = (
    SELECT "Id" FROM "User" WHERE "Email" = 'localadmin@citya.local'
);

-- Přiřaďte ke všem oblastem
INSERT INTO "GeoAreaUser" ("GeoAreasId", "UsersId")
SELECT "Id", (SELECT "Id" FROM "User" WHERE "Email" = 'localadmin@citya.local')
FROM "GeoArea"
ON CONFLICT DO NOTHING;

Problém: Cache prohlížeče - staré JS soubory

Symptom: Chyby typu Failed to fetch dynamically imported module nebo 404 na JS soubory.

Řešení: Vyčistěte cache prohlížeče: - Chrome: Cmd+Shift+R (Mac) nebo Ctrl+Shift+R (Win/Linux) - Safari: Cmd+Option+E pak Cmd+R - Nebo otevřete inkognito okno

Problém: Google Maps InvalidKeyMapError

Symptom: Mapy se nezobrazují, v konzoli InvalidKeyMapError.

Řešení: 1. Získejte platný API klíč z GCP Secret Manager 2. Aktualizujte .env.backend 3. Restartujte backend

Problém: Revgeo adresy 404

Symptom: Požadavky na citya-revgeo-storage vracejí 404.

Vysvětlení: Toto je očekávané chování - revgeo cache obsahuje pouze adresy z produkce/stage. Pro lokální vývoj není kritické.


Přílohy

A. Kompletní seznam portů

Služba Interní port Externí port URL
PostgreSQL 5432 5433 localhost:5433
Redis 6379 6380 localhost:6380
Backend API 8080 8085 http://localhost:8085
Dispatcher 80 8086 http://localhost:8086
Traefik Dashboard 8080 8080 http://localhost:8080
HTTPS (Traefik) 443 443 https://your-domain.com

B. Užitečné příkazy

# Restart všech služeb
docker compose restart

# Rebuild a restart konkrétní služby
docker compose up -d --build dispatcher

# Zobrazení logů
docker compose logs -f backend

# Připojení do databáze
docker exec -it citya-postgres psql -U postgres -d citya

# Připojení do Redis
docker exec -it citya-redis redis-cli

# Vyčištění všech dat (POZOR - smaže vše!)
docker compose down -v

C. Kontakty a zdroje

  • Azure DevOps: https://dev.azure.com/citya-team/Citya
  • GCP Console: https://console.cloud.google.com/
  • Dokumentace Traefik: https://doc.traefik.io/traefik/

Poslední aktualizace: Leden 2026