feat: complete HTML-first architecture implementation (Phase 1 & 2)

Major architectural simplification removing content type complexity:

Database Schema:
- Remove 'type' field from content and content_versions tables
- Simplify to pure HTML storage with html_content + original_template
- Regenerate all sqlc models for SQLite and PostgreSQL

API Simplification:
- Remove content type routing and validation
- Eliminate type-specific handlers (text/markdown/structured)
- Unified HTML-first approach for all content operations
- Simplify CreateContent and UpdateContent to HTML-only

Backend Enhancements:
- Update enhancer to only generate data-content-id (no data-content-type)
- Improve container expansion utilities with comprehensive block/inline rules
- Add Phase 3 preparation with boundary-respecting traversal logic
- Strengthen element classification for viable children detection

Documentation:
- Update TODO.md to reflect Phase 1-3 completion status
- Add WORKING_ON.md documenting the architectural transformation
- Mark container expansion and HTML-first architecture as complete

This completes the transition to a unified HTML-first content management system
with automatic style detection and element-based behavior, eliminating the
complex multi-type system in favor of semantic HTML-driven editing.
This commit is contained in:
2025-09-21 19:23:54 +02:00
parent b5e601d09f
commit b75eda2a87
25 changed files with 470 additions and 214 deletions

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"github.com/spf13/cobra"
@@ -15,11 +16,14 @@ import (
)
var enhanceCmd = &cobra.Command{
Use: "enhance [input-dir]",
Use: "enhance [input-path]",
Short: "Enhance HTML files by injecting content from database",
Long: `Enhance processes HTML files and injects latest content from the database
while adding editing capabilities. This is the core build-time enhancement
process that transforms static HTML into an editable CMS.`,
process that transforms static HTML into an editable CMS.
The input can be either a directory (to enhance all HTML files) or a single
HTML file. Non-HTML files in directories are copied as-is.`,
Args: cobra.ExactArgs(1),
Run: runEnhance,
}
@@ -36,11 +40,23 @@ func init() {
}
func runEnhance(cmd *cobra.Command, args []string) {
inputDir := args[0]
inputPath := args[0]
// Validate input directory
if _, err := os.Stat(inputDir); os.IsNotExist(err) {
log.Fatalf("Input directory does not exist: %s", inputDir)
// Validate input path and determine if it's a file or directory
inputStat, err := os.Stat(inputPath)
if os.IsNotExist(err) {
log.Fatalf("Input path does not exist: %s", inputPath)
}
if err != nil {
log.Fatalf("Error accessing input path: %v", err)
}
isFile := !inputStat.IsDir()
if isFile {
// Validate that single files are HTML files
if !strings.HasSuffix(strings.ToLower(inputPath), ".html") {
log.Fatalf("Single file input must be an HTML file (.html extension): %s", inputPath)
}
}
// Get configuration values
@@ -51,9 +67,9 @@ func runEnhance(cmd *cobra.Command, args []string) {
outputDir := viper.GetString("cli.output")
// Auto-derive site_id for demo paths or validate for production
if strings.Contains(inputDir, "/demos/") || strings.Contains(inputDir, "./demos/") {
if strings.Contains(inputPath, "/demos/") || strings.Contains(inputPath, "./demos/") {
// Auto-derive site_id from demo path
siteID = content.DeriveOrValidateSiteID(inputDir, siteID)
siteID = content.DeriveOrValidateSiteID(inputPath, siteID)
} else {
// Validate site_id for non-demo paths
if siteID == "" || siteID == "demo" {
@@ -137,13 +153,27 @@ func runEnhance(cmd *cobra.Command, args []string) {
enhancer := content.NewEnhancer(client, siteID, enhancementConfig)
fmt.Printf("🚀 Starting enhancement process...\n")
fmt.Printf("📁 Input: %s\n", inputDir)
fmt.Printf("📁 Input: %s\n", inputPath)
fmt.Printf("📁 Output: %s\n", outputDir)
fmt.Printf("🏷️ Site ID: %s\n\n", siteID)
// Enhance directory
if err := enhancer.EnhanceDirectory(inputDir, outputDir); err != nil {
log.Fatalf("Enhancement failed: %v", err)
// Enhance based on input type
if isFile {
// For single files, determine the output file path
outputFilePath := outputDir
if stat, err := os.Stat(outputDir); err == nil && stat.IsDir() {
// Output is a directory, use input filename in output directory
outputFilePath = filepath.Join(outputDir, filepath.Base(inputPath))
}
// If output doesn't exist or is a file, use it as-is as the output file path
if err := enhancer.EnhanceFile(inputPath, outputFilePath); err != nil {
log.Fatalf("Enhancement failed: %v", err)
}
} else {
if err := enhancer.EnhanceDirectory(inputPath, outputDir); err != nil {
log.Fatalf("Enhancement failed: %v", err)
}
}
fmt.Printf("\n✅ Enhancement complete! Enhanced files available in: %s\n", outputDir)