diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..d9f9b1b --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,32 @@ +{ + "name": "FastAPI Jinja2 Postgres WebApp", + "image": "mcr.microsoft.com/devcontainers/python:3.13-bookworm", + "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", + + "features": { + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} + }, + + "runArgs": [ + "--add-host=host.docker.internal:host-gateway" + ], + + "forwardPorts": [8000, 5432], + "portsAttributes": { + "8000": { "label": "FastAPI", "onAutoForward": "openBrowser" }, + "5432": { "label": "PostgreSQL" } + }, + + "initializeCommand": "bash \"${localWorkspaceFolder}/.devcontainer/ensure-env.sh\"", + "postStartCommand": "docker compose -f .devcontainer/docker-compose.yml up -d", + "postCreateCommand": "bash .devcontainer/init-env.sh && curl -LsSf https://astral.sh/uv/install.sh | sh && ~/.local/bin/uv sync", + + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance" + ] + } + } +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..48bc1d4 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -0,0 +1,15 @@ +services: + db: + image: postgres:16 + restart: unless-stopped + ports: + - "5432:5432" + environment: + POSTGRES_USER: ${DB_USER:-postgres} + POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres} + POSTGRES_DB: ${DB_NAME:-fastapi-jinja2-postgres-webapp} + volumes: + - pgdata:/var/lib/postgresql/data + +volumes: + pgdata: diff --git a/.devcontainer/ensure-env.sh b/.devcontainer/ensure-env.sh new file mode 100644 index 0000000..9acc18b --- /dev/null +++ b/.devcontainer/ensure-env.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run from repo root +cd "$(dirname "${BASH_SOURCE[0]}")/.." + +# Ensure a .env exists BEFORE docker compose evaluates env_file +if [ ! -f ".env" ]; then + if [ -f ".env.example" ]; then + cp .env.example .env || true + else + touch .env + fi +fi + +echo ".env ensured for compose evaluation." + diff --git a/.devcontainer/init-env.sh b/.devcontainer/init-env.sh new file mode 100644 index 0000000..909a461 --- /dev/null +++ b/.devcontainer/init-env.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Run from repo root +cd "$(dirname "${BASH_SOURCE[0]}")/.." + +# Ensure a working .env exists +if [ ! -f ".env" ]; then + if [ -f ".env.example" ]; then + cp .env.example .env || true + else + touch .env + fi +fi + +# Ensure DB_HOST points to host.docker.internal for DooD sibling container access +if grep -q '^DB_HOST=' .env; then + sed -i 's/^DB_HOST=.*/DB_HOST=host.docker.internal/' .env +else + echo 'DB_HOST=host.docker.internal' >> .env +fi + +generate_secret() { + if command -v openssl >/dev/null 2>&1; then + openssl rand -base64 32 + else + python - <<'PY' +import base64, os +print(base64.b64encode(os.urandom(32)).decode('ascii')) +PY + fi +} + +# Ensure SECRET_KEY exists and is non-empty/non-placeholder +if grep -q '^SECRET_KEY=' .env; then + current_secret="$(grep '^SECRET_KEY=' .env | cut -d= -f2-)" + if [ -z "${current_secret}" ] || [ "${current_secret}" = "changeme" ] || [ "${current_secret}" = "REPLACE_ME" ]; then + new_secret="$(generate_secret)" + sed -i "s/^SECRET_KEY=.*/SECRET_KEY=${new_secret}/" .env + fi +else + echo "SECRET_KEY=$(generate_secret)" >> .env +fi + +echo "Environment prepared. DB_HOST set to 'host.docker.internal' and SECRET_KEY ensured." + diff --git a/.gitignore b/.gitignore index d46de6b..521c4c6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -.devcontainer __pycache__ *.pyc .env diff --git a/docker-compose.yml b/docker-compose.yml index 73e2ebb..fa0a960 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,11 +2,11 @@ services: db: image: postgres:latest environment: - POSTGRES_USER: ${DB_USER} - POSTGRES_PASSWORD: ${DB_PASSWORD} - POSTGRES_DB: ${DB_NAME} + POSTGRES_USER: ${DB_USER:-postgres} + POSTGRES_PASSWORD: ${DB_PASSWORD:-postgres} + POSTGRES_DB: ${DB_NAME:-fastapi-jinja2-postgres-webapp} ports: - - "${DB_PORT}:5432" + - "${DB_PORT:-5432}:5432" volumes: - postgres_data:/var/lib/postgresql/data