A modern, developer-first web interface for the pbuf.io Protocol Buffers registry. Built with Vue.js 3, Vite, and Tailwind CSS.
- 🎨 Modern Dark Theme - Developer-first aesthetic with high contrast and technical clarity
- 📦 Module Browsing - Browse and search all registered protobuf modules
- 🏷️ Version Management - View and manage module tags and versions
- 📄 Proto File Viewer - Inspect proto file contents and structure
- 🔍 Metadata Explorer - Browse parsed protobuf messages, services, and fields
- 🔗 Dependency Tracking - View module dependencies and their relationships
- 📱 Fully Responsive - Optimized for desktop, tablet, and mobile devices
- Vue.js 3.4.21 - Progressive JavaScript framework with Composition API
- Vite 5.2.8 - Next-generation frontend build tool with HMR
- Tailwind CSS 3.4.3 - Utility-first CSS framework
- Vue Router 4.3.0 - Official router for Vue.js SPA
- Axios 1.6.8 - Promise-based HTTP client for API communication
The UI follows a "Developer-First" design aesthetic:
- Colors: Deep dark theme (Zinc-950) with Blue-500 brand accent
- Typography: Inter for UI, JetBrains Mono for code
- Components: Minimalist with subtle shadows and borders
- Interactions: Smooth transitions and hover effects
- Node.js 18+ and npm (Node.js 20 recommended for production builds)
- API Access - Valid authentication token for pbuf.cloud API
- Git - For cloning the repository
- Clone the repository:
git clone <repository-url>
cd pbuf-registry-ui- Install dependencies:
npm install- Configure environment variables:
cp .env.example .envEdit .env and configure:
API_BASE_URL- Backend API endpoint (default:http://pbuf.cloud)API_TOKEN- Your raw pbuf registry token (optional in public mode)PUBLIC_ENABLED- Enable public (unauthenticated) browsing + optional token login
Important:
- When
API_TOKENis set, it is used server-side only by the Vite dev proxy and nginx in production. It is never exposed to the browser. - If the browser sends an
Authorizationheader (token login), the proxies forward it to the backend. If the browser does not send one, the proxies fall back toAPI_TOKEN(when configured). - The UI always uses Bearer tokens (
Authorization: Bearer <token>). ProvideAPI_TOKENas a raw token (without theBearerprefix).
If PUBLIC_ENABLED is set, you can also login via the UI at /login, which stores the token in sessionStorage and sends it on requests.
- Start the development server:
npm run dev- Open your browser:
http://localhost:5173
| Command | Description |
|---|---|
npm run dev |
Start Vite development server with HMR on port 5173 |
npm run build |
Build production bundle to dist/ directory |
npm run preview |
Preview production build locally |
Build the application for production deployment:
npm run buildThe optimized static files will be output to the dist/ directory, ready to be served by any static file server or CDN.
The application includes a production-ready multi-stage Dockerfile with nginx as the web server.
docker build -t pbuf-registry-ui:latest .The build process:
- Uses Node 20 Alpine to build the application with
npm ciandnpm run build - Creates production image with nginx Alpine
- Copies built assets from build stage
- Configures nginx with custom entrypoint for runtime environment variable substitution
docker run -d \
-p 8080:80 \
-e API_BASE_URL=http://pbuf.cloud \
-e API_TOKEN=your_raw_token_here \
-e PUBLIC_ENABLED=true \
--name pbuf-ui \
pbuf-registry-ui:latestThe application will be available at http://localhost:8080.
| Variable | Required | Default | Description |
|---|---|---|---|
API_BASE_URL |
No | http://pbuf.cloud |
Backend API endpoint to proxy requests to |
API_TOKEN |
No | (empty) | Raw registry token used as Authorization: Bearer <token> by the proxy |
PUBLIC_ENABLED |
No | (empty/false) | Enable public browsing + optional token login via UI |
- Set
PUBLIC_ENABLED=trueto allow using the UI without a server-side token. - Users can then open
/loginand paste a token; it will be stored insessionStoragefor the session.
Note: Environment variables are substituted at container startup by the docker-entrypoint.sh script using envsubst.
- Health Check Endpoint:
GET /healthreturns200 OKfor monitoring - Gzip Compression: Enabled for text assets (HTML, CSS, JS, JSON)
- Static Asset Caching: 1-year cache for immutable assets
- Security Headers: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection
- SPA Routing: All routes fallback to
index.htmlfor Vue Router - API Proxy:
/api/*requests proxied to backend with auth header injection
The nginx configuration includes:
- Method Restrictions: Only specific endpoints allow POST (metadata, dependencies, get, pull)
- Proxy Pass: Strips
/apiprefix and forwards toAPI_BASE_URL - Authorization Header: Automatically added from
API_TOKENenvironment variable - Timeouts: 60s for connect, send, and read operations
pbuf-registry-ui/
├── src/
│ ├── assets/ # Static assets and global styles
│ ├── components/ # Reusable Vue components (P* prefix = shared components)
│ │ ├── PButton.vue
│ │ ├── PCodeBlock.vue
│ │ ├── PFeatureCard.vue
│ │ ├── PInput.vue
│ │ ├── PCard.vue
│ │ ├── PBadge.vue
│ │ ├── PTable.vue
│ │ ├── AppHeader.vue
│ │ └── AppFooter.vue
│ ├── views/ # Page components (Vue Router views)
│ │ ├── HomeView.vue # Landing page
│ │ ├── ModulesView.vue # Module list/browse
│ │ ├── ModuleDetailView.vue # Single module details
│ │ └── ModuleVersionView.vue # Module version viewer
│ ├── services/ # API service layer (Axios instances)
│ │ ├── registryApi.js # Module registry operations
│ │ └── metadataApi.js # Protobuf metadata parsing
│ ├── router/ # Vue Router configuration
│ │ └── index.js
│ ├── App.vue # Root component
│ └── main.js # Application entry point
├── index.html # HTML entry point
├── vite.config.js # Vite configuration with proxy setup
├── tailwind.config.js # Tailwind CSS configuration
├── postcss.config.js # PostCSS configuration
├── package.json # Project dependencies and scripts
├── Dockerfile # Multi-stage Docker build
├── docker-entrypoint.sh # Runtime environment variable substitution
├── nginx.conf # Production nginx configuration template
└── .env.example # Environment variable template
- @ Alias:
vite.config.jsconfigures@as alias forsrc/directory - API Services: Centralized Axios instances in
services/for clean separation - Component Prefix:
P*components are part of the shared component library - SPA Routing: Vue Router handles client-side navigation
- Proxy Pattern: Both dev (Vite) and prod (nginx) use identical proxy configuration
The UI connects to the pbuf registry API endpoints:
- List all modules
- Get module details
- Register new modules
- Push module versions
- Pull module versions
- Delete modules and tags
- Get module dependencies
- Get parsed protobuf metadata
- View messages, services, fields, and enums
- PButton - Primary and secondary action buttons
- PCodeBlock - Terminal-style code display with copy functionality
- PFeatureCard - Feature highlight cards with icons
- PInput - Form input with dark theme styling
- PCard - Generic card container
- PBadge - Tags and version labels
- PTable - Data table with custom cell rendering
- AppHeader - Navigation header with logo and menu
- AppFooter - Footer with links and branding
The project follows Vue.js 3 best practices:
- Composition API with
<script setup> - Single File Components (SFC)
- Tailwind CSS utility classes
- Responsive design patterns
Security Design: The frontend never directly connects to pbuf.cloud. All API calls are proxied through a backend server to avoid exposing authentication tokens in the browser.
[Browser] ---> [Proxy Server] ---> [pbuf.cloud API]
/api/* + Auth Header
When running npm run dev, Vite's built-in proxy server handles API requests:
- Frontend makes requests to
/api/*(e.g.,/api/v1/modules) - Vite proxy intercepts these requests
- Strips
/apiprefix:/api/v1/modules→/v1/modules - Adds
Authorizationheader usingAPI_TOKENfrom.env - Forwards to
API_BASE_URL(default:http://pbuf.cloud) - Returns the response to the frontend
Configuration: Edit .env file (copy from .env.example):
API_BASE_URL=http://pbuf.cloud
API_TOKEN=your_token_hereImplementation: See vite.config.js proxy configuration with proxyReq event handler.
When running in Docker, nginx acts as the proxy server with identical behavior:
- Browser requests
/api/* - Nginx intercepts and strips
/apiprefix - Adds
Authorizationheader fromAPI_TOKENenvironment variable - Forwards to
API_BASE_URL - Returns response to browser
Configuration: Set environment variables when running Docker container:
docker run -e API_BASE_URL=... -e API_TOKEN=... pbuf-registry-uiImplementation: See nginx.conf and docker-entrypoint.sh for runtime substitution.
| Variable | Context | Required | Default | Description |
|---|---|---|---|---|
API_BASE_URL |
Dev & Prod | No | http://pbuf.cloud |
Backend API endpoint for proxy target |
API_TOKEN |
Dev & Prod | Yes | (none) | Authentication token for pbuf.cloud API (server-side only) |
Important Security Notes:
- Environment variables are used server-side only (Vite proxy in dev, nginx in prod)
API_TOKENis never exposed to the browser or included in the built JavaScript bundle- No
VITE_*prefixed variables are needed (Vite variables would be embedded in the bundle)
Problem: Browser console shows 401 or 403 errors when accessing /api/* endpoints.
Solution:
- Verify
API_TOKENis set correctly in.envfile - Ensure
.envfile is in the project root directory - Restart the dev server after changing
.env(npm run dev) - Check that the token is valid and not expired
Problem: Dev server shows connection refused errors or cannot reach backend.
Solution:
- Verify
API_BASE_URLis correct in.env(default:http://pbuf.cloud) - Check if the backend API is accessible from your machine
- Try using the full URL with port if needed:
http://pbuf.cloud:8080 - Check firewall or network restrictions
Problem: Container exits immediately or nginx fails to start.
Solution:
- Check container logs:
docker logs pbuf-ui - Verify environment variables are passed correctly
- Test nginx config:
docker run --rm pbuf-registry-ui nginx -t - Ensure
API_TOKENdoesn't contain special characters that need escaping
Problem: Production build shows blank page or routing doesn't work.
Solution:
- Check browser console for errors
- Ensure your web server is configured for SPA routing (fallback to
index.html) - Verify all assets are being served correctly
- Check that
dist/directory was built successfully
- Hot Module Replacement (HMR): Vite provides instant feedback on code changes
- Vue DevTools: Install the Vue.js DevTools browser extension for component inspection
- API Debugging: Check Network tab in browser DevTools to inspect
/api/*requests - Environment Check: Run
console.log(import.meta.env)to debug environment variables (note: onlyVITE_*vars are exposed)
- Fork & Clone: Fork the repository and clone your fork
- Create Branch: Create a feature branch from
main - Install Dependencies: Run
npm install - Make Changes: Follow the existing code style and patterns
- Test Locally: Ensure dev server runs without errors
- Commit: Write clear, descriptive commit messages
- Push & PR: Push to your fork and open a pull request
- Use Composition API with
<script setup>syntax - Follow Vue 3 best practices and component naming conventions
- Use Tailwind utility classes instead of custom CSS when possible
- Keep components small and focused (single responsibility)
- Add comments for complex logic or non-obvious behavior
- Maintain consistent formatting (prettier/eslint compatible)
- Component Naming: Use
PascalCasefor component files (e.g.,PButton.vue) - Component Prefix: Shared components use
Pprefix (e.g.,PCard,PButton) - View Naming: Page views use
*View.vuesuffix (e.g.,HomeView.vue) - Import Alias: Use
@/for imports fromsrc/directory - API Services: Centralize API calls in
services/directory
This project is part of the pbuf.io ecosystem.
Contributions are welcome! Please feel free to submit pull requests.