changeset 5714:98300739f761

Merged revive-cleanup branch into default.
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Wed, 21 Feb 2024 14:27:07 +0100
parents 37c8feeecb4d (current diff) e1cec58f6af0 (diff)
children e29c942d3e8c
files
diffstat 85 files changed, 513 insertions(+), 318 deletions(-) [+]
line wrap: on
line diff
--- a/cmd/gemma/main.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/cmd/gemma/main.go	Wed Feb 21 14:27:07 2024 +0100
@@ -48,7 +48,7 @@
 	auth.Sessions = ss
 }
 
-func start(cmd *cobra.Command, args []string) {
+func start(_ *cobra.Command, _ []string) {
 
 	if lf := config.LogFile(); lf != "" {
 		log.SetupLog(lf, 0666)
--- a/contrib/gmaggregate/go.mod	Tue Feb 20 21:28:56 2024 +0100
+++ b/contrib/gmaggregate/go.mod	Wed Feb 21 14:27:07 2024 +0100
@@ -1,6 +1,6 @@
 module heptapod.host/intevation/gemma/gmaggregate
 
-go 1.17
+go 1.21
 
 require github.com/jackc/pgx/v4 v4.13.0
 
--- a/contrib/gmaggregate/go.sum	Tue Feb 20 21:28:56 2024 +0100
+++ b/contrib/gmaggregate/go.sum	Wed Feb 21 14:27:07 2024 +0100
@@ -15,7 +15,6 @@
 github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
 github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
-github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
 github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
 github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
 github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
@@ -36,7 +35,6 @@
 github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
 github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
 github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
-github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
 github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
 github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
 github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
--- a/contrib/gmaggregate/main.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/contrib/gmaggregate/main.go	Wed Feb 21 14:27:07 2024 +0100
@@ -455,7 +455,7 @@
 
 	if _, err := tx.ExecContext(ctx, createFilteredLogsSQL); err != nil {
 		tx.Rollback()
-		return fmt.Errorf("cannot create new log table: %v\n", err)
+		return fmt.Errorf("cannot create new log table: %v", err)
 	}
 
 	stmt, err := tx.PrepareContext(ctx, insertFilteredLogsSQL)
@@ -503,11 +503,11 @@
 	}
 }
 
-func (pr *processor) Push(x interface{}) {
+func (pr *processor) Push(x any) {
 	pr.aggregated = append(pr.aggregated, x.(*importLines))
 }
 
-func (pr *processor) Pop() interface{} {
+func (pr *processor) Pop() any {
 	n := len(pr.aggregated)
 	x := pr.aggregated[n-1]
 	pr.aggregated[n-1] = nil
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/auth/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package auth implements the auth infrastructure of the gemma server.
+package auth
--- a/pkg/auth/encode.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/auth/encode.go	Wed Feb 21 14:27:07 2024 +0100
@@ -38,7 +38,7 @@
 
 // ReadBin reads big endian encodes binary data into x.
 // If an error was encountered before no data is read.
-func (r *BinReader) ReadBin(x interface{}) {
+func (r *BinReader) ReadBin(x any) {
 	if r.Err == nil {
 		r.Err = binary.Read(r.Reader, binary.BigEndian, x)
 	}
@@ -83,7 +83,7 @@
 
 // WriteBin writes x big endian encoded to the underlying io.Writer.
 // If an error was encountered before no data is written.
-func (w *BinWriter) WriteBin(x interface{}) {
+func (w *BinWriter) WriteBin(x any) {
 	if w.Err == nil {
 		w.Err = binary.Write(w.Writer, binary.BigEndian, x)
 	}
--- a/pkg/auth/session.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/auth/session.go	Wed Feb 21 14:27:07 2024 +0100
@@ -69,7 +69,7 @@
 )
 
 // newSession creates a new session.
-func newSession(user, password string, roles Roles) *Session {
+func newSession(user string, roles Roles) *Session {
 
 	// Create the Claims
 	return &Session{
@@ -167,7 +167,7 @@
 		return "", nil, ErrInvalidRole
 	}
 	token := generateSessionKey()
-	session := newSession(user, password, roles)
+	session := newSession(user, roles)
 	Sessions.Add(token, session)
 	return token, session, nil
 }
--- a/pkg/common/attributes.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/common/attributes.go	Wed Feb 21 14:27:07 2024 +0100
@@ -41,7 +41,7 @@
 )
 
 // Marshal fills src into ca.
-func (ca Attributes) Marshal(src interface{}) error {
+func (ca Attributes) Marshal(src any) error {
 	if ca == nil {
 		return nil
 	}
@@ -53,7 +53,7 @@
 }
 
 // Unmarshal stored ca into dst.
-func (ca Attributes) Unmarshal(dst interface{}) error {
+func (ca Attributes) Unmarshal(dst any) error {
 	if ca == nil {
 		return nil
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/common/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package common implements some algorithms used in the gemma server.
+package common
--- a/pkg/common/json.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/common/json.go	Wed Feb 21 14:27:07 2024 +0100
@@ -19,13 +19,13 @@
 )
 
 // FromJSONString revives data from a JSON string.
-func FromJSONString(data string, dst interface{}) error {
+func FromJSONString(data string, dst any) error {
 	return json.NewDecoder(strings.NewReader(data)).Decode(dst)
 }
 
 // ToJSONString serializes src into a string to
 // be revived by FromJSONString.
-func ToJSONString(src interface{}) (string, error) {
+func ToJSONString(src any) (string, error) {
 	var b strings.Builder
 	if err := json.NewEncoder(&b).Encode(src); err != nil {
 		return "", err
--- a/pkg/common/nashsutcliffe.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/common/nashsutcliffe.go	Wed Feb 21 14:27:07 2024 +0100
@@ -50,7 +50,9 @@
 // NashSutcliffe calculates the Nash-Sutcliffe coefficent for
 // given predicted and observed values.
 // See
-//   https://en.wikipedia.org/wiki/Nash%E2%80%93Sutcliffe_model_efficiency_coefficient
+//
+//	https://en.wikipedia.org/wiki/Nash%E2%80%93Sutcliffe_model_efficiency_coefficient
+//
 // for details.
 // The function panics if predicted and observed are of different lengths.
 func NashSutcliffe(predicted, observed []float64) float64 {
--- a/pkg/common/warn.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/common/warn.go	Wed Feb 21 14:27:07 2024 +0100
@@ -16,7 +16,7 @@
 // WarningLimiter limits outputs with Log to a maximal number
 // of MaxWarnings outputs.
 type WarningLimiter struct {
-	Log         func(format string, args ...interface{})
+	Log         func(format string, args ...any)
 	MaxWarnings int
 	Warnings    int
 }
@@ -24,7 +24,7 @@
 // Warn is a wrapper around the Log function with the
 // same signature as the Log function so it can be used
 // instead.
-func (w *WarningLimiter) Warn(format string, args ...interface{}) {
+func (w *WarningLimiter) Warn(format string, args ...any) {
 	if w.Warnings++; w.Warnings <= w.MaxWarnings {
 		w.Log(format, args...)
 	}
--- a/pkg/config/config.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/config/config.go	Wed Feb 21 14:27:07 2024 +0100
@@ -12,6 +12,7 @@
 //  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
 //  * Bernhard E. Reiter <bernhard.reiter@intevation.de>
 
+// Package config holds the configuration of the gemma server.
 package config
 
 import (
--- a/pkg/controllers/common.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/common.go	Wed Feb 21 14:27:07 2024 +0100
@@ -25,12 +25,12 @@
 
 type (
 	filterNode interface {
-		serialize(*strings.Builder, *[]interface{})
+		serialize(*strings.Builder, *[]any)
 	}
 
 	filterTerm struct {
 		format string
-		args   []interface{}
+		args   []any
 	}
 
 	filterNot struct {
@@ -41,8 +41,8 @@
 	filterOr  []filterNode
 )
 
-func (ft *filterTerm) serialize(stmt *strings.Builder, args *[]interface{}) {
-	indices := make([]interface{}, len(ft.args))
+func (ft *filterTerm) serialize(stmt *strings.Builder, args *[]any) {
+	indices := make([]any, len(ft.args))
 	for i := range indices {
 		indices[i] = len(*args) + i + 1
 	}
@@ -50,11 +50,11 @@
 	*args = append(*args, (*ft).args...)
 }
 
-func buildFilterTerm(format string, args ...interface{}) *filterTerm {
+func buildFilterTerm(format string, args ...any) *filterTerm {
 	return &filterTerm{format: format, args: args}
 }
 
-func (fa filterAnd) serialize(stmt *strings.Builder, args *[]interface{}) {
+func (fa filterAnd) serialize(stmt *strings.Builder, args *[]any) {
 	for i, node := range fa {
 		if i > 0 {
 			stmt.WriteString(" AND ")
@@ -65,7 +65,7 @@
 	}
 }
 
-func (fo filterOr) serialize(stmt *strings.Builder, args *[]interface{}) {
+func (fo filterOr) serialize(stmt *strings.Builder, args *[]any) {
 	for i, node := range fo {
 		if i > 0 {
 			stmt.WriteString(" OR ")
@@ -76,7 +76,7 @@
 	}
 }
 
-func (fn *filterNot) serialize(stmt *strings.Builder, args *[]interface{}) {
+func (fn *filterNot) serialize(stmt *strings.Builder, args *[]any) {
 	stmt.WriteString("NOT (")
 	fn.filterNode.serialize(stmt, args)
 	stmt.WriteByte(')')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/controllers/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package controllers are the various HTTP endpoints of the gemma server.
+package controllers
--- a/pkg/controllers/gauges.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/gauges.go	Wed Feb 21 14:27:07 2024 +0100
@@ -715,7 +715,7 @@
 	}
 
 	var stmt strings.Builder
-	var args []interface{}
+	var args []any
 
 	stmt.WriteString(selectWaterlevelsSQL)
 	filters.serialize(&stmt, &args)
--- a/pkg/controllers/importqueue.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/importqueue.go	Wed Feb 21 14:27:07 2024 +0100
@@ -110,10 +110,10 @@
 
 type filledStmt struct {
 	stmt strings.Builder
-	args []interface{}
+	args []any
 }
 
-func buildFilters(projection string, req *http.Request, args ...interface{}) (
+func buildFilters(projection string, req *http.Request, args ...any) (
 	*filledStmt,
 	*filledStmt,
 	*filledStmt,
@@ -124,7 +124,7 @@
 
 	var noBefore, noAfter bool
 
-	cond := func(format string, args ...interface{}) {
+	cond := func(format string, args ...any) {
 		term := &filterTerm{format: format, args: args}
 		l = append(l, term)
 		a = append(a, term)
@@ -560,7 +560,7 @@
 	}
 	enqueued = enqueued.UTC()
 
-	var sum interface{}
+	var sum any
 	if summary.Valid {
 		if err = json.NewDecoder(
 			strings.NewReader(summary.String)).Decode(&sum); err != nil {
@@ -595,7 +595,7 @@
 	jr = mw.JSONResult{
 		Result: struct {
 			Enqueued models.ImportTime        `json:"enqueued"`
-			Summary  interface{}              `json:"summary,omitempty"`
+			Summary  any                      `json:"summary,omitempty"`
 			Entries  []*models.ImportLogEntry `json:"entries"`
 		}{
 			Enqueued: models.ImportTime{Time: enqueued},
--- a/pkg/controllers/manualimports.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/manualimports.go	Wed Feb 21 14:27:07 2024 +0100
@@ -29,7 +29,7 @@
 	mw "gemma.intevation.de/gemma/pkg/middleware"
 )
 
-func importModel(req *http.Request) interface{} {
+func importModel(req *http.Request) any {
 	kind := mux.Vars(req)["kind"]
 	ctor := imports.ImportModelForJobKind(imports.JobKind(kind))
 	if ctor == nil {
--- a/pkg/controllers/printtemplates.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/printtemplates.go	Wed Feb 21 14:27:07 2024 +0100
@@ -85,7 +85,7 @@
 	filter := buildFilterTerm("template_type = ANY($%d) ", types)
 
 	var stmt strings.Builder
-	var args []interface{}
+	var args []any
 
 	stmt.WriteString(listPrintTemplatesSQL)
 	filter.serialize(&stmt, &args)
--- a/pkg/controllers/proxy.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/proxy.go	Wed Feb 21 14:27:07 2024 +0100
@@ -36,16 +36,16 @@
 
 // proxyBlackList is a set of URLs that should not be rewritten by the proxy.
 var proxyBlackList = map[string]struct{}{
-	"http://www.w3.org/2001/XMLSchema-instance": struct{}{},
-	"http://www.w3.org/1999/xlink":              struct{}{},
-	"http://www.w3.org/2001/XMLSchema":          struct{}{},
-	"http://www.w3.org/XML/1998/namespace":      struct{}{},
-	"http://www.opengis.net/wfs/2.0":            struct{}{},
-	"http://www.opengis.net/ows/1.1":            struct{}{},
-	"http://www.opengis.net/gml/3.2":            struct{}{},
-	"http://www.opengis.net/fes/2.0":            struct{}{},
-	"http://schemas.opengis.net/gml":            struct{}{},
-	"http://www.opengis.net/wfs":                struct{}{},
+	"http://www.w3.org/2001/XMLSchema-instance": {},
+	"http://www.w3.org/1999/xlink":              {},
+	"http://www.w3.org/2001/XMLSchema":          {},
+	"http://www.w3.org/XML/1998/namespace":      {},
+	"http://www.opengis.net/wfs/2.0":            {},
+	"http://www.opengis.net/ows/1.1":            {},
+	"http://www.opengis.net/gml/3.2":            {},
+	"http://www.opengis.net/fes/2.0":            {},
+	"http://schemas.opengis.net/gml":            {},
+	"http://www.opengis.net/wfs":                {},
 }
 
 func proxyDirector(lookup func(string) (string, bool)) func(*http.Request) {
@@ -54,7 +54,7 @@
 
 		//log.Debugf("proxyDirector: %s\n", req.RequestURI)
 
-		abort := func(format string, args ...interface{}) {
+		abort := func(format string, args ...any) {
 			log.Errorf(format, args...)
 			panic(http.ErrAbortHandler)
 		}
--- a/pkg/controllers/publish.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/publish.go	Wed Feb 21 14:27:07 2024 +0100
@@ -21,7 +21,7 @@
 	mw "gemma.intevation.de/gemma/pkg/middleware"
 )
 
-func published(req *http.Request) (mw.JSONResult, error) {
+func published(*http.Request) (mw.JSONResult, error) {
 	return mw.JSONResult{
 		Result: struct {
 			Internal    []models.IntEntry   `json:"internal"`
--- a/pkg/controllers/report.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/report.go	Wed Feb 21 14:27:07 2024 +0100
@@ -32,7 +32,7 @@
 	"github.com/xuri/excelize/v2"
 )
 
-func listReports(req *http.Request) (jr mw.JSONResult, err error) {
+func listReports(*http.Request) (jr mw.JSONResult, err error) {
 	path := config.ReportPath()
 	if path == "" {
 		err = mw.JSONError{
--- a/pkg/controllers/routes.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/routes.go	Wed Feb 21 14:27:07 2024 +0100
@@ -36,12 +36,12 @@
 	var (
 		sysAdmin      = auth.EnsureRole("sys_admin")
 		waterwayAdmin = auth.EnsureRole("waterway_admin")
-		any           = auth.EnsureRole("sys_admin", "waterway_admin", "waterway_user")
+		anyUser       = auth.EnsureRole("sys_admin", "waterway_admin", "waterway_user")
 	)
 
 	// Password resets.
 	api.Handle("/users/passwordreset", &mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return new(models.PWResetUser) },
+		Input:  func(*http.Request) any { return new(models.PWResetUser) },
 		Handle: passwordResetRequest,
 		NoConn: true,
 	}).Methods(http.MethodPost)
@@ -50,26 +50,26 @@
 		Methods(http.MethodGet)
 
 	// User management.
-	api.Handle("/users", any(&mw.JSONHandler{
+	api.Handle("/users", anyUser(&mw.JSONHandler{
 		Handle: listUsers,
 	})).Methods(http.MethodGet)
 
 	api.Handle("/users", sysAdmin(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return new(models.User) },
+		Input:  func(*http.Request) any { return new(models.User) },
 		Handle: createUser,
 	})).Methods(http.MethodPost)
 
-	api.Handle("/users/{user:.+}", any(&mw.JSONHandler{
+	api.Handle("/users/{user:.+}", anyUser(&mw.JSONHandler{
 		Handle: listUser,
 	})).Methods(http.MethodGet)
 
-	api.Handle("/users/{user:.+}", any(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return new(models.User) },
+	api.Handle("/users/{user:.+}", anyUser(&mw.JSONHandler{
+		Input:  func(*http.Request) any { return new(models.User) },
 		Handle: updateUser,
 	})).Methods(http.MethodPut)
 
-	api.Handle("/users/{user:.+}", any(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return new(models.UserPatch) },
+	api.Handle("/users/{user:.+}", anyUser(&mw.JSONHandler{
+		Input:  func(*http.Request) any { return new(models.UserPatch) },
 		Handle: patchUser,
 	})).Methods(http.MethodPatch)
 
@@ -89,37 +89,37 @@
 	})).Methods(http.MethodGet)
 
 	// System Settings
-	api.Handle("/system/config", any(&mw.JSONHandler{
+	api.Handle("/system/config", anyUser(&mw.JSONHandler{
 		Handle: getSystemConfig,
 		NoConn: true,
 	})).Methods(http.MethodGet)
 
-	api.Handle("/system/settings", any(&mw.JSONHandler{
+	api.Handle("/system/settings", anyUser(&mw.JSONHandler{
 		Handle: getSystemSettings,
 	})).Methods(http.MethodGet)
 
 	api.Handle("/system/settings", sysAdmin(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return &map[string]string{} },
+		Input:  func(*http.Request) any { return &map[string]string{} },
 		Handle: setSystemSettings,
 	})).Methods(http.MethodPut)
 
 	// Print templates
-	api.Handle("/templates", any(&mw.JSONHandler{
+	api.Handle("/templates", anyUser(&mw.JSONHandler{
 		Handle: listPrintTemplates,
 	})).Methods(http.MethodGet)
 
 	tTypes := "{type:" + strings.Join(templateTypes, "|") + "}"
 
-	api.Handle("/templates/"+tTypes, any(&mw.JSONHandler{
+	api.Handle("/templates/"+tTypes, anyUser(&mw.JSONHandler{
 		Handle: listPrintTemplates,
 	})).Methods(http.MethodGet)
 
-	api.Handle("/templates/"+tTypes+"/{name}", any(&mw.JSONHandler{
+	api.Handle("/templates/"+tTypes+"/{name}", anyUser(&mw.JSONHandler{
 		Handle: fetchPrintTemplate,
 	})).Methods(http.MethodGet)
 
 	api.Handle("/templates/"+tTypes+"/{name}", waterwayAdmin(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return &json.RawMessage{} },
+		Input:  func(*http.Request) any { return &json.RawMessage{} },
 		Handle: createPrintTemplate,
 		Limit:  maxPrintTemplateSize,
 	})).Methods(http.MethodPost)
@@ -129,7 +129,7 @@
 	})).Methods(http.MethodDelete)
 
 	api.Handle("/templates/"+tTypes+"/{name}", waterwayAdmin(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return &json.RawMessage{} },
+		Input:  func(*http.Request) any { return &json.RawMessage{} },
 		Handle: updatePrintTemplate,
 		Limit:  maxPrintTemplateSize,
 	})).Methods(http.MethodPatch)
@@ -140,7 +140,7 @@
 		ModifyResponse: proxyModifyResponse("/api/external/"),
 	})
 
-	externalAuth := any(external)
+	externalAuth := anyUser(external)
 
 	api.Handle("/external/{hash}/{url}", externalAuth).
 		Methods(
@@ -158,7 +158,7 @@
 		ModifyResponse: proxyModifyResponse("/api/internal/"),
 	})
 
-	internalAuth := any(
+	internalAuth := anyUser(
 		mw.ModifyQuery(internal, mw.InjectUser))
 
 	api.Handle("/internal/{hash}/{url}", internalAuth).
@@ -171,36 +171,36 @@
 			http.MethodGet, http.MethodPost,
 			http.MethodPut, http.MethodDelete)
 
-	api.Handle("/published", any(&mw.JSONHandler{
+	api.Handle("/published", anyUser(&mw.JSONHandler{
 		Handle: published,
 		NoConn: true,
 	})).Methods(http.MethodGet)
 
 	// Survey selection
-	api.Handle("/surveys", any(&mw.JSONHandler{
+	api.Handle("/surveys", anyUser(&mw.JSONHandler{
 		Handle: listSurveys,
 	})).Methods(http.MethodGet).Queries("id", "{id}")
 
-	api.Handle("/surveys", any(&mw.JSONHandler{
+	api.Handle("/surveys", anyUser(&mw.JSONHandler{
 		Handle: listSurveys,
 	})).Methods(http.MethodGet).Queries("name", "{name}", "date", "{date}")
 
 	// difference calculation
-	api.Handle("/diff", any(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return new(models.DiffCalculationInput) },
+	api.Handle("/diff", anyUser(&mw.JSONHandler{
+		Input:  func(*http.Request) any { return new(models.DiffCalculationInput) },
 		Handle: diffCalculation,
 		NoConn: true,
 	})).Methods(http.MethodPost)
 
 	// Cross sections
-	api.Handle("/cross", any(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return new(models.CrossSectionInput) },
+	api.Handle("/cross", anyUser(&mw.JSONHandler{
+		Input:  func(*http.Request) any { return new(models.CrossSectionInput) },
 		Handle: crossSection,
 	})).Methods(http.MethodPost)
 
 	// Feature search
-	api.Handle("/search", any(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return new(models.SearchRequest) },
+	api.Handle("/search", anyUser(&mw.JSONHandler{
+		Input:  func(*http.Request) any { return new(models.SearchRequest) },
 		Handle: searchFeature,
 	})).Methods(http.MethodPost)
 
@@ -282,7 +282,7 @@
 
 	api.Handle("/imports/config/{id:[0-9]+}",
 		waterwayAdmin(&mw.JSONHandler{
-			Input:  func(*http.Request) interface{} { return &json.RawMessage{} },
+			Input:  func(*http.Request) any { return &json.RawMessage{} },
 			Handle: modifyImportConfig,
 		})).Methods(http.MethodPatch)
 
@@ -298,7 +298,7 @@
 
 	api.Handle("/imports/config",
 		waterwayAdmin(&mw.JSONHandler{
-			Input:  func(*http.Request) interface{} { return new(imports.ImportConfigIn) },
+			Input:  func(*http.Request) any { return new(imports.ImportConfigIn) },
 			Handle: addImportConfig,
 		})).Methods(http.MethodPost)
 
@@ -321,7 +321,7 @@
 	})).Methods(http.MethodGet)
 
 	api.Handle("/imports", waterwayAdmin(&mw.JSONHandler{
-		Input:  func(*http.Request) interface{} { return &[]models.Review{} },
+		Input:  func(*http.Request) any { return &[]models.Review{} },
 		Handle: reviewImports,
 		NoConn: true,
 	})).Methods(http.MethodPatch)
@@ -340,7 +340,7 @@
 	// Handler for reporting
 
 	api.Handle("/data/reports",
-		any(&mw.JSONHandler{
+		anyUser(&mw.JSONHandler{
 			Handle: listReports,
 			NoConn: true,
 		})).Methods(http.MethodGet)
@@ -361,23 +361,23 @@
 
 	// Handler to serve data to the client.
 
-	api.Handle("/data/{type:availability|fairway}/{kind:stretch|section|bottleneck}/{name:.+}", any(
+	api.Handle("/data/{type:availability|fairway}/{kind:stretch|section|bottleneck}/{name:.+}", anyUser(
 		mw.DBConn(http.HandlerFunc(fairwayAvailability)))).Methods(http.MethodGet)
 
-	api.Handle("/data/stretch/shape/{name:.+}", any(
+	api.Handle("/data/stretch/shape/{name:.+}", anyUser(
 		mw.DBConn(http.HandlerFunc(stretchShapeDownload)))).Methods(http.MethodGet)
 
-	api.Handle("/data/waterlevels/{gauge:.+}", any(
+	api.Handle("/data/waterlevels/{gauge:.+}", anyUser(
 		mw.DBConn(http.HandlerFunc(waterlevels)))).Methods(http.MethodGet)
 
-	api.Handle("/data/longterm-waterlevels/{gauge:.+}", any(
+	api.Handle("/data/longterm-waterlevels/{gauge:.+}", anyUser(
 		mw.DBConn(http.HandlerFunc(longtermWaterlevels)))).Methods(http.MethodGet)
 
 	// TODO: gauge should not contain '/'s.
-	api.Handle("/data/year-waterlevels/{gauge}/{year:[0-9]+}", any(
+	api.Handle("/data/year-waterlevels/{gauge}/{year:[0-9]+}", anyUser(
 		mw.DBConn(http.HandlerFunc(yearWaterlevels)))).Methods(http.MethodGet)
 
-	api.Handle("/data/nash-sutcliffe/{gauge:.+}", any(&mw.JSONHandler{
+	api.Handle("/data/nash-sutcliffe/{gauge:.+}", anyUser(&mw.JSONHandler{
 		Handle: nashSutcliffe,
 	})).Methods(http.MethodGet)
 
--- a/pkg/controllers/shapestretches.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/shapestretches.go	Wed Feb 21 14:27:07 2024 +0100
@@ -231,7 +231,7 @@
 
 		writer.Write(p)
 
-		write := func(field int, v interface{}) {
+		write := func(field int, v any) {
 			if err == nil {
 				err = writer.WriteAttribute(0, field, v)
 			}
--- a/pkg/controllers/srimports.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/srimports.go	Wed Feb 21 14:27:07 2024 +0100
@@ -239,9 +239,9 @@
 	}
 
 	var result struct {
-		Token    string      `json:"token,omitempty"`
-		Meta     interface{} `json:"meta,omitempty"`
-		Messages []string    `json:"messages,omitempty"`
+		Token    string   `json:"token,omitempty"`
+		Meta     any      `json:"meta,omitempty"`
+		Messages []string `json:"messages,omitempty"`
 	}
 
 	find := func(ext string) *zip.File { return common.FindInZIP(zr, ext) }
--- a/pkg/controllers/statsupdates.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/statsupdates.go	Wed Feb 21 14:27:07 2024 +0100
@@ -110,6 +110,6 @@
 		return
 	}
 
-	jr = mw.JSONResult{Result: map[string]interface{}{}}
+	jr = mw.JSONResult{Result: map[string]any{}}
 	return
 }
--- a/pkg/controllers/system.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/system.go	Wed Feb 21 14:27:07 2024 +0100
@@ -103,7 +103,7 @@
 	return
 }
 
-func getSystemConfig(req *http.Request) (jr mw.JSONResult, err error) {
+func getSystemConfig(*http.Request) (jr mw.JSONResult, err error) {
 
 	cfg := config.PublishedConfig()
 	if cfg == "" {
--- a/pkg/controllers/user.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/controllers/user.go	Wed Feb 21 14:27:07 2024 +0100
@@ -323,10 +323,10 @@
 	var (
 		columns   []string
 		positions []string
-		args      []interface{}
+		args      []any
 	)
 
-	update := func(column string, value interface{}) {
+	update := func(column string, value any) {
 		columns = append(columns, column)
 		positions = append(positions, "$"+strconv.Itoa(len(positions)+1))
 		args = append(args, value)
--- a/pkg/geoserver/boot.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/geoserver/boot.go	Wed Feb 21 14:27:07 2024 +0100
@@ -50,7 +50,7 @@
 	}
 }
 
-func toStream(x interface{}) io.Reader {
+func toStream(x any) io.Reader {
 	var buf bytes.Buffer
 
 	if err := json.NewEncoder(&buf).Encode(x); err != nil {
@@ -62,7 +62,7 @@
 
 // XXX: Creating SQL views with JSON via GeoServer REST-API fails
 // Begin code for handling with XML instead
-func toXMLStream(x interface{}) io.Reader {
+func toXMLStream(x any) io.Reader {
 	buf := bytes.NewBufferString(xml.Header)
 	if err := xml.NewEncoder(buf).Encode(x); err != nil {
 		// Should not happen
@@ -166,15 +166,15 @@
 	log.Infoln("creating datastore " + datastoreName)
 
 	type entry struct {
-		Key   interface{} `json:"@key"`
-		Value interface{} `json:"$"`
+		Key   any `json:"@key"`
+		Value any `json:"$"`
 	}
 
 	// Create datastore.
-	ds := map[string]interface{}{
-		"dataStore": map[string]interface{}{
+	ds := map[string]any{
+		"dataStore": map[string]any{
 			"name": datastoreName,
-			"connectionParameters": map[string]interface{}{
+			"connectionParameters": map[string]any{
 				"entry": []entry{
 					{"host", config.DBHost()},
 					{"port", config.DBPort()},
@@ -301,7 +301,7 @@
 
 		var req *http.Request
 
-		ft := map[string]interface{}{
+		ft := map[string]any{
 			"name":       table,
 			"nativeName": table,
 			"title":      table,
@@ -310,7 +310,7 @@
 			ft["srs"] = *srs
 			// A bit of a hack!
 			if *srs == "EPSG:4326" {
-				box := map[string]interface{}{
+				box := map[string]any{
 					"minx": -180,
 					"maxx": +180,
 					"miny": -90,
@@ -322,17 +322,17 @@
 			}
 		}
 
-		var entries []map[string]interface{}
+		var entries []map[string]any
 
 		if models.IntSQLView(tables[i]) {
-			vt := map[string]interface{}{
+			vt := map[string]any{
 				"name": table,
 				"sql":  *tables[i].SQL,
 			}
 			if kc := tables[i].KeyColumn; kc != nil {
 				vt["keyColumn"] = *kc
 			}
-			entry := map[string]interface{}{
+			entry := map[string]any{
 				"@key":         "JDBC_VIRTUAL_TABLE",
 				"virtualTable": vt,
 			}
@@ -340,7 +340,7 @@
 		}
 
 		if attr := tables[i].WMSTAttribute; attr != nil {
-			di := map[string]interface{}{
+			di := map[string]any{
 				"enabled":             true,
 				"attribute":           *attr,
 				"presentation":        "CONTINUOUS_INTERVAL",
@@ -354,7 +354,7 @@
 			if endAttr := tables[i].WMSTEndAttribute; endAttr != nil {
 				di["endAttribute"] = *endAttr
 			}
-			entry := map[string]interface{}{
+			entry := map[string]any{
 				"@key":          "time",
 				"dimensionInfo": di,
 			}
@@ -362,12 +362,12 @@
 		}
 
 		if len(entries) > 0 {
-			ft["metadata"] = map[string]interface{}{
+			ft["metadata"] = map[string]any{
 				"entry": entries,
 			}
 		}
 
-		doc := map[string]interface{}{
+		doc := map[string]any{
 			"featureType": ft,
 		}
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/geoserver/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package geoserver provides a way to setup a GeoServer remotely.
+package geoserver
--- a/pkg/imports/agm.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/agm.go	Wed Feb 21 14:27:07 2024 +0100
@@ -252,7 +252,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/bn.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/bn.go	Wed Feb 21 14:27:07 2024 +0100
@@ -216,7 +216,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	fetch := func() ([]*ifbn.BottleNeckType, error) {
 		client := ifbn.NewIBottleneckService(bn.URL, bn.Insecure, nil)
@@ -290,7 +290,7 @@
 	conn *sql.Conn,
 	feedback Feedback,
 	tolerance float64,
-) (interface{}, error) {
+) (any, error) {
 	start := time.Now()
 
 	bns, err := fetch()
--- a/pkg/imports/config.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/config.go	Wed Feb 21 14:27:07 2024 +0100
@@ -41,10 +41,10 @@
 	// JSON versions to the REST endpoints
 	// which are stored in the database.
 	ImportConfigOut struct {
-		ID     int64       `json:"id"`
-		Kind   ImportKind  `json:"kind"`
-		User   string      `json:"user"`
-		Config interface{} `json:"config,omitempty"`
+		ID     int64      `json:"id"`
+		Kind   ImportKind `json:"kind"`
+		User   string     `json:"user"`
+		Config any        `json:"config,omitempty"`
 	}
 
 	// PersistentConfig is the the in-memory
--- a/pkg/imports/dma.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/dma.go	Wed Feb 21 14:27:07 2024 +0100
@@ -108,10 +108,10 @@
 // Do executes the actual fairway dimension import.
 func (dma *DistanceMarksAshore) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/dmv.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/dmv.go	Wed Feb 21 14:27:07 2024 +0100
@@ -89,10 +89,10 @@
 // of the virtual distance marks.
 func (dmv *DistanceMarksVirtual) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/imports/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package imports implements the various data imports.
+package imports
--- a/pkg/imports/dsec.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/dsec.go	Wed Feb 21 14:27:07 2024 +0100
@@ -92,7 +92,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	tx, err := conn.BeginTx(ctx, nil)
 	if err != nil {
--- a/pkg/imports/dsr.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/dsr.go	Wed Feb 21 14:27:07 2024 +0100
@@ -100,7 +100,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	tx, err := conn.BeginTx(ctx, nil)
 	if err != nil {
--- a/pkg/imports/dst.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/dst.go	Wed Feb 21 14:27:07 2024 +0100
@@ -77,7 +77,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	tx, err := conn.BeginTx(ctx, nil)
 	if err != nil {
--- a/pkg/imports/fa.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/fa.go	Wed Feb 21 14:27:07 2024 +0100
@@ -281,7 +281,7 @@
 	conn *sql.Conn,
 	feedback Feedback,
 	fetch func(context.Context, *sql.Tx, bottlenecks) ([]*ifaf.FairwayAvailability, error),
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
@@ -338,7 +338,7 @@
 
 func doForFAs(
 	ctx context.Context,
-	bnIds bottlenecks,
+	bnIDs bottlenecks,
 	fas []*ifaf.FairwayAvailability,
 	tx *sql.Tx,
 	feedback Feedback,
@@ -371,7 +371,7 @@
 	for _, faRes := range fas {
 		// FIXME: The following test is propably unneccessary as already
 		//   done by DB constraints...  [sw]
-		if !bnIds.contains(faRes.Bottleneck_id) {
+		if !bnIDs.contains(faRes.Bottleneck_id) {
 			feedback.Warn("Bottleneck %s not found in database.", faRes.Bottleneck_id)
 			continue
 		}
@@ -479,10 +479,10 @@
 // Do executes the actual fairway availability import.
 func (fa *FairwayAvailability) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	fetch := func(
 		ctx context.Context,
--- a/pkg/imports/fd.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/fd.go	Wed Feb 21 14:27:07 2024 +0100
@@ -254,7 +254,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/fm.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/fm.go	Wed Feb 21 14:27:07 2024 +0100
@@ -235,7 +235,7 @@
 				),
 				consume,
 				createInvalidation("bcnlat_hydro"),
-				newPointFeature(func() interface{} { return new(bcnlatHydroProperties) }),
+				newPointFeature(func() any { return new(bcnlatHydroProperties) }),
 			),
 		})
 
@@ -251,7 +251,7 @@
 				),
 				consume,
 				createInvalidation("bcnlat_ienc"),
-				newPointFeature(func() interface{} { return new(bcnlatIencProperties) }),
+				newPointFeature(func() any { return new(bcnlatIencProperties) }),
 			),
 		})
 
@@ -267,7 +267,7 @@
 				),
 				consume,
 				createInvalidation("boylat_hydro"),
-				newPointFeature(func() interface{} { return new(boylatHydroProperties) }),
+				newPointFeature(func() any { return new(boylatHydroProperties) }),
 			),
 		})
 
@@ -283,7 +283,7 @@
 				),
 				consume,
 				createInvalidation("boylat_ienc"),
-				newPointFeature(func() interface{} { return new(boylatIencProperties) }),
+				newPointFeature(func() any { return new(boylatIencProperties) }),
 			),
 		})
 
@@ -299,7 +299,7 @@
 				),
 				consume,
 				createInvalidation("boycar"),
-				newPointFeature(func() interface{} { return new(boycarProperties) }),
+				newPointFeature(func() any { return new(boycarProperties) }),
 			),
 		})
 
@@ -314,7 +314,7 @@
 				),
 				consume,
 				createInvalidation("boysaw"),
-				newPointFeature(func() interface{} { return new(boysawProperties) }),
+				newPointFeature(func() any { return new(boysawProperties) }),
 			),
 		})
 
@@ -330,7 +330,7 @@
 				),
 				consume,
 				createInvalidation("boyspp"),
-				newPointFeature(func() interface{} { return new(boysppProperties) }),
+				newPointFeature(func() any { return new(boysppProperties) }),
 			),
 		})
 
@@ -345,7 +345,7 @@
 				),
 				consume,
 				createInvalidation("daymar_hydro"),
-				newPointFeature(func() interface{} { return new(daymarHydroProperties) }),
+				newPointFeature(func() any { return new(daymarHydroProperties) }),
 			),
 		})
 
@@ -361,7 +361,7 @@
 				),
 				consume,
 				createInvalidation("daymar_ienc"),
-				newPointFeature(func() interface{} { return new(daymarIencProperties) }),
+				newPointFeature(func() any { return new(daymarIencProperties) }),
 			),
 		})
 
@@ -380,7 +380,7 @@
 				),
 				consume,
 				createInvalidation("lights"),
-				newPointFeature(func() interface{} { return new(lightsProperties) }),
+				newPointFeature(func() any { return new(lightsProperties) }),
 			),
 		})
 
@@ -399,7 +399,7 @@
 				),
 				consume,
 				createInvalidation("notmrk"),
-				newPointFeature(func() interface{} { return new(notmrkProperties) }),
+				newPointFeature(func() any { return new(notmrkProperties) }),
 			),
 		})
 
@@ -414,7 +414,7 @@
 				),
 				consume,
 				createInvalidation("rtpbcn"),
-				newPointFeature(func() interface{} { return new(rtpbcnProperties) }),
+				newPointFeature(func() any { return new(rtpbcnProperties) }),
 			),
 		})
 
@@ -429,7 +429,7 @@
 				),
 				consume,
 				createInvalidation("topmar"),
-				newPointFeature(func() interface{} { return new(topmarProperties) }),
+				newPointFeature(func() any { return new(topmarProperties) }),
 			),
 		})
 }
@@ -583,7 +583,7 @@
 
 func consume(
 	spc *SQLGeometryConsumer,
-	geom, properties interface{},
+	geom, properties any,
 	epsg int,
 ) error {
 	var fmid int64
@@ -591,7 +591,7 @@
 		return spc.stmts[0].QueryRowContext(
 			spc.ctx,
 			append(
-				[]interface{}{
+				[]any{
 					geom.(interface{ asWKB() []byte }).asWKB(),
 					epsg,
 				},
--- a/pkg/imports/gm.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/gm.go	Wed Feb 21 14:27:07 2024 +0100
@@ -161,7 +161,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	fetch := func() ([]*nts.RIS_Message_Type, error) {
 		client := nts.NewINtSMessageService(gm.URL, gm.Insecure, nil)
@@ -257,11 +257,11 @@
 
 func storeGaugeMeasurements(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	fetch func() ([]*nts.RIS_Message_Type, error),
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
@@ -430,7 +430,7 @@
 func (gls gmLogs) logBool(
 	access func(*gmLog) bool,
 	header string,
-	log func(string, ...interface{}),
+	log func(string, ...any),
 ) {
 	var sb strings.Builder
 	for _, gl := range gls {
@@ -451,7 +451,7 @@
 func (gls gmLogs) logInt(
 	access func(*gmLog) int,
 	header string,
-	log func(string, ...interface{}),
+	log func(string, ...any),
 ) {
 	gs := make(gmLogs, 0, len(gls))
 	for _, g := range gls {
@@ -494,7 +494,7 @@
 func (gls gmLogs) logString(
 	access func(*gmLog) []string,
 	header string,
-	log func(string, ...interface{}),
+	log func(string, ...any),
 ) {
 	var sb strings.Builder
 	for _, gl := range gls {
--- a/pkg/imports/isr.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/isr.go	Wed Feb 21 14:27:07 2024 +0100
@@ -130,10 +130,10 @@
 // Do executes the actual refreshing of the iso areas.
 func (isr *IsoRefresh) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 	feedback.Info("Regenerating iso areas for sounding results " +
--- a/pkg/imports/modelconvert.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/modelconvert.go	Wed Feb 21 14:27:07 2024 +0100
@@ -17,47 +17,47 @@
 	"gemma.intevation.de/gemma/pkg/models"
 )
 
-var kindToImportModel = map[JobKind]func() interface{}{
-	BNJobKind:          func() interface{} { return new(models.BottleneckImport) },
-	GMJobKind:          func() interface{} { return new(models.GaugeMeasurementImport) },
-	FAJobKind:          func() interface{} { return new(models.FairwayAvailabilityImport) },
-	WXJobKind:          func() interface{} { return FindJobCreator(WXJobKind).Create() },
-	WAJobKind:          func() interface{} { return new(models.WaterwayAreaImport) },
-	WGJobKind:          func() interface{} { return new(models.WaterwayGaugeImport) },
-	DMVJobKind:         func() interface{} { return new(models.DistanceMarksVirtualImport) },
-	FDJobKind:          func() interface{} { return new(models.FairwayDimensionImport) },
-	DMAJobKind:         func() interface{} { return new(models.DistanceMarksAshoreImport) },
-	BCNLATHYDROJobKind: func() interface{} { return FindJobCreator(BCNLATHYDROJobKind).Create() },
-	BCNLATIENCJobKind:  func() interface{} { return FindJobCreator(BCNLATIENCJobKind).Create() },
-	BOYCARJobKind:      func() interface{} { return FindJobCreator(BOYCARJobKind).Create() },
-	BOYLATHYDROJobKind: func() interface{} { return FindJobCreator(BOYLATHYDROJobKind).Create() },
-	BOYLATIENCJobKind:  func() interface{} { return FindJobCreator(BOYLATIENCJobKind).Create() },
-	BOYSAWJobKind:      func() interface{} { return FindJobCreator(BOYSAWJobKind).Create() },
-	BOYSPPJobKind:      func() interface{} { return FindJobCreator(BOYSPPJobKind).Create() },
-	DAYMARHYDROJobKind: func() interface{} { return FindJobCreator(DAYMARHYDROJobKind).Create() },
-	DAYMARIENCJobKind:  func() interface{} { return FindJobCreator(DAYMARIENCJobKind).Create() },
-	LIGHTSJobKind:      func() interface{} { return FindJobCreator(LIGHTSJobKind).Create() },
-	RTPBCNJobKind:      func() interface{} { return FindJobCreator(RTPBCNJobKind).Create() },
-	TOPMARJobKind:      func() interface{} { return FindJobCreator(TOPMARJobKind).Create() },
-	NOTMRKJobKind:      func() interface{} { return FindJobCreator(NOTMRKJobKind).Create() },
-	STJobKind:          func() interface{} { return new(models.StretchImport) },
-	SECJobKind:         func() interface{} { return new(models.SectionImport) },
-	DSECJobKind:        func() interface{} { return new(models.SectionDelete) },
-	DSTJobKind:         func() interface{} { return new(models.StretchDelete) },
-	DSRJobKind:         func() interface{} { return new(models.SoundingResultDelete) },
-	ReportJobKind:      func() interface{} { return FindJobCreator(ReportJobKind).Create() },
-	StatsUpdateJobKind: func() interface{} { return FindJobCreator(StatsUpdateJobKind).Create() },
+var kindToImportModel = map[JobKind]func() any{
+	BNJobKind:          func() any { return new(models.BottleneckImport) },
+	GMJobKind:          func() any { return new(models.GaugeMeasurementImport) },
+	FAJobKind:          func() any { return new(models.FairwayAvailabilityImport) },
+	WXJobKind:          func() any { return FindJobCreator(WXJobKind).Create() },
+	WAJobKind:          func() any { return new(models.WaterwayAreaImport) },
+	WGJobKind:          func() any { return new(models.WaterwayGaugeImport) },
+	DMVJobKind:         func() any { return new(models.DistanceMarksVirtualImport) },
+	FDJobKind:          func() any { return new(models.FairwayDimensionImport) },
+	DMAJobKind:         func() any { return new(models.DistanceMarksAshoreImport) },
+	BCNLATHYDROJobKind: func() any { return FindJobCreator(BCNLATHYDROJobKind).Create() },
+	BCNLATIENCJobKind:  func() any { return FindJobCreator(BCNLATIENCJobKind).Create() },
+	BOYCARJobKind:      func() any { return FindJobCreator(BOYCARJobKind).Create() },
+	BOYLATHYDROJobKind: func() any { return FindJobCreator(BOYLATHYDROJobKind).Create() },
+	BOYLATIENCJobKind:  func() any { return FindJobCreator(BOYLATIENCJobKind).Create() },
+	BOYSAWJobKind:      func() any { return FindJobCreator(BOYSAWJobKind).Create() },
+	BOYSPPJobKind:      func() any { return FindJobCreator(BOYSPPJobKind).Create() },
+	DAYMARHYDROJobKind: func() any { return FindJobCreator(DAYMARHYDROJobKind).Create() },
+	DAYMARIENCJobKind:  func() any { return FindJobCreator(DAYMARIENCJobKind).Create() },
+	LIGHTSJobKind:      func() any { return FindJobCreator(LIGHTSJobKind).Create() },
+	RTPBCNJobKind:      func() any { return FindJobCreator(RTPBCNJobKind).Create() },
+	TOPMARJobKind:      func() any { return FindJobCreator(TOPMARJobKind).Create() },
+	NOTMRKJobKind:      func() any { return FindJobCreator(NOTMRKJobKind).Create() },
+	STJobKind:          func() any { return new(models.StretchImport) },
+	SECJobKind:         func() any { return new(models.SectionImport) },
+	DSECJobKind:        func() any { return new(models.SectionDelete) },
+	DSTJobKind:         func() any { return new(models.StretchDelete) },
+	DSRJobKind:         func() any { return new(models.SoundingResultDelete) },
+	ReportJobKind:      func() any { return FindJobCreator(ReportJobKind).Create() },
+	StatsUpdateJobKind: func() any { return FindJobCreator(StatsUpdateJobKind).Create() },
 }
 
 // ImportModelForJobKind returns the constructor function to
 // de-serialize an incoming JSON REST represention of an import.
-func ImportModelForJobKind(kind JobKind) func() interface{} {
+func ImportModelForJobKind(kind JobKind) func() any {
 	return kindToImportModel[kind]
 }
 
-var convertModel = map[JobKind]func(interface{}) interface{}{
+var convertModel = map[JobKind]func(any) any{
 
-	BNJobKind: func(input interface{}) interface{} {
+	BNJobKind: func(input any) any {
 		bi := input.(*models.BottleneckImport)
 		return &Bottleneck{
 			URL:       bi.URL,
@@ -66,7 +66,7 @@
 		}
 	},
 
-	GMJobKind: func(input interface{}) interface{} {
+	GMJobKind: func(input any) any {
 		gi := input.(*models.GaugeMeasurementImport)
 		return &GaugeMeasurement{
 			URL:      gi.URL,
@@ -74,7 +74,7 @@
 		}
 	},
 
-	FAJobKind: func(input interface{}) interface{} {
+	FAJobKind: func(input any) any {
 		fai := input.(*models.FairwayAvailabilityImport)
 		return &FairwayAvailability{
 			URL:      fai.URL,
@@ -82,7 +82,7 @@
 		}
 	},
 
-	WAJobKind: func(input interface{}) interface{} {
+	WAJobKind: func(input any) any {
 		wai := input.(*models.WaterwayAreaImport)
 		return &WaterwayArea{
 			URL:         wai.URL,
@@ -93,7 +93,7 @@
 		}
 	},
 
-	WGJobKind: func(input interface{}) interface{} {
+	WGJobKind: func(input any) any {
 		wgi := input.(*models.WaterwayGaugeImport)
 		return &WaterwayGauge{
 			URL:      wgi.URL,
@@ -103,7 +103,7 @@
 		}
 	},
 
-	DMVJobKind: func(input interface{}) interface{} {
+	DMVJobKind: func(input any) any {
 		dmvi := input.(*models.DistanceMarksVirtualImport)
 		return &DistanceMarksVirtual{
 			URL:      dmvi.URL,
@@ -113,7 +113,7 @@
 		}
 	},
 
-	FDJobKind: func(input interface{}) interface{} {
+	FDJobKind: func(input any) any {
 		fdi := input.(*models.FairwayDimensionImport)
 		return &FairwayDimension{
 			URL:                fdi.URL,
@@ -129,7 +129,7 @@
 		}
 	},
 
-	DMAJobKind: func(input interface{}) interface{} {
+	DMAJobKind: func(input any) any {
 		dmai := input.(*models.DistanceMarksAshoreImport)
 		return &DistanceMarksAshore{
 			URL:         dmai.URL,
@@ -140,7 +140,7 @@
 		}
 	},
 
-	STJobKind: func(input interface{}) interface{} {
+	STJobKind: func(input any) any {
 		sti := input.(*models.StretchImport)
 		return &Stretch{
 			Name:      sti.Name,
@@ -155,7 +155,7 @@
 		}
 	},
 
-	SECJobKind: func(input interface{}) interface{} {
+	SECJobKind: func(input any) any {
 		seci := input.(*models.SectionImport)
 		return &Section{
 			Name:      seci.Name,
@@ -169,17 +169,17 @@
 		}
 	},
 
-	DSECJobKind: func(input interface{}) interface{} {
+	DSECJobKind: func(input any) any {
 		dsec := input.(*models.SectionDelete)
 		return &DeleteSection{ID: dsec.ID}
 	},
 
-	DSTJobKind: func(input interface{}) interface{} {
+	DSTJobKind: func(input any) any {
 		dst := input.(*models.StretchDelete)
 		return &DeleteStretch{ID: dst.ID}
 	},
 
-	DSRJobKind: func(input interface{}) interface{} {
+	DSRJobKind: func(input any) any {
 		dsr := input.(*models.SoundingResultDelete)
 		return &DeleteSoundingResult{
 			BottleneckID: dsr.BottleneckID,
@@ -197,7 +197,7 @@
 
 // ConvertToInternal converts an external JSON REST represention
 // of an import into the internal one store in the import queue.
-func ConvertToInternal(kind JobKind, src interface{}) interface{} {
+func ConvertToInternal(kind JobKind, src any) any {
 	fn := convertModel[kind]
 	if fn == nil {
 		return src
--- a/pkg/imports/queue.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/queue.go	Wed Feb 21 14:27:07 2024 +0100
@@ -39,11 +39,11 @@
 	// informations, warnings or errors.
 	Feedback interface {
 		// Info logs informations.
-		Info(fmt string, args ...interface{})
+		Info(fmt string, args ...any)
 		// Warn logs warnings.
-		Warn(fmt string, args ...interface{})
+		Warn(fmt string, args ...any)
 		// Error logs errors.
-		Error(fmt string, args ...interface{})
+		Error(fmt string, args ...any)
 	}
 
 	// UnchangedError may be issued by Do of a Job to indicate
@@ -61,7 +61,7 @@
 		// be successfull. The non-error return value is
 		// serialized as a JSON string into the database as
 		// a summary to the import to be used by the review process.
-		Do(ctx context.Context, id int64, conn *sql.Conn, feedback Feedback) (interface{}, error)
+		Do(ctx context.Context, id int64, conn *sql.Conn, feedback Feedback) (any, error)
 		// CleanUp is called to clean up ressources hold by the import.
 		// It is called whether the import succeeded or not.
 		CleanUp() error
@@ -294,8 +294,8 @@
 	ctx context.Context,
 	importID int64,
 	conn *sql.Conn,
-	feedback Feedback,
-) (interface{}, error) {
+	_ Feedback,
+) (any, error) {
 
 	tx, err := conn.BeginTx(ctx, nil)
 	if err != nil {
@@ -749,7 +749,7 @@
 
 type logFeedback int64
 
-func (lf logFeedback) log(kind, format string, args ...interface{}) {
+func (lf logFeedback) log(kind, format string, args ...any) {
 	ctx := context.Background()
 	err := auth.RunAs(ctx, queueUser, func(conn *sql.Conn) error {
 		_, err := conn.ExecContext(
@@ -761,15 +761,15 @@
 	}
 }
 
-func (lf logFeedback) Info(format string, args ...interface{}) {
+func (lf logFeedback) Info(format string, args ...any) {
 	lf.log("info", format, args...)
 }
 
-func (lf logFeedback) Warn(format string, args ...interface{}) {
+func (lf logFeedback) Warn(format string, args ...any) {
 	lf.log("warn", format, args...)
 }
 
-func (lf logFeedback) Error(format string, args ...interface{}) {
+func (lf logFeedback) Error(format string, args ...any) {
 	lf.log("error", format, args...)
 }
 
@@ -900,7 +900,7 @@
 	ctx context.Context,
 	id int64,
 	state string,
-	summary interface{},
+	summary any,
 ) error {
 	var s sql.NullString
 	if summary != nil {
@@ -924,7 +924,7 @@
 	})
 }
 
-func errorAndFail(id int64, format string, args ...interface{}) error {
+func errorAndFail(id int64, format string, args ...any) error {
 	ctx := context.Background()
 	return tryHardToStoreState(ctx, func(conn *sql.Conn) error {
 		tx, err := conn.BeginTx(ctx, nil)
@@ -1020,7 +1020,7 @@
 			}
 
 			ctx := context.Background()
-			var summary interface{}
+			var summary any
 
 			errDo := survive(func() error {
 				return auth.RunAs(ctx, idj.user,
--- a/pkg/imports/report.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/report.go	Wed Feb 21 14:27:07 2024 +0100
@@ -164,10 +164,10 @@
 // Do executes the actual report generation.
 func (r *Report) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/sec.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/sec.go	Wed Feb 21 14:27:07 2024 +0100
@@ -148,7 +148,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/sr.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/sr.go	Wed Feb 21 14:27:07 2024 +0100
@@ -332,7 +332,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
@@ -489,7 +489,7 @@
 	xyz mesh.MultiPointZ,
 	boundary polygonSlice,
 	zpgException bool,
-) (interface{}, error) {
+) (any, error) {
 
 	feedback.Info("Processing as %s beam scan.", m.SurveyType)
 
--- a/pkg/imports/st.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/st.go	Wed Feb 21 14:27:07 2024 +0100
@@ -148,7 +148,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/statsupdate.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/statsupdate.go	Wed Feb 21 14:27:07 2024 +0100
@@ -86,10 +86,10 @@
 // Do executes the actual report generation.
 func (su *StatsUpdate) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/stsh.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/stsh.go	Wed Feb 21 14:27:07 2024 +0100
@@ -130,7 +130,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 	defer func() {
--- a/pkg/imports/ubn.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/ubn.go	Wed Feb 21 14:27:07 2024 +0100
@@ -70,7 +70,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	fetch := func() ([]*ifbn.BottleNeckType, error) {
 		var dst ifbn.Export_bn_by_isrsResponse
--- a/pkg/imports/ufa.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/ufa.go	Wed Feb 21 14:27:07 2024 +0100
@@ -64,15 +64,15 @@
 // Do executes the actual uploaded fairway availability import.
 func (ufa *UploadedFairwayAvailability) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	fetch := func(
-		ctx context.Context,
-		tx *sql.Tx,
-		bns bottlenecks,
+		_ context.Context,
+		_ *sql.Tx,
+		_ bottlenecks,
 	) ([]*ifaf.FairwayAvailability, error) {
 
 		var response ifaf.Get_bottleneck_faResponse
--- a/pkg/imports/ugm.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/ugm.go	Wed Feb 21 14:27:07 2024 +0100
@@ -57,7 +57,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	fetch := func() ([]*nts.RIS_Message_Type, error) {
 
--- a/pkg/imports/wa.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/wa.go	Wed Feb 21 14:27:07 2024 +0100
@@ -113,10 +113,10 @@
 // Do executes the actual waterway axis import.
 func (wa *WaterwayArea) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
--- a/pkg/imports/wfsjob.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/wfsjob.go	Wed Feb 21 14:27:07 2024 +0100
@@ -43,9 +43,9 @@
 		Commit() error
 		Rollback() error
 
-		NewFeature() (kind string, properties interface{})
+		NewFeature() (kind string, properties any)
 
-		Consume(geom, properties interface{}, epsg int) error
+		Consume(geom, properties any, epsg int) error
 	}
 
 	// WFSFeatureJobCreator is a factory to create feature consumers.
@@ -66,16 +66,16 @@
 )
 
 var (
-	kindToGeometry = map[string]func() interface{}{
+	kindToGeometry = map[string]func() any{
 		// TODO: extend me!
-		"Point":           func() interface{} { return new(pointSlice) },
-		"LineString":      func() interface{} { return new(lineSlice) },
-		"MultiLineString": func() interface{} { return new(multiLineSlice) },
+		"Point":           func() any { return new(pointSlice) },
+		"LineString":      func() any { return new(lineSlice) },
+		"MultiLineString": func() any { return new(multiLineSlice) },
 	}
 
-	wrapGeomKind = map[[2]string]func(interface{}) interface{}{
+	wrapGeomKind = map[[2]string]func(any) any{
 		// TODO: extend me!
-		{"LineString", "MultiLineString"}: func(x interface{}) interface{} {
+		{"LineString", "MultiLineString"}: func(x any) any {
 			return &multiLineSlice{*x.(*lineSlice)}
 		},
 	}
@@ -128,10 +128,10 @@
 // Do implements the actual WFS import.
 func (wfj *WFSFeatureJob) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
@@ -226,7 +226,7 @@
 			}
 
 			// Optional wrapping
-			wrap := func(x interface{}) interface{} { return x }
+			wrap := func(x any) any { return x }
 			if feature.Geometry.Type != kind {
 				// Look if we can wrap it
 				if wrap = wrapGeomKind[[2]string{feature.Geometry.Type, kind}]; wrap == nil {
@@ -298,8 +298,8 @@
 	ctx        context.Context
 	tx         *sql.Tx
 	feedback   Feedback
-	consume    func(*SQLGeometryConsumer, interface{}, interface{}, int) error
-	newFeature func() (string, interface{})
+	consume    func(*SQLGeometryConsumer, any, any, int) error
+	newFeature func() (string, any)
 	preCommit  func(*SQLGeometryConsumer) error
 	savepoint  func(func() error) error
 	stmts      []*sql.Stmt
@@ -337,13 +337,13 @@
 }
 
 // NewFeature forwards the feature creation.
-func (sgc *SQLGeometryConsumer) NewFeature() (string, interface{}) {
+func (sgc *SQLGeometryConsumer) NewFeature() (string, any) {
 	return sgc.newFeature()
 }
 
 // Consume forwards the consumption of the given feature.
 func (sgc *SQLGeometryConsumer) Consume(
-	geom, properties interface{},
+	geom, properties any,
 	epsg int,
 ) error {
 	return sgc.consume(sgc, geom, properties, epsg)
@@ -352,7 +352,7 @@
 // ConsumePolygon forwards the consumption of a polygon.
 func (sgc *SQLGeometryConsumer) ConsumePolygon(
 	polygon polygonSlice,
-	properties interface{},
+	properties any,
 	epsg int,
 ) error {
 	return sgc.consume(sgc, polygon, properties, epsg)
@@ -360,9 +360,9 @@
 
 func newSQLConsumer(
 	init func(*SQLGeometryConsumer) error,
-	consume func(*SQLGeometryConsumer, interface{}, interface{}, int) error,
+	consume func(*SQLGeometryConsumer, any, any, int) error,
 	preCommit func(*SQLGeometryConsumer) error,
-	newFeature func() (string, interface{}),
+	newFeature func() (string, any),
 
 ) func(context.Context, *sql.Conn, Feedback) (WFSFeatureConsumer, error) {
 	return func(ctx context.Context, conn *sql.Conn, feedback Feedback) (WFSFeatureConsumer, error) {
--- a/pkg/imports/wg.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/wg.go	Wed Feb 21 14:27:07 2024 +0100
@@ -185,10 +185,10 @@
 // Do implements the actual import.
 func (wg *WaterwayGauge) Do(
 	ctx context.Context,
-	importID int64,
+	_ int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 
 	start := time.Now()
 
@@ -595,10 +595,9 @@
 
 	if unchanged == len(gauges) {
 		return nil, UnchangedError("All gauges unchanged")
-	} else {
-		feedback.Info("Unchanged gauges: %d",
-			unchanged)
 	}
+	feedback.Info("Unchanged gauges: %d",
+		unchanged)
 
 	feedback.Info("Importing gauges took %s",
 		time.Since(start))
--- a/pkg/imports/wkb.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/wkb.go	Wed Feb 21 14:27:07 2024 +0100
@@ -32,14 +32,14 @@
 	multiPolygonSlice []polygonSlice
 )
 
-func newPointFeature(newProperties func() interface{}) func() (string, interface{}) {
-	return func() (string, interface{}) { return "Point", newProperties() }
+func newPointFeature(newProperties func() any) func() (string, any) {
+	return func() (string, any) { return "Point", newProperties() }
 }
 
 func newMultiLineFeature(
-	newProperties func() interface{},
-) func() (string, interface{}) {
-	return func() (string, interface{}) {
+	newProperties func() any,
+) func() (string, any) {
+	return func() (string, any) {
 		return "MultiLineString", newProperties()
 	}
 }
--- a/pkg/imports/wp.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/wp.go	Wed Feb 21 14:27:07 2024 +0100
@@ -169,7 +169,7 @@
 	importID int64,
 	conn *sql.Conn,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 	start := time.Now()
 
 	tx, err := conn.BeginTx(ctx, nil)
@@ -178,8 +178,7 @@
 	}
 	defer tx.Rollback()
 
-	if err := wp.downloadGeometries(
-		ctx, importID, tx, start, feedback); err != nil {
+	if err := wp.downloadGeometries(ctx, tx, feedback); err != nil {
 		return nil, fmt.Errorf("error downloading geometries: %v", err)
 	}
 
@@ -202,9 +201,7 @@
 
 func (wp *WaterwayProfiles) downloadGeometries(
 	ctx context.Context,
-	importID int64,
 	tx *sql.Tx,
-	start time.Time,
 	feedback Feedback,
 ) error {
 	feedback.Info("Start downloading geometries from WFS.")
@@ -357,7 +354,7 @@
 	tx *sql.Tx,
 	start time.Time,
 	feedback Feedback,
-) (interface{}, error) {
+) (any, error) {
 	feedback.Info("Start processing CSV file.")
 
 	f, err := os.Open(filepath.Join(wp.Dir, "wp.csv"))
--- a/pkg/imports/wx.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/imports/wx.go	Wed Feb 21 14:27:07 2024 +0100
@@ -26,7 +26,7 @@
 				prepareStmnts(insertWaterwayAxisSQL),
 				consume,
 				axisInvalidation,
-				newMultiLineFeature(func() interface{} {
+				newMultiLineFeature(func() any {
 					return new(waterwayAxisProperties)
 				}),
 			),
--- a/pkg/log/log.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/log/log.go	Wed Feb 21 14:27:07 2024 +0100
@@ -11,6 +11,7 @@
 // Author(s):
 //  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
+// Package log is a leveled logger used in the gemma server.
 package log
 
 import (
@@ -137,7 +138,7 @@
 }
 
 // Tracef formats a log message as a TRACE output.
-func Tracef(f string, args ...interface{}) {
+func Tracef(f string, args ...any) {
 	if TraceLogLevel >= GetLogLevel() {
 		s := fmt.Sprintf(f, args...)
 		lg.Output(callDepth, "[TRACE] "+s)
@@ -152,7 +153,7 @@
 }
 
 // Debugf formats a log message as a DEBUG output.
-func Debugf(f string, args ...interface{}) {
+func Debugf(f string, args ...any) {
 	if DebugLogLevel >= GetLogLevel() {
 		s := fmt.Sprintf(f, args...)
 		lg.Output(callDepth, "[DEBUG] "+s)
@@ -167,7 +168,7 @@
 }
 
 // Infof formats a log message as a INFO output.
-func Infof(f string, args ...interface{}) {
+func Infof(f string, args ...any) {
 	if InfoLogLevel >= GetLogLevel() {
 		s := fmt.Sprintf(f, args...)
 		lg.Output(callDepth, "[INFO] "+s)
@@ -182,7 +183,7 @@
 }
 
 // Warnf formats a log message as a WARN output.
-func Warnf(f string, args ...interface{}) {
+func Warnf(f string, args ...any) {
 	if WarnLogLevel >= GetLogLevel() {
 		s := fmt.Sprintf(f, args...)
 		lg.Output(callDepth, "[WARN] "+s)
@@ -197,7 +198,7 @@
 }
 
 // Errorf formats a log message as an ERROR output.
-func Errorf(f string, args ...interface{}) {
+func Errorf(f string, args ...any) {
 	if ErrorLogLevel >= GetLogLevel() {
 		s := fmt.Sprintf(f, args...)
 		lg.Output(callDepth, "[ERROR] "+s)
@@ -213,7 +214,7 @@
 
 // Fatalf formats a log message as a FATAL output
 // and terminates the programs with an error code (1).
-func Fatalf(f string, args ...interface{}) {
+func Fatalf(f string, args ...any) {
 	if FatalLogLevel >= GetLogLevel() {
 		s := fmt.Sprintf(f, args...)
 		lg.Output(callDepth, "[FATAL] "+s)
@@ -232,7 +233,7 @@
 
 // Panicf formats a log message as a PANIC output
 // and throws a panic.
-func Panicf(f string, args ...interface{}) {
+func Panicf(f string, args ...any) {
 	s := fmt.Sprintf(f, args...)
 	lg.Output(callDepth, "[PANIC] "+s)
 	panic(s)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/mesh/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,16 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2025 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package mesh provides serveral data types to handle
+// the 3D models of the sounding results.
+package mesh
--- a/pkg/mesh/polygon.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/mesh/polygon.go	Wed Feb 21 14:27:07 2024 +0100
@@ -232,7 +232,7 @@
 
 	for _, index := range p.indices {
 		var intersects bool
-		index.Search(min, max, func(_, _ [2]float64, item interface{}) bool {
+		index.Search(min, max, func(_, _ [2]float64, item any) bool {
 			if item.(lineSegment).intersects(box) {
 				intersects = true
 				return false
@@ -270,7 +270,7 @@
 	min, max := box.Rect()
 	for _, index := range p.indices {
 		var intersects bool
-		index.Search(min, max, func(_, _ [2]float64, item interface{}) bool {
+		index.Search(min, max, func(_, _ [2]float64, item any) bool {
 			ls := item.(lineSegment)
 			other := make(lineSegment, 4)
 			for i := range t {
--- a/pkg/mesh/tin.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/mesh/tin.go	Wed Feb 21 14:27:07 2024 +0100
@@ -196,7 +196,7 @@
 }
 
 // Scan implements the sql.Scanner interface.
-func (t *Tin) Scan(raw interface{}) error {
+func (t *Tin) Scan(raw any) error {
 	if raw == nil {
 		return nil
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/middleware/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 204 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package middleware implements some http handler middleware.
+package middleware
--- a/pkg/middleware/json.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/middleware/json.go	Wed Feb 21 14:27:07 2024 +0100
@@ -30,7 +30,7 @@
 
 // GetJSONInput returns the deserialized JSON data from
 // the incoming request if any.
-func GetJSONInput(req *http.Request) interface{} {
+func GetJSONInput(req *http.Request) any {
 	return req.Context().Value(jsonInputKey)
 }
 
@@ -40,7 +40,7 @@
 // GetJSONInput can be used to receive the deserialized data.
 // limit limits the size of the incoming body to prevent
 // flooding the server.
-func JSONMiddleware(next http.Handler, input func(*http.Request) interface{}, limit int64) http.Handler {
+func JSONMiddleware(next http.Handler, input func(*http.Request) any, limit int64) http.Handler {
 
 	return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
 		dst := input(req)
--- a/pkg/middleware/jsonhandler.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/middleware/jsonhandler.go	Wed Feb 21 14:27:07 2024 +0100
@@ -33,7 +33,7 @@
 	Code int
 	// Result is serialized to JSON.
 	// If the type is an io.Reader its copied through.
-	Result interface{}
+	Result any
 }
 
 // JSONDefaultLimit is default size limit in bytes of an accepted
@@ -45,7 +45,7 @@
 type JSONHandler struct {
 	// Input (if not nil) is called to fill a data structure
 	// returned by this function.
-	Input func(*http.Request) interface{}
+	Input func(*http.Request) any
 	// Handle is called to handle the incoming HTTP request.
 	// in is the data structure returned by Input. Its nil if Input is nil.
 	Handle func(rep *http.Request) (JSONResult, error)
@@ -89,7 +89,7 @@
 }
 
 // JSONInput extracts the de-serialized input from the context of the request.
-func JSONInput(req *http.Request) interface{} {
+func JSONInput(req *http.Request) any {
 	return req.Context().Value(jsonHandlerInputKey)
 }
 
@@ -201,7 +201,7 @@
 
 // SendJSON sends data JSON encoded to the response writer
 // with a given HTTP status code.
-func SendJSON(rw http.ResponseWriter, code int, data interface{}) {
+func SendJSON(rw http.ResponseWriter, code int, data any) {
 	rw.Header().Set("Content-Type", "application/json")
 	rw.Header().Set("X-Content-Type-Options", "nosniff")
 	rw.WriteHeader(code)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/misc/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package misc implements miscellaneous helper functions.
+package misc
--- a/pkg/models/common.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/models/common.go	Wed Feb 21 14:27:07 2024 +0100
@@ -124,7 +124,7 @@
 }
 
 // Scan implements the sql.Scanner interfaces.
-func (c *Country) Scan(src interface{}) (err error) {
+func (c *Country) Scan(src any) (err error) {
 	if s, ok := src.(string); ok {
 		*c = Country(s)
 	} else {
--- a/pkg/models/cross.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/models/cross.go	Wed Feb 21 14:27:07 2024 +0100
@@ -96,7 +96,7 @@
 	CrossSectionOutput struct {
 		Type       string                     `json:"type"`
 		Geometry   CrossSectionOutputGeometry `json:"geometry"`
-		Properties map[string]interface{}     `json:"properties"`
+		Properties map[string]any             `json:"properties"`
 	}
 )
 
@@ -201,7 +201,7 @@
 }
 
 // Scan implements sql.Scanner interface.
-func (lcz *GeoJSONLineCoordinatesZ) Scan(src interface{}) error {
+func (lcz *GeoJSONLineCoordinatesZ) Scan(src any) error {
 	data, ok := src.([]byte)
 	if !ok {
 		return errNoByteSlice
@@ -378,7 +378,7 @@
 }
 
 // Scan implements the sql.Scanner interface.
-func (mls *GeoJSONMultiLineCoordinatesZ) Scan(src interface{}) error {
+func (mls *GeoJSONMultiLineCoordinatesZ) Scan(src any) error {
 	if src == nil {
 		return nil
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/models/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package models implements several models used by the gemma server.
+package models
--- a/pkg/models/import.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/models/import.go	Wed Feb 21 14:27:07 2024 +0100
@@ -78,7 +78,7 @@
 }
 
 // Scan implements the sql.Scanner interface.
-func (it *ImportTime) Scan(x interface{}) error {
+func (it *ImportTime) Scan(x any) error {
 	t, ok := x.(time.Time)
 	if !ok {
 		*it = ImportTime{}
--- a/pkg/models/user.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/models/user.go	Wed Feb 21 14:27:07 2024 +0100
@@ -104,7 +104,7 @@
 }
 
 // Scan implements the sql.Scanner interface.
-func (e *Email) Scan(src interface{}) (err error) {
+func (e *Email) Scan(src any) (err error) {
 	if s, ok := src.(string); ok {
 		*e = Email(s)
 	} else {
@@ -134,7 +134,7 @@
 }
 
 // Scan implements the sql.Scanner interface.
-func (u *UserName) Scan(src interface{}) (err error) {
+func (u *UserName) Scan(src any) (err error) {
 	if s, ok := src.(string); ok {
 		*u = UserName(s)
 	} else {
@@ -158,7 +158,7 @@
 }
 
 // Scan implements the sql.Scanner interface.
-func (r *Role) Scan(src interface{}) (err error) {
+func (r *Role) Scan(src any) (err error) {
 	if s, ok := src.(string); ok {
 		*r = Role(s)
 	} else {
--- a/pkg/pgxutils/errors.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/pgxutils/errors.go	Wed Feb 21 14:27:07 2024 +0100
@@ -12,6 +12,7 @@
 //  * Tom Gottfried <tom.gottfried@intevation.de>
 //  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
 
+// Package pgxutils is used for error handling related to the pgx PostgreSQL driver.
 package pgxutils
 
 import (
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/scheduler/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package scheduler implements the cron like import scheduler.
+package scheduler
--- a/pkg/soap/ifbn/service.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/soap/ifbn/service.go	Wed Feb 21 14:27:07 2024 +0100
@@ -864,12 +864,12 @@
 	}
 }
 
-func (service *IBottleneckService) AddHeader(header interface{}) {
+func (service *IBottleneckService) AddHeader(header any) {
 	service.client.AddHeader(header)
 }
 
 // Backwards-compatible function: use AddHeader instead
-func (service *IBottleneckService) SetHeader(header interface{}) {
+func (service *IBottleneckService) SetHeader(header any) {
 	service.client.AddHeader(header)
 }
 
--- a/pkg/soap/soap.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/soap/soap.go	Wed Feb 21 14:27:07 2024 +0100
@@ -39,14 +39,14 @@
 type SOAPHeader struct {
 	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Header"`
 
-	Items []interface{} `xml:",omitempty"`
+	Items []any `xml:",omitempty"`
 }
 
 type SOAPBody struct {
 	XMLName xml.Name `xml:"http://schemas.xmlsoap.org/soap/envelope/ Body"`
 
-	Fault   *SOAPFault  `xml:",omitempty"`
-	Content interface{} `xml:",omitempty"`
+	Fault   *SOAPFault `xml:",omitempty"`
+	Content any        `xml:",omitempty"`
 }
 
 type SOAPFault struct {
@@ -119,7 +119,7 @@
 	url     string
 	tlsCfg  *tls.Config
 	auth    Auth
-	headers []interface{}
+	headers []any
 }
 
 // **********
@@ -230,19 +230,19 @@
 	}
 }
 
-func (s *SOAPClient) AddHeader(header interface{}) {
+func (s *SOAPClient) AddHeader(header any) {
 	s.headers = append(s.headers, header)
 }
 
-func (s *SOAPClient) CallContext(ctx context.Context, soapAction string, request, response interface{}) error {
+func (s *SOAPClient) CallContext(ctx context.Context, soapAction string, request, response any) error {
 	return s.Call(soapAction, request, response)
 }
 
-func (s *SOAPClient) Call(soapAction string, request, response interface{}) error {
+func (s *SOAPClient) Call(soapAction string, request, response any) error {
 	envelope := SOAPEnvelope{}
 
 	if s.headers != nil && len(s.headers) > 0 {
-		soapHeader := &SOAPHeader{Items: make([]interface{}, len(s.headers))}
+		soapHeader := &SOAPHeader{Items: make([]any, len(s.headers))}
 		copy(soapHeader.Items, s.headers)
 		envelope.Header = soapHeader
 	}
--- a/pkg/soap/validate.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/soap/validate.go	Wed Feb 21 14:27:07 2024 +0100
@@ -69,7 +69,7 @@
 	return "", nil
 }
 
-func ValidateFile(fname, schema string, dst interface{}) error {
+func ValidateFile(fname, schema string, dst any) error {
 	f, err := os.Open(fname)
 	if err != nil {
 		return err
@@ -78,7 +78,7 @@
 	return Validate(f, schema, dst)
 }
 
-func Validate(r io.Reader, schema string, dst interface{}) error {
+func Validate(r io.Reader, schema string, dst any) error {
 	schemaPath, err := FindSchema(schema)
 	if err != nil {
 		return err
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/wfs/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2019 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package wfs implements downloading of WFS data.
+package wfs
--- a/pkg/wkb/data.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/wkb/data.go	Wed Feb 21 14:27:07 2024 +0100
@@ -21,7 +21,7 @@
 )
 
 type (
-	// PointGeom is a 2D point,
+	// PointGeom is a 2D point.
 	PointGeom struct {
 		X float64
 		Y float64
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/wkb/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package wkb implements some WKB (Well Known Binary) data types.
+package wkb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkg/xlsx/doc.go	Wed Feb 21 14:27:07 2024 +0100
@@ -0,0 +1,15 @@
+// This is Free Software under GNU Affero General Public License v >= 3.0
+// without warranty, see README.md and license for details.
+//
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// License-Filename: LICENSES/AGPL-3.0.txt
+//
+// Copyright (C) 2024 by via donau
+//   – Österreichische Wasserstraßen-Gesellschaft mbH
+// Software engineering by Intevation GmbH
+//
+// Author(s):
+//  * Sascha L. Teichmann <sascha.teichmann@intevation.de>
+
+// Package xlsx implements a little XLSX templating engine.
+package xlsx
--- a/pkg/xlsx/sql.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/xlsx/sql.go	Wed Feb 21 14:27:07 2024 +0100
@@ -23,7 +23,7 @@
 
 type sqlResult struct {
 	columns []string
-	rows    [][]interface{}
+	rows    [][]any
 }
 
 func (sr *sqlResult) find(column string) int {
@@ -62,11 +62,11 @@
 	ctx context.Context,
 	tx *sql.Tx,
 	stmt string,
-	eval func(string) (interface{}, error),
+	eval func(string) (any, error),
 ) (*sqlResult, error) {
 
 	nstmt, nargs := replaceStmt(stmt)
-	args := make([]interface{}, len(nargs))
+	args := make([]any, len(nargs))
 	for i, n := range nargs {
 		var err error
 		if args[i], err = eval(n); err != nil {
@@ -84,12 +84,12 @@
 	if err != nil {
 		return nil, err
 	}
-	var rows [][]interface{}
+	var rows [][]any
 
-	ptrs := make([]interface{}, len(columns))
+	ptrs := make([]any, len(columns))
 
 	for rs.Next() {
-		row := make([]interface{}, len(columns))
+		row := make([]any, len(columns))
 		for i := range row {
 			ptrs[i] = &row[i]
 		}
--- a/pkg/xlsx/templater.go	Tue Feb 20 21:28:56 2024 +0100
+++ b/pkg/xlsx/templater.go	Wed Feb 21 14:27:07 2024 +0100
@@ -200,7 +200,7 @@
 	e.frames = append(e.frames, frame{
 		res: &sqlResult{
 			columns: vars,
-			rows:    [][]interface{}{make([]interface{}, len(vars))},
+			rows:    [][]any{make([]any, len(vars))},
 		},
 	})
 }
@@ -419,7 +419,7 @@
 func (e *executor) sel(action *Action) error {
 	vars := e.vars()
 
-	eval := func(x string) (interface{}, error) {
+	eval := func(x string) (any, error) {
 		f, err := e.expr(x)
 		if err != nil {
 			return nil, err
@@ -518,7 +518,7 @@
 	return nil
 }
 
-func columnToNum(col interface{}) interface{} {
+func columnToNum(col any) any {
 	var name string
 	switch v := col.(type) {
 	case string:
@@ -534,7 +534,7 @@
 	return num
 }
 
-func asInt(i interface{}) (int, error) {
+func asInt(i any) (int, error) {
 	switch v := i.(type) {
 	case int:
 		return v, nil
@@ -557,7 +557,7 @@
 	}
 }
 
-func coord2cell(ix, iy interface{}) interface{} {
+func coord2cell(ix, iy any) any {
 	x, err := asInt(ix)
 	if err != nil {
 		log.Errorf("invalid x value: %v\n", err)
@@ -594,8 +594,8 @@
 	return f, nil
 }
 
-func (e *executor) vars() map[string]interface{} {
-	vars := map[string]interface{}{}
+func (e *executor) vars() map[string]any {
+	vars := map[string]any{}
 	if len(e.frames) > 0 {
 		vars["row_number"] = e.frames[len(e.frames)-1].index
 	}
@@ -612,7 +612,7 @@
 
 func (e *executor) expand(
 	str string,
-	vars map[string]interface{},
+	vars map[string]any,
 ) (string, error) {
 
 	var err error
@@ -638,13 +638,13 @@
 
 func (e *executor) typedExpand(
 	str string,
-	vars map[string]interface{},
-) (interface{}, error) {
+	vars map[string]any,
+) (any, error) {
 
 	var (
 		err      error
 		repCount int
-		last     interface{}
+		last     any
 	)
 
 	replace := func(s string) string {