Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3b34316
feat(slackbot): initial commit of slackbot monorepo integration
evanpetzoldt Jun 11, 2026
186b722
fix(slackbot): added pytest to deps and fixed some failing tests
evanpetzoldt Jun 11, 2026
29b511a
Merge branch 'dev' into feat-adding-slackbot
evanpetzoldt Jun 12, 2026
348103f
refactor(slackbot): removed python semantic release in favor of relea…
evanpetzoldt Jun 12, 2026
6f57ea9
feat(slackbot): starting to add tag-based deployment for slackbot
evanpetzoldt Jun 12, 2026
ee65c03
Merge branch 'dev' into feat-adding-slackbot
evanpetzoldt Jun 12, 2026
e98b457
refactor(slackbot): transitioning to GCP deployment conventions
evanpetzoldt Jun 13, 2026
24b834f
Merge branch 'dev' into feat-adding-slackbot
evanpetzoldt Jun 13, 2026
61a8d7e
refactor(slackbot): adopting .env.example convention
evanpetzoldt Jun 13, 2026
ee637e3
Merge branch 'dev' into feat-adding-slackbot
evanpetzoldt Jun 13, 2026
c7d8e59
refactor(slackbot): cleaning up env var and added script for deployin…
evanpetzoldt Jun 14, 2026
f1ae64b
Merge branch 'dev' into feat-adding-slackbot
evanpetzoldt Jun 14, 2026
6d095c2
refactor(slackbot): simplifying startup process
evanpetzoldt Jun 14, 2026
6e96cd6
refactor(slackbot): making it easier to connect to locally seeded data
evanpetzoldt Jun 14, 2026
a74a32f
refactor(slackbot): adding more graceful handling of slack secrets no…
evanpetzoldt Jun 14, 2026
4114085
refactor(slackbot): misc deployment and docs updates
evanpetzoldt Jun 15, 2026
2c9a9c8
Merge branch 'dev' into feat-adding-slackbot
evanpetzoldt Jun 15, 2026
ab9ca5c
refactor(slackbot): more dependency cleanup
evanpetzoldt Jun 15, 2026
294aa67
fix(slackbot): removed missing reference to alembic
evanpetzoldt Jun 15, 2026
16b6993
feat(slackbot): added local event instance seeding
evanpetzoldt Jun 15, 2026
390ced9
feat(slackbot): adding enhancements to the connect region flow
evanpetzoldt Jun 15, 2026
3e33938
feat(slackbot): handling phone addition to orgs
evanpetzoldt Jun 15, 2026
41db043
Merge branch 'dev' into feat-adding-slackbot
evanpetzoldt Jun 15, 2026
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
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ npm-debug.log
*Dockerfile*
docker-compose*
README.md
!apps/slackbot/README.md
!packages/db-python/README.md
LICENSE

*.swp
Expand Down
15 changes: 11 additions & 4 deletions .github/actions/setup-node-pnpm/action.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
name: Setup Node and pnpm
name: Setup Node, pnpm, Python, and uv
description: >-
Install pnpm and Node (pinned via .nvmrc), restore the pnpm store cache, and
install workspace dependencies from the frozen lockfile. Shared by every CI
job so the toolchain setup can never drift between jobs.
Install Python and uv, then pnpm and Node (pinned via .nvmrc), restore the
pnpm store cache, and install workspace dependencies from the frozen
lockfile. Shared by every CI job so the toolchain setup can never drift
between jobs.

runs:
using: composite
steps:
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"

- uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0

- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
Expand Down
224 changes: 224 additions & 0 deletions .github/workflows/_deploy-cloudrun-job.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
name: Reusable Cloud Run Job Deploy

# Reusable pipeline for Cloud Run Jobs (batch/cron workloads).
# ci-gate -> build image once -> deploy staging job -> promote + deploy prod job.

on:
workflow_call:
inputs:
image_name:
description: "Artifact Registry image name (e.g. f3-bot-scripts)"
required: true
type: string
job_name:
description: "Cloud Run Job name"
required: true
type: string
staging_project:
description: "GCP project ID for staging"
required: true
type: string
prod_project:
description: "GCP project ID for production"
required: true
type: string
tag_prefix:
description: "Tag prefix to strip for the image version (e.g. slackbot@)"
required: true
type: string
dockerfile:
description: "Path to the Dockerfile"
required: true
type: string
build_context:
description: "Docker build context path"
required: false
type: string
default: "."
staging_environment:
description: "GitHub Environment name for staging"
required: true
type: string
prod_environment:
description: "GitHub Environment name for production"
required: true
type: string
region:
description: "GCP region"
required: false
type: string
default: us-east1
ar_repo:
description: "Artifact Registry repository"
required: false
type: string
default: cloud-run-builds
flags:
description: "Extra flags passed directly to gcloud run jobs deploy"
required: false
type: string
default: ""

