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
11 changes: 3 additions & 8 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Local development. For Docker self-hosting, use selfhost.env.example.

CLICKHOUSE_URL="http://default:@localhost:8123/databuddy_analytics"
# Required by DQL. This must use the separately provisioned dql_user account;
# never point it at the application/admin ClickHouse credentials.
Expand All @@ -6,13 +8,6 @@ DATABASE_URL="postgres://databuddy:databuddy_dev_password@localhost:5432/databud
REDIS_URL="redis://localhost:6379"
BULLMQ_REDIS_URL="redis://localhost:6379"

# Required only by docker-compose.selfhost.yml. Use URL-safe passwords and make
# the local database URLs above use the same credentials before initialization.
IMAGE_TAG=""
POSTGRES_PASSWORD=""
CLICKHOUSE_PASSWORD=""
REDIS_PASSWORD=""

# Public URLs. Local development uses built-in localhost defaults when blank.
DASHBOARD_URL=""
API_URL=""
Expand All @@ -31,7 +26,7 @@ FIRECRAWL_API_KEY=""
SUPERMEMORY_API_KEY=""

BETTER_AUTH_URL="http://localhost:3000"
# Required by docker-compose.selfhost.yml. Generate independent random values.
# Generate independent random values for sessions and encryption.
BETTER_AUTH_SECRET="generate-a-random-32-byte-base64-secret"
DATABUDDY_ENCRYPTION_KEY=""

Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ jobs:
run: >-
bun test --no-env-file apps/dashboard/next-config.test.ts
apps/dashboard/app/layout.test.ts
apps/dashboard/lib/app-url.test.ts
'apps/dashboard/app/(main)/websites/[id]/_components/utils/code-generators.test.ts'
'apps/dashboard/app/(main)/onboarding/_components/step-install-tracking.test.ts'
packages/auth/src/selfhost-config.test.ts
Expand Down
14 changes: 6 additions & 8 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
EVENT_NAME: ${{ github.event_name }}
BEFORE_SHA: ${{ github.event.before }}
run: |
ALL='["api","basket","dashboard","insights","links","uptime"]'
ALL='["api","basket","dashboard","init","insights","links","uptime"]'
if [[ "$EVENT_NAME" != "push" ]]; then
echo "services=$ALL" >> "$GITHUB_OUTPUT"
exit 0
Expand All @@ -60,19 +60,16 @@ jobs:
fi
export TURBO_SCM_BASE="$BEFORE_SHA"
export TURBO_SCM_HEAD="HEAD"
affected=()
# The init image ships the schema and tooling for every release.
affected=('"init"')
for svc in api basket dashboard insights links uptime; do
count=$(bunx turbo ls --affected --filter="@databuddy/$svc" --output=json | jq -r '.packages.count')
if [[ "$count" != "0" ]]; then
affected+=("\"$svc\"")
fi
done
if [[ ${#affected[@]} -eq 0 ]]; then
echo "services=[]" >> "$GITHUB_OUTPUT"
else
IFS=,
echo "services=[${affected[*]}]" >> "$GITHUB_OUTPUT"
fi
IFS=,
echo "services=[${affected[*]}]" >> "$GITHUB_OUTPUT"

build:
name: Build ${{ matrix.service }} (${{ matrix.platform.arch }})
Expand Down Expand Up @@ -136,6 +133,7 @@ jobs:
api) text="Databuddy API service - analytics backend" ;;
basket) text="Databuddy Basket service - event ingestion" ;;
dashboard) text="Databuddy Dashboard service - web analytics UI" ;;
init) text="Databuddy database initialization and schema tools" ;;
insights) text="Databuddy Insights service - queued insight generation" ;;
links) text="Databuddy Links service - URL shortening and tracking" ;;
uptime) text="Databuddy Uptime service - availability monitoring" ;;
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/health-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches: [main]
paths:
- "*.Dockerfile"
- "docker-compose.selfhost.yml"
- "selfhost.env.example"
- "scripts/test-selfhost-init.sh"
Comment thread
izadoesdev marked this conversation as resolved.
- ".dockerignore"
- "apps/api/**"
- "apps/basket/**"
Expand All @@ -15,11 +18,15 @@ on:
- "bun.lock"
- "package.json"
- "turbo.json"
- "tsconfig/**"
- ".github/workflows/health-check.yml"
pull_request:
branches: [main, staging]
paths:
- "*.Dockerfile"
- "docker-compose.selfhost.yml"
- "selfhost.env.example"
- "scripts/test-selfhost-init.sh"
- ".dockerignore"
- "apps/api/**"
- "apps/basket/**"
Expand All @@ -30,6 +37,7 @@ on:
- "bun.lock"
- "package.json"
- "turbo.json"
- "tsconfig/**"
- ".github/workflows/health-check.yml"

permissions:
Expand All @@ -40,6 +48,14 @@ concurrency:
cancel-in-progress: true

jobs:
selfhost-init:
name: Self-host Database Initialization
runs-on: blacksmith-4vcpu-ubuntu-2404
timeout-minutes: 15
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
- run: bash scripts/test-selfhost-init.sh

