diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.env diff --git a/docker-compose.yml b/docker-compose.yml index f42b197..8b30631 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,17 +1,93 @@ services: + postgres: + image: postgres:17-alpine + environment: + POSTGRES_DB: docuvault + POSTGRES_USER: postgres + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + volumes: + - postgres_data:/var/lib/postgresql/data + - ./docker/postgres/initdb.d:/docker-entrypoint-initdb.d:ro + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres -d docuvault"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + + minio: + image: minio/minio:latest + command: server /data --console-address ":9001" + environment: + MINIO_ROOT_USER: ${MINIO_ROOT_USER} + MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} + ports: + - "9000:9000" + - "9001:9001" + volumes: + - minio_data:/data + healthcheck: + test: ["CMD", "mc", "ready", "local"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 15s + + redis: + image: redis:7-alpine + command: redis-server --requirepass ${REDIS_PASSWORD} + healthcheck: + test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] + interval: 10s + timeout: 3s + retries: 5 + backend: build: ./backend ports: - "8000:8000" volumes: - - ./backend/data:/app/data - ./backend:/app environment: - - DATA_DIR=/app/data + - DATABASE_URL=${DATABASE_URL} + - DATABASE_MIGRATE_URL=${DATABASE_MIGRATE_URL} + - MINIO_ENDPOINT=${MINIO_ENDPOINT} + - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} + - MINIO_SECRET_KEY=${MINIO_SECRET_KEY} + - MINIO_BUCKET=${MINIO_BUCKET} + - REDIS_URL=${REDIS_URL} - PYTHONDONTWRITEBYTECODE=1 extra_hosts: - "host.docker.internal:host-gateway" command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload + depends_on: + postgres: + condition: service_healthy + minio: + condition: service_healthy + redis: + condition: service_healthy + + celery-worker: + build: ./backend + environment: + - DATABASE_URL=${DATABASE_URL} + - MINIO_ENDPOINT=${MINIO_ENDPOINT} + - MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY} + - MINIO_SECRET_KEY=${MINIO_SECRET_KEY} + - MINIO_BUCKET=${MINIO_BUCKET} + - REDIS_URL=${REDIS_URL} + - PYTHONDONTWRITEBYTECODE=1 + extra_hosts: + - "host.docker.internal:host-gateway" + command: celery -A celery_app worker --loglevel=info -Q documents + depends_on: + postgres: + condition: service_healthy + minio: + condition: service_healthy + redis: + condition: service_healthy frontend: build: ./frontend @@ -23,3 +99,7 @@ services: depends_on: - backend command: npm run dev -- --host 0.0.0.0 + +volumes: + postgres_data: + minio_data: diff --git a/docker/postgres/initdb.d/01-init-users.sql b/docker/postgres/initdb.d/01-init-users.sql new file mode 100644 index 0000000..13ec8a2 --- /dev/null +++ b/docker/postgres/initdb.d/01-init-users.sql @@ -0,0 +1,12 @@ +-- docker/postgres/initdb.d/01-init-users.sql +-- Runs as the POSTGRES_USER (postgres superuser) on first container start only. +-- Note: Table-level grants (USAGE ON SCHEMA public, SELECT/INSERT/UPDATE/DELETE ON ALL TABLES, +-- ALTER DEFAULT PRIVILEGES) are issued by the Alembic initial migration (Plan 03), not here. + +-- Migration user: DDL privileges (CREATE TABLE, ALTER TABLE, CREATE INDEX) +CREATE USER docuvault_migrate WITH PASSWORD 'changeme_migrate'; +GRANT ALL PRIVILEGES ON DATABASE docuvault TO docuvault_migrate; + +-- App user: runtime DML only (SELECT, INSERT, UPDATE, DELETE) — no DDL +CREATE USER docuvault_app WITH PASSWORD 'changeme_app'; +GRANT CONNECT ON DATABASE docuvault TO docuvault_app;