diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..76e71d7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,44 @@ +# Dependencies +node_modules +**/node_modules + +# Build outputs (will be rebuilt in container) +dist +**/dist +build +**/build + +# Git +.git +.gitignore + +# IDE +.idea +.vscode +*.swp +*.swo + +# Logs +*.log +logs + +# Environment files +.env +.env.local +.env.*.local + +# OS files +.DS_Store +Thumbs.db + +# Test files +coverage +.nyc_output + +# Project-specific (not needed in app container) +.claude +.git_backup +db_connections +final_endpoints_v2 +nowContext +queries diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..3bcdd23 --- /dev/null +++ b/.env.example @@ -0,0 +1,29 @@ +# ============================================ +# KIS API Builder - Configuration +# ============================================ +# Copy this file to .env and adjust values +# +# For default setup (built-in DB): +# Only APP_PORT, DB_PASSWORD and JWT_SECRET are needed +# +# For external database: +# Set all DB_* variables +# ============================================ + +# External port (access from host machine) +APP_PORT=3000 + +# Database password (used by both built-in and external DB) +DB_PASSWORD=your_secure_password_here + +# JWT Configuration +JWT_SECRET=your-super-secret-jwt-key-change-this-in-production +JWT_EXPIRES_IN=24h + +# ============================================ +# External Database (only for docker-compose.external-db.yml) +# ============================================ +# DB_HOST=your-postgres-host +# DB_PORT=5432 +# DB_NAME=api_builder +# DB_USER=postgres diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..98fd01d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,68 @@ +# ============================================ +# Stage 1: Build Frontend +# ============================================ +FROM node:20-alpine AS frontend-builder + +WORKDIR /app/frontend + +# Copy frontend package files +COPY frontend/package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy frontend source +COPY frontend/ ./ + +# Build frontend +RUN npm run build + +# ============================================ +# Stage 2: Build Backend +# ============================================ +FROM node:20-alpine AS backend-builder + +WORKDIR /app/backend + +# Copy backend package files +COPY backend/package*.json ./ + +# Install dependencies +RUN npm ci + +# Copy backend source +COPY backend/ ./ + +# Build TypeScript +RUN npm run build + +# ============================================ +# Stage 3: Production +# ============================================ +FROM node:20-alpine AS production + +WORKDIR /app + +# Copy backend package files and install production deps +COPY backend/package*.json ./ +RUN npm ci --only=production && npm cache clean --force + +# Copy built backend +COPY --from=backend-builder /app/backend/dist ./dist + +# Copy built frontend to the location expected by backend +COPY --from=frontend-builder /app/frontend/dist ./frontend/dist + +# Set environment +ENV NODE_ENV=production +ENV PORT=3000 + +# Expose port +EXPOSE 3000 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1 + +# Start the application +CMD ["node", "dist/server.js"] diff --git a/backend/.env.example b/backend/.env.example index e06d308..2871f01 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -15,31 +15,4 @@ JWT_EXPIRES_IN=24h # API Rate Limiting RATE_LIMIT_WINDOW_MS=900000 -RATE_LIMIT_MAX_REQUESTS=100 - -# Target Databases Configuration (JSON format) -# This is where your API endpoints will execute queries -TARGET_DATABASES='[ - { - "id": "main_postgres", - "name": "Main PostgreSQL", - "type": "postgresql", - "host": "localhost", - "port": 5432, - "database": "your_database", - "user": "your_user", - "password": "your_password", - "ssl": false - }, - { - "id": "analytics_db", - "name": "Analytics Database", - "type": "postgresql", - "host": "localhost", - "port": 5432, - "database": "analytics", - "user": "analytics_user", - "password": "analytics_password", - "ssl": false - } -]' +RATE_LIMIT_MAX_REQUESTS=100 \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index 99afb9a..b5912df 100644 --- a/backend/package.json +++ b/backend/package.json @@ -7,8 +7,8 @@ "dev": "nodemon", "build": "tsc", "start": "node dist/server.js", - "migrate": "ts-node src/migrations/run.ts", - "seed": "ts-node src/migrations/seed.ts" + "migrate": "ts-node src/scripts/run.ts", + "seed": "ts-node src/scripts/seed.ts" }, "keywords": [ "api", diff --git a/backend/src/migrations/run.ts b/backend/src/scripts/run.ts similarity index 51% rename from backend/src/migrations/run.ts rename to backend/src/scripts/run.ts index 9a7b567..8031d79 100644 --- a/backend/src/migrations/run.ts +++ b/backend/src/scripts/run.ts @@ -6,14 +6,18 @@ async function runMigrations() { console.log('Running migrations...'); try { - const migrationFile = fs.readFileSync( - path.join(__dirname, '001_initial_schema.sql'), - 'utf-8' - ); + const migrationsDir = path.join(__dirname, '../migrations'); + const files = fs.readdirSync(migrationsDir) + .filter(f => f.endsWith('.sql')) + .sort(); + + for (const file of files) { + console.log(` Running ${file}...`); + const sql = fs.readFileSync(path.join(migrationsDir, file), 'utf-8'); + await mainPool.query(sql); + } - await mainPool.query(migrationFile); console.log('✅ Migrations completed successfully'); - process.exit(0); } catch (error) { console.error('❌ Migration failed:', error); diff --git a/backend/src/migrations/seed.ts b/backend/src/scripts/seed.ts similarity index 100% rename from backend/src/migrations/seed.ts rename to backend/src/scripts/seed.ts diff --git a/docker-compose.external-db.yml b/docker-compose.external-db.yml new file mode 100644 index 0000000..d392b0f --- /dev/null +++ b/docker-compose.external-db.yml @@ -0,0 +1,29 @@ +# ============================================ +# KIS API Builder - External Database +# ============================================ +# Use this when you have your own PostgreSQL +# +# 1. Copy .env.example to .env +# 2. Set DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD +# 3. Run: docker compose -f docker-compose.external-db.yml up -d +# ============================================ + +services: + app: + build: + context: . + dockerfile: Dockerfile + container_name: kis-api-builder-app + restart: unless-stopped + ports: + - "${APP_PORT:-3000}:3000" + environment: + NODE_ENV: production + PORT: 3000 + DB_HOST: ${DB_HOST:?DB_HOST is required} + DB_PORT: ${DB_PORT:-5432} + DB_NAME: ${DB_NAME:-api_builder} + DB_USER: ${DB_USER:-postgres} + DB_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required} + JWT_SECRET: ${JWT_SECRET:-change-this-secret-in-production} + JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-24h} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9cca6c4 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,63 @@ +# ============================================ +# KIS API Builder - Docker Compose +# ============================================ +# Default setup with built-in PostgreSQL +# Just run: docker compose up -d +# +# For external database, use: +# docker compose -f docker-compose.external-db.yml up -d +# ============================================ + +services: + # PostgreSQL Database (built-in) + db: + image: postgres:16-alpine + container_name: kis-api-builder-db + restart: unless-stopped + environment: + POSTGRES_DB: api_builder + POSTGRES_USER: postgres + POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres} + volumes: + - postgres_data:/var/lib/postgresql/data + - ./backend/src/migrations:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres -d api_builder"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + networks: + - kis-network + + # Application (Backend + Frontend) + app: + build: + context: . + dockerfile: Dockerfile + container_name: kis-api-builder-app + restart: unless-stopped + ports: + - "${APP_PORT:-3000}:3000" + environment: + NODE_ENV: production + PORT: 3000 + DB_HOST: db + DB_PORT: 5432 + DB_NAME: api_builder + DB_USER: postgres + DB_PASSWORD: ${DB_PASSWORD:-postgres} + JWT_SECRET: ${JWT_SECRET:-change-this-secret-in-production} + JWT_EXPIRES_IN: ${JWT_EXPIRES_IN:-24h} + depends_on: + db: + condition: service_healthy + networks: + - kis-network + +volumes: + postgres_data: + +networks: + kis-network: + driver: bridge