Gleam Lustre Fullstack Atproto Demo App w/Slices.Network GraphQL API

get deploy working

Changed files
+159 -1
.github
workflows
server
+31
.dockerignore
···
··· 1 + # flyctl launch added from client/.gitignore 2 + client/**/*.beam 3 + client/**/*.ez 4 + client/build 5 + client/**/erl_crash.dump 6 + 7 + #Added automatically by Lustre Dev Tools 8 + client/.lustre 9 + client/dist 10 + client/node_modules 11 + 12 + # flyctl launch added from server/.gitignore 13 + server/**/*.beam 14 + server/**/*.ez 15 + server/build 16 + server/**/erl_crash.dump 17 + server/**/*db* 18 + server/**/.env 19 + 20 + # flyctl launch added from server/build/packages/squall/.gitignore 21 + server/build/packages/squall/**/*.beam 22 + server/build/packages/squall/**/*.ez 23 + server/build/packages/squall/**/build 24 + server/build/packages/squall/**/erl_crash.dump 25 + 26 + # flyctl launch added from shared/.gitignore 27 + shared/**/*.beam 28 + shared/**/*.ez 29 + shared/build 30 + shared/**/erl_crash.dump 31 + fly.toml
+18
.github/workflows/fly-deploy.yml
···
··· 1 + # See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/ 2 + 3 + name: Fly Deploy 4 + on: 5 + push: 6 + branches: 7 + - main 8 + jobs: 9 + deploy: 10 + name: Deploy app 11 + runs-on: ubuntu-latest 12 + concurrency: deploy-group # optional: ensure only one action runs at a time 13 + steps: 14 + - uses: actions/checkout@v4 15 + - uses: superfly/flyctl-actions/setup-flyctl@master 16 + - run: flyctl deploy --remote-only 17 + env: 18 + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
+58
Dockerfile
···
··· 1 + ARG GLEAM_VERSION=v1.13.0 2 + 3 + # Build stage - compile the application 4 + FROM ghcr.io/gleam-lang/gleam:${GLEAM_VERSION}-erlang-alpine AS builder 5 + 6 + # Install build dependencies 7 + RUN apk add --no-cache \ 8 + git \ 9 + nodejs \ 10 + npm \ 11 + build-base \ 12 + sqlite-dev 13 + 14 + # Configure git for non-interactive use 15 + ENV GIT_TERMINAL_PROMPT=0 16 + 17 + # Add project code 18 + COPY ./shared /build/shared 19 + COPY ./client /build/client 20 + COPY ./server /build/server 21 + 22 + # Install dependencies for all projects 23 + RUN cd /build/shared && gleam deps download 24 + RUN cd /build/client && gleam deps download 25 + RUN cd /build/server && gleam deps download 26 + 27 + # Install JavaScript dependencies for client 28 + RUN cd /build/client && npm install 29 + 30 + # Compile the client code and output to server's static directory 31 + RUN cd /build/client \ 32 + && gleam add --dev lustre_dev_tools \ 33 + && gleam run -m lustre/dev build client --minify --outdir=/build/server/priv/static 34 + 35 + # Compile the server code 36 + RUN cd /build/server \ 37 + && gleam export erlang-shipment 38 + 39 + # Runtime stage - slim image with only what's needed to run 40 + FROM ghcr.io/gleam-lang/gleam:${GLEAM_VERSION}-erlang-alpine 41 + 42 + # Copy the compiled server code from the builder stage 43 + COPY --from=builder /build/server/build/erlang-shipment /app 44 + 45 + # Set up the entrypoint 46 + WORKDIR /app 47 + RUN echo -e '#!/bin/sh\nexec ./entrypoint.sh "$@"' > ./start.sh \ 48 + && chmod +x ./start.sh 49 + 50 + # Set environment variables 51 + ENV HOST=0.0.0.0 52 + ENV PORT=8080 53 + 54 + # Expose the port the server will run on 55 + EXPOSE $PORT 56 + 57 + # Run the server 58 + CMD ["./start.sh", "run"]
+22
fly.toml
···
··· 1 + # fly.toml app configuration file generated for atconf on 2025-10-24T14:04:15-07:00 2 + # 3 + # See https://fly.io/docs/reference/configuration/ for information about how to use this file. 4 + # 5 + 6 + app = 'atconf' 7 + primary_region = 'sjc' 8 + 9 + [build] 10 + 11 + [http_service] 12 + internal_port = 8080 13 + force_https = true 14 + auto_stop_machines = 'stop' 15 + auto_start_machines = true 16 + min_machines_running = 0 17 + processes = ['app'] 18 + 19 + [[vm]] 20 + memory = '512mb' 21 + cpu_kind = 'shared' 22 + cpus = 1
+8
server/.env.example
··· 3 # Or the server will generate one on first run and print it to console 4 SECRET_KEY_BASE=CHANGE_ME_TO_A_RANDOM_64_CHARACTER_STRING 5 6 # OAuth Configuration 7 # These values will be used if environment variables are not set 8
··· 3 # Or the server will generate one on first run and print it to console 4 SECRET_KEY_BASE=CHANGE_ME_TO_A_RANDOM_64_CHARACTER_STRING 5 6 + # Server Configuration 7 + # Host address to bind to (defaults to 127.0.0.1 if not set) 8 + # Use 0.0.0.0 to listen on all interfaces (required for Docker/production) 9 + HOST=127.0.0.1 10 + 11 + # Port the server will listen on (defaults to 3000 if not set) 12 + PORT=3000 13 + 14 # OAuth Configuration 15 # These values will be used if environment variables are not set 16
+22 -1
server/src/server.gleam
··· 9 import gleam/http.{Get, Post} 10 import gleam/http/request 11 import gleam/httpc 12 import gleam/io 13 import gleam/json 14 import gleam/list ··· 82 use db <- sqlight.with_connection("./sessions.db") 83 let assert Ok(_) = session.init_db(db) 84 85 let assert Ok(_) = 86 handle_request(static_directory, db, oauth_config, _) 87 |> wisp_mist.handler(secret_key_base) 88 |> mist.new 89 - |> mist.port(3000) 90 |> mist.start 91 92 process.sleep_forever()
··· 9 import gleam/http.{Get, Post} 10 import gleam/http/request 11 import gleam/httpc 12 + import gleam/int 13 import gleam/io 14 import gleam/json 15 import gleam/list ··· 83 use db <- sqlight.with_connection("./sessions.db") 84 let assert Ok(_) = session.init_db(db) 85 86 + // Get host from environment or default to 127.0.0.1 87 + let host = case envoy.get("HOST") { 88 + Ok(h) -> h 89 + Error(_) -> "127.0.0.1" 90 + } 91 + 92 + // Get port from environment or default to 3000 93 + let port = case envoy.get("PORT") { 94 + Ok(port_str) -> { 95 + case int.parse(port_str) { 96 + Ok(p) -> p 97 + Error(_) -> 3000 98 + } 99 + } 100 + Error(_) -> 3000 101 + } 102 + 103 + io.println("Listening on http://" <> host <> ":" <> int.to_string(port)) 104 + 105 let assert Ok(_) = 106 handle_request(static_directory, db, oauth_config, _) 107 |> wisp_mist.handler(secret_key_base) 108 |> mist.new 109 + |> mist.bind(host) 110 + |> mist.port(port) 111 |> mist.start 112 113 process.sleep_forever()