-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add Fly deployment template #87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
vieiralucas
wants to merge
7
commits into
main
Choose a base branch
from
feat/3.2-fly-deployment-template
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
9612af4
chore: mark story 3.2 in-progress, add story spec
vieiralucas d95eac1
feat: add Fly deployment template and instructions
vieiralucas ec0b108
chore: update story 3.2 tracking files
vieiralucas 7b5131e
fix: use fly checks list for health check troubleshooting
vieiralucas a2280c5
fix: correct --server flag position in zopp join example
vieiralucas 7e1280c
chore: mark story 3.2 as completed
vieiralucas 8bb47e3
chore: mark epic 3 as complete
vieiralucas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
189 changes: 189 additions & 0 deletions
189
_bmad-output/implementation-artifacts/3-2-create-fly-deployment-template.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| # Story 3.2: Create Fly deployment template | ||
|
|
||
| Status: review | ||
|
|
||
| ## Story | ||
|
|
||
| As a developer, | ||
| I want to deploy zopp-server on Fly using a provided template, | ||
| so that my team has a shared server without managing infrastructure. | ||
|
|
||
| ## Acceptance Criteria | ||
|
|
||
| 1. **Given** the deployment template exists at `deploy/fly/fly.toml`, **When** the user runs `fly launch` with the template, **Then** Fly provisions the app with the correct configuration. | ||
|
|
||
| 2. **Given** the template configuration, **When** the server starts, **Then** PostgreSQL is configured as the database backend (not SQLite) **And** TLS is handled automatically by Fly's platform **And** a health check endpoint is configured at `/healthz` on port 8080. | ||
|
|
||
| 3. **Given** the server is deployed and running, **When** the user runs `fly ssh console -C "zopp-server invite create"`, **Then** an invite token is generated that can be shared with team members. | ||
|
|
||
| 4. **Given** the `deploy/fly/README.md` exists, **When** a user reads it, **Then** it contains step-by-step deployment instructions **And** it documents required and optional environment variables **And** it explains how to generate the first invite token **And** it explains how to connect the CLI to the deployed server. | ||
|
|
||
| ## Tasks / Subtasks | ||
|
|
||
| - [x] Task 1: Create Fly deployment template (AC: 1, 2) | ||
| - [x] 1.1 Create `deploy/fly/fly.toml` with app configuration | ||
| - [x] 1.2 Configure PostgreSQL as attached database (Fly Postgres) | ||
| - [x] 1.3 Configure health check using `/healthz` on port 8080 | ||
| - [x] 1.4 Configure gRPC service on internal port 50051 | ||
| - [x] 1.5 Set appropriate VM size and auto-stop settings | ||
|
|
||
| - [x] Task 2: Create deployment README (AC: 3, 4) | ||
| - [x] 2.1 Create `deploy/fly/README.md` with step-by-step instructions | ||
| - [x] 2.2 Document `fly launch` and `fly deploy` workflow | ||
| - [x] 2.3 Document Fly Postgres setup (`fly postgres create` + `fly postgres attach`) | ||
| - [x] 2.4 Document environment variables (DATABASE_URL, email config, etc.) | ||
| - [x] 2.5 Document invite token generation via `fly ssh console` | ||
| - [x] 2.6 Document connecting CLI to deployed server | ||
| - [x] 2.7 Document TLS (automatic via Fly's edge, gRPC uses h2c internally) | ||
|
|
||
| - [x] Task 3: Validation | ||
| - [x] 3.1 Verify fly.toml passes `fly launch --config deploy/fly/fly.toml` syntax check (dry review) | ||
| - [x] 3.2 Ensure README instructions are consistent with fly.toml settings | ||
|
|
||
| ## Dev Notes | ||
|
|
||
| ### Fly Platform Details | ||
|
|
||
| **Fly Machines Configuration:** | ||
| - Fly uses `fly.toml` for app configuration | ||
| - Apps are deployed as Machines (micro VMs) | ||
| - Fly handles TLS termination at the edge — the app runs plain gRPC (h2c) internally | ||
| - Fly Postgres is a managed Postgres service attached to apps | ||
|
|
||
| **Key fly.toml Sections:** | ||
| ```toml | ||
| app = "zopp-server" # User will change this during fly launch | ||
|
|
||
| [build] | ||
| dockerfile = "server.Dockerfile" | ||
|
|
||
| [env] | ||
| # Non-secret environment variables | ||
| ZOPP_EMAIL_VERIFICATION_REQUIRED = "false" | ||
|
|
||
| [http_service] | ||
| internal_port = 50051 | ||
| force_https = true | ||
| auto_stop_machines = "stop" | ||
| auto_start_machines = true | ||
| min_machines_running = 0 | ||
| processes = ["app"] | ||
|
|
||
| [[services]] | ||
| protocol = "tcp" | ||
| internal_port = 50051 | ||
|
|
||
| [[services.ports]] | ||
| port = 443 | ||
| handlers = ["tls", "http"] | ||
|
|
||
| [[services.ports]] | ||
| port = 80 | ||
| handlers = ["http"] | ||
|
|
||
| [checks] | ||
| [checks.health] | ||
| port = 8080 | ||
| type = "http" | ||
| interval = "10s" | ||
| timeout = "2s" | ||
| path = "/healthz" | ||
| method = "GET" | ||
|
|
||
| [[vm]] | ||
| size = "shared-cpu-1x" | ||
| memory = "256mb" | ||
| ``` | ||
|
|
||
| **Database Configuration:** | ||
| - Users create a Fly Postgres cluster: `fly postgres create --name zopp-db` | ||
| - Attach to app: `fly postgres attach zopp-db --app zopp-server` | ||
| - This automatically sets `DATABASE_URL` as a secret on the app | ||
| - zopp-server detects the postgres:// URL and uses PostgreSQL backend | ||
|
|
||
| **Health Checks:** | ||
| - zopp-server serves HTTP health on port 8080 by default (`--health-addr 0.0.0.0:8080`) | ||
| - Liveness: `GET /healthz` → 200 "ok" | ||
| - Readiness: `GET /readyz` → 200 when gRPC ready, 503 otherwise | ||
| - Fly uses checks to determine if a Machine is healthy | ||
|
|
||
| **TLS:** | ||
| - Fly automatically terminates TLS at the edge | ||
| - Internal traffic within Fly's network is h2c (HTTP/2 cleartext) | ||
| - No need for `--tls-cert` / `--tls-key` flags on the server | ||
| - CLI connects to `https://<app>.fly.dev:443` — Fly routes to internal port 50051 | ||
|
|
||
| **Invite Token Generation:** | ||
| - Users run: `fly ssh console -C "/usr/local/bin/zopp-server invite create"` | ||
| - The zopp-server binary is at `/usr/local/bin/zopp-server` in the Docker image | ||
| - This outputs an invite token that can be shared | ||
| - Note: The `invite create` subcommand on the server binary creates a bootstrap invite | ||
|
|
||
| **CLI Connection:** | ||
| - After deployment, the server is available at `https://<appname>.fly.dev` | ||
| - Users configure their CLI: `zopp join <invite-token> <email> --server https://<appname>.fly.dev` | ||
|
|
||
| ### Environment Variables Reference | ||
|
|
||
| **Required (set automatically by Fly Postgres attach):** | ||
| - `DATABASE_URL` — PostgreSQL connection string | ||
|
|
||
| **Optional:** | ||
| - `ZOPP_EMAIL_VERIFICATION_REQUIRED` — "true"/"false" (default "true") | ||
| - `ZOPP_EMAIL_PROVIDER` — "resend" or "smtp" | ||
| - `ZOPP_EMAIL_FROM` — Sender email address | ||
| - `RESEND_API_KEY` — If using Resend email provider | ||
| - SMTP variables if using SMTP | ||
|
|
||
| ### Architecture Notes | ||
|
|
||
| - This story is purely configuration/documentation — no Rust code changes | ||
| - The existing `server.Dockerfile` is used as-is (Fly builds from Dockerfile) | ||
| - The `deploy/` directory is new; this is the first deployment template | ||
| - Follow similar patterns to the Helm chart in `charts/zopp/` for reference on configuration values | ||
|
|
||
| ### Project Structure Notes | ||
|
|
||
| - New directory: `deploy/fly/` | ||
| - Files: `deploy/fly/fly.toml`, `deploy/fly/README.md` | ||
| - No changes to existing source code | ||
| - No Cargo.toml changes | ||
|
|
||
| ### References | ||
|
|
||
| - [Source: server.Dockerfile] — Docker build for zopp-server | ||
| - [Source: apps/zopp-server/src/main.rs] — Server startup, health check endpoints, CLI args | ||
| - [Source: charts/zopp/values.yaml] — Helm chart defaults (reference for env vars) | ||
| - [Source: CLAUDE.md] — Server commands, TLS configuration, DATABASE_URL usage | ||
|
|
||
| ### Pre-Submission Checklist | ||
|
|
||
| Before submitting a PR, verify each item relevant to your story's scope. | ||
|
|
||
| **Documentation:** | ||
|
|
||
| - [ ] fly.toml uses correct ports (50051 gRPC, 8080 health) | ||
| - [ ] README instructions are accurate and complete | ||
| - [ ] No secrets or credentials appear in template files | ||
| - [ ] Environment variable documentation matches server implementation | ||
|
|
||
| ## Dev Agent Record | ||
|
|
||
| ### Agent Model Used | ||
|
|
||
| Claude Opus 4.6 | ||
|
|
||
| ### Debug Log References | ||
|
|
||
| ### Completion Notes List | ||
|
|
||
| - Created fly.toml with gRPC on port 50051, health checks on port 8080 | ||
| - PostgreSQL via Fly Postgres attach (sets DATABASE_URL automatically) | ||
| - TLS handled by Fly edge — no server-side TLS config needed | ||
| - README covers full deployment workflow: launch, postgres, deploy, invite, connect CLI | ||
| - Email verification disabled by default in template (enable after configuring email provider) | ||
|
|
||
| ### File List | ||
|
|
||
| - deploy/fly/fly.toml (new) — Fly deployment configuration | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| - deploy/fly/README.md (new) — Step-by-step deployment instructions | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,154 @@ | ||
| # Deploy zopp-server on Fly | ||
|
|
||
| Deploy a zopp-server instance on [Fly.io](https://fly.io) with PostgreSQL. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - [Fly CLI](https://fly.io/docs/flyctl/install/) installed and authenticated (`fly auth login`) | ||
| - A Fly account with billing configured | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ### 1. Launch the app | ||
|
|
||
| From the repository root: | ||
|
|
||
| ```bash | ||
| fly launch --config deploy/fly/fly.toml --no-deploy | ||
| ``` | ||
|
|
||
| Fly will prompt you to set the app name and region. Choose a region close to your team. | ||
|
|
||
| ### 2. Create a PostgreSQL database | ||
|
|
||
| ```bash | ||
| fly postgres create --name zopp-db | ||
| ``` | ||
|
|
||
| Choose the same region as your app. For development, the "Development" plan is sufficient. | ||
|
|
||
| ### 3. Attach the database | ||
|
|
||
| ```bash | ||
| fly postgres attach zopp-db --app <your-app-name> | ||
| ``` | ||
|
|
||
| This automatically sets the `DATABASE_URL` secret on your app. | ||
|
|
||
| ### 4. Deploy | ||
|
|
||
| ```bash | ||
| fly deploy --config deploy/fly/fly.toml | ||
| ``` | ||
|
|
||
| The first deploy takes a few minutes to build the Docker image. | ||
|
|
||
| ### 5. Verify the deployment | ||
|
|
||
| ```bash | ||
| fly status --app <your-app-name> | ||
| ``` | ||
|
|
||
| Check that the Machine is running and healthy. | ||
|
|
||
| ## Generate an Invite Token | ||
|
|
||
| After deploying, create the first invite token to bootstrap your workspace: | ||
|
|
||
| ```bash | ||
| fly ssh console --app <your-app-name> -C "/usr/local/bin/zopp-server invite create" | ||
| ``` | ||
|
|
||
| This outputs an invite token. Save it securely — you'll use it to join the server from the CLI. | ||
|
|
||
| ## Connect the CLI | ||
|
|
||
| With the invite token from the previous step: | ||
|
|
||
| ```bash | ||
| zopp --server https://<your-app-name>.fly.dev join <invite-token> <your-email> | ||
| ``` | ||
|
|
||
| This registers your device as a principal on the server. You can then create workspaces and manage secrets: | ||
|
|
||
| ```bash | ||
| zopp workspace create my-workspace | ||
| zopp project create my-project | ||
| zopp environment create production | ||
| zopp secret set API_KEY "my-secret-value" | ||
| ``` | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| ### Set automatically | ||
|
|
||
| | Variable | Description | | ||
| |---|---| | ||
| | `DATABASE_URL` | PostgreSQL connection string (set by `fly postgres attach`) | | ||
|
|
||
| ### Configured in fly.toml | ||
|
|
||
| | Variable | Default | Description | | ||
| |---|---|---| | ||
| | `ZOPP_EMAIL_VERIFICATION_REQUIRED` | `false` | Set to `true` once email is configured | | ||
|
|
||
| ### Optional (set as Fly secrets) | ||
|
|
||
| Set these with `fly secrets set`: | ||
|
|
||
| ```bash | ||
| # Enable email verification with Resend | ||
| fly secrets set \ | ||
| ZOPP_EMAIL_VERIFICATION_REQUIRED=true \ | ||
| ZOPP_EMAIL_PROVIDER=resend \ | ||
| ZOPP_EMAIL_FROM=noreply@yourdomain.com \ | ||
| RESEND_API_KEY=re_xxxxx | ||
|
|
||
| # Or use SMTP | ||
| fly secrets set \ | ||
| ZOPP_EMAIL_VERIFICATION_REQUIRED=true \ | ||
| ZOPP_EMAIL_PROVIDER=smtp \ | ||
| ZOPP_EMAIL_FROM=noreply@yourdomain.com \ | ||
| SMTP_HOST=smtp.example.com \ | ||
| SMTP_PORT=587 \ | ||
| SMTP_USERNAME=user \ | ||
| SMTP_PASSWORD=pass | ||
| ``` | ||
|
|
||
| ## TLS | ||
|
|
||
| Fly automatically terminates TLS at the edge. The zopp-server runs plain gRPC internally — no TLS certificate configuration is needed. | ||
|
|
||
| Your CLI connects via `https://<your-app-name>.fly.dev` and Fly handles the TLS termination. | ||
|
|
||
| ## Scaling | ||
|
|
||
| The default configuration uses a shared CPU with 256MB RAM and auto-stop enabled. To adjust: | ||
|
|
||
| ```bash | ||
| # Scale VM size | ||
| fly scale vm shared-cpu-2x --memory 512 --app <your-app-name> | ||
|
|
||
| # Keep at least one Machine running (disable auto-stop) | ||
| fly scale count 1 --app <your-app-name> | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Check server logs | ||
|
|
||
| ```bash | ||
| fly logs --app <your-app-name> | ||
| ``` | ||
|
|
||
| ### Check health | ||
|
|
||
| ```bash | ||
| fly checks list --app <your-app-name> | ||
| ``` | ||
|
|
||
| ### SSH into the Machine | ||
|
|
||
| ```bash | ||
| fly ssh console --app <your-app-name> | ||
| ``` |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.