feat: CE-Akte mit Anhang IV + Tech-File Sections fuer alle 4 Projekte
- 9 Sections nach EU MVO 2023/1230 Anhang IV (alle approved) - Store fixes: html_content, tenant_id, nullable columns - Frontend: _constants.ts mit Section-Types extrahiert - 65 Verifikationseintraege automatisch generiert Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,8 +14,18 @@ import (
|
||||
// Tech File Section Operations
|
||||
// ============================================================================
|
||||
|
||||
// CreateTechFileSection creates a new section in the technical file
|
||||
// CreateTechFileSection creates a new section in the technical file.
|
||||
// tenantID is extracted from the project's owning tenant.
|
||||
func (s *Store) CreateTechFileSection(ctx context.Context, projectID uuid.UUID, sectionType, title, content string) (*TechFileSection, error) {
|
||||
// Resolve tenant_id from the project
|
||||
var tenantID uuid.UUID
|
||||
err := s.pool.QueryRow(ctx,
|
||||
`SELECT tenant_id FROM iace_projects WHERE id = $1`, projectID,
|
||||
).Scan(&tenantID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("resolve tenant_id for project %s: %w", projectID, err)
|
||||
}
|
||||
|
||||
tf := &TechFileSection{
|
||||
ID: uuid.New(),
|
||||
ProjectID: projectID,
|
||||
@@ -28,19 +38,19 @@ func (s *Store) CreateTechFileSection(ctx context.Context, projectID uuid.UUID,
|
||||
UpdatedAt: time.Now().UTC(),
|
||||
}
|
||||
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
_, err = s.pool.Exec(ctx, `
|
||||
INSERT INTO iace_tech_file_sections (
|
||||
id, project_id, section_type, title, content,
|
||||
version, status, approved_by, approved_at, metadata,
|
||||
id, project_id, tenant_id, section_type, title, html_content,
|
||||
status, approved_by, approved_at, metadata,
|
||||
created_at, updated_at
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5,
|
||||
$6, $7, $8, $9, $10,
|
||||
$1, $2, $3, $4, $5, $6,
|
||||
$7, $8, $9, $10,
|
||||
$11, $12
|
||||
)
|
||||
`,
|
||||
tf.ID, tf.ProjectID, tf.SectionType, tf.Title, tf.Content,
|
||||
tf.Version, string(tf.Status), uuid.Nil, nil, nil,
|
||||
tf.ID, tf.ProjectID, tenantID, tf.SectionType, tf.Title, tf.Content,
|
||||
string(tf.Status), "", nil, nil,
|
||||
tf.CreatedAt, tf.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -50,12 +60,11 @@ func (s *Store) CreateTechFileSection(ctx context.Context, projectID uuid.UUID,
|
||||
return tf, nil
|
||||
}
|
||||
|
||||
// UpdateTechFileSection updates the content of a tech file section and bumps version
|
||||
// UpdateTechFileSection updates the content of a tech file section
|
||||
func (s *Store) UpdateTechFileSection(ctx context.Context, id uuid.UUID, content string) error {
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
UPDATE iace_tech_file_sections SET
|
||||
content = $2,
|
||||
version = version + 1,
|
||||
html_content = $2,
|
||||
status = $3,
|
||||
updated_at = NOW()
|
||||
WHERE id = $1
|
||||
@@ -69,19 +78,15 @@ func (s *Store) UpdateTechFileSection(ctx context.Context, id uuid.UUID, content
|
||||
// ApproveTechFileSection marks a tech file section as approved
|
||||
func (s *Store) ApproveTechFileSection(ctx context.Context, id uuid.UUID, approvedBy string) error {
|
||||
now := time.Now().UTC()
|
||||
approvedByUUID, err := uuid.Parse(approvedBy)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid approved_by UUID: %w", err)
|
||||
}
|
||||
|
||||
_, err = s.pool.Exec(ctx, `
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
UPDATE iace_tech_file_sections SET
|
||||
status = $2,
|
||||
approved_by = $3,
|
||||
approved_at = $4,
|
||||
updated_at = $4
|
||||
WHERE id = $1
|
||||
`, id, string(TechFileSectionStatusApproved), approvedByUUID, now)
|
||||
`, id, string(TechFileSectionStatusApproved), approvedBy, now)
|
||||
if err != nil {
|
||||
return fmt.Errorf("approve tech file section: %w", err)
|
||||
}
|
||||
@@ -93,11 +98,13 @@ func (s *Store) ApproveTechFileSection(ctx context.Context, id uuid.UUID, approv
|
||||
func (s *Store) ListTechFileSections(ctx context.Context, projectID uuid.UUID) ([]TechFileSection, error) {
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT
|
||||
id, project_id, section_type, title, content,
|
||||
version, status, approved_by, approved_at, metadata,
|
||||
created_at, updated_at
|
||||
id, project_id, section_type, title,
|
||||
COALESCE(html_content, '') AS content, status,
|
||||
COALESCE(approved_by, '') AS approved_by, approved_at,
|
||||
COALESCE(metadata, '{}'::jsonb) AS metadata,
|
||||
created_at, COALESCE(updated_at, created_at) AS updated_at
|
||||
FROM iace_tech_file_sections WHERE project_id = $1
|
||||
ORDER BY section_type ASC, created_at ASC
|
||||
ORDER BY created_at ASC
|
||||
`, projectID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list tech file sections: %w", err)
|
||||
@@ -108,11 +115,13 @@ func (s *Store) ListTechFileSections(ctx context.Context, projectID uuid.UUID) (
|
||||
for rows.Next() {
|
||||
var tf TechFileSection
|
||||
var status string
|
||||
var approvedByStr string
|
||||
var metadata []byte
|
||||
|
||||
err := rows.Scan(
|
||||
&tf.ID, &tf.ProjectID, &tf.SectionType, &tf.Title, &tf.Content,
|
||||
&tf.Version, &status, &tf.ApprovedBy, &tf.ApprovedAt, &metadata,
|
||||
&tf.ID, &tf.ProjectID, &tf.SectionType, &tf.Title,
|
||||
&tf.Content, &status,
|
||||
&approvedByStr, &tf.ApprovedAt, &metadata,
|
||||
&tf.CreatedAt, &tf.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -120,6 +129,12 @@ func (s *Store) ListTechFileSections(ctx context.Context, projectID uuid.UUID) (
|
||||
}
|
||||
|
||||
tf.Status = TechFileSectionStatus(status)
|
||||
tf.Version = 1
|
||||
if approvedByStr != "" {
|
||||
if parsed, e := uuid.Parse(approvedByStr); e == nil {
|
||||
tf.ApprovedBy = parsed
|
||||
}
|
||||
}
|
||||
json.Unmarshal(metadata, &tf.Metadata)
|
||||
|
||||
sections = append(sections, tf)
|
||||
|
||||
Reference in New Issue
Block a user