Skip to content

Commit e5df891

Browse files
committed
fix
2 parents bdbbaeb + 548616a commit e5df891

28 files changed

+1269
-135
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ poetry.toml
199199

200200
# ruff
201201
.ruff_cache/
202-
202+
pgdata
203203
# LSP config files
204204
pyrightconfig.json
205205

Dockerfile

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,64 @@ FROM python:3.13-slim-bookworm
44
# Install UV (ultra-fast Python package installer) from Astral.sh
55
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
66

7+
# Create non-root user for security
8+
RUN groupadd -r appuser && useradd -r -g appuser appuser
9+
710
# Ensure Python output is sent straight to terminal without buffering
811
ENV PYTHONUNBUFFERED=1 \
9-
PYTHONDONTWRITEBYTECODE=1
12+
PYTHONDONTWRITEBYTECODE=1 \
13+
UV_SYSTEM_PYTHON=1
1014

1115
# ======================
1216
# SYSTEM DEPENDENCIES
1317
# ======================
1418
RUN apt-get update && \
15-
apt-get install -y --no-install-recommends curl gettext && \
16-
apt-get clean && rm -rf /var/lib/apt/lists/*
19+
apt-get install -y --no-install-recommends \
20+
curl \
21+
gettext \
22+
ca-certificates && \
23+
apt-get clean && \
24+
rm -rf /var/lib/apt/lists/* && \
25+
rm -rf /tmp/* /var/tmp/*
1726

1827
# Set working directory inside container
1928
WORKDIR /app
2029

2130
# ======================
2231
# DEPENDENCY INSTALLATION
2332
# ======================
24-
# Copies the dependency files (py project.tool and uv.lock) to /app.
25-
COPY pyproject.toml uv.lock ./
33+
# Copy dependency files with proper ownership
34+
COPY --chown=appuser:appuser pyproject.toml uv.lock ./
2635

27-
# Install Python dependencies using UV:
28-
# --locked: ensures exact versions from lockfile are used
29-
# Copies the rest of the project code to /app.
30-
RUN uv sync --locked
36+
# Install Python dependencies using UV
37+
RUN uv sync --locked --no-dev
3138

3239
# ======================
3340
# APPLICATION CODE
3441
# ======================
42+
# Copy entrypoint script first
43+
COPY --chown=appuser:appuser entrypoint.sh /app/entrypoint.sh
44+
RUN chmod +x /app/entrypoint.sh
45+
3546
# Copy the rest of the application code
36-
# Note: This is done after dependency installation for better caching
37-
COPY . .
47+
COPY --chown=appuser:appuser . .
3848

39-
# Copies the script entrypoint.sh in /app.
40-
# Makes it executable (chmod +x).
41-
COPY entrypoint.sh /app/entrypoint.sh
42-
RUN chmod +x /app/entrypoint.sh
49+
# Create directories for Django with proper permissions
50+
RUN mkdir -p /app/static /app/media && \
51+
chown -R appuser:appuser /app
4352

4453
# ======================
4554
# RUNTIME CONFIGURATION
4655
# ======================
56+
# Switch to non-root user
57+
USER appuser
58+
4759
# Expose the port Django runs on
4860
EXPOSE 8000
4961

62+
# Health check
63+
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
64+
CMD curl -f http://localhost:8000/health/ || exit 1
65+
5066
# Launches the application through a script entrypoint.sh
5167
ENTRYPOINT ["/app/entrypoint.sh"]

Makefile

Lines changed: 109 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,129 @@
1+
# ======================
2+
# VARIABLES
3+
# ======================
14
USERID := $(shell id -u)
25
GROUPID := $(shell id -g)
36
PYTHON := docker compose run -u $(USERID):$(GROUPID) --rm django uv run
7+
DOCKER_COMPOSE := docker compose
8+
RUFF := uvx ruff
49

5-
collectstatic:
10+
# ======================
11+
# HELP
12+
# ======================
13+
.PHONY: help
14+
help: ## Show this help message
15+
@echo "Available commands:"
16+
@awk 'BEGIN {FS = ":.*##"; printf "\n"} /^[a-zA-Z_-]+:.*?##/ { printf " %-20s %s\n", $$1, $$2 } /^##@/ { printf "\n%s\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
17+
18+
# ======================
19+
# DOCKER MANAGEMENT
20+
# ======================
21+
.PHONY: build up down restart logs clean
22+
build: ## Build Docker images
23+
$(DOCKER_COMPOSE) build
24+
25+
up: ## Start all services
26+
$(DOCKER_COMPOSE) up -d
27+
28+
down: ## Stop all services
29+
$(DOCKER_COMPOSE) down
30+
31+
restart: ## Restart all services
32+
$(DOCKER_COMPOSE) restart
33+
34+
logs: ## Show logs for all services
35+
$(DOCKER_COMPOSE) logs -f
36+
37+
clean: ## Clean up Docker resources
38+
$(DOCKER_COMPOSE) down -v --remove-orphans
39+
docker system prune -f
40+
41+
# ======================
42+
# DJANGO MANAGEMENT
43+
# ======================
44+
.PHONY: collectstatic startapp makemigrations migrate createsuperuser shell reset_db
45+
collectstatic: ## Collect static files
646
$(PYTHON) manage.py collectstatic --noinput -c
747

8-
startapp:
48+
startapp: ## Create new Django app (usage: make startapp app=myapp)
949
$(PYTHON) manage.py startapp ${app}
1050

11-
makemigrations:
51+
makemigrations: ## Create database migrations
1252
$(PYTHON) manage.py makemigrations ${app}
1353

14-
migrate:
54+
migrate: ## Apply database migrations
1555
$(PYTHON) manage.py migrate ${app}
1656

17-
createsuperuser:
57+
createsuperuser: ## Create Django superuser
1858
$(PYTHON) manage.py createsuperuser
1959

20-
shell:
60+
shell: ## Open Django shell
2161
$(PYTHON) manage.py shell_plus
2262

23-
reset_db:
63+
reset_db: ## Reset database
2464
$(PYTHON) manage.py reset_db
2565

26-
format:
27-
uvx ruff check --fix apps config && uvx ruff check --select I --fix apps config && uvx ruff format apps config
66+
# ======================
67+
# CODE QUALITY
68+
# ======================
69+
.PHONY: format lint check test
70+
format: ## Format code with ruff
71+
$(RUFF) check --fix apps config
72+
$(RUFF) check --select I --fix apps config
73+
$(RUFF) format apps config
74+
75+
lint: ## Run linting checks
76+
$(RUFF) check apps config
77+
78+
check: ## Run all code quality checks
79+
$(RUFF) check apps config
80+
$(RUFF) format --check apps config
81+
82+
test: ## Run tests
83+
$(PYTHON) manage.py test
2884

29-
run:
30-
$(PYTHON) manage.py migrate
85+
# ======================
86+
# DEVELOPMENT
87+
# ======================
88+
.PHONY: run dev install requirements
89+
run: migrate ## Run Django development server
3190
$(PYTHON) manage.py runserver 0.0.0.0:8000
91+
92+
dev: up ## Start development environment
93+
@echo "Development environment started"
94+
@echo "Django: http://localhost:8000"
95+
@echo "PostgreSQL: localhost:5432"
96+
97+
install: ## Install dependencies
98+
uv sync --locked
99+
100+
requirements: ## Update requirements
101+
uv lock
102+
103+
# ======================
104+
# PRODUCTION
105+
# ======================
106+
.PHONY: prod-build prod-up prod-down
107+
prod-build: ## Build production images
108+
$(DOCKER_COMPOSE) -f docker-compose.prod.yml build
109+
110+
prod-up: ## Start production environment
111+
$(DOCKER_COMPOSE) -f docker-compose.prod.yml up -d
112+
113+
prod-down: ## Stop production environment
114+
$(DOCKER_COMPOSE) -f docker-compose.prod.yml down
115+
116+
# ======================
117+
# UTILITIES
118+
# ======================
119+
.PHONY: backup restore health
120+
backup: ## Create database backup
121+
$(DOCKER_COMPOSE) exec postgres pg_dump -U $$POSTGRES_USER $$POSTGRES_DB > backup_$$(date +%Y%m%d_%H%M%S).sql
122+
123+
restore: ## Restore database from backup (usage: make restore file=backup.sql)
124+
$(DOCKER_COMPOSE) exec -T postgres psql -U $$POSTGRES_USER $$POSTGRES_DB < ${file}
125+
126+
health: ## Check services health
127+
$(DOCKER_COMPOSE) ps
128+
@echo "\n--- Service Health ---"
129+
@curl -f http://localhost:8000/health/ || echo "Django service not responding"

0 commit comments

Comments
 (0)