Prepare CI and deployment scaffolding
Some checks failed
CI / Backend Tests (push) Has been cancelled
CI / Frontend Tests (push) Has been cancelled
CI / Build Docker Images (push) Has been cancelled

This commit is contained in:
2025-10-16 17:18:18 -05:00
parent 0ecd6c67eb
commit 42dc3c8097
6 changed files with 326 additions and 5 deletions

10
.env.example Normal file
View File

@@ -0,0 +1,10 @@
# Global defaults
NODE_ENV=development
# Backend service
DATABASE_URL=postgresql://merchantsofhope_user:merchantsofhope_password@merchantsofhope-supplyanddemandportal-database:5432/merchantsofhope_supplyanddemandportal
JWT_SECRET=merchantsofhope_jwt_secret_key_2024
PORT=3001
# Frontend service
REACT_APP_API_URL=http://localhost:3001

137
.gitea/workflows/ci.yml Normal file
View File

@@ -0,0 +1,137 @@
name: CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
backend:
name: Backend Tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15-alpine
env:
POSTGRES_DB: merchantsofhope_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd="pg_isready -U postgres" --health-interval=10s --health-timeout=5s --health-retries=5
env:
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/merchantsofhope_test
JWT_SECRET: merchantsofhope_test_secret
NODE_ENV: test
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: backend/package-lock.json
- name: Install dependencies
run: npm ci
working-directory: backend
- name: Run database migrations
run: npm run migrate
working-directory: backend
- name: Run backend tests
run: npm test -- --runInBand
working-directory: backend
frontend:
name: Frontend Tests
runs-on: ubuntu-latest
steps:
- name: Checkout
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
working-directory: frontend
- name: Run frontend tests
run: npm test -- --watchAll=false
working-directory: frontend
docker-images:
name: Build Docker Images
runs-on: ubuntu-latest
needs: [backend, frontend]
if: github.ref == 'refs/heads/main'
env:
REGISTRY_HOST: ${{ secrets.REGISTRY_HOST }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
IMAGE_TAG: ${{ github.sha }}
BACKEND_IMAGE: merchantsofhope-supplyanddemandportal-backend
FRONTEND_IMAGE: merchantsofhope-supplyanddemandportal-frontend
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to registry
if: env.REGISTRY_HOST != ''
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY_HOST }}
username: ${{ env.REGISTRY_USERNAME }}
password: ${{ env.REGISTRY_PASSWORD }}
- name: Determine image tags
id: meta
run: |
if [ -n "${REGISTRY_HOST}" ]; then
echo "push=true" >> $GITHUB_OUTPUT
echo "backend_tag=${REGISTRY_HOST}/${BACKEND_IMAGE}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
echo "frontend_tag=${REGISTRY_HOST}/${FRONTEND_IMAGE}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
else
echo "push=false" >> $GITHUB_OUTPUT
echo "backend_tag=${BACKEND_IMAGE}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
echo "frontend_tag=${FRONTEND_IMAGE}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
fi
- name: Build backend image
uses: docker/build-push-action@v5
with:
context: backend
file: backend/Dockerfile
push: ${{ steps.meta.outputs.push == 'true' }}
tags: ${{ steps.meta.outputs.backend_tag }}
- name: Build frontend image
uses: docker/build-push-action@v5
with:
context: frontend
file: frontend/Dockerfile
push: ${{ steps.meta.outputs.push == 'true' }}
tags: ${{ steps.meta.outputs.frontend_tag }}
- name: Summary
run: |
echo "Backend image tag: ${{ steps.meta.outputs.backend_tag }}" >> $GITHUB_STEP_SUMMARY
echo "Frontend image tag: ${{ steps.meta.outputs.frontend_tag }}" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.meta.outputs.push }}" = 'true' ]; then
echo "Images pushed to ${{ env.REGISTRY_HOST }}" >> $GITHUB_STEP_SUMMARY
else
echo "Images built locally (not pushed). Set REGISTRY_* secrets to enable pushing." >> $GITHUB_STEP_SUMMARY
fi

1
.gitignore vendored
View File

@@ -2,6 +2,7 @@ node_modules/
dist/ dist/
.env .env
.env.* .env.*
!.env.example
*.log *.log
tmp/ tmp/
.DS_Store .DS_Store

View File

