Initial commit: auth
This commit is contained in:
commit
372e71c8f5
11 changed files with 500 additions and 0 deletions
67
src/db.js
Normal file
67
src/db.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import pg from 'pg'
|
||||
import { hashPassword } from './jwt.js'
|
||||
|
||||
const { Pool } = pg
|
||||
export const pool = new Pool({ connectionString: process.env.DATABASE_URL })
|
||||
|
||||
export async function initDb() {
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
email TEXT UNIQUE NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
offsite_allowed BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
is_admin BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS apps (
|
||||
id SERIAL PRIMARY KEY,
|
||||
slug TEXT UNIQUE NOT NULL,
|
||||
name TEXT NOT NULL,
|
||||
description TEXT,
|
||||
base_path TEXT NOT NULL,
|
||||
icon TEXT NOT NULL DEFAULT '📋',
|
||||
theme_color TEXT NOT NULL DEFAULT '#1e3a5f',
|
||||
active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS user_app_perms (
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
app_id INTEGER NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
|
||||
granted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (user_id, app_id)
|
||||
);
|
||||
`)
|
||||
|
||||
// Seed built-in apps
|
||||
await pool.query(`
|
||||
INSERT INTO apps (slug, name, description, base_path, icon, theme_color)
|
||||
VALUES
|
||||
('noticeboard', 'Noticeboard', 'Staff notices and announcements', '/notices', '📋', '#1e3a5f'),
|
||||
('kitchen', 'Kitchen Flash', 'Invoice processing and GP tracking', '/kitchen', '🍳', '#e85d04'),
|
||||
('cashup', 'Cash Up', 'Hotel daily cashing up', '/cashup', '💷', '#6b2d8b'),
|
||||
('housekeeping','Housekeeping', 'Room status and task management', '/hk', '🛏️', '#2d6a4f'),
|
||||
('forecasting', 'Forecasting', 'Revenue forecasting and reporting', '/forecast', '📈', '#0077b6'),
|
||||
('rates', 'Rate Scraper', 'Competitor rate monitoring', '/rates', '🔍', '#7b4f00')
|
||||
ON CONFLICT (slug) DO NOTHING
|
||||
`)
|
||||
|
||||
// Seed first admin user if table is empty
|
||||
const { rows } = await pool.query('SELECT COUNT(*) FROM users')
|
||||
if (parseInt(rows[0].count) === 0) {
|
||||
const email = process.env.ADMIN_EMAIL
|
||||
const password = process.env.ADMIN_PASSWORD
|
||||
if (email && password) {
|
||||
await pool.query(
|
||||
`INSERT INTO users (email, name, password_hash, is_admin, offsite_allowed)
|
||||
VALUES ($1, $2, $3, true, true)`,
|
||||
[email, 'Admin', await hashPassword(password)]
|
||||
)
|
||||
console.log(`Created initial admin: ${email}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue