Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Deploy to Cloudflare Pages

on:
push:
branches:
- main
pull_request:
workflow_dispatch:

jobs:
build-and-test:
runs-on: ubuntu-latest
name: Build and Test

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run linter
run: npm run lint

- name: Build for Cloudflare
run: npm run build:cloudflare
env:
NODE_ENV: production

deploy:
runs-on: ubuntu-latest
name: Deploy to Production
needs: build-and-test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Build for Cloudflare
run: npm run build:cloudflare
env:
NODE_ENV: production

- name: Run database migrations
run: npm run migrate
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
D1_DATABASE_ID: ${{ secrets.D1_DATABASE_ID }}

- name: Deploy to Cloudflare Pages
run: npm run deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}

- name: Comment deployment URL
uses: actions/github-script@v7
with:
script: |
github.rest.repos.createCommitComment({
owner: context.repo.owner,
repo: context.repo.repo,
commit_sha: context.sha,
body: '🚀 Deployed to Cloudflare Pages!\n\nProduction: https://workos-tv.pages.dev'
})
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

# production
/build
.open-next

# misc
.DS_Store
Expand Down
11 changes: 11 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,18 @@ const eslintConfig = defineConfig([
"out/**",
"build/**",
"next-env.d.ts",
// Cloudflare build output:
".open-next/**",
// Debug scripts:
"scripts/debug/**",
]),
// Custom rules
{
rules: {
// Allow apostrophes and quotes in JSX - they're handled fine in modern React
"react/no-unescaped-entities": "off",
},
},
]);

export default eslintConfig;
99 changes: 99 additions & 0 deletions migrations/20260206_initial_schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
-- Initial database schema
-- This migration creates all the core tables for WorkOS TV

CREATE TABLE IF NOT EXISTS recordings (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
description TEXT,
video_url TEXT NOT NULL,
duration INTEGER NOT NULL,
space TEXT DEFAULT 'Zoom Meetings',
source TEXT DEFAULT 'zoom',
media_type TEXT DEFAULT 'video',
media_url_expires_at TEXT,
created_at TEXT NOT NULL,
synced_at TEXT NOT NULL,
poster_url TEXT,
preview_gif_url TEXT
);

CREATE TABLE IF NOT EXISTS video_files (
id TEXT PRIMARY KEY,
recording_id TEXT NOT NULL,
view_type TEXT NOT NULL,
video_url TEXT NOT NULL,
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_video_files_recording ON video_files(recording_id);

CREATE TABLE IF NOT EXISTS speakers (
id TEXT PRIMARY KEY,
recording_id TEXT NOT NULL,
name TEXT NOT NULL,
color TEXT NOT NULL,
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS segments (
id TEXT PRIMARY KEY,
recording_id TEXT NOT NULL,
start_time REAL NOT NULL,
end_time REAL NOT NULL,
speaker TEXT NOT NULL,
text TEXT NOT NULL,
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_segments_recording ON segments(recording_id);
CREATE INDEX IF NOT EXISTS idx_speakers_recording ON speakers(recording_id);

CREATE TABLE IF NOT EXISTS chat_messages (
id TEXT PRIMARY KEY,
recording_id TEXT NOT NULL,
timestamp REAL NOT NULL,
sender TEXT NOT NULL,
message TEXT NOT NULL,
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_chat_recording ON chat_messages(recording_id);
CREATE INDEX IF NOT EXISTS idx_recordings_source ON recordings(source);

CREATE TABLE IF NOT EXISTS summaries (
id TEXT PRIMARY KEY,
recording_id TEXT NOT NULL UNIQUE,
content TEXT NOT NULL,
model TEXT NOT NULL,
generated_at TEXT NOT NULL,
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_summaries_recording ON summaries(recording_id);

CREATE TABLE IF NOT EXISTS clips (
id TEXT PRIMARY KEY,
recording_id TEXT NOT NULL,
title TEXT,
start_time REAL NOT NULL,
end_time REAL NOT NULL,
created_at TEXT NOT NULL,
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_clips_recording ON clips(recording_id);

CREATE TABLE IF NOT EXISTS participants (
id TEXT PRIMARY KEY,
recording_id TEXT NOT NULL,
name TEXT NOT NULL,
email TEXT,
user_id TEXT,
join_time TEXT,
leave_time TEXT,
duration INTEGER,
FOREIGN KEY (recording_id) REFERENCES recordings(id) ON DELETE CASCADE
);

CREATE INDEX IF NOT EXISTS idx_participants_recording ON participants(recording_id);
CREATE INDEX IF NOT EXISTS idx_participants_email ON participants(email);
Loading