jobs:
ci-gate:
runs-on: ubuntu-latest
permissions:
contents: read
checks: read
steps:
- name: Wait for CI to pass
uses: lewagon/wait-on-check-action@9312864dfbc9fd208e9c0417843430751c042800 # v1.7.0
with:
ref: ${{ github.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
check-regexp: "^(build|lint|typecheck|format-check|test-coverage)$"
wait-interval: 15
allowed-conclusions: success

build:
needs: ci-gate
runs-on: ubuntu-latest
environment: ${{ inputs.staging_environment }}
permissions:
contents: read
id-token: write
outputs:
image: ${{ steps.meta.outputs.image }}
version: ${{ steps.meta.outputs.version }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Authenticate to GCP (staging project for AR)
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
workload_identity_provider: ${{ vars.WIF_PROVIDER }}
service_account: ${{ vars.WIF_SA }}

- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1

- name: Authorize Docker to Artifact Registry
run: gcloud auth configure-docker ${{ inputs.region }}-docker.pkg.dev --quiet

- name: Extract tag version
id: meta
env:
TAG_PREFIX: ${{ inputs.tag_prefix }}
REGION: ${{ inputs.region }}
STAGING_PROJECT: ${{ inputs.staging_project }}
AR_REPO: ${{ inputs.ar_repo }}
IMAGE_NAME: ${{ inputs.image_name }}
run: |
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#"${TAG_PREFIX}"}"
IMAGE="${REGION}-docker.pkg.dev/${STAGING_PROJECT}/${AR_REPO}/${IMAGE_NAME}:${VERSION}"
echo "image=${IMAGE}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"

- name: Build and push Docker image
env:
DOCKERFILE: ${{ inputs.dockerfile }}
BUILD_CONTEXT: ${{ inputs.build_context }}
run: |
TURBO_VERSION=$(grep '^ turbo:' pnpm-workspace.yaml | awk '{print $2}')
docker build \
--file "${DOCKERFILE}" \
--build-arg TURBO_VERSION="${TURBO_VERSION}" \
--tag "${{ steps.meta.outputs.image }}" \
"${BUILD_CONTEXT}"
docker push "${{ steps.meta.outputs.image }}"

deploy-staging:
needs: build
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
environment:
name: ${{ inputs.staging_environment }}
steps:
- name: Authenticate to GCP (staging)
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
workload_identity_provider: ${{ vars.WIF_PROVIDER }}
service_account: ${{ vars.WIF_SA }}

- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1

- name: Deploy Cloud Run Job (staging)
env:
JOB_NAME: ${{ inputs.job_name }}
IMAGE: ${{ needs.build.outputs.image }}
REGION: ${{ inputs.region }}
PROJECT_ID: ${{ inputs.staging_project }}
FLAGS: ${{ inputs.flags }}
run: |
if [[ -n "${FLAGS}" ]]; then
# shellcheck disable=SC2206
extra_flags=(${FLAGS})
else
extra_flags=()
fi

gcloud run jobs deploy "${JOB_NAME}" \
--image "${IMAGE}" \
--region "${REGION}" \
--project "${PROJECT_ID}" \
"${extra_flags[@]}"

deploy-prod:
needs: [build, deploy-staging]
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
environment:
name: ${{ inputs.prod_environment }}
steps:
- name: Authenticate to GCP (staging — pull image from staging AR)
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
with:
workload_identity_provider: ${{ vars.WIF_PROVIDER }}
service_account: ${{ vars.WIF_SA }}

- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1

- name: Promote image to production Artifact Registry
env:
REGION: ${{ inputs.region }}
PROD_PROJECT: ${{ inputs.prod_project }}
AR_REPO: ${{ inputs.ar_repo }}
IMAGE_NAME: ${{ inputs.image_name }}
run: |
STAGING_IMAGE="${{ needs.build.outputs.image }}"
PROD_IMAGE="${REGION}-docker.pkg.dev/${PROD_PROJECT}/${AR_REPO}/${IMAGE_NAME}:${STAGING_IMAGE##*:}"
gcloud auth configure-docker ${REGION}-docker.pkg.dev --quiet
docker pull "${STAGING_IMAGE}"
docker tag "${STAGING_IMAGE}" "${PROD_IMAGE}"
docker push "${PROD_IMAGE}"
echo "prod_image=${PROD_IMAGE}" >> "$GITHUB_ENV"

- name: Deploy Cloud Run Job (prod)
env:
JOB_NAME: ${{ inputs.job_name }}
IMAGE: ${{ env.prod_image }}
REGION: ${{ inputs.region }}
PROJECT_ID: ${{ inputs.prod_project }}
FLAGS: ${{ inputs.flags }}
run: |
if [[ -n "${FLAGS}" ]]; then
# shellcheck disable=SC2206
extra_flags=(${FLAGS})
else
extra_flags=()
fi

gcloud run jobs deploy "${JOB_NAME}" \
--image "${IMAGE}" \
--region "${REGION}" \
--project "${PROJECT_ID}" \
"${extra_flags[@]}"
14 changes: 11 additions & 3 deletions .github/workflows/_deploy-cloudrun.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ on:
description: "Path to the app Dockerfile"
required: true
type: string
build_context:
description: "Docker build context path"
required: false
type: string
default: "."
staging_environment:
description: "GitHub Environment name for staging"
required: true
Expand All @@ -42,12 +47,14 @@ on:
type: string
staging_url:
description: "Public staging URL"
required: true
required: false
type: string
default: ""
prod_url:
description: "Public production URL"
required: true
required: false
type: string
default: ""
region:
description: "GCP region"
required: false
Expand Down Expand Up @@ -127,13 +134,14 @@ jobs:
- name: Build and push Docker image
env:
DOCKERFILE: ${{ inputs.dockerfile }}
BUILD_CONTEXT: ${{ inputs.build_context }}
run: |
TURBO_VERSION=$(grep '^ turbo:' pnpm-workspace.yaml | awk '{print $2}')
docker build \
--file "${DOCKERFILE}" \
--build-arg TURBO_VERSION="${TURBO_VERSION}" \
--tag "${{ steps.meta.outputs.image }}" \
.
"${BUILD_CONTEXT}"
docker push "${{ steps.meta.outputs.image }}"

# ── Deploy to staging ──
Expand Down
49 changes: 49 additions & 0 deletions .github/workflows/deploy-slackbot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Deploy Slackbot

on:
push:
tags:
- "slackbot@*"

# Prevent concurrent deploys of the same tag.
concurrency:
group: deploy-slackbot-${{ github.ref_name }}
cancel-in-progress: false

# Reusable workflows can't elevate GITHUB_TOKEN beyond what the caller grants.
# id-token: write -> GCP OIDC (google-github-actions/auth); checks: read -> CI gate.
permissions:
contents: read
id-token: write
checks: read

jobs:
deploy-main:
uses: ./.github/workflows/_deploy-cloudrun.yml
with:
image_name: f3-slackbot
service_name: f3-slackbot
staging_project: f3-slackbot-staging
prod_project: f3-slackbot
tag_prefix: slackbot@
dockerfile: apps/slackbot/Dockerfile
build_context: .
staging_environment: slackbot-staging
prod_environment: slackbot-production
region: us-central1
ar_repo: cloud-run-builds

deploy-scripts:
uses: ./.github/workflows/_deploy-cloudrun-job.yml
with:
image_name: f3-slackbot-scripts
job_name: f3-slackbot-scripts
staging_project: f3-slackbot-staging
prod_project: f3-slackbot
tag_prefix: slackbot@
dockerfile: apps/slackbot/scripts/Dockerfile
build_context: .
staging_environment: slackbot-staging
prod_environment: slackbot-production
region: us-central1
ar_repo: cloud-run-builds
3 changes: 2 additions & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
"apps/auth": "1.2.1",
"apps/homepage": "1.1.0",
"apps/map": "5.0.0",
"apps/me": "1.3.1"
"apps/me": "1.3.1",
"apps/slackbot": "1.13.0"
}
7 changes: 6 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,10 @@
"next/router.d.ts",
"next/dist/client/router.d.ts"
],
"typescript.tsdk": "node_modules/typescript/lib"
"typescript.tsdk": "node_modules/typescript/lib",
"[toml]": {
"editor.defaultFormatter": "tamasfe.even-better-toml"
},
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
"python.analysis.extraPaths": ["${workspaceFolder}/packages/db-python"]
}
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ that app's `AGENTS.md`.
## Project Structure & Module Organization

- Use Node >=24.14 (see `.nvmrc`), pnpm 11, and Turborepo for workspace orchestration.
- `apps/` holds the deployable Next.js apps: `map` (the Next.js 15 map UI, port 3000), `admin`, `api`, `auth`, `homepage`, and `me`.
- `apps/` holds the deployable apps: Next.js apps `map` (port 3000), `admin`, `api`, `auth`, `homepage`, and `me`; plus the Python Slack app `slackbot` (port 3006).
- Shared code is organized in `packages/`: `api` (oRPC routers), `auth` (auth helpers), `db` (Drizzle schema/migrations), `env` (environment validation), `mail` (transactional email), `shared` (utilities), `sso` (single sign-on helpers), `storage` (object storage), `ui` (shared components), and `validators` (Zod schemas).
- Configuration files are in `tooling/`; Turbo generators live in `turbo/`.

Expand Down
Loading
Loading