Skip to main content

Database Service

Overview

The database service uses PostgreSQL with TimescaleDB extension for time-series data management. It provides the foundation for all data storage and retrieval operations in the SSA backend application.

What This Service Does

  • PostgreSQL Database: Primary relational database for all application data
  • TimescaleDB Extension: Time-series data management for historical data
  • Data Storage: Stores satellite data, TLEs, news articles, user data, and more
  • Query Optimization: Optimized queries for time-series and spatial data
  • Backup and Recovery: Automated backup and recovery procedures
  • Connection Pooling: Efficient connection management for high concurrency

How It Works

  1. Initialization: Database starts with TimescaleDB extension enabled
  2. Schema Creation: Automatic table creation from SQL scripts
  3. Data Storage: Structured storage of all application data
  4. Query Processing: Optimized query execution with indexes
  5. Time-series Management: Automatic partitioning and retention policies
  6. Backup: Regular automated backups to persistent storage

Database Schema

Core Tables

Users and Authentication

CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
name VARCHAR(255) NOT NULL,
hashed_password VARCHAR(255) NOT NULL,
is_active BOOLEAN DEFAULT true,
is_admin BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Satellite Data

CREATE TABLE maneuver_app_norad_db (
id SERIAL PRIMARY KEY,
norad_id VARCHAR(10) NOT NULL,
satellite_name VARCHAR(255),
country_operator VARCHAR(100),
detailed_purpose VARCHAR(255),
constellation_name VARCHAR(255),
launch_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE maneuver_app_tle_data (
id SERIAL PRIMARY KEY,
norad_id VARCHAR(10) NOT NULL,
tle_date DATE NOT NULL,
tle TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(norad_id, tle_date)
);

News Data

CREATE TABLE space_news_prod (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(500) NOT NULL,
short_description TEXT,
source VARCHAR(100) NOT NULL,
mission_name VARCHAR(200),
date TIMESTAMP WITH TIME ZONE,
url TEXT,
slug VARCHAR(200),
last_updated TIMESTAMP WITH TIME ZONE,
country_code VARCHAR(10),
mission_description TEXT,
off_url TEXT,
insertion_time TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
UNIQUE(title, source, date)
);

Favorites and Groups

CREATE TABLE favorite_groups (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
name VARCHAR(255) NOT NULL,
description TEXT,
color VARCHAR(7),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE favorites (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
norad_id VARCHAR(10) NOT NULL,
group_id INTEGER REFERENCES favorite_groups(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, norad_id, group_id)
);

TimescaleDB Tables

Time-series Data

-- Enable TimescaleDB extension
CREATE EXTENSION IF NOT EXISTS timescaledb;

-- Convert tables to hypertables
SELECT create_hypertable('maneuver_app_tle_data', 'tle_date');
SELECT create_hypertable('space_news_prod', 'date');

-- Create time-based indexes
CREATE INDEX idx_tle_data_norad_date ON maneuver_app_tle_data (norad_id, tle_date DESC);
CREATE INDEX idx_news_date_source ON space_news_prod (date DESC, source);

Configuration

Environment Variables

VariableDefaultDescription
POSTGRES_USERmaneuver_dbDatabase username
POSTGRES_PASSWORDsecret@796Database password
POSTGRES_DBmaneuverDatabase name
POSTGRES_PORT5432Database port
POSTGRES_HOSTpostgresDatabase host

Docker Configuration

postgres:
image: timescale/timescaledb:2.11.2-pg15
container_name: sss_db_postgres
restart: always
ports:
- "${POSTGRES_PORT:-5435}:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./data/01_create_tables.sql:/docker-entrypoint-initdb.d/01_create_tables.sql
- ./data/maneuver_app_norad_db.sql:/docker-entrypoint-initdb.d/02_maneuver_app_norad_db.sql
- ./data/02_timescaledb_setup.sql:/docker-entrypoint-initdb.d/03_timescaledb_setup.sql
- ./data/04_create_news_table.sql:/docker-entrypoint-initdb.d/04_create_news_table.sql
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5

Usage

Connect to Database

# Connect using psql
docker exec -it sss_db_postgres psql -U maneuver_db -d maneuver

# Connect using external client
psql -h localhost -p 5435 -U maneuver_db -d maneuver

Common Queries

Satellite Data

-- Get latest TLE for a satellite
SELECT tle, tle_date
FROM maneuver_app_tle_data
WHERE norad_id = '25544'
ORDER BY tle_date DESC
LIMIT 1;

-- Get satellites by country
SELECT norad_id, satellite_name, country_operator
FROM maneuver_app_norad_db
WHERE country_operator = 'USA';

News Data

-- Get latest news articles
SELECT title, source, date
FROM space_news_prod
ORDER BY date DESC
LIMIT 10;

-- Get news by source
SELECT title, date
FROM space_news_prod
WHERE source = 'LaunchLibrary2'
ORDER BY date DESC;

User Data

-- Get user favorites
SELECT f.norad_id, fg.name as group_name
FROM favorites f
JOIN favorite_groups fg ON f.group_id = fg.id
WHERE f.user_id = 1;

Performance Optimization

Indexes

-- Primary indexes
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_norad_db_country ON maneuver_app_norad_db(country_operator);
CREATE INDEX idx_tle_data_norad ON maneuver_app_tle_data(norad_id);
CREATE INDEX idx_news_source_date ON space_news_prod(source, date);

-- Composite indexes
CREATE INDEX idx_favorites_user_norad ON favorites(user_id, norad_id);
CREATE INDEX idx_news_title_source ON space_news_prod(title, source);

Query Optimization

-- Use EXPLAIN ANALYZE for query optimization
EXPLAIN ANALYZE
SELECT * FROM maneuver_app_tle_data
WHERE norad_id = '25544'
AND tle_date >= '2024-01-01';

-- Use time-based partitioning
SELECT create_hypertable('maneuver_app_tle_data', 'tle_date',
chunk_time_interval => INTERVAL '1 month');

Backup and Recovery

Automated Backups

# Create backup
docker exec sss_db_postgres pg_dump -U maneuver_db -d maneuver > backup_$(date +%Y%m%d).sql

# Restore backup
docker exec -i sss_db_postgres psql -U maneuver_db -d maneuver < backup_20240115.sql

Backup Script

#!/bin/bash
# backup.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups"
docker exec sss_db_postgres pg_dump -U maneuver_db -d maneuver > $BACKUP_DIR/backup_$DATE.sql
gzip $BACKUP_DIR/backup_$DATE.sql

Monitoring

Database Metrics

-- Check database size
SELECT pg_size_pretty(pg_database_size('maneuver'));

-- Check table sizes
SELECT
schemaname,
tablename,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;

-- Check active connections
SELECT count(*) FROM pg_stat_activity WHERE state = 'active';

Health Checks

# Check database health
docker exec sss_db_postgres pg_isready -U maneuver_db -d maneuver

# Check TimescaleDB status
docker exec sss_db_postgres psql -U maneuver_db -d maneuver -c "SELECT * FROM timescaledb_information.hypertables;"

Troubleshooting

Common Issues

  1. Connection Issues:

    # Check if database is running
    docker-compose ps postgres

    # Check database logs
    docker-compose logs postgres
  2. Performance Issues:

    -- Check slow queries
    SELECT query, mean_time, calls
    FROM pg_stat_statements
    ORDER BY mean_time DESC
    LIMIT 10;
  3. Storage Issues:

    # Check disk usage
    docker exec sss_db_postgres df -h

    # Check database size
    docker exec sss_db_postgres psql -U maneuver_db -d maneuver -c "SELECT pg_size_pretty(pg_database_size('maneuver'));"

Maintenance

-- Vacuum database
VACUUM ANALYZE;

-- Reindex tables
REINDEX TABLE maneuver_app_tle_data;
REINDEX TABLE space_news_prod;

-- Update statistics
ANALYZE;

Security

Access Control

-- Create read-only user
CREATE USER readonly WITH PASSWORD 'readonly_password';
GRANT CONNECT ON DATABASE maneuver TO readonly;
GRANT USAGE ON SCHEMA public TO readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;

Data Encryption

  • At Rest: Database files encrypted using filesystem encryption
  • In Transit: SSL/TLS connections required
  • Backups: Encrypted backup storage

Integration

With FastAPI Service

  • SQLAlchemy ORM: Object-relational mapping for database operations
  • Connection Pooling: Efficient connection management
  • Migration Support: Alembic for schema migrations

With Other Services

  • TLE Processor: Direct database access for TLE storage
  • News Processor: Direct database access for news storage
  • Monitoring: Prometheus metrics for database performance