Skip to content

Database

Niuton uses PostgreSQL with separate databases for each environment.

Databases

DatabaseEnvironmentUser
niuton_dbE2E (Development)niuton_user
niuton_prodPROD (Production)niuton_prod_user

Core Tables

Users & Auth

sql
niuton_users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    display_name VARCHAR(100),
    email VARCHAR(255),
    is_admin BOOLEAN DEFAULT false,
    avatar_color VARCHAR(7),
    totp_secret VARCHAR(32),
    totp_enabled BOOLEAN DEFAULT false,
    backup_codes TEXT,
    last_login TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW()
);

niuton_login_attempts (
    id SERIAL PRIMARY KEY,
    username VARCHAR(50),
    ip_address VARCHAR(45),
    success BOOLEAN,
    attempted_at TIMESTAMP DEFAULT NOW()
);

niuton_api_tokens (
    id SERIAL PRIMARY KEY,
    user_id INTEGER REFERENCES niuton_users(id),
    token_hash VARCHAR(64) NOT NULL,
    device_name VARCHAR(100),
    device_id VARCHAR(100),
    last_used TIMESTAMP,
    created_at TIMESTAMP DEFAULT NOW()
);

App Data

sql
niuton_notes (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    title VARCHAR(255),
    content TEXT,
    category VARCHAR(100),
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

niuton_finance (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    type VARCHAR(20),     -- 'income' or 'expense'
    amount DECIMAL(12,2),
    category VARCHAR(100),
    description TEXT,
    date DATE,
    created_at TIMESTAMP DEFAULT NOW()
);

niuton_docs (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    title VARCHAR(255) NOT NULL,
    slug VARCHAR(255) NOT NULL,
    content TEXT,
    category VARCHAR(100),
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

niuton_places (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    name VARCHAR(255),
    lat DECIMAL(10,7),
    lng DECIMAL(10,7),
    description TEXT,
    category VARCHAR(100),
    created_at TIMESTAMP DEFAULT NOW()
);

Team Chat

sql
niuton_chat_rooms (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    type VARCHAR(20) DEFAULT 'channel',
    created_by INTEGER REFERENCES niuton_users(id),
    quota_mb INTEGER DEFAULT 200,
    created_at TIMESTAMP DEFAULT NOW()
);

niuton_chat_participants (
    room_id INTEGER REFERENCES niuton_chat_rooms(id) ON DELETE CASCADE,
    user_id INTEGER REFERENCES niuton_users(id),
    last_read_at TIMESTAMP,
    last_active TIMESTAMP,
    PRIMARY KEY (room_id, user_id)
);

niuton_chat_messages (
    id SERIAL PRIMARY KEY,
    room_id INTEGER REFERENCES niuton_chat_rooms(id) ON DELETE CASCADE,
    user_id INTEGER REFERENCES niuton_users(id),
    content TEXT,
    metadata JSONB,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP
);

niuton_chat_reactions (
    id SERIAL PRIMARY KEY,
    message_id INTEGER REFERENCES niuton_chat_messages(id) ON DELETE CASCADE,
    user_id INTEGER REFERENCES niuton_users(id),
    emoji VARCHAR(10),
    created_at TIMESTAMP DEFAULT NOW()
);

niuton_chat_mentions (
    id SERIAL PRIMARY KEY,
    message_id INTEGER REFERENCES niuton_chat_messages(id) ON DELETE CASCADE,
    user_id INTEGER REFERENCES niuton_users(id)
);

niuton_chat_presence (
    user_id INTEGER PRIMARY KEY REFERENCES niuton_users(id),
    last_seen TIMESTAMP DEFAULT NOW()
);

Apps & System

sql
niuton_apps (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    slug VARCHAR(50) UNIQUE NOT NULL,
    description TEXT,
    icon_url VARCHAR(255),
    app_path VARCHAR(255),
    category VARCHAR(50),
    is_system BOOLEAN DEFAULT false,
    is_active BOOLEAN DEFAULT true,
    supports_context BOOLEAN DEFAULT false,
    created_by_user_id INTEGER,
    created_at TIMESTAMP DEFAULT NOW()
);

niuton_system_config (
    key VARCHAR(100) PRIMARY KEY,
    value TEXT,
    updated_at TIMESTAMP DEFAULT NOW()
);

niuton_trash (
    id SERIAL PRIMARY KEY,
    user_id INTEGER NOT NULL,
    item_type VARCHAR(20),
    item_name VARCHAR(255),
    original_path TEXT,
    app_id INTEGER,
    metadata JSONB,
    trashed_at TIMESTAMP DEFAULT NOW()
);

niuton_sync_log (
    id SERIAL PRIMARY KEY,
    table_name VARCHAR(100),
    record_id INTEGER,
    operation VARCHAR(10),
    user_id INTEGER,
    changed_at TIMESTAMP DEFAULT NOW()
);

niuton_audit_log (
    id SERIAL PRIMARY KEY,
    user_id INTEGER,
    action VARCHAR(100),
    details JSONB,
    created_at TIMESTAMP DEFAULT NOW()
);

Chess

sql
niuton_chess_games (
    id SERIAL PRIMARY KEY,
    white_user_id INTEGER,  -- nullable (AI plays white)
    black_user_id INTEGER,
    pgn TEXT,
    fen VARCHAR(100),
    status VARCHAR(20),
    result VARCHAR(10),
    mode VARCHAR(20),
    engine_depth INTEGER,
    created_at TIMESTAMP DEFAULT NOW(),
    updated_at TIMESTAMP DEFAULT NOW()
);

niuton_chess_challenges (
    id SERIAL PRIMARY KEY,
    from_user_id INTEGER NOT NULL,
    to_user_id INTEGER NOT NULL,
    color VARCHAR(10),
    status VARCHAR(20) DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT NOW()
);

Encoding

UTF-8 Required

PostgreSQL must use UTF-8 encoding. The connection sets client_encoding = 'UTF8' explicitly:

php
$pdo->exec("SET client_encoding = 'UTF8'");

If your database was created with SQL_ASCII encoding, you need to migrate:

bash
# Dump, recreate with UTF8, restore
pg_dump -U postgres niuton_db > /tmp/dump.sql
dropdb -U postgres niuton_db
createdb -U postgres -E UTF8 -O niuton_user niuton_db
psql -U postgres niuton_db < /tmp/dump.sql

Accessing the Database

bash
# From the Niuton container (114)
sudo -u postgres psql -d niuton_db

# Common queries
\dt niuton_*          -- List all Niuton tables
\d niuton_users       -- Show table structure
SELECT count(*) FROM niuton_users;

AI-Powered Cloud Desktop OS