Skip to content

Commit e0f6995

Browse files
salamaashoushclaude
andcommitted
feat: add frontend lib utilities and database migrations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 740b1f6 commit e0f6995

File tree

5 files changed

+173
-0
lines changed

5 files changed

+173
-0
lines changed

frontend/src/lib/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { type ClassValue, clsx } from 'clsx';
2+
import { twMerge } from 'tailwind-merge';
3+
4+
export function cn(...inputs: ClassValue[]) {
5+
return twMerge(clsx(inputs));
6+
}

migrations/0001_initial_schema.sql

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
-- Users table
2+
CREATE TABLE users (
3+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
4+
email VARCHAR(255) NOT NULL UNIQUE,
5+
password_hash VARCHAR(255) NOT NULL,
6+
name VARCHAR(255) NOT NULL DEFAULT '',
7+
role VARCHAR(20) NOT NULL DEFAULT 'user',
8+
email_verified BOOLEAN NOT NULL DEFAULT false,
9+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
10+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
11+
);
12+
13+
-- Organizations table
14+
CREATE TABLE organizations (
15+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
16+
name VARCHAR(255) NOT NULL,
17+
slug VARCHAR(255) NOT NULL UNIQUE,
18+
owner_id UUID NOT NULL REFERENCES users(id),
19+
storage_provider VARCHAR(20),
20+
storage_config JSONB,
21+
billing_plan VARCHAR(50) NOT NULL DEFAULT 'free',
22+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
23+
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
24+
);
25+
26+
-- Organization members (composite PK)
27+
CREATE TABLE org_members (
28+
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
29+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
30+
role VARCHAR(20) NOT NULL DEFAULT 'member',
31+
invited_at TIMESTAMPTZ NOT NULL DEFAULT now(),
32+
joined_at TIMESTAMPTZ,
33+
PRIMARY KEY (org_id, user_id)
34+
);
35+
36+
-- Teams table
37+
CREATE TABLE teams (
38+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
39+
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
40+
name VARCHAR(255) NOT NULL,
41+
slug VARCHAR(255) NOT NULL,
42+
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
43+
UNIQUE (org_id, slug)
44+
);
45+
46+
-- Team members (composite PK)
47+
CREATE TABLE team_members (
48+
team_id UUID NOT NULL REFERENCES teams(id) ON DELETE CASCADE,
49+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
50+
role VARCHAR(20) NOT NULL DEFAULT 'member',
51+
added_at TIMESTAMPTZ NOT NULL DEFAULT now(),
52+
PRIMARY KEY (team_id, user_id)
53+
);
54+
55+
-- API tokens
56+
CREATE TABLE api_tokens (
57+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
58+
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
59+
team_id UUID REFERENCES teams(id) ON DELETE CASCADE,
60+
name VARCHAR(255) NOT NULL,
61+
token_hash VARCHAR(128) NOT NULL UNIQUE,
62+
token_prefix VARCHAR(12) NOT NULL,
63+
scopes TEXT[] NOT NULL DEFAULT ARRAY['read', 'write'],
64+
created_by UUID NOT NULL REFERENCES users(id),
65+
expires_at TIMESTAMPTZ,
66+
last_used_at TIMESTAMPTZ,
67+
revoked BOOLEAN NOT NULL DEFAULT false,
68+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
69+
);
70+
71+
-- Sessions (refresh tokens)
72+
CREATE TABLE sessions (
73+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
74+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
75+
token_hash VARCHAR(128) NOT NULL UNIQUE,
76+
expires_at TIMESTAMPTZ NOT NULL,
77+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
78+
);
79+
80+
-- Cache events (analytics)
81+
CREATE TABLE cache_events (
82+
id BIGSERIAL PRIMARY KEY,
83+
org_id UUID NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
84+
team_id UUID,
85+
artifact_hash VARCHAR(255) NOT NULL,
86+
event_type VARCHAR(10) NOT NULL,
87+
size_bytes BIGINT NOT NULL DEFAULT 0,
88+
duration_ms INTEGER NOT NULL DEFAULT 0,
89+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
90+
);
91+
92+
-- Indexes for performance
93+
CREATE INDEX idx_org_members_user_id ON org_members(user_id);
94+
CREATE INDEX idx_team_members_user_id ON team_members(user_id);
95+
CREATE INDEX idx_api_tokens_org_id ON api_tokens(org_id);
96+
CREATE INDEX idx_api_tokens_token_hash ON api_tokens(token_hash);
97+
CREATE INDEX idx_sessions_user_id ON sessions(user_id);
98+
CREATE INDEX idx_sessions_token_hash ON sessions(token_hash);
99+
CREATE INDEX idx_cache_events_org_id ON cache_events(org_id);
100+
CREATE INDEX idx_cache_events_created_at ON cache_events(created_at);
101+
CREATE INDEX idx_cache_events_org_created ON cache_events(org_id, created_at);
102+
103+
-- Auto-update updated_at trigger
104+
CREATE OR REPLACE FUNCTION update_updated_at_column()
105+
RETURNS TRIGGER AS $$
106+
BEGIN
107+
NEW.updated_at = now();
108+
RETURN NEW;
109+
END;
110+
$$ LANGUAGE plpgsql;
111+
112+
CREATE TRIGGER update_users_updated_at
113+
BEFORE UPDATE ON users
114+
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
115+
116+
CREATE TRIGGER update_organizations_updated_at
117+
BEFORE UPDATE ON organizations
118+
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-- Remove billing_plan (dead code for self-hosted)
2+
ALTER TABLE organizations DROP COLUMN IF EXISTS billing_plan;
3+
4+
-- Email verification & password reset tokens
5+
CREATE TABLE email_tokens (
6+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
7+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
8+
token_hash VARCHAR(128) NOT NULL UNIQUE,
9+
token_type VARCHAR(20) NOT NULL,
10+
expires_at TIMESTAMPTZ NOT NULL,
11+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
12+
);
13+
14+
CREATE INDEX idx_email_tokens_hash ON email_tokens(token_hash);
15+
CREATE INDEX idx_email_tokens_user ON email_tokens(user_id);
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
-- Two-factor authentication support
2+
3+
ALTER TABLE users
4+
ADD COLUMN twofa_method VARCHAR(10) NOT NULL DEFAULT 'none',
5+
ADD COLUMN totp_secret VARCHAR(255),
6+
ADD COLUMN totp_enabled BOOLEAN NOT NULL DEFAULT false;
7+
8+
CREATE TABLE recovery_codes (
9+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
10+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
11+
code_hash VARCHAR(128) NOT NULL,
12+
used BOOLEAN NOT NULL DEFAULT false,
13+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
14+
);
15+
CREATE INDEX idx_recovery_codes_user ON recovery_codes(user_id);
16+
17+
CREATE TABLE twofa_pending (
18+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
19+
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20+
token_hash VARCHAR(128) NOT NULL UNIQUE,
21+
method VARCHAR(10) NOT NULL,
22+
expires_at TIMESTAMPTZ NOT NULL,
23+
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
24+
);
25+
CREATE INDEX idx_twofa_pending_token ON twofa_pending(token_hash);
26+
CREATE INDEX idx_twofa_pending_user ON twofa_pending(user_id);
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- User activation/deactivation
2+
ALTER TABLE users
3+
ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;
4+
5+
-- Organization limits
6+
ALTER TABLE organizations
7+
ADD COLUMN cache_size_limit_bytes BIGINT,
8+
ADD COLUMN max_tokens INT;

0 commit comments

Comments
 (0)