Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RequestHub

RequestHub is a public request intake system. Users submit bug reports, configuration changes, or feature requests through a public web form; the backend checks the request against existing tickets for likely duplicates and, if it's not a duplicate, files it as a Jira issue.

How it works

  1. A user fills out the public form (type, title, description, email, school) and answers a simple captcha.
  2. The API pulls recent tickets of the same type and asks an LLM (via the OpenAI API) whether the new request duplicates one of them.
  3. If a duplicate is found above the configured confidence threshold, the API returns 409 Conflict with the matching ticket's key instead of creating a new one.
  4. Otherwise, the API creates a Jira issue (mapped to Bug/Task/Story depending on the request type) and stores the ticket and submission in Postgres.

Project structure

backend/    FastAPI service (SQLAlchemy models, Alembic migrations, Jira & duplicate
            detection integrations, tests)
frontend/   React + Vite public request form
docker-compose.yml   Local Postgres instance

Tech stack

  • Backend: FastAPI, SQLAlchemy, Alembic, Postgres, httpx
  • Frontend: React 19, TypeScript, Vite, Axios
  • Integrations: Jira REST API (issue creation), OpenAI API (duplicate detection)

Getting started

1. Start the database

docker compose up -d

This starts Postgres on localhost:5433 (user/password/db: requesthub).

2. Backend setup

cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Create a .env file in backend/ with:

DATABASE_URL=postgresql://requesthub:requesthub@localhost:5433/requesthub

JIRA_BASE_URL=https://your-domain.atlassian.net
JIRA_EMAIL=you@example.com
JIRA_API_TOKEN=your-jira-api-token
JIRA_PROJECT_KEY=REQ

OPENAI_API_KEY=your-openai-api-key
OPENAI_MODEL=gpt-4o-mini
DUPLICATE_CONFIDENCE_THRESHOLD=0.7

ADMIN_USERNAME=admin
ADMIN_PASSWORD_HASH=your-argon2-password-hash
JWT_SECRET_KEY=a-long-random-secret

# Only needed in production, to allow the deployed frontend to call this API.
FRONTEND_URL=https://your-app.vercel.app

Run migrations and start the API:

alembic upgrade head
uvicorn app.main:app --reload

The API is available at http://localhost:8000 (health check at /api/health).

3. Frontend setup

cd frontend
npm install
npm run dev

The app is available at http://localhost:5173 by default.

Deployment

The simplest setup for a demo/test deployment: Railway for the API + Postgres, Vercel for the frontend.

Backend + database (Railway)

  1. Create a new Railway project from this GitHub repo, root directory backend/.
  2. Add a Postgres service to the same project — Railway injects DATABASE_URL automatically.
  3. Set the rest of the environment variables from the list above (JIRA_*, OPENAI_*, ADMIN_*, JWT_SECRET_KEY) in the service's Variables tab.
  4. Railway uses the repo's Procfile, which runs migrations before starting the server on every deploy:
    web: alembic upgrade head && uvicorn app.main:app --host 0.0.0.0 --port $PORT
    
  5. Once deployed, note the public URL Railway gives you (e.g. https://requesthub-api.up.railway.app) — the frontend needs it.
  6. Set FRONTEND_URL to the Vercel URL from the next step, so CORS allows it.

Frontend (Vercel)

  1. Import the repo into Vercel, root directory frontend/. It auto-detects the Vite build.
  2. Set the environment variable VITE_API_URL to the Railway backend URL from above.
  3. The repo's vercel.json adds the SPA rewrite so client-side routes (like /admin/login) work on refresh.

Testing

cd backend
pytest

API

POST /api/requests

Creates a new request. Returns the created ticket (201), or a 409 with the matching ticket_key and confidence if it looks like a duplicate of an existing ticket.

GET /api/health

Basic health check.

POST /api/admin/login

Authenticates with username/password and returns a JWT access_token for the admin endpoints below.

GET /api/admin/dashboard

Requires a bearer token. Basic auth check / welcome payload.

GET /api/admin/requests

Requires a bearer token. Paginated, filterable list of tickets, with each ticket's submission count. Query params: page, limit, request_type, school, title, sort (newest (default), oldest, or requests).

GET /api/admin/requests/{ticket_id}

Requires a bearer token. Full detail for a single ticket, including its Jira URL and the list of requesters (email, school, submission date) who filed it. Returns 404 if the ticket doesn't exist.

About

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages