Init project
This commit is contained in:
179
docker/docker-compose.yml
Normal file
179
docker/docker-compose.yml
Normal file
@@ -0,0 +1,179 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
# Core Service (Go)
|
||||
core-service:
|
||||
build:
|
||||
context: ./core-service
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8080:8080"
|
||||
environment:
|
||||
- SERVER_HOST=0.0.0.0
|
||||
- SERVER_PORT=8080
|
||||
- DB_HOST=postgres
|
||||
- DB_PORT=5432
|
||||
- DB_USER=erp_user
|
||||
- DB_PASSWORD=erp_pass
|
||||
- DB_NAME=erp_mvp
|
||||
- DB_SSLMODE=disable
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_PASSWORD=
|
||||
- REDIS_DB=0
|
||||
- JWT_SECRET=your-super-secret-jwt-key-change-in-production
|
||||
- JWT_EXPIRATION=24
|
||||
- DOC_SERVICE_URL=http://doc-service:8000
|
||||
- LOG_LEVEL=info
|
||||
depends_on:
|
||||
- postgres
|
||||
- redis
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Document Service (Python)
|
||||
doc-service:
|
||||
build:
|
||||
context: ./doc-service
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
- HOST=0.0.0.0
|
||||
- PORT=8000
|
||||
- DEBUG=false
|
||||
- LOG_LEVEL=INFO
|
||||
- REDIS_HOST=redis
|
||||
- REDIS_PORT=6379
|
||||
- REDIS_PASSWORD=
|
||||
- REDIS_DB=1
|
||||
- CORE_SERVICE_URL=http://core-service:8080
|
||||
- DOCUMENTS_CACHE_TTL=86400
|
||||
- MAX_DOCUMENT_SIZE=10485760
|
||||
- TEMPLATES_DIR=/app/templates
|
||||
- OUTPUT_DIR=/app/output
|
||||
- QR_CODE_SIZE=10
|
||||
- QR_CODE_BORDER=2
|
||||
volumes:
|
||||
- doc_templates:/app/templates
|
||||
- doc_output:/app/output
|
||||
depends_on:
|
||||
- redis
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Frontend (Angular)
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- "3000:80"
|
||||
environment:
|
||||
- API_URL=http://localhost:8080
|
||||
- DOC_SERVICE_URL=http://localhost:8000
|
||||
depends_on:
|
||||
- core-service
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Database (PostgreSQL)
|
||||
postgres:
|
||||
image: postgres:15-alpine
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRES_DB=erp_mvp
|
||||
- POSTGRES_USER=erp_user
|
||||
- POSTGRES_PASSWORD=erp_pass
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
- ./docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
|
||||
# Cache (Redis)
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
command: redis-server --appendonly yes
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
|
||||
# API Gateway (Traefik) - опционально
|
||||
traefik:
|
||||
image: traefik:v2.10
|
||||
command:
|
||||
- --api.insecure=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "8081:8080"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- gateway
|
||||
|
||||
# Monitoring (Prometheus)
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
|
||||
- prometheus_data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--web.console.libraries=/etc/prometheus/console_libraries'
|
||||
- '--web.console.templates=/etc/prometheus/consoles'
|
||||
- '--storage.tsdb.retention.time=200h'
|
||||
- '--web.enable-lifecycle'
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- monitoring
|
||||
|
||||
# Monitoring (Grafana)
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
ports:
|
||||
- "3001:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
volumes:
|
||||
- grafana_data:/var/lib/grafana
|
||||
- ./docker/grafana/provisioning:/etc/grafana/provisioning
|
||||
networks:
|
||||
- erp-network
|
||||
restart: unless-stopped
|
||||
profiles:
|
||||
- monitoring
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
doc_templates:
|
||||
doc_output:
|
||||
prometheus_data:
|
||||
grafana_data:
|
||||
|
||||
networks:
|
||||
erp-network:
|
||||
driver: bridge
|
||||
124
docker/postgres/init.sql
Normal file
124
docker/postgres/init.sql
Normal file
@@ -0,0 +1,124 @@
|
||||
-- Инициализация базы данных ERP MVP
|
||||
|
||||
-- Создание расширений
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Создание таблиц
|
||||
|
||||
-- Организации
|
||||
CREATE TABLE IF NOT EXISTS organizations (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
type VARCHAR(100),
|
||||
settings JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Пользователи
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(50) DEFAULT 'user',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Места хранения
|
||||
CREATE TABLE IF NOT EXISTS storage_locations (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
parent_id UUID REFERENCES storage_locations(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
address VARCHAR(100) NOT NULL,
|
||||
type VARCHAR(50) NOT NULL,
|
||||
coordinates JSONB DEFAULT '{}',
|
||||
qr_code VARCHAR(255),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Товары
|
||||
CREATE TABLE IF NOT EXISTS items (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
category VARCHAR(100),
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Размещение товаров
|
||||
CREATE TABLE IF NOT EXISTS item_placements (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
item_id UUID NOT NULL REFERENCES items(id) ON DELETE CASCADE,
|
||||
location_id UUID NOT NULL REFERENCES storage_locations(id) ON DELETE CASCADE,
|
||||
quantity INTEGER DEFAULT 1,
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
||||
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Операции
|
||||
CREATE TABLE IF NOT EXISTS operations (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
organization_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
||||
operation_type VARCHAR(50) NOT NULL,
|
||||
item_id UUID REFERENCES items(id) ON DELETE SET NULL,
|
||||
from_location_id UUID REFERENCES storage_locations(id) ON DELETE SET NULL,
|
||||
to_location_id UUID REFERENCES storage_locations(id) ON DELETE SET NULL,
|
||||
quantity INTEGER,
|
||||
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
||||
metadata JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Создание индексов для производительности
|
||||
CREATE INDEX IF NOT EXISTS idx_users_organization_id ON users(organization_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
||||
CREATE INDEX IF NOT EXISTS idx_storage_locations_organization_id ON storage_locations(organization_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_storage_locations_parent_id ON storage_locations(parent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_storage_locations_type ON storage_locations(type);
|
||||
CREATE INDEX IF NOT EXISTS idx_items_organization_id ON items(organization_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_items_category ON items(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_item_placements_organization_id ON item_placements(organization_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_item_placements_item_id ON item_placements(item_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_item_placements_location_id ON item_placements(location_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_operations_organization_id ON operations(organization_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_operations_created_at ON operations(created_at);
|
||||
|
||||
-- Создание триггеров для автоматического обновления updated_at
|
||||
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
||||
RETURNS TRIGGER AS $$
|
||||
BEGIN
|
||||
NEW.updated_at = NOW();
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$ language 'plpgsql';
|
||||
|
||||
CREATE TRIGGER update_organizations_updated_at BEFORE UPDATE ON organizations
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_storage_locations_updated_at BEFORE UPDATE ON storage_locations
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_items_updated_at BEFORE UPDATE ON items
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
CREATE TRIGGER update_item_placements_updated_at BEFORE UPDATE ON item_placements
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- Создание тестовых данных (опционально)
|
||||
INSERT INTO organizations (id, name, type) VALUES
|
||||
('550e8400-e29b-41d4-a716-446655440000', 'Тестовая мастерская', 'workshop')
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
|
||||
INSERT INTO users (id, organization_id, email, password_hash, role) VALUES
|
||||
('550e8400-e29b-41d4-a716-446655440001', '550e8400-e29b-41d4-a716-446655440000', 'admin@test.com', '$2a$10$example', 'admin')
|
||||
ON CONFLICT (id) DO NOTHING;
|
||||
Reference in New Issue
Block a user