feat: auto-cleanup articles > 30d and relocate AI summary to reader view

This commit is contained in:
Michael committed 2026-02-09 11:49:54 +01:00
1 parent b3cbaf741d
commit c4cc7eaf87
5 files changed
+136 -10

No files matched your search

+17
View File
@@ -521,6 +521,23 @@ func (r *ArticleRepository) UpdateAISummary(id uuid.UUID, summary string) error
return nil
}
// DeleteOldArticles removes articles older than the specified duration, except for favorites.
func (r *ArticleRepository) DeleteOldArticles(ctx context.Context, olderThan time.Duration) (int64, error) {
threshold := time.Now().Add(-olderThan)
query := `
DELETE FROM articles
WHERE created_at < $1 AND is_favorite = false
`
result, err := r.pool.Exec(ctx, query, threshold)
if err != nil {
return 0, fmt.Errorf("deleting old articles: %w", err)
}
return result.RowsAffected(), nil
}
// nullString returns nil if string is empty.
func nullString(s string) *string {
if s == "" {
+76
View File
@@ -0,0 +1,76 @@
package worker
import (
"context"
"log"
"sync"
"time"
"github.com/michael/flowreader/internal/repository"
)
// Cleaner handles periodic database maintenance.
type Cleaner struct {
repo *repository.ArticleRepository
interval time.Duration
stopCh chan struct{}
wg sync.WaitGroup
}
// NewCleaner creates a new database cleaner worker.
func NewCleaner(repo *repository.ArticleRepository, interval time.Duration) *Cleaner {
return &Cleaner{
repo: repo,
interval: interval,
stopCh: make(chan struct{}),
}
}
// Start begins the background maintenance loop.
func (c *Cleaner) Start() {
c.wg.Add(1)
go c.run()
log.Printf("Maintenance worker started (interval: %s)", c.interval)
}
// Stop gracefully stops the cleaner.
func (c *Cleaner) Stop() {
close(c.stopCh)
c.wg.Wait()
log.Println("Maintenance worker stopped")
}
func (c *Cleaner) run() {
defer c.wg.Done()
// Initial cleanup on startup
c.cleanup()
ticker := time.NewTicker(c.interval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
c.cleanup()
case <-c.stopCh:
return
}
}
}
func (c *Cleaner) cleanup() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
// Delete articles older than 30 days
count, err := c.repo.DeleteOldArticles(ctx, 30*24*time.Hour)
if err != nil {
log.Printf("Maintenance cleanup error: %v", err)
return
}
if count > 0 {
log.Printf("Maintenance: cleaned up %d old articles", count)
}
}