Fix demo site auto-enhancement and content persistence

- Restructure demo directory from test-sites/ to demos/ with flattened layout
- Add auto-enhancement on server startup for all sites with auto_enhance: true
- Fix inconsistent content ID generation that prevented dan-eden-portfolio content persistence
- Update server configuration to enhance from source to separate output directories
- Remove manual enhancement from justfile in favor of automatic server enhancement
- Clean up legacy test files and unused restore command
- Update build system to use CDN endpoint instead of file copying
This commit is contained in:
2025-09-17 00:07:40 +02:00
parent 1fa607c47c
commit 71561316da
73 changed files with 190 additions and 4827 deletions

View File

@@ -192,6 +192,11 @@ func (e *Enhancer) enhanceWithEngine(htmlContent []byte, filePath string) ([]byt
return []byte(buf.String()), nil
}
// SetSiteID sets the site ID for the enhancer
func (e *Enhancer) SetSiteID(siteID string) {
e.siteID = siteID
}
// EnhanceInPlace performs in-place enhancement of static site files
func (e *Enhancer) EnhanceInPlace(sitePath string, siteID string) error {
// Use the provided siteID (derivation should happen at CLI level)
@@ -204,7 +209,7 @@ func (e *Enhancer) EnhanceInPlace(sitePath string, siteID string) error {
// DeriveOrValidateSiteID automatically derives site_id for demo paths or validates for production
func DeriveOrValidateSiteID(sitePath string, configSiteID string) string {
// Check if this is a demo path
if strings.Contains(sitePath, "/demos/") {
if strings.Contains(sitePath, "/demos/") || strings.Contains(sitePath, "./demos/") {
return deriveDemoSiteID(sitePath)
}
@@ -222,10 +227,10 @@ func deriveDemoSiteID(sitePath string) string {
}
absPath = filepath.Clean(absPath)
// Look for patterns in demo paths:
// demos/demo-site_enhanced -> "demo"
// demos/simple/test-simple_enhanced -> "simple"
// demos/simple/dan-eden-portfolio -> "dan-eden"
// Flattened structure - just use directory name after demos/
// demos/default -> "default"
// demos/simple -> "simple"
// demos/dan-eden-portfolio -> "dan-eden-portfolio"
parts := strings.Split(absPath, string(filepath.Separator))
@@ -240,41 +245,14 @@ func deriveDemoSiteID(sitePath string) string {
if demosIndex == -1 || demosIndex >= len(parts)-1 {
// Fallback if demos not found in path
return "demo"
return "default"
}
// Get the segment after demos/
nextSegment := parts[demosIndex+1]
// Get the segment after demos/ and clean it
dirName := parts[demosIndex+1]
dirName = strings.TrimSuffix(dirName, "_enhanced")
// Handle different demo directory patterns:
if strings.HasPrefix(nextSegment, "demo-site") {
return "demo"
}
if nextSegment == "simple" && len(parts) > demosIndex+2 {
// For demos/simple/something, use the something part
finalSegment := parts[demosIndex+2]
// Extract meaningful name from directory
if strings.HasPrefix(finalSegment, "test-") {
// test-simple_enhanced -> simple
return "simple"
}
if strings.Contains(finalSegment, "dan-eden") {
return "dan-eden"
}
// Generic case: use the directory name as-is
return strings.TrimSuffix(finalSegment, "_enhanced")
}
// Default case: use the immediate subdirectory of demos/
result := strings.TrimSuffix(nextSegment, "_enhanced")
// Clean up common suffixes
result = strings.TrimSuffix(result, "-site")
return result
return dirName
}
// copyFile copies a file from src to dst

View File

@@ -5,41 +5,35 @@ import (
"log"
"os"
"path/filepath"
"strings"
"sync"
"time"
"github.com/insertr/insertr/internal/engine"
)
// SiteConfig represents configuration for a registered site
type SiteConfig struct {
SiteID string `yaml:"site_id"`
Path string `yaml:"path"`
Domain string `yaml:"domain,omitempty"`
AutoEnhance bool `yaml:"auto_enhance"`
BackupOriginals bool `yaml:"backup_originals"`
SiteID string `yaml:"site_id"`
Path string `yaml:"path"` // Served path (enhanced output)
SourcePath string `yaml:"source_path"` // Source path (for enhancement)
Domain string `yaml:"domain,omitempty"`
AutoEnhance bool `yaml:"auto_enhance"`
}
// SiteManager handles registration and enhancement of static sites
type SiteManager struct {
sites map[string]*SiteConfig
enhancer *Enhancer
mutex sync.RWMutex
backupDir string
devMode bool
sites map[string]*SiteConfig
enhancer *Enhancer
mutex sync.RWMutex
devMode bool
}
// NewSiteManager creates a new site manager
func NewSiteManager(contentClient engine.ContentClient, backupDir string, devMode bool) *SiteManager {
if backupDir == "" {
backupDir = "./insertr-backups"
}
func NewSiteManager(contentClient engine.ContentClient, devMode bool) *SiteManager {
return &SiteManager{
sites: make(map[string]*SiteConfig),
enhancer: NewDefaultEnhancer(contentClient, ""), // siteID will be set per operation
backupDir: backupDir,
devMode: devMode,
sites: make(map[string]*SiteConfig),
enhancer: NewDefaultEnhancer(contentClient, ""), // siteID will be set per operation
devMode: devMode,
}
}
@@ -56,9 +50,17 @@ func (sm *SiteManager) RegisterSite(config *SiteConfig) error {
return fmt.Errorf("path is required for site %s", config.SiteID)
}
// Check if path exists
// Check if path exists, auto-create enhancement directories
if _, err := os.Stat(config.Path); os.IsNotExist(err) {
return fmt.Errorf("site path does not exist: %s", config.Path)
// Auto-create directory if it appears to be an enhancement target
if strings.HasSuffix(config.Path, "_enhanced") {
log.Printf("📁 Creating enhancement directory: %s", config.Path)
if err := os.MkdirAll(config.Path, 0755); err != nil {
return fmt.Errorf("failed to create enhancement directory %s: %w", config.Path, err)
}
} else {
return fmt.Errorf("site path does not exist: %s", config.Path)
}
}
// Convert to absolute path
@@ -115,7 +117,7 @@ func (sm *SiteManager) IsAutoEnhanceEnabled(siteID string) bool {
return exists && site.AutoEnhance
}
// EnhanceSite performs in-place enhancement of a registered site
// EnhanceSite performs enhancement from source to output directory
func (sm *SiteManager) EnhanceSite(siteID string) error {
sm.mutex.RLock()
site, exists := sm.sites[siteID]
@@ -125,18 +127,25 @@ func (sm *SiteManager) EnhanceSite(siteID string) error {
return fmt.Errorf("site %s is not registered", siteID)
}
log.Printf("🔄 Enhancing site %s at %s", siteID, site.Path)
// Use source path if available, otherwise use main path (for backwards compatibility)
sourcePath := site.SourcePath
if sourcePath == "" {
sourcePath = site.Path
}
outputPath := site.Path
// Create backup if enabled
if site.BackupOriginals {
if err := sm.createBackup(siteID, site.Path); err != nil {
log.Printf("⚠️ Failed to create backup for site %s: %v", siteID, err)
// Continue with enhancement even if backup fails
}
log.Printf("🔄 Enhancing site %s from %s to %s", siteID, sourcePath, outputPath)
// Create output directory if it doesn't exist
if err := os.MkdirAll(outputPath, 0755); err != nil {
return fmt.Errorf("failed to create output directory %s: %w", outputPath, err)
}
// Perform in-place enhancement
if err := sm.enhancer.EnhanceInPlace(site.Path, siteID); err != nil {
// Set site ID on enhancer
sm.enhancer.SetSiteID(siteID)
// Perform enhancement from source to output
if err := sm.enhancer.EnhanceDirectory(sourcePath, outputPath); err != nil {
return fmt.Errorf("failed to enhance site %s: %w", siteID, err)
}
@@ -169,121 +178,6 @@ func (sm *SiteManager) EnhanceAllSites() error {
return nil
}
// createBackup creates a timestamped backup of the site
func (sm *SiteManager) createBackup(siteID, sitePath string) error {
// Create backup directory structure
timestamp := time.Now().Format("20060102-150405")
backupPath := filepath.Join(sm.backupDir, siteID, timestamp)
if err := os.MkdirAll(backupPath, 0755); err != nil {
return fmt.Errorf("failed to create backup directory: %w", err)
}
// Copy HTML files to backup
return filepath.Walk(sitePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
// Only backup HTML files
if !info.IsDir() && filepath.Ext(path) == ".html" {
relPath, err := filepath.Rel(sitePath, path)
if err != nil {
return err
}
backupFilePath := filepath.Join(backupPath, relPath)
// Create directory structure in backup
if err := os.MkdirAll(filepath.Dir(backupFilePath), 0755); err != nil {
return err
}
// Copy file
content, err := os.ReadFile(path)
if err != nil {
return err
}
return os.WriteFile(backupFilePath, content, info.Mode())
}
return nil
})
}
// RestoreFromBackup restores a site from a specific backup
func (sm *SiteManager) RestoreFromBackup(siteID, timestamp string) error {
sm.mutex.RLock()
site, exists := sm.sites[siteID]
sm.mutex.RUnlock()
if !exists {
return fmt.Errorf("site %s is not registered", siteID)
}
backupPath := filepath.Join(sm.backupDir, siteID, timestamp)
if _, err := os.Stat(backupPath); os.IsNotExist(err) {
return fmt.Errorf("backup not found: %s", backupPath)
}
log.Printf("🔄 Restoring site %s from backup %s", siteID, timestamp)
// Copy backup files back to site directory
return filepath.Walk(backupPath, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
relPath, err := filepath.Rel(backupPath, path)
if err != nil {
return err
}
targetPath := filepath.Join(site.Path, relPath)
// Create directory structure
if err := os.MkdirAll(filepath.Dir(targetPath), 0755); err != nil {
return err
}
// Copy file
content, err := os.ReadFile(path)
if err != nil {
return err
}
return os.WriteFile(targetPath, content, info.Mode())
}
return nil
})
}
// ListBackups returns available backups for a site
func (sm *SiteManager) ListBackups(siteID string) ([]string, error) {
backupSitePath := filepath.Join(sm.backupDir, siteID)
if _, err := os.Stat(backupSitePath); os.IsNotExist(err) {
return []string{}, nil // No backups exist
}
entries, err := os.ReadDir(backupSitePath)
if err != nil {
return nil, fmt.Errorf("failed to read backup directory: %w", err)
}
var backups []string
for _, entry := range entries {
if entry.IsDir() {
backups = append(backups, entry.Name())
}
}
return backups, nil
}
// GetStats returns statistics about registered sites
func (sm *SiteManager) GetStats() map[string]interface{} {
sm.mutex.RLock()
@@ -299,6 +193,5 @@ func (sm *SiteManager) GetStats() map[string]interface{} {
return map[string]interface{}{
"total_sites": len(sm.sites),
"auto_enhance_sites": autoEnhanceCount,
"backup_directory": sm.backupDir,
}
}