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:
2026-09-22 15:07:15 +03:00
co-authored by Claude Sonnet 5
commit 2664cb8213
71 changed files with 4999 additions and 0 deletions
+108
View File
@@ -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: