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
137 changes: 23 additions & 114 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Deploy
name: Deploy to Production

on:
push:
Expand All @@ -9,132 +9,41 @@ concurrency:
group: deploy-${{ github.ref }}
cancel-in-progress: false

env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}

jobs:
ci:
name: CI Checks
uses: ./.github/workflows/ci.yml
secrets: inherit

deploy-client:
name: Deploy Client
deploy:
name: Deploy to DigitalOcean
runs-on: ubuntu-latest
needs: ci
timeout-minutes: 10
environment: production
steps:
- uses: actions/checkout@v4

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.10"

- name: Cache Bun dependencies
uses: actions/cache@v4
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-bun-${{ hashFiles('bun.lock') }}
restore-keys: |
${{ runner.os }}-bun-

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Build client
run: bun run build
env:
VITE_API_BASE_URL: ${{ vars.VITE_API_BASE_URL }}

# Uncomment and configure for your deployment target:

# --- Vercel ---
# - uses: amondnet/vercel-action@v25
# with:
# vercel-token: ${{ secrets.VERCEL_TOKEN }}
# vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
# vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
# vercel-args: --prod
# working-directory: apps/client

# --- Cloudflare Pages ---
# - uses: cloudflare/wrangler-action@v3
# with:
# apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
# accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
# command: pages deploy apps/client/dist --project-name=tradingflow

# --- Netlify ---
# - uses: nwtgck/actions-netlify@v3
# with:
# publish-dir: apps/client/dist
# production-deploy: true
# env:
# NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
# NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

deploy-backend:
name: Deploy Backend
runs-on: ubuntu-latest
needs: ci
environment: production
steps:
- uses: actions/checkout@v4

# Uncomment and configure for your deployment target:

# --- Railway ---
# - uses: bervProject/railway-deploy@main
# with:
# railway_token: ${{ secrets.RAILWAY_TOKEN }}
# service: backend

# --- Fly.io ---
# - uses: superfly/flyctl-actions/setup-flyctl@master
# - run: flyctl deploy --app tradingflow-backend
# working-directory: apps/backend
# env:
# FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

# --- Docker + any registry ---
# - uses: docker/login-action@v3
# with:
# registry: ghcr.io
# username: ${{ github.actor }}
# password: ${{ secrets.GITHUB_TOKEN }}
# - uses: docker/build-push-action@v6
# with:
# context: .
# file: apps/backend/Dockerfile
# push: true
# tags: ghcr.io/${{ github.repository }}/backend:latest

- name: Placeholder
run: echo "Configure deployment target above"
- name: Deploy via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_SSH_KEY }}
script_stop: true
script: |
cd ~/tradingflow

deploy-executor:
name: Deploy Executor
runs-on: ubuntu-latest
needs: ci
environment: production
steps:
- uses: actions/checkout@v4
echo "==> Pulling latest code..."
git pull origin main

# Same deployment options as backend — uncomment and configure:
echo "==> Installing dependencies..."
bun install --frozen-lockfile

# --- Railway ---
# - uses: bervProject/railway-deploy@main
# with:
# railway_token: ${{ secrets.RAILWAY_TOKEN }}
# service: executor
echo "==> Building all apps..."
bun run build

# --- Fly.io ---
# - uses: superfly/flyctl-actions/setup-flyctl@master
# - run: flyctl deploy --app tradingflow-executor
# working-directory: apps/executor
# env:
# FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
echo "==> Restarting PM2 processes..."
pm2 restart ecosystem.config.cjs

- name: Placeholder
run: echo "Configure deployment target above"
echo "==> Deploy complete!"
pm2 status
2 changes: 1 addition & 1 deletion apps/client
Submodule client updated from 527f44 to f3b3b6
145 changes: 145 additions & 0 deletions apps/executor/emails/alert-email.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import {
Body,
Container,
Head,
Heading,
Hr,
Html,
Preview,
Section,
Text,
} from "@react-email/components";
import * as React from "react";

type AlertEmailProps = {
subject: string;
body: string;
};

const ACCENT = "#10b981";

export const AlertEmail = ({ subject, body }: AlertEmailProps) => (
<Html>
<Head />
<Preview>{subject}</Preview>
<Body style={main}>
<Container style={container}>
<Section style={header}>
<Text style={logo}>
<span style={logoChevron}>≫</span> TRADINGFLOW
</Text>
</Section>
<Hr style={divider} />
<Section style={content}>
<Text style={label}>ALERT</Text>
<Heading as="h2" style={heading}>
{subject}
</Heading>
<Section style={bodyCard}>
<Text style={bodyText}>{body}</Text>
</Section>
</Section>
<Hr style={divider} />
<Text style={footer}>
You received this because you have an active workflow on TradingFlow.
</Text>
<Text style={version}>v0.1.0 // OPERATIONAL</Text>
</Container>
</Body>
</Html>
);

const main: React.CSSProperties = {
backgroundColor: "#09090b",
fontFamily:
'"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif',
};

const container: React.CSSProperties = {
backgroundColor: "#18181b",
margin: "0 auto",
padding: "32px 24px",
maxWidth: "560px",
borderRadius: "0",
border: "1px solid #3f3f46",
};

const header: React.CSSProperties = {
padding: "0",
};

const logo: React.CSSProperties = {
color: "#fafafa",
fontSize: "13px",
fontWeight: 800,
letterSpacing: "0.05em",
textTransform: "uppercase" as const,
margin: "0",
};

const logoChevron: React.CSSProperties = {
color: ACCENT,
marginRight: "4px",
};

const divider: React.CSSProperties = {
borderColor: "#3f3f46",
margin: "20px 0",
};

const content: React.CSSProperties = {
padding: "0",
};

const label: React.CSSProperties = {
color: ACCENT,
fontSize: "11px",
fontWeight: 600,
letterSpacing: "0.1em",
textTransform: "uppercase" as const,
margin: "0 0 8px",
fontFamily: '"IBM Plex Mono", ui-monospace, monospace',
};

const heading: React.CSSProperties = {
color: "#fafafa",
fontSize: "20px",
fontWeight: 600,
margin: "0 0 16px",
letterSpacing: "-0.025em",
};

const bodyCard: React.CSSProperties = {
backgroundColor: "#27272a",
border: "1px solid #3f3f46",
padding: "16px",
borderRadius: "0",
};

const bodyText: React.CSSProperties = {
color: "#a1a1aa",
fontSize: "14px",
lineHeight: "24px",
margin: "0",
whiteSpace: "pre-wrap" as const,
fontFamily: '"IBM Plex Mono", ui-monospace, monospace',
};

const footer: React.CSSProperties = {
color: "#71717a",
fontSize: "11px",
lineHeight: "16px",
textAlign: "center" as const,
margin: "0 0 4px",
};

const version: React.CSSProperties = {
color: "#52525b",
fontSize: "9px",
fontFamily: '"IBM Plex Mono", ui-monospace, monospace',
textAlign: "center" as const,
margin: "0",
letterSpacing: "0.05em",
};

export default AlertEmail;
Loading
Loading