Skip to content

Commit 1a76a6f

Browse files
committed
Docker & Nginx
1 parent 217321e commit 1a76a6f

22 files changed

Lines changed: 272 additions & 181 deletions

.dockerignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.git
2+
.gitignore
3+
.github
4+
.vscode
5+
__pycache__/
6+
*.pyc
7+
*.pyo
8+
*.pyd
9+
*.log
10+
tests/
11+
docs/
12+
.env
13+
.env.*
14+
Dockerfile.*
15+
docker-compose.yml
16+
db/

Dockerfile.api

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
FROM python:3.12-slim-bookworm AS base
2+
3+
RUN apt-get update && apt-get install -y --no-install-recommends \
4+
ca-certificates \
5+
build-essential \
6+
libpq-dev \
7+
gcc \
8+
curl \
9+
&& rm -rf /var/lib/apt/lists/*
10+
11+
ENV PYTHONDONTWRITEBYTECODE=1 \
12+
PYTHONUNBUFFERED=1 \
13+
PIP_NO_CACHE_DIR=1 \
14+
DEBIAN_FRONTEND=noninteractive
15+
16+
WORKDIR /app
17+
18+
COPY requirements.txt /app/requirements.txt
19+
RUN pip install --upgrade pip && pip install -r /app/requirements.txt
20+
21+
COPY . /app
22+
23+
ENV PYTHONPATH=/app
24+
25+
EXPOSE 5000
26+
27+
HEALTHCHECK --interval=10s --timeout=3s --retries=5 CMD curl -fsS http://localhost:5000/api/health || exit 1
28+
29+
ENV GUNICORN_WORKERS=1
30+
ENV GUNICORN_THREADS=1
31+
32+
CMD ["sh", "-c", "gunicorn -w ${GUNICORN_WORKERS} -k gthread --threads ${GUNICORN_THREADS} -b 0.0.0.0:5000 web.api.app:app"]

Dockerfile.nginx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM nginx:1.27-alpine
2+
3+
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
4+
5+
COPY web/ /usr/share/nginx/html/
6+
7+
EXPOSE 80
8+
9+
HEALTHCHECK --interval=10s --timeout=3s --retries=5 CMD wget -qO- http://localhost/ || exit 1

config.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ class Settings(BaseSettings):
1818
OUTPUT_XLSX: str = r"data_real/defense_schedule.xlsx"
1919

2020
# --- PostgreSQL ---
21-
# DB_URL: str = "postgresql+psycopg://user:pass@host/db"
22-
DB_URL: str = "postgresql://postgres:1234567890@localhost/thesis_planner"
21+
DB_URL: str = "postgresql://admin:rhAJPj3N6o7Ln6toR@db:5432/thesis_planner"
2322
RUN_ID: str = str(uuid.uuid4())
2423

2524
# --- Planning / parsing ---

db/init/00_init.sql

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
CREATE TABLE IF NOT EXISTS academic_staff (
2+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
3+
first_name TEXT NOT NULL,
4+
last_name TEXT NOT NULL,
5+
academic_rank TEXT,
6+
committee_time INT CHECK (committee_time IS NULL OR committee_time >= 0),
7+
UNIQUE (first_name, last_name, academic_rank)
8+
);
9+
10+
CREATE TABLE IF NOT EXISTS staff_availability (
11+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
12+
staff_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE CASCADE,
13+
availability_date DATE NOT NULL,
14+
start_time TIME NOT NULL,
15+
end_time TIME NOT NULL,
16+
CHECK (end_time > start_time)
17+
);
18+
19+
CREATE TABLE IF NOT EXISTS soft_constraints (
20+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
21+
staff_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE CASCADE,
22+
colleague_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE CASCADE,
23+
likes BOOLEAN NOT NULL,
24+
CHECK (staff_id <> colleague_id),
25+
UNIQUE (staff_id, colleague_id)
26+
);
27+
28+
CREATE TABLE IF NOT EXISTS theses (
29+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
30+
student_first_name TEXT NOT NULL,
31+
student_last_name TEXT NOT NULL,
32+
reviewer_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE RESTRICT,
33+
supervisor_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE RESTRICT,
34+
field_of_study TEXT NOT NULL,
35+
thesis_title TEXT NOT NULL,
36+
CHECK (reviewer_id <> supervisor_id)
37+
);
38+
39+
CREATE TABLE IF NOT EXISTS defense_schedule (
40+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
41+
defense_date DATE NOT NULL,
42+
chairman_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE RESTRICT,
43+
member2_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE RESTRICT,
44+
member3_id BIGINT NOT NULL REFERENCES academic_staff(id) ON DELETE RESTRICT,
45+
start_time TIME NOT NULL,
46+
end_time TIME NOT NULL,
47+
thesis_count INT NOT NULL CHECK (thesis_count >= 0),
48+
CHECK (end_time > start_time),
49+
CHECK (chairman_id <> member2_id
50+
AND chairman_id <> member3_id
51+
AND member2_id <> member3_id)
52+
);
53+
54+
CREATE TABLE IF NOT EXISTS committee_thesis_assignment (
55+
id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
56+
defense_schedule_id BIGINT NOT NULL REFERENCES defense_schedule(id) ON DELETE CASCADE,
57+
thesis_id BIGINT NOT NULL REFERENCES theses(id) ON DELETE CASCADE,
58+
assignment_order INT NOT NULL,
59+
UNIQUE (thesis_id),
60+
UNIQUE (defense_schedule_id, assignment_order)
61+
);
62+
63+
CREATE INDEX IF NOT EXISTS idx_staff_availability_staff_time
64+
ON staff_availability (staff_id, availability_date, start_time, end_time);
65+
66+
CREATE INDEX IF NOT EXISTS idx_soft_constraints_colleague
67+
ON soft_constraints (colleague_id);
68+
69+
CREATE INDEX IF NOT EXISTS idx_theses_reviewer
70+
ON theses (reviewer_id);
71+
72+
CREATE INDEX IF NOT EXISTS idx_theses_supervisor
73+
ON theses (supervisor_id);
74+
75+
CREATE INDEX IF NOT EXISTS idx_defsch_chairman
76+
ON defense_schedule (chairman_id);
77+
78+
CREATE INDEX IF NOT EXISTS idx_defsch_member2
79+
ON defense_schedule (member2_id);
80+
81+
CREATE INDEX IF NOT EXISTS idx_defsch_member3
82+
ON defense_schedule (member3_id);
83+
84+
CREATE INDEX IF NOT EXISTS idx_defsch_start_time
85+
ON defense_schedule (start_time);
86+
87+
CREATE INDEX IF NOT EXISTS idx_committee_thesis_defense
88+
ON committee_thesis_assignment (defense_schedule_id);
89+
90+
CREATE INDEX IF NOT EXISTS idx_committee_thesis_thesis
91+
ON committee_thesis_assignment (thesis_id);

docker-compose.yml

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
services:
2+
db:
3+
restart: unless-stopped
4+
image: postgres:17
5+
container_name: thesis-db
6+
environment:
7+
POSTGRES_DB: ${POSTGRES_DB:-thesis}
8+
POSTGRES_USER: ${POSTGRES_USER:-thesis_user}
9+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-thesis_pass}
10+
volumes:
11+
- pgdata:/var/lib/postgresql/data
12+
- ./db/init:/docker-entrypoint-initdb.d
13+
healthcheck:
14+
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB -h localhost"]
15+
interval: 10s
16+
timeout: 5s
17+
retries: 10
18+
networks:
19+
- app-net
20+
21+
api:
22+
restart: unless-stopped
23+
build:
24+
context: .
25+
dockerfile: Dockerfile.api
26+
container_name: thesis-api
27+
depends_on:
28+
db:
29+
condition: service_healthy
30+
environment:
31+
DATABASE_URL: ${DATABASE_URL:-postgresql+psycopg://thesis_user:thesis_pass@db:5432/thesis}
32+
PYTHONUNBUFFERED: "1"
33+
expose:
34+
- "5000"
35+
networks:
36+
- app-net
37+
38+
nginx:
39+
restart: unless-stopped
40+
build:
41+
context: .
42+
dockerfile: Dockerfile.nginx
43+
container_name: thesis-nginx
44+
depends_on:
45+
- api
46+
ports:
47+
- "80:80"
48+
networks:
49+
- app-net
50+
51+
volumes:
52+
pgdata:
53+
54+
networks:
55+
app-net:
56+
driver: bridge

main.py

Lines changed: 0 additions & 148 deletions
This file was deleted.

0 commit comments

Comments
 (0)