Ctrl K
ComunidadGuías…

README.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Request Inbox

![CI/CD](https://github.com/jesusnoseq/request-inbox/actions/workflows/deploy_app.yaml/badge.svg)
![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)
![Go Version](https://img.shields.io/badge/Go-1.26.6+-00ADD8?logo=go)
![Node Version](https://img.shields.io/badge/Node-20+-339933?logo=node.js)
![AWS](https://img.shields.io/badge/AWS-Lambda%20%7C%20DynamoDB-orange?logo=aws)

A web application to collect and inspect HTTP requests for testing and debugging purposes. Request Inbox provides a simple and free alternative to services like webhook.site and webhookinbox.com.

🔗 **Try it live at [request-inbox.com](https://request-inbox.com/)**

## ✨ Features

### Core Functionality

- 📬 **Create, list, and delete inboxes** - Organize your inboxes
- 🎯 **Endpoint collection** - Capture HTTP requests with detailed information
- 🔧 **Custom responses** - Configure response headers and body content
- 👀 **Request inspection** - View detailed request information including headers, body, and metadata
- 🗑️ **Request management** - Remove requests from an inbox
- 🔔 **Callbacks** - Call another service when a request lands, forwarding headers and templating the body
- 🔁 **Callback retry** - Send any callback of a captured request again and inspect the new response

### User Experience

- 🌓 **Light and dark themes** - Choose your preferred interface style
- 🔍 **Inbox search** - Quickly find your inboxes
- ♻️ **Auto-refresh** - Real-time request updates
- 📖 **JSON viewer** - Pretty-print and inspect request bodies
- 📊 **OpenAPI documentation** - Complete API specification

### Security & Access

- 👤 **User authentication** - Secure login with GitHub and Google OAuth
- 🔒 **Private inboxes** - Control access to your testing environments
- 🔑 **API keys** - Programmatic access to your inboxes

## 🚀 Quick Start

### Using Docker

Run the complete application in a single container with nginx and the Go API:

```bash
# Using Docker Compose
docker-compose up -d

# Or pull from Docker Hub
docker pull jesusnoseq/request-inbox:latest
docker run -d -p 80:80 -p 8080:8080 -v inbox-data:/app/data jesusnoseq/request-inbox:latest

# Or pull from GitHub Container Registry
docker pull ghcr.io/jesusnoseq/request-inbox:latest
docker run -d -p 80:80 -p 8080:8080 -v inbox-data:/app/data ghcr.io/jesusnoseq/request-inbox:latest
```

The application will be available at `http://localhost`

📖 **[Full Docker deployment guide](DOCKER.md)**

### Using Docker Compose (Development)

Run separate containers for frontend and backend development:

```bash
docker-compose -f docker-compose-dev.yml up --build
```

This will start:

- **API server** on `http://localhost:8080`
- **Frontend** on `http://localhost:3000`

### Prerequisites

- Docker and Docker Compose (for containerized deployment)
- Go 1.26.10+ (for local development)
- Node.js 22+ and pnpm 9.15.1 (for local development)

### Local Development

1. **Backend setup:**

```bash
cd api
make install          # Download Go dependencies
make run-api-hot      # Start with hot reloading
```

1. **Frontend setup:**

```bash
make install-front    # Install frontend dependencies with pnpm
make launch-front     # Start frontend development server
```

1. **View all available commands:**

```bash
make help
```

## 🏗️ Architecture

### Technology Stack

- **Backend**: Go 1.26.6+ with Gin web framework. Can also work as an AWS lambda.
- **Frontend**: React 18 with TypeScript and Material-UI
- **Database**: BadgerDB (embedded) for local development, DynamoDB for production
- **Infrastructure**: Terraform on AWS (Lambda, API Gateway, S3, CloudFront)
- **Authentication**: JWT with OAuth2 (GitHub, Google)
- **Monitoring**: PostHog analytics

### Deployment

- **Development**: Local Docker containers
- **Production**: Serverless AWS infrastructure with CI/CD via GitHub Actions

## Project Structure

```text
request-inbox/
├── .github/workflows/       # CI/CD pipelines (GitHub Actions)
├── api/                     # Backend application (Go)
│   ├── cmd/                 # Application entry points
│   ├── pkg/                 # Shared packages and business logic
│   │   ├──  handler/        # HTTP request handlers
│   │   ├──  model/          # Data models and validation
│   │   ├──  database/       # Database abstraction layer
│   │   ├──  login/          # Authentication & authorization
│   │   └──  route/          # API route definitions
│   ├── go.mod               # Go module dependencies
│   └── air.toml             # Hot reload configuration
├── front/                   # Frontend application (React + TypeScript)
│   ├── src/                 # Source code
│   │   ├── components/      # Reusable UI components
│   │   ├── pages/           # Application pages
│   │   ├── services/        # API client services
│   │   └── types/           # TypeScript type definitions
│   ├── public/              # Static assets
│   ├── package.json         # Node.js dependencies
│   └── tsconfig.json        # TypeScript configuration
├── deploy/                  # Infrastructure as Code (Terraform)
│   ├── back.tf              # Backend infrastructure
│   ├── front.tf             # Frontend infrastructure
│   ├── cert.tf              # SSL certificates
│   └── variables.tf         # Configuration variables
├── docs/                    # Documentation
│   └── openapi.yaml         # API specification (OpenAPI 3.1)
├── docker-compose-local.yml # Local development environment
├── Dockerfile-api           # Backend container definition
├── Dockerfile-front         # Frontend container definition
├── Makefile                 # Development commands
└── README.md                # This file
```

## 📚 API Documentation

Our REST API is documented using OpenAPI 3.1 specification:

- **Online**: [API Documentation](https://request-inbox.com/docs)
- **Source**: [OpenAPI YAML](./docs/openapi.yaml)

### Base URLs

- **Production**: `https://api.request-inbox.com/api/v1`
- **Local Development**: `http://localhost:8080/api/v1`

### MCP Server

The backend exposes a stateless Streamable HTTP MCP server alongside the REST API:

- **Production**: `https://api.request-inbox.com/mcp`
- **Local Development**: `http://localhost:8080/mcp`

Configure an MCP client with the endpoint URL above. To access inboxes owned by your account, send an existing Request Inbox API key in the `X-API-KEY` header. Without that header, MCP tools follow the same anonymous and public-inbox rules as the REST API.

The server provides these tools:

- `create_request_inbox` - Create an inbox.
- `edit_request_inbox` - Replace an inbox configuration.
- `list_request_inboxes` - List accessible inboxes.
- `add_request_inbox_callback` - Add a callback to an inbox.
- `delete_request_inbox` - Delete an inbox.
- `clear_request_inbox_requests` - Remove all captured requests from an inbox.
- `list_request_inbox_requests` - List captured requests.

### Browser WebMCP

The frontend also exposes contextual [WebMCP](https://webmachinelearning.github.io/webmcp/) tools to compatible browser agents. Unlike the backend MCP server, these tools operate in the active browser session, use the current page and authenticated user, and can navigate or update the visible application.

WebMCP support uses both APIs:

- **Imperative tools** are registered from React with `navigator.modelContext.registerTool()`.
- **Declarative tools** are customized HTML forms marked with `toolname`, `tooltitle`, `tooldescription`, `toolautosubmit`, and `toolparamdescription`. Agent submissions return their asynchronous result through `SubmitEvent.respondWith()`.

#### Imperative WebMCP Tools

| Tool | Availability | Purpose and inputs |
| --- | --- | --- |
| `create_request_inbox` | All pages except where the declarative create form is active | Creates an inbox. It has no inputs. |
| `open_request_inbox` | All pages | Opens an inbox after validating `inboxId`. |
| `list_request_inboxes` | Signed-in users | Lists the user's inboxes. It has no inputs. |
| `search_request_inboxes` | Signed-in users | Searches inbox names and IDs using `query`. |
| `inspect_request_inbox` | Signed-in users | Returns up to 20 recent requests using `inboxId` and optional `requestLimit`. |
| `open_api_documentation` | All pages | Opens the interactive API documentation. It has no inputs. |
| `open_user_documentation` | All pages | Opens the user documentation. It has no inputs. |
| `update_request_inbox` | Open inbox page | Partially updates the display `name`, `isPrivate` visibility, and HTTP `response`. Response fields include fallback `code`, optional `codeTemplate`, complete `headers`, `body`, and required `isDynamic` mode; omitted fields are preserved. |
| `add_request_inbox_callback` | Open inbox page | Adds a custom or preset callback using `destinationUrl`, optional `template`, `method`, `headers`, `body`, `isEnabled`, `isDynamic`, and `forwardHeaders`. |
| `get_request_inbox_requests` | Open inbox page | Reads captured requests using optional `requestLimit` and `afterRequestId` cursor values. |

The imperative `add_request_inbox_callback` tool intentionally remains registered. Callback editing and deletion use the declarative forms below.

#### Declarative WebMCP Forms

| Form tool | Availability | Customized form behavior |
| --- | --- | --- |
| `create_request_inbox` | Landing/home create button | Creates an inbox with no parameters and navigates to it. It replaces the imperative tool on pages where this form is active, avoiding duplicate tool names. |
| `update_request_inbox_response` | Editable open inbox | Replaces the inbox response using `code`, `codeTemplate`, `headers` as JSON, `body`, and `isDynamic`. The form remains discoverable while its visual editor is closed. |
| `update_request_inbox_callback_<index>` | Each callback in an editable open inbox | Replaces the complete callback at the zero-based `<index>` using `toURL`, `method`, `headers` as JSON, `body`, `isEnabled`, `isDynamic`, and `isForwardingHeaders`. The normal edit button still opens the visual editor. |
| `delete_request_inbox_callback_<index>` | Each callback in an editable open inbox | Deletes the callback at the zero-based `<index>`. Agent invocation submits immediately; the normal delete button still asks the user for confirmation. |
| `copy_request_as_curl_<requestId>` | Each captured request | Copies that request as a cURL command and returns the generated command. `<requestId>` is the request's stored zero-based ID. |
| `retry_callback_<requestId>_<index>` | Each callback response that can be retried | Sends callback `<index>` for the captured request again and returns the new response. Both dynamic suffixes are zero-based. |

Inbox response and callback mutation forms are omitted for read-only inboxes. Form values are initialized from the current UI state, validated before persistence, and the open inbox state is refreshed after callback changes so the page reflects an agent action without requiring a reload.

## 📄 Template Docs

Responses can work as golang templates is the response is mark as dynamic.

[Template documentation](https://request-inbox.com/docs)

## 🛠️ Development

### Available Make Commands

```bash
make help               # Show all commands
```

### Environment Variables

For local development, create `.env.development` in the `api/` directory:

```bash
# Database
DB_ENGINE=embedded

# Server
API_HTTP_PORT=8080
API_MODE=server

# CORS
CORS_ALLOW_ORIGINS=http://localhost:3000

# Permissive callbacks for local development
ENABLE_CALLBACK_URL_VALIDATION=false
CALLBACK_ALLOWED_HOSTS=""
CALLBACK_BLOCKED_HOSTS=""
CALLBACK_ALLOW_PUBLIC_IPS=true
CALLBACK_ALLOW_PRIVATE_IPS=true
CALLBACK_ALLOW_LOOPBACK_IPS=true
CALLBACK_ALLOW_LINK_LOCAL_IPS=true
ENABLE_CALLBACK_FOLLOW_REDIRECTS=false

# Authentication (optional for local development)
LOGIN_GITHUB_CLIENT_ID=your_github_client_id
LOGIN_GITHUB_CLIENT_SECRET=your_github_client_secret
LOGIN_GOOGLE_CLIENT_ID=your_google_client_id
LOGIN_GOOGLE_CLIENT_SECRET=your_google_client_secret
JWT_SECRET=your_jwt_secret
```

#### Development and production callback policies

`api/.env.development` and `docker-compose.yml` use a permissive local policy:
`ENABLE_CALLBACK_URL_VALIDATION=false` bypasses URL, host-list, and destination
IP checks. The development IP-type flags are all `true`; redirects remain
disabled. Docker Compose accepts overrides from shell variables or its `.env`
file.

Production AWS Lambda uses the application's secure built-in defaults below
when no callback environment overrides are set. No callback settings are needed
in `deploy/back.tf`; the local development env file and Compose settings do not
apply to Lambda:

```dotenv
ENABLE_CALLBACK_URL_VALIDATION=true
CALLBACK_ALLOWED_HOSTS=""
CALLBACK_BLOCKED_HOSTS=""
CALLBACK_ALLOW_PUBLIC_IPS=true
CALLBACK_ALLOW_PRIVATE_IPS=false
CALLBACK_ALLOW_LOOPBACK_IPS=false
CALLBACK_ALLOW_LINK_LOCAL_IPS=false
ENABLE_CALLBACK_FOLLOW_REDIRECTS=false
```

In production, private, loopback, link-local (including cloud metadata), and
reserved destinations are blocked. DNS answers are checked and connections are
pinned to validated IPs. The configured `BACKEND_APPLICATION_DOMAIN` is also
blocked as a callback destination. To enable host-list restrictions during local
development, set
`ENABLE_CALLBACK_URL_VALIDATION=true` and select the appropriate IP-type flags.

#### Callback host-list format

`CALLBACK_ALLOWED_HOSTS` and `CALLBACK_BLOCKED_HOSTS` accept **space-separated
exact hostnames or IP addresses**. Quote the value when listing multiple hosts:

```dotenv
CALLBACK_ALLOWED_HOSTS="hooks.example.com events.example.net 10.20.0.5 ::1"
CALLBACK_BLOCKED_HOSTS="retired.example.com 192.168.1.10"
```

- Use hostnames or IP literals only, without a scheme (`https://`), port, path,
  wildcard, or CIDR notation. Separate entries with spaces, not commas.
- Matching is case-insensitive, ignores a trailing DNS dot, and normalizes
  equivalent IP representations. A hostname entry matches only that hostname,
  not its subdomains; an IP entry does not match a different hostname that
  resolves to that IP.
- An empty `CALLBACK_ALLOWED_HOSTS` permits any host that passes the other
  checks; an empty `CALLBACK_BLOCKED_HOSTS` adds no blocked hosts. If a host is
  in both lists, blocking takes precedence.
- Entries apply across all ports and paths. Allowlisting a host does not
  override the IP-type policy: private, loopback, and link-local destinations
  require their corresponding `CALLBACK_ALLOW_*_IPS` setting to be `true`.
- Both lists are enforced only when `ENABLE_CALLBACK_URL_VALIDATION=true`.

## 🤝 Contributing

1. Fork the repository
2. Create a feature branch (`git checkout -b feat/amazing-feature`)
3. Commit your changes (`git commit -m 'Add amazing feature'`)
4. Push to the branch (`git push origin feat/amazing-feature`)
5. Open a Pull Request

### Development Guidelines

- Follow Go best practices and run `make lint` and `make test`
- Write tests for new functionality
- Update documentation for API changes
- Use conventional commit messages

## 📄 License

This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details.

## 🗺️ Roadmap

### Recent Additions

- ✅ **Docker images** - Production-ready Docker image with nginx and API
- ✅ **GitHub Container Registry** - Automated image publishing
- ✅ **Callbacks** - Request callback/passthrough, including manual retry of a callback result

### Planned Features

- **Alerts**: Notification system for new requests
- **Import/Export**: Inbox configuration backup and restore fromt github
- **Testing**: Request testing capabilities. Mark request as Pass or Fail
- **Limits**: Configurable request and inbox limits

### Future Enhancements

- WebSocket support for real-time updates
- Custom domain support for inboxes
- Advanced filtering and search
- Performance monitoring and metrics