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
39 changes: 39 additions & 0 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Deploy Docs

on:
push:
branches:
- main
- dev
paths:
- "apps/docs/**"

jobs:
deploy:
runs-on: ubuntu-latest
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
defaults:
run:
working-directory: apps/docs

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

- name: Setup Bun
uses: oven-sh/setup-bun@v2

- name: Install dependencies
run: bun install

- name: Build
run: bun run build

- name: Deploy to Vercel
uses: amondnet/vercel-action@v42
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: ${{ github.ref == 'refs/heads/main' && '--prod' || '' }}
working-directory: apps/docs
89 changes: 89 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Release

on:
push:
tags:
- "v*"

env:
REGISTRY: ghcr.io

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
packages: write

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

- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT

- name: Set image names
run: |
REPO_LC="${REPO,,}"
echo "API_IMAGE=ghcr.io/${REPO_LC}/api" >> $GITHUB_ENV
echo "WEB_IMAGE=ghcr.io/${REPO_LC}/web" >> $GITHUB_ENV
env:
REPO: ${{ github.repository }}

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build and push API image
uses: docker/build-push-action@v6
with:
context: apps/api
push: true
tags: |
${{ env.API_IMAGE }}:${{ steps.version.outputs.VERSION }}
${{ env.API_IMAGE }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build and push Web image
uses: docker/build-push-action@v6
with:
context: apps/web
push: true
tags: |
${{ env.WEB_IMAGE }}:${{ steps.version.outputs.VERSION }}
${{ env.WEB_IMAGE }}:latest
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Build config tarball
run: |
VERSION="${{ steps.version.outputs.VERSION }}"
TAR_DIR=_tar
mkdir -p "$TAR_DIR/infra/caddy" "$TAR_DIR/infra/monitoring/grafana/datasources"
cp docker-compose.yml "$TAR_DIR/"
cp scripts/dequel "$TAR_DIR/dequel"
cp infra/caddy/Caddyfile "$TAR_DIR/infra/caddy/"
cp infra/monitoring/prometheus.yml "$TAR_DIR/infra/monitoring/"
cp infra/monitoring/loki-config.yml "$TAR_DIR/infra/monitoring/"
cp infra/monitoring/promtail-config.yml "$TAR_DIR/infra/monitoring/"
cp infra/monitoring/grafana/datasources/loki.yml "$TAR_DIR/infra/monitoring/grafana/datasources/"
cp infra/monitoring/grafana/datasources/prometheus.yml "$TAR_DIR/infra/monitoring/grafana/datasources/"
cd "$TAR_DIR" && tar -czf "../dequel-config-${VERSION}.tar.gz" .

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: v${{ steps.version.outputs.VERSION }}
body_path: CHANGELOG.md
generate_release_notes: true
files: |
scripts/install.sh
dequel-config-${{ steps.version.outputs.VERSION }}.tar.gz
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ node_modules
dist
.DS_Store
*.log
.env
data
workspace
.specs
routes/
infra/caddy/routes/
bugs
apps/api/index
docker-compose.yml
194 changes: 194 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# Dequel

Self-hosted deployment platform. Deploy apps from Git, ZIP, or Docker Compose with zero infrastructure setup.

## Tech Stack

- **Runtime**: Bun
- **Backend**: ElysiaJS (`apps/api/`) — TypeScript, port 3001
- **Frontend**: React 18 + Vite + TanStack Router + TanStack Query (`apps/web/`) — port 3000
- **Docs**: Astro 4 + Tailwind CSS (`apps/docs/`) — deployed to Vercel
- **Database**: SQLite (`data/dequel.db`) — raw SQL
- **Queue**: Redis (`ioredis`) for async job queue
- **Container build**: Railpack CLI + BuildKit daemon
- **Container runtime**: Docker Engine API (mounted Docker socket)
- **Ingress**: Caddy (dynamic route files + auto SSL)

## Architecture

```
Caddy ──▶ API ──▶ Buildkit
│ │
▼ ▼
Web SQLite Redis

Observability: cAdvisor → Prometheus → Grafana / Loki
```

Services run in Docker Compose: Caddy, API, Web, Buildkit, Redis, cAdvisor, Prometheus, Loki, Promtail, Grafana.

## Directory Structure

```
├── apps/
│ ├── api/ # Backend orchestrator (Bun + ElysiaJS)
│ │ ├── src/
│ │ │ ├── api/ # Route handlers
│ │ │ ├── db/ # Database migrations + queries
│ │ │ ├── orchestrator/ # Deployment orchestration logic
│ │ │ ├── scaling/ # Auto-scaling engine
│ │ │ ├── monitoring/ # Alert evaluation, Prometheus metrics
│ │ │ ├── servers/ # Server management
│ │ │ └── git/ # Git operations
│ │ └── Dockerfile
│ ├── web/ # React dashboard (Vite + TanStack)
│ │ ├── src/
│ │ │ ├── routes/ # TanStack Router route definitions
│ │ │ ├── components/ # Shared UI components
│ │ │ ├── api/ # API client
│ │ │ └── hooks/ # Custom hooks
│ │ └── Dockerfile
│ └── docs/ # Documentation site (Astro)
│ ├── src/
│ │ ├── content/docs/ # Markdown doc pages (content collection)
│ │ ├── layouts/ # Layout component with sidebar
│ │ ├── components/ # Landing page components
│ │ └── styles/ # Global CSS
│ └── vercel.json
├── infra/
│ ├── caddy/ # Caddyfile + dynamic route files
│ └── monitoring/ # Prometheus, Loki, Grafana configs
├── scripts/
│ ├── install.sh # One-command install script
│ └── dequel # CLI for managing the platform
├── data/ # SQLite database (persisted)
├── workspace/ # Build staging area
├── docker-compose.yml
├── VERSION # Single source of truth for version
├── CHANGELOG.md # Release history
└── AGENTS.md # This file
```

## Key Files

| File | Purpose |
|------|---------|
| `apps/api/src/index.ts` | API entry point — bootstraps DB, queue, scaling engine, etc. |
| `apps/api/src/db/schema.ts` | Drizzle ORM schema definitions (all tables) |
| `apps/api/src/db/drizzle.ts` | Drizzle client wrapper (wraps `bun:sqlite`) |
| `apps/api/src/db/migrations/` | Drizzle Kit migration files (`drizzle-kit generate` outputs here) |
| `apps/api/drizzle.config.ts` | Drizzle Kit configuration |
| `apps/web/src/main.tsx` | Frontend entry point |
| `apps/web/src/routes/index.tsx` | TanStack Router tree definition |
| `apps/web/src/routes/Dashboard.tsx` | Main dashboard page |
| `apps/web/src/components/Layout.tsx` | Shared app layout (sidebar, header) |
| `apps/docs/src/layouts/Layout.astro` | Docs layout with sidebar (auto-generated from content collection) |
| `apps/docs/src/pages/docs/[...slug].astro` | Catch-all route rendering content collection entries |
| `apps/docs/src/content.config.ts` | Astro content collection schema |
| `scripts/install.sh` | Install script — downloads configs, pulls images, installs CLI |
| `scripts/dequel` | CLI tool — `start`, `stop`, `status`, `logs`, `update`, `uninstall` |
| `.github/workflows/release.yml` | On `v*` tag: build Docker images → ghcr.io, create GitHub Release |
| `.github/workflows/deploy-docs.yml` | On push to `main`/`dev` (docs changes): deploy to Vercel |

## Commands

```bash
# Development (API)
bun apps/api/src/index.ts

# Development (Web)
bun apps/web/src/main.tsx

# Inside apps/web/
bun run build # Vite build
bun run dev # Vite dev server

# Inside apps/api/
bun test # Run tests

# Inside apps/docs/
bun run dev # Astro dev server
bun run build # Astro build

# Docker
docker compose up -d # Start full stack
docker compose up -d --build # Rebuild and start

# Install / Manage
curl -fsSL https://raw.githubusercontent.com/Lftobs/dequel/main/scripts/install.sh | sh
scripts/dequel start # Start platform
scripts/dequel uninstall # Remove everything (prompts)

# Drizzle migrations (run from apps/api/)
bunx drizzle-kit generate # Generate migration from schema changes
bunx drizzle-kit push # Push schema directly (dev only)

# Version sync
bun run sync-versions # Syncs VERSION → sub-package.json files
```

## Code Conventions

- No comments in source code unless absolutely necessary
- no file should be above 500 lines of code...if it really is, refactor and split into smaller files properly managed in a folder not scattered across the codebase (proper feature grouping).
- Named exports over default exports
- No emojis in code or UI unless explicitly requested
- Functional components with hooks (React)
- Tailwind CSS for styling (both web and docs)
- Astro content collections for docs

## Adding a Doc Page

1. Create `.md` file in `apps/docs/src/content/docs/` with frontmatter:
```yaml
---
title: Page Title
category: Category Name
description: Short description.
slug: page-slug
---
```
2. If it's a new category, add it to `categoryOrder` array in `apps/docs/src/layouts/Layout.astro`.
3. The sidebar updates automatically from the content collection.

## Release Process

```bash
git tag vX.Y.Z
git push origin vX.Y.Z
```

CI builds Docker images → `ghcr.io/lftobs/dequel/{api,web}:X.Y.Z` and creates a GitHub Release with `docker-compose.yml`, `scripts/install.sh`, `scripts/dequel` as assets.

## Vercel Deploy (Docs)

`.github/workflows/deploy-docs.yml` deploys docs on push to `main` or `dev`:

| Branch | Domain |
|--------|--------|
| `main` | `dequel.intrep.xyz` |
| `dev` | `dev.dequel.intrep.xyz` |

Requires secrets: `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_PROJECT_ID`

## Environment Variables (API)

| Variable | Default | Description |
|----------|---------|-------------|
| `PORT` | `3001` | API listen port |
| `DATABASE_PATH` | `./data/dequel.db` | SQLite database |
| `WORKSPACE_ROOT` | `./workspace` | Build staging |
| `CADDY_ROUTES_DIR` | `./infra/caddy/routes` | Caddy route output |
| `DOCKER_NETWORK` | `dequel_net` | Docker network for deployments |
| `BUILDKIT_HOST` | `tcp://buildkit:1234` | Buildkit daemon |
| `RAILPACK_BUILD_TIMEOUT_MS` | `1200000` | Build timeout |

## Boundaries

- Never commit secrets or `.env` files
- Drizzle ORM for migrations; raw SQL is still used in `repo.ts` for queries (may be migrated incrementally)
- Database: SQLite with `bun:sqlite` (future: Drizzle ORM + PostgreSQL)
- `.gitignore` ignores `infra/caddy/routes/`, NOT `apps/web/src/routes/`
- Always run `bun test` in `apps/api/` before committing API changes
- Docs landing page (`index.astro`) is standalone — no shared layout
- `set -euo pipefail` in all bash scripts; use functions, not flat code
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.0] - 2026-06-08

