diff --git a/docker-compose.local.yml b/docker-compose.local.yml deleted file mode 100644 index dcca6db..0000000 --- a/docker-compose.local.yml +++ /dev/null @@ -1,28 +0,0 @@ -version: '3.8' - -services: - api: - build: . - command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload - volumes: - - .:/code - ports: - - "8000:8000" - environment: - DATABASE_URL: postgresql+asyncpg://fastapi:secret@postgres:5432/fastapi_dev - depends_on: - - postgres - - postgres: - image: postgres:15-alpine - environment: - POSTGRES_USER: fastapi - POSTGRES_PASSWORD: secret - POSTGRES_DB: fastapi_dev - volumes: - - postgres_data:/var/lib/postgresql/data - ports: - - "5432:5432" - -volumes: - postgres_data: \ No newline at end of file diff --git a/gateway/routers/__init__.py b/server/__init__.py similarity index 100% rename from gateway/routers/__init__.py rename to server/__init__.py diff --git a/server/auth_service/.dockerignore b/server/auth_service/.dockerignore new file mode 100644 index 0000000..e31985f --- /dev/null +++ b/server/auth_service/.dockerignore @@ -0,0 +1,3 @@ +.venv +__pycache__ +.idea \ No newline at end of file diff --git a/server/auth_service/.gitkeep b/server/auth_service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/auth_service/Dockerfile b/server/auth_service/Dockerfile new file mode 100644 index 0000000..c41bb0c --- /dev/null +++ b/server/auth_service/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.13.3-slim + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir fastapi[standard] && \ + pip install --no-cache-dir -r requirements.txt + +COPY . . + +WORKDIR /app/src + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8002", "--reload"] \ No newline at end of file diff --git a/server/auth_service/requirements.txt b/server/auth_service/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/server/auth_service/src/config.py b/server/auth_service/src/config.py new file mode 100644 index 0000000..66fc382 --- /dev/null +++ b/server/auth_service/src/config.py @@ -0,0 +1,10 @@ +import os +from abc import ABC +from dataclasses import asdict, dataclass + + +class CfgBase(ABC): + dict: callable = asdict + +class PostgresCfg(CfgBase): + url: str = os.getenv("DATABASE_URL") \ No newline at end of file diff --git a/server/auth_service/src/main.py b/server/auth_service/src/main.py new file mode 100644 index 0000000..e69de29 diff --git a/server/data_service/.dockerignore b/server/data_service/.dockerignore new file mode 100644 index 0000000..e31985f --- /dev/null +++ b/server/data_service/.dockerignore @@ -0,0 +1,3 @@ +.venv +__pycache__ +.idea \ No newline at end of file diff --git a/server/data_service/.gitkeep b/server/data_service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/data_service/Dockerfile b/server/data_service/Dockerfile new file mode 100644 index 0000000..79d41a0 --- /dev/null +++ b/server/data_service/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.13.3-slim + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir fastapi[standard] && \ + pip install --no-cache-dir -r requirements.txt + +COPY . . + +WORKDIR /app/src + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8003", "--reload"] \ No newline at end of file diff --git a/server/data_service/requirements.txt b/server/data_service/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/server/data_service/src/config.py b/server/data_service/src/config.py new file mode 100644 index 0000000..66fc382 --- /dev/null +++ b/server/data_service/src/config.py @@ -0,0 +1,10 @@ +import os +from abc import ABC +from dataclasses import asdict, dataclass + + +class CfgBase(ABC): + dict: callable = asdict + +class PostgresCfg(CfgBase): + url: str = os.getenv("DATABASE_URL") \ No newline at end of file diff --git a/server/data_service/src/main.py b/server/data_service/src/main.py new file mode 100644 index 0000000..e69de29 diff --git a/server/docker-compose.local.yml b/server/docker-compose.local.yml new file mode 100644 index 0000000..8e4811b --- /dev/null +++ b/server/docker-compose.local.yml @@ -0,0 +1,83 @@ +version: '3.8' + +services: + gateway: + build: ./gateway + container_name: gateway + ports: + - "8001:8001" + depends_on: + - postgres + environment: + DATABASE_URL: postgresql+asyncpg://fastapi:secret@postgres:5432/fastapi_dev + restart: unless-stopped + + auth_service: + build: ./auth_service + container_name: auth_service + ports: + - "8002:8002" + depends_on: + - postgres + environment: + DATABASE_URL: postgresql+asyncpg://fastapi:secret@postgres:5432/fastapi_dev + restart: unless-stopped + + data_service: + build: ./data_service + container_name: data_service + ports: + - "8003:8003" + depends_on: + - postgres + environment: + DATABASE_URL: postgresql+asyncpg://fastapi:secret@postgres:5432/fastapi_dev + restart: unless-stopped + + route_service: + build: ./route_service + container_name: route_service + ports: + - "8004:8004" + depends_on: + - postgres + environment: + DATABASE_URL: postgresql+asyncpg://fastapi:secret@postgres:5432/fastapi_dev + restart: unless-stopped + + station_service: + build: ./station_service + container_name: station_service + ports: + - "8005:8005" + depends_on: + - postgres + environment: + DATABASE_URL: postgresql+asyncpg://fastapi:secret@postgres:5432/fastapi_dev + restart: unless-stopped + + user_service: + build: ./user_service + container_name: user_service + ports: + - "8006:8006" + depends_on: + - postgres + environment: + DATABASE_URL: postgresql+asyncpg://fastapi:secret@postgres:5432/fastapi_dev + restart: unless-stopped + + postgres: + image: postgres:15-alpine + container_name: postgres + environment: + POSTGRES_USER: fastapi + POSTGRES_PASSWORD: secret + POSTGRES_DB: fastapi_dev + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "5432:5432" + +volumes: + postgres_data: \ No newline at end of file diff --git a/server/gateway/.dockerignire b/server/gateway/.dockerignire new file mode 100644 index 0000000..74a9069 --- /dev/null +++ b/server/gateway/.dockerignire @@ -0,0 +1,3 @@ +.venv +.idea +__pycache__ \ No newline at end of file diff --git a/server/gateway/.gitkeep b/server/gateway/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/gateway/Dockerfile b/server/gateway/Dockerfile new file mode 100644 index 0000000..cafbaf3 --- /dev/null +++ b/server/gateway/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.13.3-slim + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir fastapi[standard] && \ + pip install --no-cache-dir -r requirements.txt + +COPY . . + +WORKDIR /app/src + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001", "--reload"] \ No newline at end of file diff --git a/requirements.txt b/server/gateway/requirements.txt similarity index 94% rename from requirements.txt rename to server/gateway/requirements.txt index 51352b4..65c38d9 100644 --- a/requirements.txt +++ b/server/gateway/requirements.txt @@ -1,38 +1,38 @@ -annotated-types==0.7.0 -anyio==4.9.0 -bcrypt==4.3.0 -certifi==2025.4.26 -click==8.1.8 -colorama==0.4.6 -dnspython==2.7.0 -email_validator==2.2.0 -fastapi==0.115.12 -fastapi-cli==0.0.7 -h11==0.16.0 -httpcore==1.0.9 -httptools==0.6.4 -httpx==0.28.1 -idna==3.10 -Jinja2==3.1.6 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -mdurl==0.1.2 -psycopg2==2.9.10 -pydantic==2.11.4 -pydantic_core==2.33.2 -Pygments==2.19.1 -PyJWT==2.10.1 -python-dotenv==1.1.0 -python-multipart==0.0.20 -PyYAML==6.0.2 -rich==14.0.0 -rich-toolkit==0.14.6 -shellingham==1.5.4 -sniffio==1.3.1 -starlette==0.46.2 -typer==0.15.4 -typing-inspection==0.4.0 -typing_extensions==4.13.2 -uvicorn==0.34.2 -watchfiles==1.0.5 -websockets==15.0.1 +annotated-types==0.7.0 +anyio==4.9.0 +bcrypt==4.3.0 +certifi==2025.4.26 +click==8.1.8 +colorama==0.4.6 +dnspython==2.7.0 +email_validator==2.2.0 +fastapi==0.115.12 +fastapi-cli==0.0.7 +h11==0.16.0 +httpcore==1.0.9 +httptools==0.6.4 +httpx==0.28.1 +idna==3.10 +Jinja2==3.1.6 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +mdurl==0.1.2 +psycopg2==2.9.10 +pydantic==2.11.4 +pydantic_core==2.33.2 +Pygments==2.19.1 +PyJWT==2.10.1 +python-dotenv==1.1.0 +python-multipart==0.0.20 +PyYAML==6.0.2 +rich==14.0.0 +rich-toolkit==0.14.6 +shellingham==1.5.4 +sniffio==1.3.1 +starlette==0.46.2 +typer==0.15.4 +typing-inspection==0.4.0 +typing_extensions==4.13.2 +uvicorn==0.34.2 +watchfiles==1.0.5 +websockets==15.0.1 diff --git a/server/gateway/src/__init__.py b/server/gateway/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/server/gateway/src/config.py b/server/gateway/src/config.py new file mode 100644 index 0000000..66fc382 --- /dev/null +++ b/server/gateway/src/config.py @@ -0,0 +1,10 @@ +import os +from abc import ABC +from dataclasses import asdict, dataclass + + +class CfgBase(ABC): + dict: callable = asdict + +class PostgresCfg(CfgBase): + url: str = os.getenv("DATABASE_URL") \ No newline at end of file diff --git a/server/gateway/src/dependencies/__init__.py b/server/gateway/src/dependencies/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gateway/dependencies/auth.py b/server/gateway/src/dependencies/auth.py similarity index 100% rename from gateway/dependencies/auth.py rename to server/gateway/src/dependencies/auth.py diff --git a/gateway/main.py b/server/gateway/src/main.py similarity index 88% rename from gateway/main.py rename to server/gateway/src/main.py index 04672cd..4e4f0ef 100644 --- a/gateway/main.py +++ b/server/gateway/src/main.py @@ -1,42 +1,43 @@ -from fastapi import FastAPI, Depends, HTTPException -from fastapi.middleware.cors import CORSMiddleware -from contextlib import asynccontextmanager -import logging -import uvicorn - -from routers import auth, user, station, route - -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s [%(levelname)s] %(name)s: %(message)s" -) -logger = logging.getLogger(__name__) - - -app = FastAPI(title="EV Route Planner Gateway") - -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# Подключение маршрутов -app.include_router(auth.router, prefix="/auth") -app.include_router(user.router, prefix="/user") -app.include_router(station.router, prefix="/stations") -app.include_router(route.router, prefix="/route") -#app.include_router(data.router, prefix="/data") - -@asynccontextmanager -async def lifespan(app: FastAPI): - logger.info("Gateway server is starting...") - yield - logger.info("Gateway server is shutting down...") - - -if __name__ == "__main__": - logger.info("Running with Uvicorn at http://0.0.0.0:8000") +from fastapi import FastAPI +from fastapi.middleware.cors import CORSMiddleware +from contextlib import asynccontextmanager +import logging +import uvicorn + +from server.gateway.src.routers import auth, route +from server.gateway.src.routers import user, station + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s [%(levelname)s] %(name)s: %(message)s" +) +logger = logging.getLogger(__name__) + + +app = FastAPI(title="EV Route Planner Gateway") + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + +# Подключение маршрутов +app.include_router(auth.router, prefix="/auth") +app.include_router(user.router, prefix="/user") +app.include_router(station.router, prefix="/stations") +app.include_router(route.router, prefix="/route") +#app.include_router(data.router, prefix="/data") + +@asynccontextmanager +async def lifespan(app: FastAPI): + logger.info("Gateway server is starting...") + yield + logger.info("Gateway server is shutting down...") + + +if __name__ == "__main__": + logger.info("Running with Uvicorn at http://0.0.0.0:8000") uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file diff --git a/server/gateway/src/routers/__init__.py b/server/gateway/src/routers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/gateway/routers/auth.py b/server/gateway/src/routers/auth.py similarity index 96% rename from gateway/routers/auth.py rename to server/gateway/src/routers/auth.py index 7c1c952..2e99684 100644 --- a/gateway/routers/auth.py +++ b/server/gateway/src/routers/auth.py @@ -1,45 +1,45 @@ -from fastapi import APIRouter, HTTPException, Depends -from pydantic import BaseModel, EmailStr -from utils import hash_password, verify_password, create_access_token -import psycopg2 - -router = APIRouter() - -SECRET_KEY = "secret" - -conn = psycopg2.connect(dbname="evroutesusers", user="roki", password="roki", host="localhost") -cursor = conn.cursor() - -class LoginData(BaseModel): - email: EmailStr - password: str - -class RegisterData(BaseModel): - email: EmailStr - password: str - role: str = "user" - -@router.post("/register") -def register(data: RegisterData): - cursor.execute("SELECT 1 FROM users WHERE email = %s", (data.email,)) - if cursor.fetchone(): - raise HTTPException(status_code=400, detail="User already exists") - - hashed_pw = hash_password(data.password) - - cursor.execute( - "INSERT INTO users (email, password_hash, role) VALUES (%s, %s, %s)", - (data.email, hashed_pw, data.role) - ) - conn.commit() - return {"status": "registered"} - -@router.post("/login") -def login(data: LoginData): - cursor.execute("SELECT password_hash, role FROM users WHERE email = %s", (data.email,)) - row = cursor.fetchone() - if not row or not verify_password(data.password, row[0]): - raise HTTPException(status_code=401, detail="Invalid credentials") - - token = create_access_token({"email": data.email, "role": row[1]}) +from fastapi import APIRouter, HTTPException, Depends +from pydantic import BaseModel, EmailStr +from utils import hash_password, verify_password, create_access_token +import psycopg2 + +router = APIRouter() + +SECRET_KEY = "secret" + +conn = psycopg2.connect(dbname="evroutesusers", user="roki", password="roki", host="localhost") +cursor = conn.cursor() + +class LoginData(BaseModel): + email: EmailStr + password: str + +class RegisterData(BaseModel): + email: EmailStr + password: str + role: str = "user" + +@router.post("/register") +def register(data: RegisterData): + cursor.execute("SELECT 1 FROM users WHERE email = %s", (data.email,)) + if cursor.fetchone(): + raise HTTPException(status_code=400, detail="User already exists") + + hashed_pw = hash_password(data.password) + + cursor.execute( + "INSERT INTO users (email, password_hash, role) VALUES (%s, %s, %s)", + (data.email, hashed_pw, data.role) + ) + conn.commit() + return {"status": "registered"} + +@router.post("/login") +def login(data: LoginData): + cursor.execute("SELECT password_hash, role FROM users WHERE email = %s", (data.email,)) + row = cursor.fetchone() + if not row or not verify_password(data.password, row[0]): + raise HTTPException(status_code=401, detail="Invalid credentials") + + token = create_access_token({"email": data.email, "role": row[1]}) return {"access_token": token} \ No newline at end of file diff --git a/gateway/routers/route.py b/server/gateway/src/routers/route.py similarity index 95% rename from gateway/routers/route.py rename to server/gateway/src/routers/route.py index 9feb94d..f51661f 100644 --- a/gateway/routers/route.py +++ b/server/gateway/src/routers/route.py @@ -1,18 +1,18 @@ -from fastapi import APIRouter -from pydantic import BaseModel - -router = APIRouter() - -class RouteRequest(BaseModel): - start: str - end: str - battery_level: int - -@router.post("/") -def calculate_route(data: RouteRequest): - return { - "start": data.start, - "end": data.end, - "estimated_time": "2h 30m", - "stations_on_route": [] +from fastapi import APIRouter +from pydantic import BaseModel + +router = APIRouter() + +class RouteRequest(BaseModel): + start: str + end: str + battery_level: int + +@router.post("/") +def calculate_route(data: RouteRequest): + return { + "start": data.start, + "end": data.end, + "estimated_time": "2h 30m", + "stations_on_route": [] } \ No newline at end of file diff --git a/gateway/routers/station.py b/server/gateway/src/routers/station.py similarity index 96% rename from gateway/routers/station.py rename to server/gateway/src/routers/station.py index b7f47dd..7554805 100644 --- a/gateway/routers/station.py +++ b/server/gateway/src/routers/station.py @@ -1,34 +1,34 @@ -from fastapi import APIRouter -from pydantic import BaseModel -import psycopg2 - -router = APIRouter() - -conn = psycopg2.connect(dbname="evroutesstations", user="roki", password="roki", host="localhost") -cursor = conn.cursor() - -class Station(BaseModel): - name: str - latitude: float - longitude: float - connector_type: str - power_kW: int - working_hours: str - -@router.post("/") -def add_station(station: Station): - cursor.execute( - """ - INSERT INTO stations (name, latitude, longitude, connector_type, power_kW, working_hours) - VALUES (%s, %s, %s, %s, %s, %s) - """, - (station.name, station.latitude, station.longitude, station.connector_type, station.power_kW, station.working_hours) - ) - conn.commit() - return {"status": "ok"} - -@router.get("/") -def get_stations(): - cursor.execute("SELECT * FROM stations") - rows = cursor.fetchall() +from fastapi import APIRouter +from pydantic import BaseModel +import psycopg2 + +router = APIRouter() + +conn = psycopg2.connect(dbname="evroutesstations", user="roki", password="roki", host="localhost") +cursor = conn.cursor() + +class Station(BaseModel): + name: str + latitude: float + longitude: float + connector_type: str + power_kW: int + working_hours: str + +@router.post("/") +def add_station(station: Station): + cursor.execute( + """ + INSERT INTO stations (name, latitude, longitude, connector_type, power_kW, working_hours) + VALUES (%s, %s, %s, %s, %s, %s) + """, + (station.name, station.latitude, station.longitude, station.connector_type, station.power_kW, station.working_hours) + ) + conn.commit() + return {"status": "ok"} + +@router.get("/") +def get_stations(): + cursor.execute("SELECT * FROM stations") + rows = cursor.fetchall() return rows \ No newline at end of file diff --git a/gateway/routers/user.py b/server/gateway/src/routers/user.py similarity index 96% rename from gateway/routers/user.py rename to server/gateway/src/routers/user.py index a18d363..3821aed 100644 --- a/gateway/routers/user.py +++ b/server/gateway/src/routers/user.py @@ -1,36 +1,36 @@ -from fastapi import APIRouter -from pydantic import BaseModel -import psycopg2 - -router = APIRouter() - -conn = psycopg2.connect(dbname="evroutesuserinfo", user="roki", password="roki", host="localhost") -cursor = conn.cursor() - -class UserData(BaseModel): - email: str - car_model: str - battery_capacity: float - connector_type: str - -@router.post("/") -def save_user(data: UserData): - cursor.execute( - """ - INSERT INTO users (email, car_model, battery_capacity, connector_type) - VALUES (%s, %s, %s, %s) - ON CONFLICT (email) DO UPDATE SET - car_model = EXCLUDED.car_model, - battery_capacity = EXCLUDED.battery_capacity, - connector_type = EXCLUDED.connector_type - """, - (data.email, data.car_model, data.battery_capacity, data.connector_type) - ) - conn.commit() - return {"status": "saved"} - -@router.get("/{email}") -def get_user(email: str): - cursor.execute("SELECT * FROM users WHERE email = %s", (email,)) - row = cursor.fetchone() +from fastapi import APIRouter +from pydantic import BaseModel +import psycopg2 + +router = APIRouter() + +conn = psycopg2.connect(dbname="evroutesuserinfo", user="roki", password="roki", host="localhost") +cursor = conn.cursor() + +class UserData(BaseModel): + email: str + car_model: str + battery_capacity: float + connector_type: str + +@router.post("/") +def save_user(data: UserData): + cursor.execute( + """ + INSERT INTO users (email, car_model, battery_capacity, connector_type) + VALUES (%s, %s, %s, %s) + ON CONFLICT (email) DO UPDATE SET + car_model = EXCLUDED.car_model, + battery_capacity = EXCLUDED.battery_capacity, + connector_type = EXCLUDED.connector_type + """, + (data.email, data.car_model, data.battery_capacity, data.connector_type) + ) + conn.commit() + return {"status": "saved"} + +@router.get("/{email}") +def get_user(email: str): + cursor.execute("SELECT * FROM users WHERE email = %s", (email,)) + row = cursor.fetchone() return row \ No newline at end of file diff --git a/gateway/utils.py b/server/gateway/src/utils.py similarity index 100% rename from gateway/utils.py rename to server/gateway/src/utils.py diff --git a/server/route_service/.dockerignore b/server/route_service/.dockerignore new file mode 100644 index 0000000..e31985f --- /dev/null +++ b/server/route_service/.dockerignore @@ -0,0 +1,3 @@ +.venv +__pycache__ +.idea \ No newline at end of file diff --git a/server/route_service/.gitkeep b/server/route_service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/route_service/Dockerfile b/server/route_service/Dockerfile new file mode 100644 index 0000000..e132f97 --- /dev/null +++ b/server/route_service/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.13.3-slim + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir fastapi[standard] && \ + pip install --no-cache-dir -r requirements.txt + +COPY . . + +WORKDIR /app/src + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8004", "--reload"] \ No newline at end of file diff --git a/server/route_service/requirements.txt b/server/route_service/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/server/route_service/src/config.py b/server/route_service/src/config.py new file mode 100644 index 0000000..66fc382 --- /dev/null +++ b/server/route_service/src/config.py @@ -0,0 +1,10 @@ +import os +from abc import ABC +from dataclasses import asdict, dataclass + + +class CfgBase(ABC): + dict: callable = asdict + +class PostgresCfg(CfgBase): + url: str = os.getenv("DATABASE_URL") \ No newline at end of file diff --git a/server/route_service/src/main.py b/server/route_service/src/main.py new file mode 100644 index 0000000..e69de29 diff --git a/server/station_service/.dockerignore b/server/station_service/.dockerignore new file mode 100644 index 0000000..e31985f --- /dev/null +++ b/server/station_service/.dockerignore @@ -0,0 +1,3 @@ +.venv +__pycache__ +.idea \ No newline at end of file diff --git a/server/station_service/.gitkeep b/server/station_service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/station_service/Dockerfile b/server/station_service/Dockerfile new file mode 100644 index 0000000..70d0a72 --- /dev/null +++ b/server/station_service/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.13.3-slim + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir fastapi[standard] && \ + pip install --no-cache-dir -r requirements.txt + +COPY . . + +WORKDIR /app/src + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8005", "--reload"] \ No newline at end of file diff --git a/server/station_service/requirements.txt b/server/station_service/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/server/station_service/src/config.py b/server/station_service/src/config.py new file mode 100644 index 0000000..66fc382 --- /dev/null +++ b/server/station_service/src/config.py @@ -0,0 +1,10 @@ +import os +from abc import ABC +from dataclasses import asdict, dataclass + + +class CfgBase(ABC): + dict: callable = asdict + +class PostgresCfg(CfgBase): + url: str = os.getenv("DATABASE_URL") \ No newline at end of file diff --git a/server/station_service/src/main.py b/server/station_service/src/main.py new file mode 100644 index 0000000..e69de29 diff --git a/server/user_service/.dockerignore b/server/user_service/.dockerignore new file mode 100644 index 0000000..e31985f --- /dev/null +++ b/server/user_service/.dockerignore @@ -0,0 +1,3 @@ +.venv +__pycache__ +.idea \ No newline at end of file diff --git a/server/user_service/.gitkeep b/server/user_service/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/server/user_service/Dockerfile b/server/user_service/Dockerfile new file mode 100644 index 0000000..e00086c --- /dev/null +++ b/server/user_service/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.13.3-slim + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir fastapi[standard] && \ + pip install --no-cache-dir -r requirements.txt + +COPY . . + +WORKDIR /app/src + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8006", "--reload"] \ No newline at end of file diff --git a/server/user_service/requirements.txt b/server/user_service/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/server/user_service/src/config.py b/server/user_service/src/config.py new file mode 100644 index 0000000..66fc382 --- /dev/null +++ b/server/user_service/src/config.py @@ -0,0 +1,10 @@ +import os +from abc import ABC +from dataclasses import asdict, dataclass + + +class CfgBase(ABC): + dict: callable = asdict + +class PostgresCfg(CfgBase): + url: str = os.getenv("DATABASE_URL") \ No newline at end of file diff --git a/server/user_service/src/main.py b/server/user_service/src/main.py new file mode 100644 index 0000000..e69de29