vector-config-check:
name: Vector Delivery Canary
runs-on: blacksmith-2vcpu-ubuntu-2404
Expand Down
25 changes: 14 additions & 11 deletions apps/dashboard/app/(main)/monitors/status-pages/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export default function StatusPageDetailsPage() {
});

const statusPage = statusPageQuery.data;
const statusPageUrl = statusPage && getStatusPageUrl(statusPage.slug);

const monitorToRemoveData = statusPage?.monitors.find(
(m: StatusPageMonitor) => m.id === monitorToRemove
Expand Down Expand Up @@ -215,17 +216,19 @@ export default function StatusPageDetailsPage() {
<div className="flex items-center gap-2">
{statusPage ? (
<>
<Link
className={buttonVariants({
size: "sm",
variant: "secondary",
})}
href={getStatusPageUrl(statusPage.slug)}
rel="noopener noreferrer"
target="_blank"
>
View Page
</Link>
{statusPageUrl && (
<Link
className={buttonVariants({
size: "sm",
variant: "secondary",
})}
href={statusPageUrl}
rel="noopener noreferrer"
target="_blank"
>
View Page
</Link>
)}
<Button
aria-label="Refresh data"
disabled={
Expand Down
42 changes: 23 additions & 19 deletions apps/dashboard/components/status-pages/status-page-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,30 @@ function StatusPageActions({
<PencilSimpleIcon className="size-4" />
Edit Details
</DropdownMenu.Item>
<DropdownMenu.Item
className="gap-2"
onClick={() => copyToClipboard(url)}
>
<CopyIcon className="size-4" />
Copy URL
</DropdownMenu.Item>
<DropdownMenu.Item
render={
<Link
{url && (
<>
<DropdownMenu.Item
className="gap-2"
href={url}
rel="noopener noreferrer"
target="_blank"
/>
}
>
<ArrowSquareOutIcon className="size-4" />
View Page
</DropdownMenu.Item>
onClick={() => copyToClipboard(url)}
>
<CopyIcon className="size-4" />
Copy URL
</DropdownMenu.Item>
<DropdownMenu.Item
render={
<Link
className="gap-2"
href={url}
rel="noopener noreferrer"
target="_blank"
/>
}
>
<ArrowSquareOutIcon className="size-4" />
View Page
</DropdownMenu.Item>
</>
)}
<DropdownMenu.Item
className="gap-2"
onClick={() => setIsTransferOpen(true)}
Expand Down
30 changes: 30 additions & 0 deletions apps/dashboard/lib/app-url.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { expect, test } from "bun:test";

test.each([
[false, undefined, "https://status.databuddy.cc/example"],
[false, "", "https://status.databuddy.cc/example"],
[true, undefined, null],
[true, "", null],
[true, " ", null],
[true, "https://status.example.com", "https://status.example.com/example"],
[false, "https://status.example.com", "https://status.example.com/example"],
] as const)("status links with self-host=%s and URL %s", (selfhost, url, expected) => {
const result = Bun.spawnSync({
cmd: [
process.execPath,
"-e",
'import { getStatusPageUrl } from "./app-url"; console.log(JSON.stringify(getStatusPageUrl("example")));',
Comment thread
izadoesdev marked this conversation as resolved.
],
cwd: import.meta.dir,
env: {
...process.env,
NODE_ENV: "production",
SELFHOST: String(selfhost),
NEXT_PUBLIC_SELFHOST: String(selfhost),
STATUS_URL: "",
NEXT_PUBLIC_STATUS_URL: url,
},
});
expect(result.exitCode).toBe(0);
expect(JSON.parse(result.stdout.toString())).toBe(expected);
});
8 changes: 5 additions & 3 deletions apps/dashboard/lib/app-url.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { publicConfig } from "@databuddy/env/public";
import { isSelfHosted, publicConfig } from "@databuddy/env/public";

export const APP_URL = publicConfig.urls.dashboard;

const STATUS_URL = publicConfig.urls.status;

export function getStatusPageUrl(slug: string): string {
return `${STATUS_URL}/${slug}`;
export function getStatusPageUrl(slug: string): string | null {
return isSelfHosted && !process.env.NEXT_PUBLIC_STATUS_URL?.trim()
? null
: `${STATUS_URL}/${slug}`;
}
3 changes: 2 additions & 1 deletion dashboard.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ COPY turbo.json turbo.json

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ARG SELFHOST=false
ENV SELFHOST=$SELFHOST
# Build-time defaults keep the image buildable. Override these with real public
# URLs when building environment-specific dashboard images.
ARG NEXT_PUBLIC_API_URL=https://api.databuddy.cc
ARG NEXT_PUBLIC_APP_URL=https://app.databuddy.cc
ARG NEXT_PUBLIC_BASKET_URL=https://basket.databuddy.cc
ARG NEXT_PUBLIC_LINKS_URL=https://dby.sh
ARG NEXT_PUBLIC_STATUS_URL=https://status.databuddy.cc
ARG SELFHOST=false

ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL
Expand Down
Loading
Loading