Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
.git
.github
node_modules
vendor
.env
.env.*
!.env.example
.idea
.vscode
storage/logs/*
storage/framework/cache/*
storage/framework/sessions/*
storage/framework/views/*
storage/app/screenshots/*
bootstrap/cache/*
*.log
.DS_Store
Thumbs.db
.claude
*.sqlite
188 changes: 188 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
services:
# Laravel Application
app:
build:
context: .
dockerfile: docker/app/Dockerfile
container_name: chat-app
restart: unless-stopped
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-8000}:8000'
environment:
APP_ENV: '${APP_ENV:-local}'
APP_DEBUG: '${APP_DEBUG:-true}'
DB_CONNECTION: pgsql
DB_HOST: postgres
DB_PORT: 5432
DB_DATABASE: '${DB_DATABASE:-chat}'
DB_USERNAME: '${DB_USERNAME:-chat}'
DB_PASSWORD: '${DB_PASSWORD:-secret}'
REDIS_HOST: redis
REDIS_PORT: 6379
CACHE_STORE: redis
SESSION_DRIVER: redis
QUEUE_CONNECTION: redis
MAIL_MAILER: smtp
MAIL_HOST: mailpit
MAIL_PORT: 1025
volumes:
- '.:/var/www/html'
- './docker/app/php.ini:/usr/local/etc/php/conf.d/custom.ini:ro'
networks:
- chat
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "php", "artisan", "about"]
interval: 10s
timeout: 5s
retries: 3

# Vite Dev Server
vite:
build:
context: .
dockerfile: docker/node/Dockerfile
container_name: chat-vite
restart: unless-stopped
ports:
- '${VITE_PORT:-5173}:5173'
volumes:
- '.:/var/www/html'
- '/var/www/html/node_modules'
networks:
- chat
command: npm run dev -- --host 0.0.0.0

# Queue Worker (Horizon)
horizon:
build:
context: .
dockerfile: docker/app/Dockerfile
container_name: chat-horizon
restart: unless-stopped
environment:
APP_ENV: '${APP_ENV:-local}'
DB_CONNECTION: pgsql
DB_HOST: postgres
DB_PORT: 5432
DB_DATABASE: '${DB_DATABASE:-chat}'
DB_USERNAME: '${DB_USERNAME:-chat}'
DB_PASSWORD: '${DB_PASSWORD:-secret}'
REDIS_HOST: redis
REDIS_PORT: 6379
QUEUE_CONNECTION: redis
volumes:
- '.:/var/www/html'
networks:
- chat
depends_on:
- app
- redis
command: php artisan horizon

# Scheduler (Cron)
scheduler:
build:
context: .
dockerfile: docker/app/Dockerfile
container_name: chat-scheduler
restart: unless-stopped
environment:
APP_ENV: '${APP_ENV:-local}'
DB_CONNECTION: pgsql
DB_HOST: postgres
DB_PORT: 5432
DB_DATABASE: '${DB_DATABASE:-chat}'
DB_USERNAME: '${DB_USERNAME:-chat}'
DB_PASSWORD: '${DB_PASSWORD:-secret}'
REDIS_HOST: redis
volumes:
- '.:/var/www/html'
networks:
- chat
depends_on:
- app
command: sh -c "while true; do php artisan schedule:run --verbose; sleep 60; done"

# PostgreSQL with pgvector for AI embeddings
postgres:
image: pgvector/pgvector:pg16
container_name: chat-postgres
restart: unless-stopped
ports:
- '${DB_PORT:-5432}:5432'
environment:
POSTGRES_DB: '${DB_DATABASE:-chat}'
POSTGRES_USER: '${DB_USERNAME:-chat}'
POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}'
volumes:
- chat-postgres:/var/lib/postgresql/data
- ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
- chat
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-chat}"]
interval: 5s
timeout: 5s
retries: 5

# Redis
redis:
image: redis:7-alpine
container_name: chat-redis
restart: unless-stopped
ports:
- '${REDIS_PORT:-6379}:6379'
volumes:
- chat-redis:/data
networks:
- chat
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
command: redis-server --appendonly yes

# Mailpit (Email Testing)
mailpit:
image: axllent/mailpit:latest
container_name: chat-mailpit
restart: unless-stopped
ports:
- '${MAILPIT_PORT:-8025}:8025'
- '1025:1025'
networks:
- chat

# Browser Testing (Playwright)
playwright:
build:
context: .
dockerfile: docker/playwright/Dockerfile
container_name: chat-playwright
volumes:
- '.:/var/www/html'
- './storage/app/screenshots:/var/www/html/storage/app/screenshots'
networks:
- chat
depends_on:
- app
profiles:
- testing

networks:
chat:
driver: bridge

volumes:
chat-postgres:
driver: local
chat-redis:
driver: local
52 changes: 52 additions & 0 deletions docker/app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
FROM php:8.4-cli

LABEL maintainer="Chat App"

ARG WWWGROUP=1000
ARG NODE_VERSION=22

WORKDIR /var/www/html

ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=UTC

RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

# Install system dependencies
RUN apt-get update && apt-get install -y \
gnupg gosu curl ca-certificates zip unzip git supervisor \
libpng-dev libonig-dev libxml2-dev libzip-dev libpq-dev \
libcurl4-openssl-dev libssl-dev \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

# Install PHP extensions
RUN docker-php-ext-install \
pdo pdo_pgsql pgsql \
mbstring exif pcntl bcmath gd zip \
opcache sockets

# Install Redis extension
RUN pecl install redis && docker-php-ext-enable redis

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Create sail user
RUN groupadd --force -g $WWWGROUP sail \
&& useradd -ms /bin/bash --no-user-group -g $WWWGROUP -u 1337 sail

# Copy application
COPY . /var/www/html

# Install dependencies (if vendor doesn't exist)
RUN if [ ! -d "vendor" ]; then composer install --no-interaction --prefer-dist --optimize-autoloader; fi

# Setup permissions
RUN chown -R sail:sail /var/www/html \
&& chmod -R 755 /var/www/html/storage /var/www/html/bootstrap/cache

USER sail

EXPOSE 8000

CMD ["php", "artisan", "serve", "--host=0.0.0.0", "--port=8000"]
17 changes: 17 additions & 0 deletions docker/app/php.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[PHP]
memory_limit = 512M
upload_max_filesize = 100M
post_max_size = 100M
max_execution_time = 300
max_input_time = 300

[opcache]
opcache.enable = 1
opcache.memory_consumption = 256
opcache.interned_strings_buffer = 16
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 0

[Date]
date.timezone = UTC
19 changes: 19 additions & 0 deletions docker/node/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
FROM node:22-alpine

WORKDIR /var/www/html

# Install dependencies for native modules
RUN apk add --no-cache python3 make g++

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci

# Copy application
COPY . .

EXPOSE 5173

CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
28 changes: 28 additions & 0 deletions docker/playwright/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
FROM mcr.microsoft.com/playwright:v1.49.0-jammy

WORKDIR /var/www/html

# Install PHP 8.4
RUN apt-get update && apt-get install -y \
software-properties-common \
&& add-apt-repository ppa:ondrej/php \
&& apt-get update \
&& apt-get install -y \
php8.4-cli php8.4-pgsql php8.4-redis php8.4-mbstring \
php8.4-xml php8.4-curl php8.4-zip php8.4-gd php8.4-bcmath \
composer \
&& apt-get clean && rm -rf /var/lib/apt/lists/*

# Copy application
COPY . /var/www/html

# Install PHP dependencies
RUN if [ ! -d "vendor" ]; then composer install --no-interaction; fi

# Install Node dependencies
RUN npm ci

# Build frontend
RUN npm run build

CMD ["php", "artisan", "test", "--filter=Browser"]
6 changes: 6 additions & 0 deletions docker/postgres/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- Enable pgvector extension for AI embeddings
CREATE EXTENSION IF NOT EXISTS vector;

-- Enable other useful extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- For fuzzy text search
14 changes: 14 additions & 0 deletions scripts/docker-browser-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
# Run browser tests with Playwright in Docker
set -e

FILTER=${1:-"Browser"}

echo "🎭 Running browser tests with Playwright..."
echo " Filter: $FILTER"

# Use the playwright profile
docker compose --profile testing run --rm playwright php artisan test --filter="$FILTER"

echo ""
echo "📸 Screenshots saved to: storage/app/screenshots/"
20 changes: 20 additions & 0 deletions scripts/docker-fresh.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash
# Fresh install: rebuild everything from scratch
set -e

echo "🔄 Fresh Docker build..."

# Stop and remove everything
docker compose down -v --remove-orphans

# Rebuild
docker compose build --no-cache

# Start
docker compose up -d

# Run migrations and seed
docker compose exec app php artisan migrate:fresh --seed

echo ""
echo "✅ Fresh install complete!"
14 changes: 14 additions & 0 deletions scripts/docker-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash
# Run tests in Docker (including browser tests)
set -e

FILTER=${1:-""}

echo "🧪 Running tests in Docker..."

if [ -n "$FILTER" ]; then
echo " Filter: $FILTER"
docker compose run --rm app php artisan test --filter="$FILTER"
else
docker compose run --rm app php artisan test
fi
Loading