refactor: extract ProxyProvider interface with None and NPM implementations

Replace direct npm.Client usage throughout the codebase with the
proxy.Provider interface, enabling pluggable proxy backends. The
deployer, API layer, and proxy manager now use provider-agnostic
route management (ConfigureRoute/DeleteRoute) instead of NPM-specific
API calls. Adds ProxyRouteID (string) to Instance model and
ProxyProvider setting to Settings, with SQLite migrations for
backward compatibility.
This commit is contained in:
2026-04-04 19:39:08 +03:00
parent 6667abf03c
commit 7d6719da12
17 changed files with 365 additions and 249 deletions
+8 -8
View File
@@ -9,14 +9,14 @@ import (
)
// instanceColumns is the canonical column list for instance queries.
const instanceColumns = `id, stage_id, project_id, container_id, image_tag, subdomain, npm_proxy_id, status, port, last_alive_at, created_at, updated_at`
const instanceColumns = `id, stage_id, project_id, container_id, image_tag, subdomain, npm_proxy_id, proxy_route_id, status, port, last_alive_at, created_at, updated_at`
// scanInstance scans a row into an Instance struct using the canonical column order.
func scanInstance(scanner interface{ Scan(...any) error }) (Instance, error) {
var inst Instance
err := scanner.Scan(
&inst.ID, &inst.StageID, &inst.ProjectID, &inst.ContainerID, &inst.ImageTag,
&inst.Subdomain, &inst.NpmProxyID, &inst.Status, &inst.Port,
&inst.Subdomain, &inst.NpmProxyID, &inst.ProxyRouteID, &inst.Status, &inst.Port,
&inst.LastAliveAt, &inst.CreatedAt, &inst.UpdatedAt,
)
return inst, err
@@ -30,9 +30,9 @@ func (s *Store) CreateInstance(inst Instance) (Instance, error) {
_, err := s.db.Exec(
`INSERT INTO instances (`+instanceColumns+`)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
inst.ID, inst.StageID, inst.ProjectID, inst.ContainerID, inst.ImageTag,
inst.Subdomain, inst.NpmProxyID, inst.Status, inst.Port,
inst.Subdomain, inst.NpmProxyID, inst.ProxyRouteID, inst.Status, inst.Port,
inst.LastAliveAt, inst.CreatedAt, inst.UpdatedAt,
)
if err != nil {
@@ -52,9 +52,9 @@ func (s *Store) CreateInstanceWithID(inst Instance) (Instance, error) {
_, err := s.db.Exec(
`INSERT INTO instances (`+instanceColumns+`)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
inst.ID, inst.StageID, inst.ProjectID, inst.ContainerID, inst.ImageTag,
inst.Subdomain, inst.NpmProxyID, inst.Status, inst.Port,
inst.Subdomain, inst.NpmProxyID, inst.ProxyRouteID, inst.Status, inst.Port,
inst.LastAliveAt, inst.CreatedAt, inst.UpdatedAt,
)
if err != nil {
@@ -123,10 +123,10 @@ func (s *Store) ListAllInstances() ([]Instance, error) {
func (s *Store) UpdateInstance(inst Instance) error {
inst.UpdatedAt = Now()
result, err := s.db.Exec(
`UPDATE instances SET stage_id=?, project_id=?, container_id=?, image_tag=?, subdomain=?, npm_proxy_id=?, status=?, port=?, last_alive_at=?, updated_at=?
`UPDATE instances SET stage_id=?, project_id=?, container_id=?, image_tag=?, subdomain=?, npm_proxy_id=?, proxy_route_id=?, status=?, port=?, last_alive_at=?, updated_at=?
WHERE id=?`,
inst.StageID, inst.ProjectID, inst.ContainerID, inst.ImageTag,
inst.Subdomain, inst.NpmProxyID, inst.Status, inst.Port,
inst.Subdomain, inst.NpmProxyID, inst.ProxyRouteID, inst.Status, inst.Port,
inst.LastAliveAt, inst.UpdatedAt, inst.ID,
)
if err != nil {
+5 -3
View File
@@ -63,6 +63,7 @@ type Settings struct {
DNSProvider string `json:"dns_provider"`
CloudflareAPIToken string `json:"cloudflare_api_token"`
CloudflareZoneID string `json:"cloudflare_zone_id"`
ProxyProvider string `json:"proxy_provider"`
BackupEnabled bool `json:"backup_enabled"`
BackupIntervalHours int `json:"backup_interval_hours"`
BackupRetentionCount int `json:"backup_retention_count"`
@@ -97,9 +98,10 @@ type Instance struct {
ContainerID string `json:"container_id"`
ImageTag string `json:"image_tag"`
Subdomain string `json:"subdomain"`
NpmProxyID int `json:"npm_proxy_id"`
Status string `json:"status"` // running, stopped, failed, removing
Port int `json:"port"`
NpmProxyID int `json:"npm_proxy_id"`
ProxyRouteID string `json:"proxy_route_id"`
Status string `json:"status"` // running, stopped, failed, removing
Port int `json:"port"`
LastAliveAt string `json:"last_alive_at"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
+4
View File
@@ -14,6 +14,7 @@ func (s *Store) GetSettings() (Settings, error) {
base_volume_path, ssl_certificate_id, stale_threshold_days,
allowed_volume_paths, wildcard_dns, dns_provider,
cloudflare_api_token, cloudflare_zone_id,
proxy_provider,
backup_enabled, backup_interval_hours, backup_retention_count,
updated_at
FROM settings WHERE id = 1`,
@@ -22,6 +23,7 @@ func (s *Store) GetSettings() (Settings, error) {
&st.BaseVolumePath, &st.SSLCertificateID, &st.StaleThresholdDays,
&st.AllowedVolumePaths, &wildcardDNS, &st.DNSProvider,
&st.CloudflareAPIToken, &st.CloudflareZoneID,
&st.ProxyProvider,
&backupEnabled, &st.BackupIntervalHours, &st.BackupRetentionCount,
&st.UpdatedAt)
if err != nil {
@@ -50,6 +52,7 @@ func (s *Store) UpdateSettings(st Settings) error {
base_volume_path=?, ssl_certificate_id=?, stale_threshold_days=?,
allowed_volume_paths=?, wildcard_dns=?, dns_provider=?,
cloudflare_api_token=?, cloudflare_zone_id=?,
proxy_provider=?,
backup_enabled=?, backup_interval_hours=?, backup_retention_count=?,
updated_at=?
WHERE id = 1`,
@@ -58,6 +61,7 @@ func (s *Store) UpdateSettings(st Settings) error {
st.BaseVolumePath, st.SSLCertificateID, st.StaleThresholdDays,
st.AllowedVolumePaths, wildcardDNS, st.DNSProvider,
st.CloudflareAPIToken, st.CloudflareZoneID,
st.ProxyProvider,
backupEnabled, st.BackupIntervalHours, st.BackupRetentionCount,
st.UpdatedAt,
)
+4
View File
@@ -100,6 +100,10 @@ func (s *Store) runMigrations() error {
`ALTER TABLE settings ADD COLUMN backup_interval_hours INTEGER NOT NULL DEFAULT 24`,
`ALTER TABLE settings ADD COLUMN backup_retention_count INTEGER NOT NULL DEFAULT 10`,
`ALTER TABLE stages ADD COLUMN notification_url TEXT NOT NULL DEFAULT ''`,
// Add proxy_route_id to instances for provider-agnostic route tracking (2026-04-04).
`ALTER TABLE instances ADD COLUMN proxy_route_id TEXT NOT NULL DEFAULT ''`,
// Add proxy_provider to settings (2026-04-04). Default to npm for backward compat.
`ALTER TABLE settings ADD COLUMN proxy_provider TEXT NOT NULL DEFAULT 'npm'`,
}
for _, m := range migrations {