asteroid/docs/POSTGRESQL-SETUP.org

7.6 KiB

PostgreSQL Setup for Asteroid Radio

Overview

Complete PostgreSQL setup with Docker, persistent storage, and Radiance integration for Asteroid Radio.

What This Provides

Persistent Storage

  • All data survives container restarts
  • Database stored in Docker volume postgres-data
  • Automatic backups possible

Full Database Features

  • Proper UPDATE/DELETE operations
  • Transactions and ACID compliance
  • Indexes for fast queries
  • Foreign key constraints
  • Triggers for automatic timestamps

Tables Created

  • users - User accounts with roles
  • tracks - Music library metadata
  • playlists - User playlists
  • playlist_tracks - Many-to-many playlist/track relationship
  • sessions - Session management

Quick Start

1. Start PostgreSQL Container

cd docker
docker compose up -d postgres

Wait 10 seconds for initialization, then verify:

docker logs asteroid-postgres

You should see: "Asteroid Radio database initialized successfully!"

2. Test Connection

docker exec -it asteroid-postgres psql -U asteroid -d asteroid

Inside psql:

\dt  -- List tables
SELECT * FROM users;  -- View users
\q   -- Quit

3. Configure Radiance (When Ready)

Edit your Radiance configuration to use PostgreSQL:

(load "config/radiance-postgres.lisp")

Database Schema

Users Table

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(255) UNIQUE NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash TEXT NOT NULL,
    role VARCHAR(50) DEFAULT 'listener',
    active BOOLEAN DEFAULT true,
    created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_login TIMESTAMP
);

Tracks Table

CREATE TABLE tracks (
    id SERIAL PRIMARY KEY,
    title VARCHAR(500) NOT NULL,
    artist VARCHAR(500),
    album VARCHAR(500),
    duration INTEGER DEFAULT 0,
    format VARCHAR(50),
    file_path TEXT NOT NULL UNIQUE,
    play_count INTEGER DEFAULT 0,
    added_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    last_played TIMESTAMP
);

Playlists Table

CREATE TABLE playlists (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    name VARCHAR(255) NOT NULL,
    description TEXT,
    created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    modified_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Playlist Tracks Junction Table

CREATE TABLE playlist_tracks (
    id SERIAL PRIMARY KEY,
    playlist_id INTEGER NOT NULL REFERENCES playlists(id) ON DELETE CASCADE,
    track_id INTEGER NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
    position INTEGER NOT NULL,
    added_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE(playlist_id, track_id, position)
);

Connection Details

From Host Machine

  • Host: localhost
  • Port: 5432
  • Database: asteroid
  • Username: asteroid
  • Password: asteroid_db_2025

From Docker Containers

  • Host: asteroid-postgres
  • Port: 5432
  • Database: asteroid
  • Username: asteroid
  • Password: asteroid_db_2025

Connection String

postgresql://asteroid:asteroid_db_2025@localhost:5432/asteroid

Default Users

Admin User

  • Username: admin
  • Password: admin (⚠️ CHANGE THIS!)
  • Role: admin

Test Listener

  • Username: listener
  • Password: admin (⚠️ CHANGE THIS!)
  • Role: listener

Management Commands

Access PostgreSQL CLI

docker exec -it asteroid-postgres psql -U asteroid -d asteroid

View All Tables

\dt

View Table Structure

\d users
\d tracks
\d playlists
\d playlist_tracks

Count Records

SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM tracks;
SELECT COUNT(*) FROM playlists;

View Playlists with Track Counts

SELECT p.id, p.name, u.username, COUNT(pt.track_id) as track_count
FROM playlists p
JOIN users u ON p.user_id = u.id
LEFT JOIN playlist_tracks pt ON p.id = pt.playlist_id
GROUP BY p.id, p.name, u.username;

Backup and Restore

Create Backup

docker exec asteroid-postgres pg_dump -U asteroid asteroid > backup.sql

Restore from Backup

cat backup.sql | docker exec -i asteroid-postgres psql -U asteroid -d asteroid

Backup with Docker Volume

docker run --rm \
  -v docker_postgres-data:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/postgres-backup.tar.gz /data

Migration from Radiance Default DB

Export Current Data

Create a script to export from current database:

(defun export-users-to-postgres ()
  "Export users from Radiance DB to PostgreSQL"
  (let ((users (db:select "users" (db:query :all))))
    (loop for user in users
          do (format t "INSERT INTO users (username, email, password_hash, role, active) VALUES (~
                       '~a', '~a', '~a', '~a', ~a);~%"
                     (gethash "username" user)
                     (gethash "email" user)
                     (gethash "password-hash" user)
                     (gethash "role" user)
                     (gethash "active" user)))))

Import to PostgreSQL

# Run export script, save to file
# Then import:
cat export.sql | docker exec -i asteroid-postgres psql -U asteroid -d asteroid

Troubleshooting

Container Won't Start

Check logs:

docker logs asteroid-postgres

Connection Refused

Ensure container is running:

docker ps | grep postgres

Check health:

docker exec asteroid-postgres pg_isready -U asteroid

Permission Denied

Reset permissions:

docker exec -it asteroid-postgres psql -U postgres -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO asteroid;"

Data Not Persisting

Check volume:

docker volume ls | grep postgres
docker volume inspect docker_postgres-data

Performance Tuning

Increase Shared Buffers

Edit docker-compose.yml:

postgres:
  command: postgres -c shared_buffers=256MB -c max_connections=100

Enable Query Logging

postgres:
  command: postgres -c log_statement=all

Security Recommendations

Change Default Passwords

ALTER USER asteroid WITH PASSWORD 'new_secure_password';
UPDATE users SET password_hash = '$2a$12$...' WHERE username = 'admin';

Restrict Network Access

In production, don't expose port 5432 externally:

postgres:
  ports: []  # Remove port mapping

Enable SSL

Add to docker-compose.yml:

postgres:
  command: postgres -c ssl=on -c ssl_cert_file=/etc/ssl/certs/server.crt

Next Steps

  1. PostgreSQL container running
  2. Configure Radiance to use PostgreSQL
  3. Migrate existing data
  4. Update application code for PostgreSQL
  5. Test playlist functionality
  6. Deploy to production

Status: READY FOR INTEGRATION

PostgreSQL is set up and ready. Next step is configuring Radiance and migrating data.

What Works Now

  • PostgreSQL container running
  • Database initialized with schema
  • Persistent storage configured
  • Default users created
  • Indexes and constraints in place

What Needs Fade

  • Radiance PostgreSQL adapter configuration
  • Data migration from current DB
  • Application code updates
  • Testing and validation