feat(workload): write-through workload sync + boot-time backfill
CRUD on Project / Stack / StaticSite now keeps a paired Workload row in sync. Secret setters (webhook secret, signing secret, require-signature toggle, notification secret) all re-sync after mutating the source-of-truth row so the workload row always reflects the canonical state. Delete cascades: DeleteProject/Stack/StaticSite now drop the matching workload row plus any container index entries owned by it, so global views don't show ghost rows. Boot-time BackfillWorkloads scans every project/stack/site and ensures each has a workload row. Idempotent — safe to run on every restart, recovers from a deleted/missing workload row. Behavior unchanged for existing call sites; the workloads table just starts being populated. Deployer / reconciler / consumer switchover land in the next commit.
This commit is contained in:
@@ -45,6 +45,9 @@ func (s *Store) CreateStaticSite(site StaticSite) (StaticSite, error) {
|
||||
if err != nil {
|
||||
return StaticSite{}, fmt.Errorf("insert static site: %w", err)
|
||||
}
|
||||
if err := s.SyncStaticSiteWorkload(site); err != nil {
|
||||
return StaticSite{}, fmt.Errorf("sync static site workload: %w", err)
|
||||
}
|
||||
return site, nil
|
||||
}
|
||||
|
||||
@@ -131,7 +134,11 @@ func (s *Store) UpdateStaticSite(site StaticSite) error {
|
||||
if n == 0 {
|
||||
return fmt.Errorf("static site %s: %w", site.ID, ErrNotFound)
|
||||
}
|
||||
return nil
|
||||
current, err := s.GetStaticSiteByID(site.ID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reread static site for workload sync: %w", err)
|
||||
}
|
||||
return s.SyncStaticSiteWorkload(current)
|
||||
}
|
||||
|
||||
// UpdateStaticSiteStatus updates the deployment status fields.
|
||||
@@ -214,6 +221,7 @@ func (s *Store) ListStaticSiteProxyRoutes(domain string) ([]ProxyRoute, error) {
|
||||
}
|
||||
|
||||
// DeleteStaticSite removes a static site by ID. Cascading deletes handle secrets.
|
||||
// Workload row + container index entries are removed too.
|
||||
func (s *Store) DeleteStaticSite(id string) error {
|
||||
result, err := s.db.Exec(`DELETE FROM static_sites WHERE id = ?`, id)
|
||||
if err != nil {
|
||||
@@ -223,6 +231,14 @@ func (s *Store) DeleteStaticSite(id string) error {
|
||||
if n == 0 {
|
||||
return fmt.Errorf("static site %s: %w", id, ErrNotFound)
|
||||
}
|
||||
if w, err := s.GetWorkloadByRef(WorkloadKindSite, id); err == nil {
|
||||
if err := s.DeleteContainersByWorkload(w.ID); err != nil {
|
||||
return fmt.Errorf("delete static site containers: %w", err)
|
||||
}
|
||||
if err := s.DeleteWorkload(w.ID); err != nil {
|
||||
return fmt.Errorf("delete static site workload: %w", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -286,7 +302,11 @@ func (s *Store) SetStaticSiteWebhookSigningSecret(id, secret string) error {
|
||||
if n == 0 {
|
||||
return fmt.Errorf("static site %s: %w", id, ErrNotFound)
|
||||
}
|
||||
return nil
|
||||
current, err := s.GetStaticSiteByID(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reread static site for workload sync: %w", err)
|
||||
}
|
||||
return s.SyncStaticSiteWorkload(current)
|
||||
}
|
||||
|
||||
// SetStaticSiteWebhookRequireSignature toggles whether unsigned (or
|
||||
@@ -307,7 +327,11 @@ func (s *Store) SetStaticSiteWebhookRequireSignature(id string, require bool) er
|
||||
if n == 0 {
|
||||
return fmt.Errorf("static site %s: %w", id, ErrNotFound)
|
||||
}
|
||||
return nil
|
||||
current, err := s.GetStaticSiteByID(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reread static site for workload sync: %w", err)
|
||||
}
|
||||
return s.SyncStaticSiteWorkload(current)
|
||||
}
|
||||
|
||||
// SetStaticSiteNotificationSecret rotates the static site's outgoing-webhook
|
||||
@@ -325,7 +349,11 @@ func (s *Store) SetStaticSiteNotificationSecret(id, secret string) error {
|
||||
if n == 0 {
|
||||
return fmt.Errorf("static site %s: %w", id, ErrNotFound)
|
||||
}
|
||||
return nil
|
||||
current, err := s.GetStaticSiteByID(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reread static site for workload sync: %w", err)
|
||||
}
|
||||
return s.SyncStaticSiteWorkload(current)
|
||||
}
|
||||
|
||||
// EnsureStaticSiteNotificationSecret returns the static site's outgoing-webhook
|
||||
@@ -394,7 +422,11 @@ func (s *Store) SetStaticSiteWebhookSecret(id, secret string) error {
|
||||
if n == 0 {
|
||||
return fmt.Errorf("static site %s: %w", id, ErrNotFound)
|
||||
}
|
||||
return nil
|
||||
current, err := s.GetStaticSiteByID(id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("reread static site for workload sync: %w", err)
|
||||
}
|
||||
return s.SyncStaticSiteWorkload(current)
|
||||
}
|
||||
|
||||
// EnsureStaticSiteWebhookSecret returns the current webhook secret for a site,
|
||||
|
||||
Reference in New Issue
Block a user