### Added

- Initial deployment platform with Git, ZIP, and Docker Compose source deploy
- Automatic build detection via Railpack
- Managed PostgreSQL and MySQL database provisioning
- Custom domain attachment with automatic SSL via Caddy/Let's Encrypt
- CPU-threshold based horizontal auto-scaling with configurable cooldown
- Per-project environment variable management with redeploy hooks
- Persistent Docker volume attachments
- Full observability stack: Prometheus, Loki, Grafana, cAdvisor
- CPU/memory threshold alerts via email or webhook
- API key management for programmatic access
- Job queue via Redis for async operations
- Deployment rollback support
- Boot-time reconciliation of container state
- Unified project versioning via root `VERSION` file and `sync-versions` script
- `CHANGELOG.md` for tracking releases
- One-command install script (`install.sh`) for quick setup
- Automated release pipeline via GitHub Actions (builds Docker images, publishes to GitHub Container Registry, creates GitHub Releases)
- Changelog page in documentation site
- Vercel deployment configuration for documentation site

### Changed

- `docker-compose.yml` now references versioned images from `ghcr.io/dequel/*` with local build as fallback
- README updated with new install flow

### Fixed

- Railpack build timeout handling and log scrolling

[0.1.0]: https://github.com/tobshub/dequel/releases/tag/v0.1.0
Loading
Loading