Files
owen 2a1ed3af04
CI / Test (linux/amd64) (push) Waiting to run
CI / Lint (push) Waiting to run
CI / Cross-build (darwin/amd64) (push) Waiting to run
CI / Cross-build (linux/amd64) (push) Waiting to run
CI / Cross-build (darwin/arm64) (push) Waiting to run
CI / Cross-build (linux/arm64) (push) Waiting to run
Normalize Railway upstream URL for web proxy
2026-06-29 20:37:33 -05:00

4.3 KiB

urapt-web

The web UI for urapt, a self-hostable APT repository server. A React single-page app that talks to a urapt-server's REST API (/api/v1) to manage repositories, members, distributions, packages, tokens, and users — full management parity with the urapt CLI.

Stack

  • Vite + React 18 + TypeScript
  • Tailwind CSS + shadcn/ui (New York, neutral)
  • React Router v7, TanStack Query v5, Zustand, Vitest

Requirements

  • Node.js 20+ (see .nvmrc) and pnpm 10+

Development

Start a local urapt-server (from the repo root):

make run-server    # listens on 0.0.0.0:8080

Then in urapt-web/:

pnpm install
pnpm dev           # http://localhost:5173

Vite proxies /api and /apt to http://localhost:8080 (override with the URAPT_SERVER env var), so the UI is same-origin with the API in dev — no CORS needed. If needs_setup is true (no users yet), you'll be sent to the first-run setup screen to create the admin account.

Scripts

Script Description
pnpm dev Start the Vite dev server
pnpm build Type-check and build to dist/
pnpm preview Preview the production build locally
pnpm typecheck Run tsc with no emit
pnpm lint Run ESLint
pnpm format Run Prettier (write)
pnpm test Run Vitest once

Configuration

Env var Default Notes
VITE_API_BASE_URL /api/v1 REST API base. Override only for cross-origin dev (requires CORS on the server).
URAPT_SERVER http://localhost:8080 Dev proxy target only.

Deployment (same-origin)

The UI is designed to be served from the same origin as a urapt-server, behind a reverse proxy that serves the SPA from dist/ and forwards /api/v1 and /apt to urapt-server. No CORS, no server changes — the API base is just /api/v1.

pnpm build    # outputs dist/

Railway

urapt-web/ includes a Dockerfile for deploying the UI as a separate Railway service. The container builds the Vite app and serves it with Caddy, proxying /api/* and /apt/* to an existing urapt-server service.

In Railway, create a new service from this repo with:

  • Root Directory: urapt-web
  • Environment variable: URAPT_SERVER_URL=https://your-urapt-server.up.railway.app

A trailing slash is okay; the container normalizes it before starting Caddy.

Do not set VITE_API_BASE_URL for this deployment; the UI should keep using the default same-origin /api/v1 path.

Caddy

apt.example.com {
    # SPA
    root * /srv/urapt-web/dist
    try_files {path} /index.html
    file_server

    # REST API + APT endpoint
    reverse_proxy /api/* 127.0.0.1:8080
    reverse_proxy /apt/*  127.0.0.1:8080
}

nginx

server {
    listen 80;
    server_name apt.example.com;
    root /srv/urapt-web/dist;

    location / { try_files $uri /index.html; }

    location /api/ { proxy_pass http://127.0.0.1:8080; }
    location /apt/  { proxy_pass http://127.0.0.1:8080; }
}

Architecture

src/
  lib/api/       typed client mirroring urapt's shared/api + shared/models
                 (client, errors, endpoints, types)
  stores/        Zustand auth store (persisted token)
  hooks/         shared server/user queries, logout
  components/    app shell, common UI (copy button, confirm, states), shadcn ui
  features/      auth, setup, repos (tabs), tokens, users, settings
  routes.tsx     route tree with lazy-loaded pages + protected/admin guards

The API client (src/lib/api/) is hand-written and typed against urapt's Go DTOs in shared/api/api.go and shared/models/models.go. A 401 anywhere clears the local session and redirects to /login.

License

GPL-3.0-or-later, matching the urapt project.