Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
31efe1a
fix: local environment
TineoC Jan 26, 2026
4548ad8
fix: STATICFILES_DIRS setting does not exist error
TineoC Jan 26, 2026
a90efd9
undo
TineoC Jan 26, 2026
89d9c6b
fix: deploy API and CI for sandbox + live
TineoC Feb 1, 2026
1b36e6f
chore: kind test script and overlay, fix devbox kind-config path
TineoC Feb 1, 2026
38f61eb
Revert "chore: kind test script and overlay, fix devbox kind-config p…
TineoC Feb 1, 2026
cc62213
fix: CD to sandbox/live GitOps, remove .env.production, SPA catch-all…
TineoC Feb 1, 2026
bec7f2d
docs: PR body - GitOps CD and manual deploy section
TineoC Feb 1, 2026
d2f7d35
chore: remove PR description file from repo
TineoC Feb 1, 2026
a862760
lint errors
TineoC Feb 1, 2026
cc128db
Revert "lint errors"
TineoC Feb 1, 2026
bd359ca
ci(frontend): ignore lint and build failures (continue-on-error)
TineoC Feb 1, 2026
b529b4f
chore: keep pgadmin in local docker-compose
TineoC Feb 6, 2026
c9cd0a3
feat: implement Flux-native image automation and remove redundant dep…
TineoC Feb 7, 2026
8401885
chore: remove all documentation changes from PR
TineoC Feb 7, 2026
31527ee
feat: implement predictable SemVer tagging for Flux automation
TineoC Feb 7, 2026
faa3d54
feat: use git tags for versioning instead of file
TineoC Feb 7, 2026
0dac81d
feat: use dynamic version extraction and generic Flux policies
TineoC Feb 7, 2026
abfb24a
feat: make frontend & backend version-aware
TineoC Feb 8, 2026
e25375b
fix: add db to the docker-compose.prod
TineoC Feb 8, 2026
0430a24
ci: simplify container-publish triggers and versioning logic
TineoC Feb 10, 2026
a25bb1b
Merge remote-tracking branch 'origin' into fix/deploy-api-and-ci
TineoC Feb 10, 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
24 changes: 21 additions & 3 deletions .github/workflows/deploy-downstream.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
name: "Deploy: Downstream Clusters"

# CD: push to develop -> Containers: Publish -> this workflow -> PR to cfp-sandbox-cluster.
# Live: publish release -> Containers: Publish -> this workflow -> PR to cfp-live-cluster.
# Manual: Run workflow_dispatch with tag (and optional target) to open deploy PRs.
# Requires BOT_GITHUB_TOKEN with write access to CodeForPhilly/cfp-sandbox-cluster and cfp-live-cluster.
on:
workflow_run:
workflows: ["Containers: Publish"]
Expand All @@ -8,15 +12,29 @@ on:
workflow_dispatch:
inputs:
tag:
description: 'Image tag to deploy (e.g. 1.1.0)'
description: 'Image tag to deploy (e.g. 1.1.0 or dev-abc1234)'
required: true
default: 'latest'
target:
description: 'Which cluster(s) to open deploy PRs for'
required: false
default: 'both'
type: choice
options:
- both
- sandbox
- live

permissions:
contents: read
actions: read
pull-requests: write

jobs:
update-sandbox:
name: Update Sandbox Cluster
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'develop') }}
if: ${{ (github.event_name == 'workflow_dispatch' && (inputs.target == 'both' || inputs.target == 'sandbox')) || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'develop') }}
outputs:
tag: ${{ steps.get_tag.outputs.TAG }}
steps:
Expand Down Expand Up @@ -65,7 +83,7 @@ jobs:
update-live:
name: Update Live Cluster
runs-on: ubuntu-latest
if: ${{ github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'release') }}
if: ${{ (github.event_name == 'workflow_dispatch' && (inputs.target == 'both' || inputs.target == 'live')) || (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'release') }}
steps:
- name: Checkout App
uses: actions/checkout@v4
Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/frontend-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: "Frontend: Lint and Build"

