Database Schema
The gallery uses Turso (LibSQL/SQLite) with Drizzle ORM.
Tables Overview
erDiagram
users ||--o{ sessions : has
users ||--o{ oauth_accounts : has
users ||--o{ themes : submits
users {
text id PK
text email UK
text password_hash
text name
text avatar_url
int created_at
}
sessions {
text id PK
text user_id FK
int expires_at
}
oauth_accounts {
text id PK
text user_id FK
text provider
text provider_user_id
text provider_username
text access_token
int created_at
}
themes {
text id PK
text name
text description
text author_id FK
text author_name
text repo_url UK
text demo_url
text preview_image
int stars
text tags
text status
int created_at
int updated_at
}
Table: users
User accounts for authentication.
| Column | Type | Description |
|---|---|---|
|
TEXT PK |
UUID primary key |
|
TEXT UNIQUE |
Email address (nullable for OAuth-only) |
|
TEXT |
Argon2 hash (null for OAuth users) |
|
TEXT NOT NULL |
Display name |
|
TEXT |
Profile picture URL |
|
INTEGER |
Unix timestamp |
Table: sessions
Active user sessions for Lucia auth.
| Column | Type | Description |
|---|---|---|
|
TEXT PK |
Session ID (random UUID) |
|
TEXT FK |
References users.id |
|
INTEGER NOT NULL |
Expiration timestamp |
Table: oauth_accounts
Links OAuth providers to user accounts.
| Column | Type | Description |
|---|---|---|
|
TEXT PK |
UUID primary key |
|
TEXT FK |
References users.id |
|
TEXT NOT NULL |
'github', 'gitlab', or 'google' |
|
TEXT NOT NULL |
User ID from the provider |
|
TEXT |
Username from the provider |
|
TEXT |
OAuth access token |
|
INTEGER |
Unix timestamp |
Table: themes
Submitted theme registry.
| Column | Type | Description |
|---|---|---|
|
TEXT PK |
UUID primary key |
|
TEXT NOT NULL |
Theme display name |
|
TEXT NOT NULL |
Theme description |
|
TEXT FK |
References users.id (nullable) |
|
TEXT NOT NULL |
Denormalized author name |
|
TEXT NOT NULL UNIQUE |
GitHub repository URL |
|
TEXT |
Live demo URL |
|
TEXT |
Screenshot URL |
|
INTEGER DEFAULT 0 |
GitHub star count |
|
TEXT DEFAULT '[]' |
JSON array of tags |
|
TEXT DEFAULT 'pending' |
'pending', 'approved', 'rejected' |
|
INTEGER |
Submission timestamp |
|
INTEGER |
Last update timestamp |
Drizzle Schema
The schema is defined in src/db/schema.ts:
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
export const users = sqliteTable('users', {
id: text('id').primaryKey(),
email: text('email').unique(),
passwordHash: text('password_hash'),
name: text('name').notNull(),
avatarUrl: text('avatar_url'),
createdAt: integer('created_at', { mode: 'timestamp' })
.notNull()
.$defaultFn(() => new Date()),
});
// ... other tables
Migrations
Push schema changes to database:
npx drizzle-kit push
Generate migration files:
npx drizzle-kit generate