@@ -55,12 +55,18 @@ A comprehensive SAAS application for managing recruiter workflows, built with mo
cd MerchantsOfHope-SupplyANdDemandPortal cd MerchantsOfHope-SupplyANdDemandPortal
``` ```
2. **Start the application** 2. **Copy environment template**
```bash
cp .env.example .env
```
The defaults support Docker-based development. Adjust values as needed for local tooling or deployment pipelines.
3. **Start the application with Docker (recommended for parity)**
```bash ```bash
docker-compose up --build docker-compose up --build
``` ```
3. **Initialize the database** 4. **Initialize the database**
```bash ```bash
# Run database migrations # Run database migrations
docker-compose exec merchantsofhope-supplyanddemandportal-backend npm run migrate docker-compose exec merchantsofhope-supplyanddemandportal-backend npm run migrate
@@ -69,11 +75,31 @@ A comprehensive SAAS application for managing recruiter workflows, built with mo
docker-compose exec merchantsofhope-supplyanddemandportal-backend npm run seed docker-compose exec merchantsofhope-supplyanddemandportal-backend npm run seed
``` ```
4. **Access the application** 5. **Access the application**
- Frontend: http://localhost:3000 - Frontend: http://localhost:3000
- Backend API: http://localhost:3001 - Backend API: http://localhost:3001
- Database: localhost:5432 - Database: localhost:5432
### Alternative: Native Node.js workflow
If you prefer running services outside Docker:
```bash
# Install dependencies
cd backend && npm install
cd ../frontend && npm install
# Start backend (uses .env)
cd ../backend
npm run dev
# In a separate terminal start frontend
cd ../frontend
npm start
```
Ensure a PostgreSQL instance is running and the `DATABASE_URL` in `.env` points to it.
### Demo Accounts ### Demo Accounts
The application comes with pre-seeded demo accounts: The application comes with pre-seeded demo accounts:
@@ -140,9 +166,23 @@ docker-compose exec merchantsofhope-supplyanddemandportal-backend npm run test:w
docker-compose exec merchantsofhope-supplyanddemandportal-frontend npm test docker-compose exec merchantsofhope-supplyanddemandportal-frontend npm test
``` ```
## Development To run tests without Docker, execute `npm test` inside `backend/` or `frontend/` after installing dependencies.
### Project Structure ## Continuous Integration
Gitea Actions configuration lives in `.gitea/workflows/ci.yml`. It:
- Runs backend and frontend unit tests on every push or pull request.
- Builds Docker images on pushes to the `main` branch, ready to publish to a registry (requires `REGISTRY_*` secrets).
See inline comments in the workflow for required secrets.
## Deployment
### Coolify
Follow `docs/COOLIFY_DEPLOYMENT.md` for guidance on connecting this repository to a Coolify environment, configuring secrets, and enabling automated deploys via Gitea CI.
## Project Structure
``` ```
MerchantsOfHope-SupplyANdDemandPortal/ MerchantsOfHope-SupplyANdDemandPortal/
├── backend/ ├── backend/

View File

