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

@@ -314,14 +314,7 @@ func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request) {
}
}
// Determine content type: use provided type, fallback to existing type, default to "text"
contentType := req.Type
if contentType == "" && contentExists {
contentType = h.getContentType(existingContent)
}
if contentType == "" {
contentType = "text" // default type for new content
}
// HTML-first approach: no content type needed
var content interface{}
var err error
@@ -333,7 +326,6 @@ func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request) {
SiteID: siteID,
HtmlContent: req.HTMLContent,
OriginalTemplate: toNullString(req.OriginalTemplate),
Type: contentType,
LastEditedBy: userID,
})
case "postgresql":
@@ -342,7 +334,6 @@ func (h *ContentHandler) CreateContent(w http.ResponseWriter, r *http.Request) {
SiteID: siteID,
HtmlContent: req.HTMLContent,
OriginalTemplate: toNullString(req.OriginalTemplate),
Type: contentType,
LastEditedBy: userID,
})
default:
@@ -447,7 +438,6 @@ func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
case "sqlite3":
updatedContent, err = h.database.GetSQLiteQueries().UpdateContent(context.Background(), sqlite.UpdateContentParams{
HtmlContent: req.HTMLContent,
Type: h.getContentType(existingContent),
LastEditedBy: userID,
ID: contentID,
SiteID: siteID,
@@ -455,7 +445,6 @@ func (h *ContentHandler) UpdateContent(w http.ResponseWriter, r *http.Request) {
case "postgresql":
updatedContent, err = h.database.GetPostgreSQLQueries().UpdateContent(context.Background(), postgresql.UpdateContentParams{
HtmlContent: req.HTMLContent,
Type: h.getContentType(existingContent),
LastEditedBy: userID,
ID: contentID,
SiteID: siteID,
@@ -664,7 +653,6 @@ func (h *ContentHandler) RollbackContent(w http.ResponseWriter, r *http.Request)
sqliteVersion := targetVersion.(sqlite.ContentVersion)
updatedContent, err = h.database.GetSQLiteQueries().UpdateContent(context.Background(), sqlite.UpdateContentParams{
HtmlContent: sqliteVersion.HtmlContent,
Type: sqliteVersion.Type,
LastEditedBy: userID,
ID: contentID,
SiteID: siteID,
@@ -673,7 +661,6 @@ func (h *ContentHandler) RollbackContent(w http.ResponseWriter, r *http.Request)
pgVersion := targetVersion.(postgresql.ContentVersion)
updatedContent, err = h.database.GetPostgreSQLQueries().UpdateContent(context.Background(), postgresql.UpdateContentParams{
HtmlContent: pgVersion.HtmlContent,
Type: pgVersion.Type,
LastEditedBy: userID,
ID: contentID,
SiteID: siteID,
@@ -704,7 +691,6 @@ func (h *ContentHandler) convertToAPIContent(content interface{}) ContentItem {
SiteID: c.SiteID,
HTMLContent: c.HtmlContent,
OriginalTemplate: fromNullString(c.OriginalTemplate),
Type: c.Type,
CreatedAt: time.Unix(c.CreatedAt, 0),
UpdatedAt: time.Unix(c.UpdatedAt, 0),
LastEditedBy: c.LastEditedBy,
@@ -716,7 +702,6 @@ func (h *ContentHandler) convertToAPIContent(content interface{}) ContentItem {
SiteID: c.SiteID,
HTMLContent: c.HtmlContent,
OriginalTemplate: fromNullString(c.OriginalTemplate),
Type: c.Type,
CreatedAt: time.Unix(c.CreatedAt, 0),
UpdatedAt: time.Unix(c.UpdatedAt, 0),
LastEditedBy: c.LastEditedBy,
@@ -757,7 +742,6 @@ func (h *ContentHandler) convertToAPIVersionList(versionList interface{}) []Cont
SiteID: version.SiteID,
HTMLContent: version.HtmlContent,
OriginalTemplate: fromNullString(version.OriginalTemplate),
Type: version.Type,
CreatedAt: time.Unix(version.CreatedAt, 0),
CreatedBy: version.CreatedBy,
}
@@ -773,7 +757,6 @@ func (h *ContentHandler) convertToAPIVersionList(versionList interface{}) []Cont
SiteID: version.SiteID,
HTMLContent: version.HtmlContent,
OriginalTemplate: fromNullString(version.OriginalTemplate),
Type: version.Type,
CreatedAt: time.Unix(version.CreatedAt, 0),
CreatedBy: version.CreatedBy,
}
@@ -792,7 +775,6 @@ func (h *ContentHandler) createContentVersion(content interface{}) error {
SiteID: c.SiteID,
HtmlContent: c.HtmlContent,
OriginalTemplate: c.OriginalTemplate,
Type: c.Type,
CreatedBy: c.LastEditedBy,
})
case "postgresql":
@@ -802,23 +784,12 @@ func (h *ContentHandler) createContentVersion(content interface{}) error {
SiteID: c.SiteID,
HtmlContent: c.HtmlContent,
OriginalTemplate: c.OriginalTemplate,
Type: c.Type,
CreatedBy: c.LastEditedBy,
})
}
return fmt.Errorf("unsupported database type")
}
func (h *ContentHandler) getContentType(content interface{}) string {
switch h.database.GetDBType() {
case "sqlite3":
return content.(sqlite.Content).Type
case "postgresql":
return content.(postgresql.Content).Type
}
return ""
}
func (h *ContentHandler) versionMatches(version interface{}, contentID, siteID string) bool {
switch h.database.GetDBType() {
case "sqlite3":

View File

@@ -8,7 +8,6 @@ type ContentItem struct {
SiteID string `json:"site_id"`
HTMLContent string `json:"html_content"`
OriginalTemplate string `json:"original_template"`
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
LastEditedBy string `json:"last_edited_by"`
@@ -20,7 +19,6 @@ type ContentVersion struct {
SiteID string `json:"site_id"`
HTMLContent string `json:"html_content"`
OriginalTemplate string `json:"original_template"`
Type string `json:"type"`
CreatedAt time.Time `json:"created_at"`
CreatedBy string `json:"created_by"`
}
@@ -48,7 +46,6 @@ type CreateContentRequest struct {
FilePath string `json:"file_path"` // File path for consistent ID generation
HTMLContent string `json:"html_content"` // HTML content value
OriginalTemplate string `json:"original_template"` // Original template markup
Type string `json:"type"` // Content type
SiteID string `json:"site_id,omitempty"` // Site identifier
CreatedBy string `json:"created_by,omitempty"` // User who created the content
}