Initial commit of Descrybe v2 without local scratch artifacts.

Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
2026-08-09 22:47:43 +02:00
commit 8580c996c3
1285 changed files with 325780 additions and 0 deletions
@@ -0,0 +1,112 @@
package feeds
import (
"context"
"errors"
"fmt"
"strings"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
)
// requiredStandardField is an enabled, required company standard field used for sync preflight.
type requiredStandardField struct {
Key string
Name string
}
// activeMappings returns rows with a non-empty source and a real target (not "none").
// Mirrors the frontend activeMappingRows filter.
func activeMappings(mappings []FieldMapping) []FieldMapping {
out := make([]FieldMapping, 0, len(mappings))
for _, m := range mappings {
src := m.sourceKey()
tgt := m.targetKey()
if src == "" || tgt == "" || strings.EqualFold(tgt, "none") {
continue
}
out = append(out, m)
}
return out
}
// validateMappingsForSync returns a ClientMsg when mappings are empty or required targets are missing.
// Optional (non-required) standard fields may remain unmapped.
func validateMappingsForSync(mappings []FieldMapping, required []requiredStandardField) error {
active := activeMappings(mappings)
if len(active) == 0 {
return ClientMsg("Map at least one source field before syncing.")
}
if len(required) == 0 {
return nil
}
mapped := make(map[string]struct{}, len(active))
for _, m := range active {
mapped[m.targetKey()] = struct{}{}
}
missing := make([]string, 0)
for _, r := range required {
if _, ok := mapped[r.Key]; ok {
continue
}
label := strings.TrimSpace(r.Name)
if label == "" {
label = r.Key
}
missing = append(missing, label)
}
if len(missing) == 0 {
return nil
}
return ClientMsg(fmt.Sprintf("Map required fields before syncing: %s.", strings.Join(missing, ", ")))
}
// loadRequiredStandardFields returns enabled+required standard field keys for the company.
func (s *Service) loadRequiredStandardFields(ctx context.Context, companyID uuid.UUID) ([]requiredStandardField, error) {
if s == nil || s.Pool == nil {
return nil, nil
}
rows, err := s.Pool.Query(ctx, `
SELECT key, COALESCE(NULLIF(TRIM(name), ''), key) AS name
FROM standard_fields
WHERE company_id = $1 AND enabled = true AND is_required = true
ORDER BY sort_order ASC, key ASC`, companyID)
if err != nil {
return nil, err
}
defer rows.Close()
out := make([]requiredStandardField, 0)
for rows.Next() {
var key, name string
if err := rows.Scan(&key, &name); err != nil {
return nil, err
}
key = strings.TrimSpace(key)
if key == "" {
continue
}
out = append(out, requiredStandardField{Key: key, Name: strings.TrimSpace(name)})
}
return out, rows.Err()
}
// ensureMappingsReadyForSync loads active mappings and required standard fields, then validates.
// Called before creating a sync job so clients get a clear 400 without a failed job row.
func (s *Service) ensureMappingsReadyForSync(ctx context.Context, companyID, feedID uuid.UUID) error {
raw, err := s.loadMappingsRaw(ctx, companyID, feedID)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return ClientMsg("Map at least one source field before syncing.")
}
return err
}
required, err := s.loadRequiredStandardFields(ctx, companyID)
if err != nil {
return err
}
return validateMappingsForSync(parseMappings(raw), required)
}