Files
dumpsterChat/internal/db/db.go
T
hobokenchicken e499ce884d Initial scaffold: Go backend, React frontend, Docker Compose
- Go backend: config, db (PostgreSQL migrations), auth (argon2id + sessions),
  middleware (cookie sessions, RequireAuth), chi router, cmd/server
- React frontend: Vite + React 18 + TS + Tailwind + Gruvbox palette + terminal CSS
- Docker: compose.yml (Postgres, Valkey, minio, LiveKit, coturn, Caddy),
  livekit.yaml, Caddyfile, Dockerfile (multi-stage Go+Node+Alpine)
- .env.example, .gitignore, README.md
2026-06-26 14:41:10 -04:00

93 lines
2.5 KiB
Go

package db
import (
"context"
"database/sql"
"fmt"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/config"
_ "github.com/jackc/pgx/v5/stdlib"
)
type DB struct {
*sql.DB
}
func New(cfg *config.Config) (*DB, error) {
db, err := sql.Open("pgx", cfg.DatabaseDSN())
if err != nil {
return nil, fmt.Errorf("open database: %w", err)
}
if err := db.Ping(); err != nil {
return nil, fmt.Errorf("ping database: %w", err)
}
return &DB{db}, nil
}
func (d *DB) RunMigrations() error {
_, err := d.ExecContext(context.Background(), migrationsSQL)
return err
}
const migrationsSQL = `
CREATE TABLE IF NOT EXISTS users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
username VARCHAR(32) NOT NULL UNIQUE,
display_name VARCHAR(32),
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255),
avatar TEXT,
status VARCHAR(16) NOT NULL DEFAULT 'offline',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS sessions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
token VARCHAR(255) NOT NULL UNIQUE,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS servers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(100) NOT NULL,
icon TEXT,
owner_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS channels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
server_id UUID NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
name VARCHAR(100) NOT NULL,
type VARCHAR(16) NOT NULL DEFAULT 'text',
category VARCHAR(100) NOT NULL DEFAULT 'general',
position INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (server_id, name)
);
CREATE TABLE IF NOT EXISTS members (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
server_id UUID NOT NULL REFERENCES servers(id) ON DELETE CASCADE,
joined_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (user_id, server_id)
);
CREATE TABLE IF NOT EXISTS messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
channel_id UUID NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
author_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
edited_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_messages_channel_created ON messages(channel_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_sessions_token ON sessions(token);
`