From e62498ba0582ec2f63c2a82898a2b830785eec21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Sun, 8 Mar 2026 11:25:21 +0000 Subject: [PATCH] fix: correct default data directory to ~/.kandev/data (#389) --- apps/backend/internal/common/config/config.go | 8 +++---- .../internal/common/config/config_test.go | 2 +- .../internal/common/portutil/portutil_test.go | 21 +++++++++++++------ docs/db.md | 4 ++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/backend/internal/common/config/config.go b/apps/backend/internal/common/config/config.go index 4a6aa4d801..82cf47c5a1 100644 --- a/apps/backend/internal/common/config/config.go +++ b/apps/backend/internal/common/config/config.go @@ -31,7 +31,7 @@ type Config struct { // ResolvedDataDir returns the base data directory for Kandev. // Config.DataDir is populated by Viper from the config file or KANDEV_DATA_DIR env var. -// If empty, falls back to ~/.kandev. +// If empty, falls back to ~/.kandev/data. func (c *Config) ResolvedDataDir() string { if c.DataDir != "" { if strings.HasPrefix(c.DataDir, "~/") { @@ -43,9 +43,9 @@ func (c *Config) ResolvedDataDir() string { } home, err := os.UserHomeDir() if err != nil { - return ".kandev" + return filepath.Join(".kandev", "data") } - return filepath.Join(home, ".kandev") + return filepath.Join(home, ".kandev", "data") } // ServerConfig holds HTTP server configuration. @@ -198,7 +198,7 @@ func setDefaults(v *viper.Viper) { v.SetDefault("server.readTimeout", 30) v.SetDefault("server.writeTimeout", 30) - // DataDir default — empty means resolve from KANDEV_DATA_DIR env or ~/.kandev + // DataDir default — empty means resolve from KANDEV_DATA_DIR env or ~/.kandev/data v.SetDefault("dataDir", "") // Database defaults diff --git a/apps/backend/internal/common/config/config_test.go b/apps/backend/internal/common/config/config_test.go index 7a2456d21b..12c2b194ae 100644 --- a/apps/backend/internal/common/config/config_test.go +++ b/apps/backend/internal/common/config/config_test.go @@ -19,7 +19,7 @@ func TestResolvedDataDir_FallbackToHome(t *testing.T) { if err != nil { t.Skip("cannot determine home directory") } - want := filepath.Join(home, ".kandev") + want := filepath.Join(home, ".kandev", "data") if got := cfg.ResolvedDataDir(); got != want { t.Errorf("ResolvedDataDir() = %q, want %q", got, want) } diff --git a/apps/backend/internal/common/portutil/portutil_test.go b/apps/backend/internal/common/portutil/portutil_test.go index 5e54a7f819..9768e34192 100644 --- a/apps/backend/internal/common/portutil/portutil_test.go +++ b/apps/backend/internal/common/portutil/portutil_test.go @@ -1,6 +1,7 @@ package portutil import ( + "net" "strings" "testing" ) @@ -19,15 +20,23 @@ func TestAllocatePort(t *testing.T) { } func TestAllocatePortUniqueness(t *testing.T) { - // Allocate multiple ports and ensure they're different + // Hold all listeners open to prevent the OS from reassigning freed ports. ports := make(map[int]bool) - for i := 0; i < 10; i++ { - port, err := AllocatePort() - if err != nil { - t.Fatalf("AllocatePort() failed on iteration %d: %v", i, err) + listeners := make([]net.Listener, 0, 10) + defer func() { + for _, l := range listeners { + _ = l.Close() } + }() + for i := 0; i < 10; i++ { + l, err := net.Listen("tcp", ":0") + if err != nil { + t.Fatalf("Listen failed on iteration %d: %v", i, err) + } + listeners = append(listeners, l) + port := l.Addr().(*net.TCPAddr).Port if ports[port] { - t.Errorf("AllocatePort() returned duplicate port: %d", port) + t.Errorf("duplicate port: %d", port) } ports[port] = true } diff --git a/docs/db.md b/docs/db.md index c8bd548cbd..e09dd051dc 100644 --- a/docs/db.md +++ b/docs/db.md @@ -10,14 +10,14 @@ SQLite requires no external services and works out of the box. | Variable | Default | Description | |----------|---------|-------------| -| `KANDEV_DATA_DIR` | `~/.kandev` | Base directory for all data (DB, worktrees, sessions, etc.) | +| `KANDEV_DATA_DIR` | `~/.kandev/data` | Base directory for all data (DB, worktrees, sessions, etc.) | | `KANDEV_DATABASE_DRIVER` | `sqlite` | Database driver | | `KANDEV_DATABASE_PATH` | `$KANDEV_DATA_DIR/kandev.db` | Path to the SQLite database file (override) | ### Config file (`config.yaml`) ```yaml -dataDir: "" # empty = resolve from KANDEV_DATA_DIR or ~/.kandev +dataDir: "" # empty = resolve from KANDEV_DATA_DIR or ~/.kandev/data database: driver: sqlite path: "" # empty = $dataDir/kandev.db