first commit

This commit is contained in:
2026-03-16 00:02:58 +06:00
commit c11f0bd5bc
36 changed files with 11938 additions and 0 deletions

55
postgres/audit/init.sql Normal file
View File

@@ -0,0 +1,55 @@
-- =============================================================================
-- postgres/audit/init.sql
-- Runs once on first container start (postgres-audit).
-- Creates login users for audit_writer and audit_maintainer roles.
-- Role privileges are granted by V2 Flyway migration.
-- =============================================================================
-- audit_writer_login: login user that maps to audit_writer role
-- Used by HAPI audit datasource. INSERT only on audit schema.
CREATE USER audit_writer_login WITH
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
NOINHERIT -- does not automatically inherit role privileges
LOGIN
CONNECTION LIMIT 20 -- hard cap: prevents connection exhaustion
PASSWORD 'PLACEHOLDER_REPLACED_BY_ENTRYPOINT';
-- NOTE: Actual password is set by the postgres Docker entrypoint
-- reading AUDIT_DB_WRITER_PASSWORD from environment. This CREATE USER
-- is a template — the entrypoint rewrites the password on init.
-- In practice, use the POSTGRES_* env vars pattern and manage user
-- creation via an init script that reads env vars:
-- Grant the audit_writer role to the login user
-- (role created by V2 migration — this runs after migration on first start)
-- This GRANT is idempotent — safe to re-run.
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'audit_writer') THEN
GRANT audit_writer TO audit_writer_login;
END IF;
END
$$;
-- audit_maintainer_login: login user for partition maintenance cron job
CREATE USER audit_maintainer_login WITH
NOSUPERUSER
NOCREATEDB
NOCREATEROLE
NOINHERIT
LOGIN
CONNECTION LIMIT 5
PASSWORD 'PLACEHOLDER_REPLACED_BY_ENTRYPOINT';
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'audit_maintainer') THEN
GRANT audit_maintainer TO audit_maintainer_login;
END IF;
END
$$;
-- Grant connect on database to both login users
GRANT CONNECT ON DATABASE auditdb TO audit_writer_login;
GRANT CONNECT ON DATABASE auditdb TO audit_maintainer_login;

View File

@@ -0,0 +1,55 @@
# =============================================================================
# postgres/audit/postgresql.conf
# PostgreSQL 15 configuration for the audit database.
# Container memory limit: 1GB (lighter than FHIR store).
# Workload: INSERT-heavy (audit events), occasional SELECT (analytics).
#
# For 1GB container:
# shared_buffers = 256MB
# effective_cache_size = 768MB
# work_mem = 4MB
# maintenance_work_mem = 100MB
# =============================================================================
max_connections = 20
superuser_reserved_connections = 3
shared_buffers = 256MB
effective_cache_size = 768MB
work_mem = 4MB
maintenance_work_mem = 100MB
wal_buffers = 8MB
checkpoint_completion_target = 0.9
synchronous_commit = on
random_page_cost = 1.1
effective_io_concurrency = 200
# Logging
log_destination = stderr
logging_collector = off
log_min_messages = WARNING
log_min_error_statement = ERROR
log_min_duration_statement = 500
log_line_prefix = '%t [%p] %u@%d '
log_checkpoints = on
log_lock_waits = on
log_temp_files = 0
# Autovacuum — partitioned tables need careful autovacuum tuning.
# Each monthly partition is a separate physical table for autovacuum purposes.
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 60s
timezone = 'UTC'
log_timezone = 'UTC'
lc_messages = 'en_US.UTF-8'
lc_monetary = 'en_US.UTF-8'
lc_numeric = 'en_US.UTF-8'
lc_time = 'en_US.UTF-8'
track_io_timing = on
track_counts = on

38
postgres/fhir/init.sql Normal file
View File

