diff --git a/faith-db/.env b/faith-db/.env new file mode 100644 index 0000000..ed090fa --- /dev/null +++ b/faith-db/.env @@ -0,0 +1,5 @@ +POSTGRES_IMAGE=postgres:17-bookworm +POSTGRES_DB=faith +POSTGRES_USER=faith +POSTGRES_PORT=5432 +POSTGRES_BIND_ADDRESS=127.0.0.1 diff --git a/faith-db/compose.production.yaml b/faith-db/compose.production.yaml new file mode 100644 index 0000000..1ac9cac --- /dev/null +++ b/faith-db/compose.production.yaml @@ -0,0 +1,49 @@ +name: faith-db-production + +services: + postgres: + image: ${POSTGRES_IMAGE:?POSTGRES_IMAGE must specify a pinned PostgreSQL image} + container_name: faith-postgres + restart: always + + environment: + POSTGRES_DB: ${POSTGRES_DB:-faith} + POSTGRES_USER: ${POSTGRES_USER:-faith} + POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password + PGDATA: /var/lib/postgresql/data/pgdata + + secrets: + - postgres_password + + volumes: + - ${POSTGRES_DATA_PATH:?POSTGRES_DATA_PATH is required}:/var/lib/postgresql/data + + healthcheck: + test: + [ + "CMD-SHELL", + "pg_isready -U ${POSTGRES_USER:-faith} -d ${POSTGRES_DB:-faith}", + ] + interval: 10s + timeout: 5s + retries: 10 + start_period: 30s + + stop_grace_period: 60s + + logging: + driver: json-file + options: + max-size: "100m" + max-file: "5" + + networks: + - faith_backend + +secrets: + postgres_password: + file: ${POSTGRES_PASSWORD_FILE:?POSTGRES_PASSWORD_FILE is required} + +networks: + faith_backend: + name: faith-backend diff --git a/faith-db/compose.yaml b/faith-db/compose.yaml new file mode 100644 index 0000000..f7b8852 --- /dev/null +++ b/faith-db/compose.yaml @@ -0,0 +1,47 @@ +name: faith-db-dev + +services: + postgres: + image: ${POSTGRES_IMAGE:-postgres:17-bookworm} + container_name: faith-postgres-dev + restart: unless-stopped + + environment: + POSTGRES_DB: ${POSTGRES_DB:-faith} + POSTGRES_USER: ${POSTGRES_USER:-faith} + POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password + PGDATA: /var/lib/postgresql/data/pgdata + + secrets: + - postgres_password + + ports: + - "${POSTGRES_BIND_ADDRESS:-127.0.0.1}:${POSTGRES_PORT:-5432}:5432" + + volumes: + - faith_postgres_dev_data:/var/lib/postgresql/data + + healthcheck: + test: + [ + "CMD-SHELL", + "pg_isready -U ${POSTGRES_USER:-faith} -d ${POSTGRES_DB:-faith}", + ] + interval: 5s + timeout: 5s + retries: 10 + start_period: 10s + + networks: + - faith_db + +secrets: + postgres_password: + file: ./secrets/postgres_password.txt + +volumes: + faith_postgres_dev_data: + +networks: + faith_db: + name: faith-db-dev diff --git a/faith-db/migrations/0001_users_devices_events.sql b/faith-db/migrations/0001_users_devices_events.sql new file mode 100644 index 0000000..4b05580 --- /dev/null +++ b/faith-db/migrations/0001_users_devices_events.sql @@ -0,0 +1,69 @@ +BEGIN; + +CREATE TABLE users ( + auth_id bytea PRIMARY KEY, + + created_at timestamptz NOT NULL DEFAULT now(), + + CONSTRAINT users_auth_id_size + CHECK (octet_length(auth_id) = 16) +); + +CREATE TABLE devices ( + auth_id bytea NOT NULL, + device_id bytea NOT NULL, + public_key bytea NOT NULL, + + registered_at timestamptz NOT NULL DEFAULT now(), + revoke_at timestamptz, + + PRIMARY KEY (auth_id, device_id), + + CONSTRAINT devices_users_fk + FOREIGN KEY (auth_id) + REFERENCES users(auth_id) + ON DELETE CASCADE, + + CONSTRAINT devices_auth_id_size + CHECK (octet_length(auth_id) = 16), + + CONSTRAINT devices_device_id_size + CHECK (octet_length(device_id) = 16), + + CONSTRAINT devices_public_key_size + CHECK (octet_length(public_key) = 32) +); + +CREATE TABLE device_events ( + event_id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, + + auth_id bytea NOT NULL, + device_id bytea NOT NULL, + + event_type integer NOT NULL, + event_data bytea NOT NULL, + + + created_at timestamptz NOT NULL DEFAULT now(), + acknowledged_at timestamptz, + + CONSTRAINT device_events_device_fk + FOREIGN KEY (auth_id, device_id) + REFERENCES devices(auth_id, device_id) + ON DELETE CASCADE, + + CONSTRAINT device_events_auth_id_size + CHECK (octet_length(auth_id) = 16), + + CONSTRAINT device_events_device_id_size + CHECK (octet_length(device_id) = 16), + + CONSTRAINT device_events_type_range + CHECK (event_type >= 0) +); + +CREATE INDEX device_events_pending_idx + ON device_events (auth_id, device_id, event_id) + WHERE acknowledged_at IS NULL; + +COMMIT; diff --git a/faith-db/secrets/postgres_password.txt b/faith-db/secrets/postgres_password.txt new file mode 100644 index 0000000..fa532dc --- /dev/null +++ b/faith-db/secrets/postgres_password.txt @@ -0,0 +1 @@ +faith