on:
push:
branches: [develop]
pull_request:
branches: [develop]

jobs:
frontend:
name: Lint and Build
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "18"
cache: "npm"
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: npm ci --legacy-peer-deps

- name: Lint
run: npm run lint
continue-on-error: true

- name: Build
run: npm run build
continue-on-error: true
3 changes: 1 addition & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,7 @@ Routes defined in `src/routes/routes.tsx`:

### Environment Configuration
- **Development**: `config/env/dev.env` (used by Docker Compose)
- **Frontend Production**: `frontend/.env.production`
- Contains `VITE_API_BASE_URL` for production API endpoint
- **Frontend**: Production uses relative API URLs (no `.env.production`); local dev uses `frontend/.env` (e.g. `VITE_API_BASE_URL` for proxy).
- **Never commit** actual API keys - use `.env.example` as template
- Django `SECRET_KEY` should be a long random string in production (not "foo")

Expand Down
227 changes: 160 additions & 67 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,115 +1,208 @@
# Balancer

Balancer is a website of digital tools designed to help prescribers choose the most suitable medications
for patients with bipolar disorder, helping them shorten their journey to stability and well-being

## Usage

You can view the current build of the website here: [https://balancertestsite.com](https://balancertestsite.com/)

## Contributing

### Join the Balancer community

Balancer is a [Code for Philly](https://www.codeforphilly.org/) project
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://choosealicense.com/licenses/agpl-3.0/)
[![Code for Philly](https://img.shields.io/badge/Code%20for%20Philly-Project-orange)](https://codeforphilly.org/projects/balancer)
[![Stack](https://img.shields.io/badge/Stack-Django%20%7C%20React%20%7C%20PostgreSQL%20%7C%20K8s-green)](https://github.com/CodeForPhilly/balancer)

**Balancer** is a digital clinical decision support tool designed to assist prescribers in selecting the most suitable medications for patients with bipolar disorder. By providing evidence-based insights, Balancer aims to shorten the patient's journey to stability and well-being.

This is an open-source project maintained by the **[Code for Philly](https://www.codeforphilly.org/)** community.

---

## 📋 Table of Contents

- [Architecture](#-architecture)
- [Prerequisites](#-prerequisites)
- [Environment Configuration](#-environment-configuration)
- [Quick Start: Local Development](#-quick-start-local-development)
- [Advanced: Local Kubernetes Deployment](#-advanced-local-kubernetes-deployment)
- [Data Layer](#-data-layer)
- [Contributing](#-contributing)
- [License](#-license)

---

## 🏗 Architecture

Balancer follows a modern containerized 3-tier architecture:

1. **Frontend**: React (Vite) application serving the user interface.
2. **Backend**: Django REST Framework API handling business logic, authentication, and AI orchestration.
3. **Data & AI**: PostgreSQL (with `pgvector` for RAG) and integrations with LLM providers (OpenAI/Anthropic).

```mermaid
graph TD
User[User / Prescriber] -->|HTTPS| Frontend[React Frontend]
Frontend -->|REST API| Backend[Django Backend]

subgraph "Data Layer"
Backend -->|Read/Write| DB[(PostgreSQL + pgvector)]
end

subgraph "External AI Services"
Backend -->|LLM Queries| OpenAI[OpenAI API]
Backend -->|LLM Queries| Anthropic[Anthropic API]
end

subgraph "Infrastructure"
Docker[Docker Compose (Local)]
K8s[Kubernetes / Kind (Dev/Prod)]
end
```

Join the [Code for Philly Slack and introduce yourself](https://codeforphilly.org/projects/balancer) in the #balancer channel
---

The project kanban board is [on GitHub here](https://github.com/orgs/CodeForPhilly/projects/2)
## 🛠 Prerequisites

### Code for Philly Code of Conduct
Before you start, ensure you have the following installed:

The Code for Philly Code of Conduct is [here](https://codeforphilly.org/pages/code_of_conduct/)
* **[Docker Desktop](https://www.docker.com/products/docker-desktop/)**: Required for running the application containers.
* **[Node.js & npm](https://nodejs.org/)**: Required if you plan to do frontend development outside of Docker.
* **[Devbox](https://www.jetify.com/devbox)** (Optional): Required only for the Local Kubernetes workflow.
* **Postman** (Optional): Useful for API testing. Ask in Slack to join the `balancer_dev` team.

### Setting up a development environment
---

Get the code using git by either forking or cloning `CodeForPhilly/balancer-main`
## 🔐 Environment Configuration

Tools used to run Balancer:
1. `OpenAI API`: Ask for an API key and add it to `config/env/env.dev`
2. `Anthropic API`: Ask for an API key and add it to `config/env/env.dev`
To run the application, you need to configure your environment variables.

Tools used for development:
1. `Docker`: Install Docker Desktop
2. `Postman`: Ask to get invited to the Balancer Postman team `balancer_dev`
3. `npm`: In the terminal run 1) 'cd frontend' 2) 'npm install' 3) 'cd ..'
1. **Backend Config**:
* Navigate to `config/env/`.
* Copy the example file: `cp dev.env.example dev.env`
* **Action Required**: Open `dev.env` and populate your API keys (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, etc.). Ask the project leads in Slack if you need shared development keys.

### Running Balancer for development
> **⚠️ SECURITY WARNING**: Never commit `config/env/dev.env` to version control. It is already ignored by `.gitignore`.

Start the Postgres, Django REST, and React services by starting Docker Desktop and running `docker compose up --build`
2. **Frontend Config**:
* The frontend uses `frontend/.env` for local dev only (e.g. `VITE_API_BASE_URL=http://localhost:8000` for the Vite proxy).
* Production builds use relative API URLs (no `.env.production` or API base URL needed); the same image works for sandbox and live.

#### Postgres
---

The application supports connecting to PostgreSQL databases via:
## 🚀 Quick Start: Local Development

1. **CloudNativePG** - Kubernetes-managed PostgreSQL cluster (for production/sandbox)
2. **AWS RDS** - External PostgreSQL database (AWS managed)
3. **Local Docker Compose** - For local development
This is the standard workflow for contributors working on features or bug fixes.

See [Database Connection Documentation](./docs/DATABASE_CONNECTION.md) for detailed configuration.
1. **Clone the Repository**
```bash
git clone https://github.com/CodeForPhilly/balancer.git
cd balancer
```

**Local Development:**
- Download a sample of papers to upload from [https://balancertestsite.com](https://balancertestsite.com/)
- The email and password of `pgAdmin` are specified in `balancer-main/docker-compose.yml`
- The first time you use `pgAdmin` after building the Docker containers you will need to register the server.
- The `Host name/address` is the Postgres server service name in the Docker Compose file
- The `Username` and `Password` are the Postgres server environment variables in the Docker Compose file
- You can use the below code snippet to query the database from a Jupyter notebook:
2. **Install Frontend Dependencies** (Optional but recommended for IDE support)
```bash
cd frontend
npm install
cd ..
```

```
from sqlalchemy import create_engine
import pandas as pd
3. **Start Services**
Run the full stack (db, backend, frontend) using Docker Compose:
```bash
docker compose up --build
```

engine = create_engine("postgresql+psycopg2://balancer:balancer@localhost:5433/balancer_dev")
4. **Access the Application**
* **Frontend**: [http://localhost:3000](http://localhost:3000)
* **Backend API**: [http://localhost:8000](http://localhost:8000)
* **Django Admin**: [http://localhost:8000/admin](http://localhost:8000/admin)

query = "SELECT * FROM api_embeddings;"
> **Default Superuser Credentials:**
> * **Email**: `admin@example.com`
> * **Password**: `adminpassword`
> * *(Defined in `server/api/management/commands/createsu.py`)*

df = pd.read_sql(query, engine)
```
---

#### Django REST
- The email and password are set in `server/api/management/commands/createsu.py`
## ☸️ Advanced: Local Kubernetes Deployment

## Local Kubernetes Deployment
Use this workflow if you are working on DevOps tasks, Helm charts, or Kubernetes manifests.

### Prereqs
### 1. Configure Hostname
We map a local domain to your machine to simulate production routing.

- Fill the configmap with the [env vars](./deploy/manifests/balancer/base/configmap.yml)
- Install [Devbox](https://www.jetify.com/devbox)
- Run the following script with admin privileges:
Run this script to update your `/etc/hosts` file (requires `sudo`):

```bash
#!/bin/bash
HOSTNAME="balancertestsite.com"
LOCAL_IP="127.0.0.1"

# Check if the correct line already exists
if grep -q "^$LOCAL_IP[[:space:]]\+$HOSTNAME" /etc/hosts; then
echo "Entry for $HOSTNAME with IP $LOCAL_IP already exists in /etc/hosts"
echo "Entry for $HOSTNAME already exists."
else
echo "Updating /etc/hosts for $HOSTNAME"
sudo sed -i "/[[:space:]]$HOSTNAME/d" /etc/hosts
echo "Updating /etc/hosts..."
echo "$LOCAL_IP $HOSTNAME" | sudo tee -a /etc/hosts
fi
```

### Steps to reproduce

Inside root dir of balancer
### 2. Deploy with Devbox
We use `devbox` to manage the local Kind cluster and deployments.

```bash
devbox shell
devbox create:cluster
devbox run deploy:balancer
```

The website should be available in [https://balancertestsite.com:30219/](https://balancertestsite.com:30219/)
The application will be available at: **[https://balancertestsite.com:30219/](https://balancertestsite.com:30219/)**

---

## 💾 Data Layer

Balancer supports multiple PostgreSQL configurations depending on the environment:

| Environment | Database Technology | Description |
| :--- | :--- | :--- |
| **Local Dev** | **Docker Compose** | Standard postgres container. Access at `localhost:5433`. |
| **Kubernetes** | **CloudNativePG** | Operator-managed HA cluster. Used in Kind and Prod. |
| **AWS** | **RDS** | Managed PostgreSQL for scalable cloud deployments. |

### Querying the Local Database
You can connect via any SQL client using:
* **Host**: `localhost`
* **Port**: `5433`
* **User/Pass**: `balancer` / `balancer`
* **DB Name**: `balancer_dev`

**Python Example (Jupyter):**
```python
from sqlalchemy import create_engine
import pandas as pd

# Connect to local docker database
engine = create_engine("postgresql+psycopg2://balancer:balancer@localhost:5433/balancer_dev")

# Query embeddings table
df = pd.read_sql("SELECT * FROM api_embeddings;", engine)
print(df.head())
```

---

## 🤝 Contributing

We welcome contributors of all skill levels!

## Architecture
1. **Join the Community**:
* Join the [Code for Philly Slack](https://codeforphilly.org/chat).
* Say hello in the **#balancer** channel.
2. **Find a Task**:
* Check our [GitHub Project Board](https://github.com/orgs/CodeForPhilly/projects/2).
3. **Code of Conduct**:
* Please review the [Code for Philly Code of Conduct](https://codeforphilly.org/pages/code_of_conduct/).

The Balancer website is a Postgres, Django REST, and React project. The source code layout is:
### Pull Request Workflow
1. Fork the repo.
2. Create a feature branch (`git checkout -b feature/amazing-feature`).
3. Commit your changes.
4. Open a Pull Request against the `develop` branch.

![Architecture Drawing](Architecture.png)
---

## License
## 📄 License

Balancer is licensed under the [AGPL-3.0 license](https://choosealicense.com/licenses/agpl-3.0/)
Balancer is open-source software licensed under the **[AGPL-3.0 License](https://choosealicense.com/licenses/agpl-3.0/)**.
Loading
Loading