@@ -0,0 +1,38 @@
-- =============================================================================
-- postgres/fhir/init.sql
-- Runs once on first container start (postgres-fhir).
-- Creates the application user that HAPI uses at runtime.
-- Flyway migrations run as superuser separately.
-- =============================================================================
-- Application user — read/write to HAPI JPA tables
-- Password injected from FHIR_DB_APP_PASSWORD environment variable
-- via docker-compose. The \getenv syntax requires psql — use DO block instead.
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = current_setting('app.db_user', true)) THEN
-- User created by the entrypoint using POSTGRES_* env vars equivalent.
-- This script creates it explicitly for auditability.
NULL;
END IF;
END
$$;
-- Create app user. Password set via environment variable substitution
-- in the Docker entrypoint. The actual CREATE USER is handled by
-- the entrypoint script reading FHIR_DB_APP_USER/PASSWORD env vars.
-- This script grants the necessary privileges after user creation.
-- Grant connect
GRANT CONNECT ON DATABASE fhirdb TO hapi_app;
-- Grant schema usage and object privileges
-- Flyway creates all tables as superuser; we then grant hapi_app access.
-- These grants run after Flyway migrations on first startup via Spring Boot
-- ApplicationListener — see DataSourceConfig.java.
-- Pre-grant public schema access:
GRANT USAGE ON SCHEMA public TO hapi_app;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO hapi_app;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO hapi_app;

View File

@@ -0,0 +1,81 @@
# =============================================================================
# postgres/fhir/postgresql.conf
# PostgreSQL 15 configuration tuned for HAPI FHIR JPA workload.
# Container memory limit: 2GB (set in docker-compose deploy.resources).
#
# Tuning methodology:
# shared_buffers = 25% of container RAM
# effective_cache = 75% of container RAM
# work_mem = (RAM - shared_buffers) / (max_connections * 2)
# maintenance_work_mem = 10% of RAM
#
# For 2GB container:
# shared_buffers = 512MB
# effective_cache_size = 1536MB
# work_mem = 8MB (conservative — many parallel queries)
# maintenance_work_mem = 200MB
# =============================================================================
# Connection settings
# max_connections must be > pgBouncer pool_size to leave headroom for
# superuser connections (Flyway, maintenance).
# pgBouncer pool_size=20 + 5 superuser = 25 total.
max_connections = 30
superuser_reserved_connections = 3
# Memory
shared_buffers = 512MB
effective_cache_size = 1536MB
work_mem = 8MB
maintenance_work_mem = 200MB
# Write performance
# wal_buffers: 16MB is good for write-heavy workloads
wal_buffers = 16MB
checkpoint_completion_target = 0.9
# synchronous_commit=on: do not disable — data integrity is non-negotiable
# for a national health record system.
synchronous_commit = on
# Query planner
# random_page_cost=1.1: appropriate for SSD storage (not spinning disk).
# If storage is HDD, set to 4.0.
random_page_cost = 1.1
effective_io_concurrency = 200
# Logging — errors and slow queries only
# log_min_duration_statement: log queries taking >500ms.
# Adjust down to 100ms if you want more visibility during initial deployment.
log_destination = stderr
logging_collector = off # Docker captures stderr directly
log_min_messages = WARNING
log_min_error_statement = ERROR
log_min_duration_statement = 500
log_line_prefix = '%t [%p] %u@%d '
log_checkpoints = on
log_connections = off # pgBouncer already logs connections
log_disconnections = off
log_lock_waits = on
log_temp_files = 0
# Autovacuum — keep defaults but tune for HAPI's high-write token tables
autovacuum = on
autovacuum_max_workers = 3
autovacuum_naptime = 30s
# HFJ_SPIDX_TOKEN is written heavily — lower threshold for autovacuum
autovacuum_vacuum_scale_factor = 0.02
autovacuum_analyze_scale_factor = 0.01
# Timezone — all timestamps in UTC
timezone = 'UTC'
log_timezone = 'UTC'
# Locale
lc_messages = 'en_US.UTF-8'
lc_monetary = 'en_US.UTF-8'
lc_numeric = 'en_US.UTF-8'
lc_time = 'en_US.UTF-8'
# Statistics
track_io_timing = on
track_counts = on