chore: change default ports to avoid common conflicts (#681)
This commit is contained in:
+5
-3
@@ -5,7 +5,7 @@
|
|||||||
# docker build -t kandev:latest .
|
# docker build -t kandev:latest .
|
||||||
#
|
#
|
||||||
# Run:
|
# Run:
|
||||||
# docker run -p 8080:8080 -v kandev-data:/data kandev:latest
|
# docker run -p 38429:38429 -v kandev-data:/data kandev:latest
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Stage 1: Go builder — compile kandev + agentctl binaries
|
# Stage 1: Go builder — compile kandev + agentctl binaries
|
||||||
@@ -114,8 +114,10 @@ RUN chown -R kandev:kandev /app /data
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
EXPOSE 8080
|
# Only the backend port is exposed — it reverse-proxies the Next.js frontend
|
||||||
|
# (which listens on 37429 internally), so users hit a single port.
|
||||||
|
EXPOSE 38429
|
||||||
|
|
||||||
# tini as PID 1 for signal handling; entrypoint handles privilege drop
|
# tini as PID 1 for signal handling; entrypoint handles privilege drop
|
||||||
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
|
ENTRYPOINT ["tini", "--", "docker-entrypoint.sh"]
|
||||||
CMD ["kandev", "start", "--backend-port", "8080", "--web-port", "37429", "--verbose"]
|
CMD ["kandev", "start", "--backend-port", "38429", "--web-port", "37429", "--verbose"]
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ help:
|
|||||||
@echo ""
|
@echo ""
|
||||||
@echo "Development Commands:"
|
@echo "Development Commands:"
|
||||||
@echo " dev Run backend + web via CLI (auto ports)"
|
@echo " dev Run backend + web via CLI (auto ports)"
|
||||||
@echo " dev-backend Run backend in development mode (port 8080)"
|
@echo " dev-backend Run backend in development mode (port 38429)"
|
||||||
@echo " dev-web Run web app in development mode (port 37429)"
|
@echo " dev-web Run web app in development mode (port 37429)"
|
||||||
@echo " dev Note: Uses apps/cli launcher (auto ports)"
|
@echo " dev Note: Uses apps/cli launcher (auto ports)"
|
||||||
@echo ""
|
@echo ""
|
||||||
@@ -114,7 +114,7 @@ endif
|
|||||||
|
|
||||||
.PHONY: dev-backend
|
.PHONY: dev-backend
|
||||||
dev-backend:
|
dev-backend:
|
||||||
@echo "Starting backend on http://localhost:8080"
|
@echo "Starting backend on http://localhost:38429"
|
||||||
@trap 'stty sane 2>/dev/null || true' EXIT INT TERM; \
|
@trap 'stty sane 2>/dev/null || true' EXIT INT TERM; \
|
||||||
$(MAKE) -C $(BACKEND_DIR) run; \
|
$(MAKE) -C $(BACKEND_DIR) run; \
|
||||||
stty sane 2>/dev/null || true
|
stty sane 2>/dev/null || true
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ apps/
|
|||||||
make dev
|
make dev
|
||||||
|
|
||||||
# Or run separately
|
# Or run separately
|
||||||
make dev-backend # Backend on :8080
|
make dev-backend # Backend on :38429
|
||||||
make dev-web # Frontend on :37429
|
make dev-web # Frontend on :37429
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -59,9 +59,14 @@ import (
|
|||||||
"github.com/kandev/kandev/internal/db"
|
"github.com/kandev/kandev/internal/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// defaultServerPort is the fallback HTTP port when neither the CLI flag nor
|
||||||
|
// the config file / env var sets one. Kept in sync with the viper default in
|
||||||
|
// internal/common/config.setDefaults.
|
||||||
|
const defaultServerPort = 38429
|
||||||
|
|
||||||
// Command-line flags
|
// Command-line flags
|
||||||
var (
|
var (
|
||||||
flagPort = flag.Int("port", 0, "HTTP server port (default: 8080)")
|
flagPort = flag.Int("port", 0, fmt.Sprintf("HTTP server port (default: %d)", defaultServerPort))
|
||||||
flagLogLevel = flag.String("log-level", "", "Log level: debug, info, warn, error")
|
flagLogLevel = flag.String("log-level", "", "Log level: debug, info, warn, error")
|
||||||
flagHelp = flag.Bool("help", false, "Show help message")
|
flagHelp = flag.Bool("help", false, "Show help message")
|
||||||
flagVersion = flag.Bool("version", false, "Show version information")
|
flagVersion = flag.Bool("version", false, "Show version information")
|
||||||
@@ -74,8 +79,8 @@ func init() {
|
|||||||
fmt.Fprintf(os.Stderr, "Options:\n")
|
fmt.Fprintf(os.Stderr, "Options:\n")
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
fmt.Fprintf(os.Stderr, "\nExamples:\n")
|
fmt.Fprintf(os.Stderr, "\nExamples:\n")
|
||||||
fmt.Fprintf(os.Stderr, " kandev # Start with default settings\n")
|
fmt.Fprintf(os.Stderr, " kandev # Start with default settings\n")
|
||||||
fmt.Fprintf(os.Stderr, " kandev -port=9000 -log-level=debug # Custom port and log level\n")
|
fmt.Fprintf(os.Stderr, " kandev -port=18080 -log-level=debug # Custom port and log level\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -418,7 +423,7 @@ func startGatewayAndServe(
|
|||||||
|
|
||||||
port := cfg.Server.Port
|
port := cfg.Server.Port
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
port = 8080
|
port = defaultServerPort
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
log.Info("WebSocket server listening", zap.Int("port", port))
|
log.Info("WebSocket server listening", zap.Int("port", port))
|
||||||
@@ -489,7 +494,7 @@ func buildHTTPServer(
|
|||||||
|
|
||||||
port := cfg.Server.Port
|
port := cfg.Server.Port
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
port = 8080
|
port = defaultServerPort
|
||||||
}
|
}
|
||||||
return &http.Server{
|
return &http.Server{
|
||||||
Addr: fmt.Sprintf(":%d", port),
|
Addr: fmt.Sprintf(":%d", port),
|
||||||
|
|||||||
@@ -53,12 +53,12 @@ WORKDIR /workspace
|
|||||||
# OPENAI_API_KEY - OpenAI API key for Codex
|
# OPENAI_API_KEY - OpenAI API key for Codex
|
||||||
#
|
#
|
||||||
# agentctl configuration:
|
# agentctl configuration:
|
||||||
# AGENTCTL_PORT - HTTP API port (default: 9999)
|
# AGENTCTL_PORT - HTTP API port (default: 39429)
|
||||||
# AGENTCTL_AGENT_COMMAND - Command to run (e.g., "auggie --acp" or "codex app-server")
|
# AGENTCTL_AGENT_COMMAND - Command to run (e.g., "auggie --acp" or "codex app-server")
|
||||||
# AGENTCTL_AUTO_START - Auto-start agent on startup (default: false)
|
# AGENTCTL_AUTO_START - Auto-start agent on startup (default: false)
|
||||||
|
|
||||||
# Expose agentctl HTTP API port
|
# Expose agentctl HTTP API port
|
||||||
EXPOSE 9999
|
EXPOSE 39429
|
||||||
|
|
||||||
# Run agentctl HTTP server
|
# Run agentctl HTTP server
|
||||||
ENTRYPOINT ["/agent/entrypoint.sh"]
|
ENTRYPOINT ["/agent/entrypoint.sh"]
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ if ! command -v codex &> /dev/null; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Run agentctl HTTP server
|
# Run agentctl HTTP server
|
||||||
echo "Starting agentctl on port ${AGENTCTL_PORT:-9999}..."
|
echo "Starting agentctl on port ${AGENTCTL_PORT:-39429}..."
|
||||||
exec /usr/local/bin/agentctl
|
exec /usr/local/bin/agentctl
|
||||||
|
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ import (
|
|||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default agentctl port
|
// Default agentctl port. Clustered near the web port (37429) to avoid
|
||||||
const AgentCtlPort = 9999
|
// collisions with commonly used ports (8080, 9090, 9999, etc.).
|
||||||
|
const AgentCtlPort = 39429
|
||||||
|
|
||||||
// AgentExecution represents a running agent execution
|
// AgentExecution represents a running agent execution
|
||||||
type AgentExecution struct {
|
type AgentExecution struct {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ type Launcher struct {
|
|||||||
type Config struct {
|
type Config struct {
|
||||||
BinaryPath string // Path to agentctl binary (auto-detected if empty)
|
BinaryPath string // Path to agentctl binary (auto-detected if empty)
|
||||||
Host string // Host to bind to (default: localhost)
|
Host string // Host to bind to (default: localhost)
|
||||||
Port int // Control port (default: 9999)
|
Port int // Control port (default: 39429)
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Launcher.
|
// New creates a new Launcher.
|
||||||
@@ -60,7 +60,7 @@ func New(cfg Config, log *logger.Logger) *Launcher {
|
|||||||
cfg.Host = "localhost"
|
cfg.Host = "localhost"
|
||||||
}
|
}
|
||||||
if cfg.Port == 0 {
|
if cfg.Port == 0 {
|
||||||
cfg.Port = 9999
|
cfg.Port = 39429
|
||||||
}
|
}
|
||||||
if cfg.BinaryPath == "" {
|
if cfg.BinaryPath == "" {
|
||||||
cfg.BinaryPath = findAgentctlBinary()
|
cfg.BinaryPath = findAgentctlBinary()
|
||||||
|
|||||||
@@ -196,10 +196,10 @@ type InstanceConfig struct {
|
|||||||
// Load loads the configuration from environment variables.
|
// Load loads the configuration from environment variables.
|
||||||
func Load() *Config {
|
func Load() *Config {
|
||||||
cfg := &Config{
|
cfg := &Config{
|
||||||
Port: getEnvInt("AGENTCTL_PORT", 9999),
|
Port: getEnvInt("AGENTCTL_PORT", 39429),
|
||||||
Ports: PortConfig{
|
Ports: PortConfig{
|
||||||
Base: getEnvInt("AGENTCTL_INSTANCE_PORT_BASE", 10001),
|
Base: getEnvInt("AGENTCTL_INSTANCE_PORT_BASE", 41001),
|
||||||
Max: getEnvInt("AGENTCTL_INSTANCE_PORT_MAX", 10100),
|
Max: getEnvInt("AGENTCTL_INSTANCE_PORT_MAX", 41100),
|
||||||
},
|
},
|
||||||
Defaults: InstanceDefaults{
|
Defaults: InstanceDefaults{
|
||||||
Protocol: agent.Protocol(getEnv("AGENTCTL_PROTOCOL", string(agent.ProtocolACP))),
|
Protocol: agent.Protocol(getEnv("AGENTCTL_PROTOCOL", string(agent.ProtocolACP))),
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ type AgentConfig struct {
|
|||||||
// StandaloneHost is the host where standalone agentctl is running (default: localhost)
|
// StandaloneHost is the host where standalone agentctl is running (default: localhost)
|
||||||
StandaloneHost string `mapstructure:"standaloneHost"`
|
StandaloneHost string `mapstructure:"standaloneHost"`
|
||||||
|
|
||||||
// StandalonePort is the control port for standalone agentctl (default: 9999)
|
// StandalonePort is the control port for standalone agentctl (default: 39429)
|
||||||
StandalonePort int `mapstructure:"standalonePort"`
|
StandalonePort int `mapstructure:"standalonePort"`
|
||||||
|
|
||||||
// StandaloneAuthToken is the per-launch auth token retrieved via handshake.
|
// StandaloneAuthToken is the per-launch auth token retrieved via handshake.
|
||||||
@@ -189,7 +189,7 @@ type AgentConfig struct {
|
|||||||
// This setting is only for running a separate standalone MCP server process.
|
// This setting is only for running a separate standalone MCP server process.
|
||||||
McpServerEnabled bool `mapstructure:"mcpServerEnabled"`
|
McpServerEnabled bool `mapstructure:"mcpServerEnabled"`
|
||||||
|
|
||||||
// McpServerPort is the port for the standalone MCP server (default: 9090)
|
// McpServerPort is the port for the standalone MCP server (default: 40429)
|
||||||
McpServerPort int `mapstructure:"mcpServerPort"`
|
McpServerPort int `mapstructure:"mcpServerPort"`
|
||||||
|
|
||||||
// McpServerURL is the URL of the Kandev MCP server for task management
|
// McpServerURL is the URL of the Kandev MCP server for task management
|
||||||
@@ -235,7 +235,7 @@ func detectDefaultLogFormat() string {
|
|||||||
func setDefaults(v *viper.Viper) {
|
func setDefaults(v *viper.Viper) {
|
||||||
// Server defaults
|
// Server defaults
|
||||||
v.SetDefault("server.host", "0.0.0.0")
|
v.SetDefault("server.host", "0.0.0.0")
|
||||||
v.SetDefault("server.port", 8080)
|
v.SetDefault("server.port", 38429)
|
||||||
v.SetDefault("server.readTimeout", 30)
|
v.SetDefault("server.readTimeout", 30)
|
||||||
v.SetDefault("server.writeTimeout", 30)
|
v.SetDefault("server.writeTimeout", 30)
|
||||||
v.SetDefault("server.webInternalUrl", "")
|
v.SetDefault("server.webInternalUrl", "")
|
||||||
@@ -274,9 +274,9 @@ func setDefaults(v *viper.Viper) {
|
|||||||
|
|
||||||
// Agent defaults (runtime selection is now per-task based on executor type)
|
// Agent defaults (runtime selection is now per-task based on executor type)
|
||||||
v.SetDefault("agent.standaloneHost", "localhost")
|
v.SetDefault("agent.standaloneHost", "localhost")
|
||||||
v.SetDefault("agent.standalonePort", 9999)
|
v.SetDefault("agent.standalonePort", 39429)
|
||||||
v.SetDefault("agent.mcpServerEnabled", false) // MCP is now embedded in agentctl
|
v.SetDefault("agent.mcpServerEnabled", false) // MCP is now embedded in agentctl
|
||||||
v.SetDefault("agent.mcpServerPort", 9090)
|
v.SetDefault("agent.mcpServerPort", 40429)
|
||||||
v.SetDefault("agent.mcpServerUrl", "")
|
v.SetDefault("agent.mcpServerUrl", "")
|
||||||
|
|
||||||
// Auth defaults
|
// Auth defaults
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import os from "node:os";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
// Default service ports (will auto-fallback if busy).
|
// Default service ports (will auto-fallback if busy).
|
||||||
export const DEFAULT_BACKEND_PORT = 8080;
|
// Clustered near the web port (37429) to avoid collisions with commonly used
|
||||||
|
// ports (8080, 9090, 9999, etc.) while keeping the numbers memorable.
|
||||||
|
export const DEFAULT_BACKEND_PORT = 38429;
|
||||||
export const DEFAULT_WEB_PORT = 37429;
|
export const DEFAULT_WEB_PORT = 37429;
|
||||||
export const DEFAULT_AGENTCTL_PORT = 9999;
|
export const DEFAULT_AGENTCTL_PORT = 39429;
|
||||||
export const DEFAULT_MCP_PORT = 9090;
|
export const DEFAULT_MCP_PORT = 40429;
|
||||||
|
|
||||||
// Random fallback range for port selection.
|
// Random fallback range for port selection.
|
||||||
export const RANDOM_PORT_MIN = 10000;
|
export const RANDOM_PORT_MIN = 10000;
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ vi.mock("./constants", () => ({
|
|||||||
return mockCacheDir.value;
|
return mockCacheDir.value;
|
||||||
},
|
},
|
||||||
DATA_DIR: "/tmp/kandev-test-data",
|
DATA_DIR: "/tmp/kandev-test-data",
|
||||||
DEFAULT_BACKEND_PORT: 8080,
|
DEFAULT_BACKEND_PORT: 38429,
|
||||||
DEFAULT_WEB_PORT: 37429,
|
DEFAULT_WEB_PORT: 37429,
|
||||||
DEFAULT_AGENTCTL_PORT: 9999,
|
DEFAULT_AGENTCTL_PORT: 39429,
|
||||||
HEALTH_TIMEOUT_MS_RELEASE: 15000,
|
HEALTH_TIMEOUT_MS_RELEASE: 15000,
|
||||||
RANDOM_PORT_MIN: 10000,
|
RANDOM_PORT_MIN: 10000,
|
||||||
RANDOM_PORT_MAX: 60000,
|
RANDOM_PORT_MAX: 60000,
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ function BackendConnectionCard() {
|
|||||||
value={displayBackendUrl}
|
value={displayBackendUrl}
|
||||||
readOnly
|
readOnly
|
||||||
disabled
|
disabled
|
||||||
placeholder="http://localhost:8080"
|
placeholder="http://localhost:38429"
|
||||||
className="cursor-default"
|
className="cursor-default"
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ function useTerminalRefs() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const WS_BASE_URL_FALLBACK = "ws://localhost:8080";
|
const WS_BASE_URL_FALLBACK = "ws://localhost:38429";
|
||||||
function useWsBaseUrl() {
|
function useWsBaseUrl() {
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ export const backendFixture = base.extend<object, { backend: BackendContext }>({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Give each worker its own agentctl port range, offset from the default
|
// Give each worker its own agentctl port range, offset from the default
|
||||||
// range (10001-10100) to avoid conflicts with a running dev instance.
|
// range (41001-41100) to avoid conflicts with a running dev instance.
|
||||||
const agentctlPortBase = 30001 + E2E_PORT_OFFSET * 1000 + workerInfo.workerIndex * 50;
|
const agentctlPortBase = 30001 + E2E_PORT_OFFSET * 1000 + workerInfo.workerIndex * 50;
|
||||||
const agentctlPortMax = agentctlPortBase + 49;
|
const agentctlPortMax = agentctlPortBase + 49;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export type AppConfig = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Server-side default (used during SSR - always localhost since SSR runs on same machine)
|
// Server-side default (used during SSR - always localhost since SSR runs on same machine)
|
||||||
const DEFAULT_API_BASE_URL = "http://localhost:8080";
|
const DEFAULT_API_BASE_URL = "http://localhost:38429";
|
||||||
|
|
||||||
export const DEBUG_UI =
|
export const DEBUG_UI =
|
||||||
process.env.NEXT_PUBLIC_KANDEV_DEBUG === "true" ||
|
process.env.NEXT_PUBLIC_KANDEV_DEBUG === "true" ||
|
||||||
@@ -18,7 +18,7 @@ export function getBackendConfig(): AppConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Client-side URL resolution:
|
// Client-side URL resolution:
|
||||||
// 1. Port-based URL via __KANDEV_API_PORT (dev mode: browser on :3000, API on :8080)
|
// 1. Port-based URL via __KANDEV_API_PORT (dev mode: browser on :37429, API on :38429)
|
||||||
// 2. Same-origin (production: Go reverse-proxies Next.js on single port)
|
// 2. Same-origin (production: Go reverse-proxies Next.js on single port)
|
||||||
// Works for any hosting scenario: localhost, custom domain, Tailscale, etc.
|
// Works for any hosting scenario: localhost, custom domain, Tailscale, etc.
|
||||||
if (window.__KANDEV_API_PORT) {
|
if (window.__KANDEV_API_PORT) {
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ export function getWsBaseUrl(): string {
|
|||||||
const protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
const protocol = url.protocol === "https:" ? "wss:" : "ws:";
|
||||||
return `${protocol}//${url.host}`;
|
return `${protocol}//${url.host}`;
|
||||||
} catch {
|
} catch {
|
||||||
return "ws://localhost:8080";
|
return "ws://localhost:38429";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export const STORAGE_KEYS = {
|
|||||||
LAST_EXECUTOR_PROFILE_ID: "kandev.dialog.lastExecutorProfileId",
|
LAST_EXECUTOR_PROFILE_ID: "kandev.dialog.lastExecutorProfileId",
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const DEFAULT_BACKEND_URL = "http://localhost:8080";
|
export const DEFAULT_BACKEND_URL = "http://localhost:38429";
|
||||||
|
|
||||||
// Kanban Preview Panel Settings
|
// Kanban Preview Panel Settings
|
||||||
export const PREVIEW_PANEL = {
|
export const PREVIEW_PANEL = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Convert HTTP URL to WebSocket URL.
|
* Convert HTTP URL to WebSocket URL.
|
||||||
* http://localhost:8080 → ws://localhost:8080/ws
|
* http://localhost:38429 → ws://localhost:38429/ws
|
||||||
* https://api.example.com → wss://api.example.com/ws
|
* https://api.example.com → wss://api.example.com/ws
|
||||||
*/
|
*/
|
||||||
export function httpToWebSocketUrl(baseUrl: string): string {
|
export function httpToWebSocketUrl(baseUrl: string): string {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ Kandev uses an event-driven architecture with **Agent Communication Protocol (AC
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TB
|
flowchart TB
|
||||||
subgraph Binary["Kandev Binary (Port 8080)"]
|
subgraph Binary["Kandev Binary (Port 38429)"]
|
||||||
Task["Task Service"]
|
Task["Task Service"]
|
||||||
Agent["Agent Manager"]
|
Agent["Agent Manager"]
|
||||||
Orch["Orchestrator Service"]
|
Orch["Orchestrator Service"]
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ This document provides a complete reference for all WebSocket API actions, their
|
|||||||
|
|
||||||
Kandev uses a **single WebSocket connection** for all API operations and real-time streaming. This eliminates the need for separate REST endpoints and enables full-duplex communication.
|
Kandev uses a **single WebSocket connection** for all API operations and real-time streaming. This eliminates the need for separate REST endpoints and enables full-duplex communication.
|
||||||
|
|
||||||
**Endpoint**: `ws://localhost:8080/ws`
|
**Endpoint**: `ws://localhost:38429/ws`
|
||||||
|
|
||||||
### Message Envelope
|
### Message Envelope
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ flowchart LR
|
|||||||
|
|
||||||
### Typical Workflow
|
### Typical Workflow
|
||||||
|
|
||||||
1. **Connect** to `ws://localhost:8080/ws`
|
1. **Connect** to `ws://localhost:38429/ws`
|
||||||
2. **Create Board** → `board.create`
|
2. **Create Board** → `board.create`
|
||||||
3. **Create Column** → `column.create`
|
3. **Create Column** → `column.create`
|
||||||
4. **Create Task** → `task.create`
|
4. **Create Task** → `task.create`
|
||||||
@@ -2282,7 +2282,7 @@ These are push notifications from the server to subscribed clients. They have `t
|
|||||||
## Complete Usage Example
|
## Complete Usage Example
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
const ws = new WebSocket('ws://localhost:8080/ws');
|
const ws = new WebSocket('ws://localhost:38429/ws');
|
||||||
const pending = new Map();
|
const pending = new Map();
|
||||||
|
|
||||||
// Handle incoming messages
|
// Handle incoming messages
|
||||||
|
|||||||
+7
-7
@@ -112,8 +112,8 @@ npx kandev start
|
|||||||
| Option | Description | Example |
|
| Option | Description | Example |
|
||||||
|--------|-------------|---------|
|
|--------|-------------|---------|
|
||||||
| `--version <tag>` | Use a specific release version | `--version v0.1.0` |
|
| `--version <tag>` | Use a specific release version | `--version v0.1.0` |
|
||||||
| `--backend-port <port>` | Override backend port | `--backend-port 8080` |
|
| `--backend-port <port>` | Override backend port | `--backend-port 18080` |
|
||||||
| `--web-port <port>` | Override web port | `--web-port 37429` |
|
| `--web-port <port>` | Override web port | `--web-port 13000` |
|
||||||
| `--help`, `-h` | Show help | `--help` |
|
| `--help`, `-h` | Show help | `--help` |
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
@@ -126,7 +126,7 @@ npx kandev --version v0.1.0
|
|||||||
npx kandev --backend-port 18080 --web-port 13000
|
npx kandev --backend-port 18080 --web-port 13000
|
||||||
|
|
||||||
# Dev mode with custom ports
|
# Dev mode with custom ports
|
||||||
npx kandev dev --backend-port 8080 --web-port 13000
|
npx kandev dev --backend-port 18080 --web-port 13000
|
||||||
```
|
```
|
||||||
|
|
||||||
## Port Selection
|
## Port Selection
|
||||||
@@ -135,10 +135,10 @@ By default, the CLI automatically finds available ports:
|
|||||||
|
|
||||||
| Service | Default Port | Fallback |
|
| Service | Default Port | Fallback |
|
||||||
|---------|--------------|----------|
|
|---------|--------------|----------|
|
||||||
| Backend | 8080 | Auto-selects from 10000-60000 |
|
| Backend | 38429 | Auto-selects from 10000-60000 |
|
||||||
| Web | 37429 | Auto-selects from 10000-60000 |
|
| Web | 37429 | Auto-selects from 10000-60000 |
|
||||||
| AgentCtl | 9999 | Auto-selects from 10000-60000 |
|
| AgentCtl | 39429 | Auto-selects from 10000-60000 |
|
||||||
| MCP Server | 9090 | Auto-selects from 10000-60000 |
|
| MCP Server | 40429 | Auto-selects from 10000-60000 |
|
||||||
|
|
||||||
If the default port is in use, the CLI finds the next available port automatically.
|
If the default port is in use, the CLI finds the next available port automatically.
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ See `make help` for all available commands.
|
|||||||
The CLI automatically finds available ports. If you need a specific port:
|
The CLI automatically finds available ports. If you need a specific port:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx kandev --backend-port 8080 --web-port 37429
|
npx kandev --backend-port 18080 --web-port 13000
|
||||||
```
|
```
|
||||||
|
|
||||||
### Backend Takes Too Long to Start
|
### Backend Takes Too Long to Start
|
||||||
|
|||||||
+12
-12
@@ -5,10 +5,10 @@ Run Kandev in a Docker container. For Kubernetes deployment, see [k8s.md](k8s.md
|
|||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 8080:8080 -v kandev-data:/data ghcr.io/kdlbs/kandev:latest
|
docker run -p 38429:38429 -v kandev-data:/data ghcr.io/kdlbs/kandev:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
Open `http://localhost:8080` in your browser.
|
Open `http://localhost:38429` in your browser.
|
||||||
|
|
||||||
## Using the Pre-built Image
|
## Using the Pre-built Image
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ Without a volume, data is lost when the container is removed.
|
|||||||
Configuration is done via `KANDEV_`-prefixed environment variables:
|
Configuration is done via `KANDEV_`-prefixed environment variables:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 8080:8080 \
|
docker run -p 38429:38429 \
|
||||||
-v kandev-data:/data \
|
-v kandev-data:/data \
|
||||||
-e KANDEV_LOG_LEVEL=debug \
|
-e KANDEV_LOG_LEVEL=debug \
|
||||||
ghcr.io/kdlbs/kandev:latest
|
ghcr.io/kdlbs/kandev:latest
|
||||||
@@ -77,7 +77,7 @@ docker run -p 8080:8080 \
|
|||||||
To use PostgreSQL instead of SQLite:
|
To use PostgreSQL instead of SQLite:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 8080:8080 \
|
docker run -p 38429:38429 \
|
||||||
-e KANDEV_DATABASE_DRIVER=postgres \
|
-e KANDEV_DATABASE_DRIVER=postgres \
|
||||||
-e KANDEV_DATABASE_HOST=host.docker.internal \
|
-e KANDEV_DATABASE_HOST=host.docker.internal \
|
||||||
-e KANDEV_DATABASE_PORT=5432 \
|
-e KANDEV_DATABASE_PORT=5432 \
|
||||||
@@ -93,7 +93,7 @@ Kandev exposes a single port. The Go backend serves the API, WebSocket, and reve
|
|||||||
|
|
||||||
| Port | Service |
|
| Port | Service |
|
||||||
|------|---------|
|
|------|---------|
|
||||||
| `8080` | API + WebSocket + Web UI |
|
| `38429` | API + WebSocket + Web UI |
|
||||||
|
|
||||||
Override the port:
|
Override the port:
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ services:
|
|||||||
kandev:
|
kandev:
|
||||||
image: ghcr.io/kdlbs/kandev:latest
|
image: ghcr.io/kdlbs/kandev:latest
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "38429:38429"
|
||||||
volumes:
|
volumes:
|
||||||
- kandev-data:/data
|
- kandev-data:/data
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -133,7 +133,7 @@ services:
|
|||||||
kandev:
|
kandev:
|
||||||
image: ghcr.io/kdlbs/kandev:latest
|
image: ghcr.io/kdlbs/kandev:latest
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "38429:38429"
|
||||||
volumes:
|
volumes:
|
||||||
- kandev-data:/data
|
- kandev-data:/data
|
||||||
environment:
|
environment:
|
||||||
@@ -170,7 +170,7 @@ volumes:
|
|||||||
|
|
||||||
## Reverse Proxy
|
## Reverse Proxy
|
||||||
|
|
||||||
Since Kandev serves everything on a single port, a reverse proxy only needs to forward all traffic to port 8080. No extra environment variables are needed — the frontend automatically uses `window.location.origin` to reach the API.
|
Since Kandev serves everything on a single port, a reverse proxy only needs to forward all traffic to port 38429. No extra environment variables are needed — the frontend automatically uses `window.location.origin` to reach the API.
|
||||||
|
|
||||||
### Docker Compose with Caddy
|
### Docker Compose with Caddy
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ Example `Caddyfile`:
|
|||||||
|
|
||||||
```
|
```
|
||||||
kandev.example.com {
|
kandev.example.com {
|
||||||
reverse_proxy kandev:8080
|
reverse_proxy kandev:38429
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ kandev.example.com {
|
|||||||
By default, `KANDEV_DOCKER_ENABLED=false` inside the container. To enable Docker-based agent execution, mount the Docker socket:
|
By default, `KANDEV_DOCKER_ENABLED=false` inside the container. To enable Docker-based agent execution, mount the Docker socket:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker run -p 8080:8080 \
|
docker run -p 38429:38429 \
|
||||||
-v kandev-data:/data \
|
-v kandev-data:/data \
|
||||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
-e KANDEV_DOCKER_ENABLED=true \
|
-e KANDEV_DOCKER_ENABLED=true \
|
||||||
@@ -224,14 +224,14 @@ docker run -p 8080:8080 \
|
|||||||
The backend exposes a `/health` endpoint:
|
The backend exposes a `/health` endpoint:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl http://localhost:8080/health
|
curl http://localhost:38429/health
|
||||||
```
|
```
|
||||||
|
|
||||||
For Docker health checks in compose:
|
For Docker health checks in compose:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
test: ["CMD", "curl", "-f", "http://localhost:38429/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
|||||||
+5
-5
@@ -56,7 +56,7 @@ kubectl logs -l app=kandev -f
|
|||||||
| Resource | File | Purpose |
|
| Resource | File | Purpose |
|
||||||
|----------|------|---------|
|
|----------|------|---------|
|
||||||
| Deployment | `deployment.yaml` | Single-replica pod running backend + web |
|
| Deployment | `deployment.yaml` | Single-replica pod running backend + web |
|
||||||
| Service | `service.yaml` | ClusterIP exposing port 8080 |
|
| Service | `service.yaml` | ClusterIP exposing port 38429 |
|
||||||
| ConfigMap | `configmap.yaml` | Non-sensitive environment configuration |
|
| ConfigMap | `configmap.yaml` | Non-sensitive environment configuration |
|
||||||
| PVC | `pvc.yaml` | 10Gi persistent volume for SQLite + worktrees |
|
| PVC | `pvc.yaml` | 10Gi persistent volume for SQLite + worktrees |
|
||||||
| Ingress | `ingress.yaml` | Example ingress with WebSocket support |
|
| Ingress | `ingress.yaml` | Example ingress with WebSocket support |
|
||||||
@@ -66,11 +66,11 @@ kubectl logs -l app=kandev -f
|
|||||||
**Port-forward** (quickest for testing):
|
**Port-forward** (quickest for testing):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
kubectl port-forward svc/kandev 8080:8080
|
kubectl port-forward svc/kandev 38429:38429
|
||||||
# Open http://localhost:8080
|
# Open http://localhost:38429
|
||||||
```
|
```
|
||||||
|
|
||||||
**Ingress**: Edit `k8s/ingress.yaml` to set your domain, then apply. The ingress routes all traffic to the backend on port 8080 (the Go backend reverse-proxies the Next.js frontend internally).
|
**Ingress**: Edit `k8s/ingress.yaml` to set your domain, then apply. The ingress routes all traffic to the backend on port 38429 (the Go backend reverse-proxies the Next.js frontend internally).
|
||||||
|
|
||||||
### Custom Domain / Reverse Proxy
|
### Custom Domain / Reverse Proxy
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ Kandev reads configuration via `KANDEV_`-prefixed environment variables (Viper).
|
|||||||
|
|
||||||
| Env Var | Default | Description |
|
| Env Var | Default | Description |
|
||||||
|---------|---------|-------------|
|
|---------|---------|-------------|
|
||||||
| `KANDEV_SERVER_PORT` | `8080` | Server port (API + WebSocket + Web UI) |
|
| `KANDEV_SERVER_PORT` | `38429` | Server port (API + WebSocket + Web UI) |
|
||||||
| `KANDEV_HOME_DIR` | `/data` | Kandev home directory — contains `data/` (DB), `tasks/`, `worktrees/`, `repos/`, `sessions/`, and `lsp-servers/` |
|
| `KANDEV_HOME_DIR` | `/data` | Kandev home directory — contains `data/` (DB), `tasks/`, `worktrees/`, `repos/`, `sessions/`, and `lsp-servers/` |
|
||||||
| `KANDEV_DATABASE_DRIVER` | `sqlite` | Database driver (`sqlite` or `postgres`) |
|
| `KANDEV_DATABASE_DRIVER` | `sqlite` | Database driver (`sqlite` or `postgres`) |
|
||||||
| `KANDEV_DATABASE_PATH` | `$KANDEV_HOME_DIR/data/kandev.db` | SQLite database file path (override) |
|
| `KANDEV_DATABASE_PATH` | `$KANDEV_HOME_DIR/data/kandev.db` | SQLite database file path (override) |
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ spec:
|
|||||||
image: kandev:latest
|
image: kandev:latest
|
||||||
ports:
|
ports:
|
||||||
- name: backend
|
- name: backend
|
||||||
containerPort: 8080
|
containerPort: 38429
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
|
|||||||
+1
-1
@@ -10,6 +10,6 @@ spec:
|
|||||||
app: kandev
|
app: kandev
|
||||||
ports:
|
ports:
|
||||||
- name: http
|
- name: http
|
||||||
port: 8080
|
port: 38429
|
||||||
targetPort: backend
|
targetPort: backend
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
|
|||||||
Reference in New Issue
Block a user