Skip to content

Database Schema

This document describes the database schema used in the Quillium backend.

Overview

Quillium uses PostgreSQL as its primary database. The schema is designed to support the core features of the application, including user management, chat functionality, and settings management.

Entity Relationship Diagram

┌─────────────┐       ┌─────────────┐       ┌─────────────┐
│    Users    │       │    Chats    │       │  Messages   │
├─────────────┤       ├─────────────┤       ├─────────────┤
│ id          │       │ id          │       │ id          │
│ email       │       │ user_id     │──┐    │ chat_id     │──┐
│ password    │       │ title       │  │    │ content     │  │
│ name        │       │ model       │  │    │ role        │  │
│ created_at  │       │ created_at  │  │    │ created_at  │  │
│ updated_at  │       │ updated_at  │  │    │ tokens      │  │
└─────────────┘       └─────────────┘  │    └─────────────┘  │
       │                               │                     │
       │                               │                     │
       │                               │                     │
       ▼                               │                     │
┌─────────────┐                        │                     │
│ UserSettings│                        │                     │
├─────────────┤                        │                     │
│ user_id     │◄──────────────────────┘                     │
│ theme       │                                              │
│ language    │                                              │
│ created_at  │                                              │
│ updated_at  │                                              │
└─────────────┘                                              │
                                                             │
┌─────────────┐                                              │
│AdminSettings│                                              │
├─────────────┤                                              │
│ id          │                                              │
│ key         │                                              │
│ value       │                                              │
│ created_at  │                                              │
│ updated_at  │                                              │
└─────────────┘                                              │
                                                             │
┌─────────────┐                                              │
│RefreshTokens│                                              │
├─────────────┤                                              │
│ id          │                                              │
│ user_id     │◄──────────────────────────────────────────┘
│ token       │
│ expires_at  │
│ created_at  │
│ revoked     │
└─────────────┘

Table Definitions

Users

Stores user account information.

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL UNIQUE,
    password VARCHAR(255) NOT NULL,
    name VARCHAR(255) NOT NULL,
    is_admin BOOLEAN NOT NULL DEFAULT FALSE,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Chats

Stores chat conversations.

CREATE TABLE chats (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    title VARCHAR(255) NOT NULL,
    model VARCHAR(50) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

Messages

Stores individual messages within chats.

CREATE TABLE messages (
    id SERIAL PRIMARY KEY,
    chat_id INTEGER NOT NULL REFERENCES chats(id) ON DELETE CASCADE,
    content TEXT NOT NULL,
    role VARCHAR(50) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    tokens INTEGER NOT NULL DEFAULT 0
);

UserSettings

Stores user-specific settings.

CREATE TABLE user_settings (
    user_id INTEGER PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
    theme VARCHAR(50) NOT NULL DEFAULT 'light',
    language VARCHAR(10) NOT NULL DEFAULT 'en',
    notifications_enabled BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

AdminSettings

Stores global application settings.

CREATE TABLE admin_settings (
    id SERIAL PRIMARY KEY,
    key VARCHAR(255) NOT NULL UNIQUE,
    value TEXT NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);

RefreshTokens

Stores refresh tokens for authentication.

CREATE TABLE refresh_tokens (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token VARCHAR(255) NOT NULL,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    revoked BOOLEAN NOT NULL DEFAULT FALSE
);

ApiKeys

Stores API keys for programmatic access.

CREATE TABLE api_keys (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    key VARCHAR(255) NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    created_at TIMESTAMP NOT NULL DEFAULT NOW(),
    last_used_at TIMESTAMP
);

Indexes

-- Improve query performance for common operations
CREATE INDEX idx_chats_user_id ON chats(user_id);
CREATE INDEX idx_messages_chat_id ON messages(chat_id);
CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);
CREATE INDEX idx_api_keys_user_id ON api_keys(user_id);

Migrations

Database migrations are managed using the golang-migrate tool. Migration files are stored in the migrations directory.

Creating a Migration

migrate create -ext sql -dir migrations -seq migration_name

This creates two files: - migrations/NNNNNN_migration_name.up.sql: Changes to apply - migrations/NNNNNN_migration_name.down.sql: Changes to revert

Running Migrations

# Apply all pending migrations
migrate -database ${DATABASE_URL} -path migrations up

# Revert the last migration
migrate -database ${DATABASE_URL} -path migrations down 1

Database Access

The backend uses a repository pattern to abstract database access. Each entity has a corresponding repository that handles CRUD operations.

Example repository interface:

type UserRepository interface {
    GetByID(id int) (*User, error)
    GetByEmail(email string) (*User, error)
    Create(user *User) (int, error)
    Update(user *User) error
    Delete(id int) error
}

Connection Management

Database connections are managed using a connection pool to ensure efficient resource utilization. The pool is configured with:

  • Maximum open connections: 25
  • Maximum idle connections: 5
  • Connection lifetime: 5 minutes

Transactions

For operations that require atomicity, the repository methods accept an optional transaction parameter:

func (r *PostgresUserRepository) Create(user *User, tx *sql.Tx) (int, error) {
    // Use provided transaction or create a new one
    // Execute SQL statements
    // Return result
}

Testing

The database layer includes comprehensive tests that verify the functionality of each repository. Integration tests use a test database to ensure that the repositories work correctly with the actual database schema.

See the Integration Tests documentation for more information on setting up and running database tests.