Initial commit: backend scaffold, auth, frontend login
- FastAPI + SQLAlchemy async + Alembic + Postgres backend - Auth: JWT access + rotating refresh tokens, argon2, roles, audit log - React 19 + Vite frontend: login page, protected route, auth context - Docker Compose: postgres, redis, migrate, api, worker (placeholder), frontend/nginx Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
name: lux-fiscal
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: ${POSTGRES_DB}
|
||||
POSTGRES_USER: ${POSTGRES_USER}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
# Порт наружу не публикуется: доступ только из сети compose.
|
||||
# Для локальной отладки раскомментируйте, привязав к loopback.
|
||||
# ports:
|
||||
# - "127.0.0.1:5432:5432"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
restart: unless-stopped
|
||||
command: ["redis-server", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Миграции выполняются отдельным одноразовым контейнером, а не при старте api.
|
||||
# Иначе при нескольких репликах api они пошли бы параллельно.
|
||||
migrate:
|
||||
build:
|
||||
context: ./backend
|
||||
env_file: .env
|
||||
environment:
|
||||
POSTGRES_HOST: postgres
|
||||
REDIS_HOST: redis
|
||||
command: ["alembic", "upgrade", "head"]
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
restart: "no"
|
||||
|
||||
api:
|
||||
build:
|
||||
context: ./backend
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
POSTGRES_HOST: postgres
|
||||
REDIS_HOST: redis
|
||||
ports:
|
||||
- "127.0.0.1:8000:8000"
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- receipt_storage:/app/storage
|
||||
|
||||
worker:
|
||||
build:
|
||||
context: ./backend
|
||||
restart: unless-stopped
|
||||
env_file: .env
|
||||
environment:
|
||||
POSTGRES_HOST: postgres
|
||||
REDIS_HOST: redis
|
||||
# Подключается на этапе 4 (Нова Пошта) — сейчас заглушка, чтобы структура
|
||||
# compose не менялась задним числом.
|
||||
command: ["python", "-c", "print('worker placeholder: см. этап 4 плана'); import time; time.sleep(3600)"]
|
||||
# Заглушка ничего не слушает на 8000, а HEALTHCHECK бэкенда унаследован
|
||||
# из общего образа — без отключения контейнер вечно висел бы "unhealthy".
|
||||
healthcheck:
|
||||
disable: true
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
volumes:
|
||||
- receipt_storage:/app/storage
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: frontend/Dockerfile
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:5173:80"
|
||||
depends_on:
|
||||
- api
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
receipt_storage:
|
||||
Reference in New Issue
Block a user