@@ -0,0 +1,45 @@
version: '3.9'
services:
merchantsofhope-supplyanddemandportal-database:
image: postgres:15-alpine
container_name: merchantsofhope-supplyanddemandportal-database
environment:
POSTGRES_DB: ${POSTGRES_DB:-merchantsofhope_supplyanddemandportal}
POSTGRES_USER: ${POSTGRES_USER:-merchantsofhope}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
volumes:
- merchantsofhope-supplyanddemandportal-postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "${POSTGRES_USER:-merchantsofhope}"]
interval: 10s
timeout: 5s
retries: 5
merchantsofhope-supplyanddemandportal-backend:
image: ${BACKEND_IMAGE:?set BACKEND_IMAGE}
container_name: merchantsofhope-supplyanddemandportal-backend
depends_on:
merchantsofhope-supplyanddemandportal-database:
condition: service_healthy
environment:
NODE_ENV: production
PORT: 3001
DATABASE_URL: postgresql://${POSTGRES_USER:-merchantsofhope}:${POSTGRES_PASSWORD}@merchantsofhope-supplyanddemandportal-database:5432/${POSTGRES_DB:-merchantsofhope_supplyanddemandportal}
JWT_SECRET: ${JWT_SECRET:?set JWT_SECRET}
ports:
- "0.0.0.0:3001:3001"
merchantsofhope-supplyanddemandportal-frontend:
image: ${FRONTEND_IMAGE:?set FRONTEND_IMAGE}
container_name: merchantsofhope-supplyanddemandportal-frontend
depends_on:
- merchantsofhope-supplyanddemandportal-backend
environment:
PORT: 3000
REACT_APP_API_URL: ${REACT_APP_API_URL:-http://merchantsofhope-supplyanddemandportal-backend:3001}
ports:
- "0.0.0.0:3000:3000"
volumes:
merchantsofhope-supplyanddemandportal-postgres-data:

View File

@@ -0,0 +1,88 @@
# Coolify Deployment Guide
This guide summarizes how to promote MerchantsOfHope-SupplyANdDemandPortal from Gitea CI to a Coolify-managed environment.
## Prerequisites
- A Coolify instance with access to your container registry.
- Gitea repository hosting this project, with Gitea Actions enabled and a runner that supports Docker builds.
- Registry credentials (username, password/access token, hostname) for publishing backend and frontend images.
- Optional: a managed PostgreSQL instance. The provided Compose file creates one automatically if you do not have an external database.
## Overview
1. Gitea Actions builds and (optionally) pushes backend and frontend images when changes land on the `main` branch.
2. Coolify pulls those images and runs the stack defined in `deploy/coolify/docker-compose.yml`.
3. Post-deploy hooks run database migrations so the schema matches the current code.
## Configure Gitea CI
Secrets required by `.gitea/workflows/ci.yml`:
| Secret | Purpose |
| ------ | ------- |
| `REGISTRY_HOST` | Hostname of the registry (e.g., `registry.example.com`). Leave blank to skip pushing. |
| `REGISTRY_USERNAME` | Registry account used to push images. |
| `REGISTRY_PASSWORD` | Token/password for the account. |
The workflow publishes two images using the commit SHA as the tag:
- `${REGISTRY_HOST}/merchantsofhope-supplyanddemandportal-backend:<sha>`
- `${REGISTRY_HOST}/merchantsofhope-supplyanddemandportal-frontend:<sha>`
Expose the tag you want Coolify to deploy by either:
- Creating a Git tag/release and configuring Coolify to deploy tags, or
- Using Coolify's "Deploy on new commit" option and translating the latest SHA into the `BACKEND_IMAGE` / `FRONTEND_IMAGE` environment variables.
## Prepare the Coolify Stack
1. **Add the repository**
- In Coolify, create a new *Docker Compose Application*.
- Connect your Gitea account and select this repository.
- Set the Compose path to `deploy/coolify/docker-compose.yml`.
2. **Set environment variables** (use the UI or a `.env` file uploaded to Coolify):
| Variable | Description |
| -------- | ----------- |
| `BACKEND_IMAGE` | Fully qualified image tag published by CI (e.g., `registry.example.com/merchantsofhope-supplyanddemandportal-backend:abcd123`). |
| `FRONTEND_IMAGE` | Fully qualified image tag published by CI. |
| `POSTGRES_DB` | Database name (defaults to `merchantsofhope_supplyanddemandportal`). |
| `POSTGRES_USER` | Database user (defaults to `merchantsofhope`). |
| `POSTGRES_PASSWORD` | **Required.** Strong password for the database. |
| `JWT_SECRET` | **Required.** Secret key for backend token signing. |
| `REACT_APP_API_URL` | URL the frontend uses to reach the backend (defaults to the internal service URL). |
Configure any additional secrets used by your environment (mail providers, analytics, etc.).
3. **Networking and ports**
- Expose port `3000` externally for the frontend.
- Optionally expose `3001` if you want direct API access; otherwise rely on the frontend or internal services.
- Attach the application to an HTTPS domain using Coolify's built-in proxy configuration.
4. **Database migrations**
- Add a post-deployment command in Coolify to run `npm run migrate` inside the backend container:
```bash
docker compose exec merchantsofhope-supplyanddemandportal-backend npm run migrate
```
- If you maintain seed data, run `npm run seed` the same way.
5. **Zero-downtime considerations**
- Enable health checks in Coolify so new backend containers pass readiness before switching traffic.
- Consider scaling the backend to more than one replica once load requires it.
## Local Development Parity
- Use `docker-compose up --build` to replicate the production stack locally.
- Keep `.env` aligned with the variables described above so Gitea CI, local development, and Coolify deployment share the same configuration keys.
## Troubleshooting
| Symptom | Likely Cause | Fix |
| ------- | ------------ | --- |
| Backend container exits immediately | Missing or incorrect `DATABASE_URL`/`POSTGRES_*` values | Verify Coolify environment variables and that the database service is healthy. |
| Frontend cannot reach API | `REACT_APP_API_URL` points to an unreachable host | Adjust to Coolify-provided domain or internal service URL. |
| CI cannot push images | Registry secrets not configured or incorrect permissions | Update `REGISTRY_*` secrets and ensure the runner has network access to the registry. |
For additional customization (e.g., connecting to an external PostgreSQL cluster or adding Redis), copy `deploy/coolify/docker-compose.yml` and extend it with your required services.