From 4f7a7d6946824fd7ac8e1d4671042b4efa47a702 Mon Sep 17 00:00:00 2001 From: sysops Date: Tue, 31 Mar 2026 01:12:51 +0200 Subject: [PATCH] feat: App-Version 0.9.1 + Modulversionsnummern - version.go: AppVersion + Modules-Map (pro Modul interne Versionsnummer) - GET /api/version: liefert App- und Modulversionen (ohne Auth) - archivmail version: zeigt App- und Modulversionen in CLI - version-Konstante aus cmd_import.go entfernt (war falsche Stelle) Co-Authored-By: Claude Sonnet 4.6 --- cmd/archivmail/cmd_import.go | 1 - cmd/archivmail/main.go | 6 +++++- cmd/archivmail/version.go | 28 ++++++++++++++++++++++++++++ internal/api/server.go | 15 ++++++++++++--- internal/api/version_handlers.go | 12 ++++++++++++ 5 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 cmd/archivmail/version.go create mode 100644 internal/api/version_handlers.go diff --git a/cmd/archivmail/cmd_import.go b/cmd/archivmail/cmd_import.go index bfce09e..89fadb1 100644 --- a/cmd/archivmail/cmd_import.go +++ b/cmd/archivmail/cmd_import.go @@ -16,7 +16,6 @@ import ( "github.com/archivmail/pkg/mailparser" ) -const version = "1.0.0" type importResult struct { Status string `json:"status"` diff --git a/cmd/archivmail/main.go b/cmd/archivmail/main.go index 1f19429..e32b657 100644 --- a/cmd/archivmail/main.go +++ b/cmd/archivmail/main.go @@ -51,7 +51,10 @@ func main() { runMigrateTenants(os.Args[2:]) return case "version": - fmt.Printf("archivmail %s\n", version) + fmt.Printf("archivmail %s\n", AppVersion) + for mod, ver := range Modules { + fmt.Printf(" %-14s %s\n", mod, ver) + } return case "help", "--help", "-h": printHelp() @@ -172,6 +175,7 @@ func main() { Secret: jwtSecret, } srv := api.New(apiCfg, mailStore, idx, authMgr, users, audlog, logger) + srv.SetVersion(AppVersion, Modules) bind := cfg.API.Bind if bind == "" { diff --git a/cmd/archivmail/version.go b/cmd/archivmail/version.go new file mode 100644 index 0000000..f121127 --- /dev/null +++ b/cmd/archivmail/version.go @@ -0,0 +1,28 @@ +package main + +// AppVersion ist die semantische Versionsnummer der Anwendung. +// Format: MAJOR.MINOR.PATCH +// MAJOR: Breaking changes / große Architekturänderungen +// MINOR: Neue Features / Module +// PATCH: Bugfixes / Security-Fixes +const AppVersion = "0.9.1" + +// Modules enthält die internen Versionsnummern der einzelnen Module. +// Format: MAJOR.MINOR — wird erhöht wenn das Modul geändert oder neu erstellt wird. +// MAJOR: Interface-Änderungen, Breaking changes innerhalb des Moduls +// MINOR: Neue Funktionen, Bugfixes, Security-Patches +var Modules = map[string]string{ + "storage": "1.4", // message-id dedup vorbereitet, verify_ok/verified_at + "smtpd": "1.2", // IP-Allowlist fail-closed, Domain→Tenant-Routing + "imapserver": "1.1", // Read-Only IMAP4rev1, Multi-Tenant-Isolation + "auth": "1.3", // JWT, bcrypt cost 12, TOTP + "audit": "1.1", // PostgreSQL append-only, QueryFilter + "index": "1.0", // Xapian-Wrapper, Async-Worker, Tenant-Index + "api": "1.6", // SEC-29 Rollen-Trennung, domain_auditor + "userstore": "1.3", // domain_auditor Rolle, bcrypt, LDAP-Auth + "imap": "1.2", // IMAP-Sync, Scheduler, POP3 + "labelstore": "1.0", // Labels, Tenant-Isolation + "tenantstore":"1.1", // Multi-Tenancy, Quotas + "ldapconfig": "1.1", // Pro-Mandant LDAP, TLS + "mailparser": "1.1", // RFC-2822, MIME, MessageID-Extraktion +} diff --git a/internal/api/server.go b/internal/api/server.go index bee6fca..b09e42c 100644 --- a/internal/api/server.go +++ b/internal/api/server.go @@ -73,11 +73,13 @@ type Server struct { pop3Store *pop3store.Store pop3Importer *pop3store.Importer uploadJobs sync.Map // jobID → *UploadJob - labels *labelstore.Store // PROJ-9: label management + labels *labelstore.Store ldapStore *ldapcfg.Store tenantStore *tenantstore.Store - tenantLdapStore *ldapcfg.TenantStore // PROJ-23: per-tenant LDAP config - idxMgr *index.TenantIndexManager // PROJ-21 Phase 4: per-tenant Xapian index + tenantLdapStore *ldapcfg.TenantStore + idxMgr *index.TenantIndexManager + appVersion string + moduleVersions map[string]string } // SetSMTPDaemon wires the SMTP daemon into the API server after construction. @@ -103,6 +105,12 @@ func (s *Server) SetIndexManager(mgr *index.TenantIndexManager) { s.idxMgr = mgr } +// SetVersion wires app version and module versions into the API server. +func (s *Server) SetVersion(appVersion string, modules map[string]string) { + s.appVersion = appVersion + s.moduleVersions = modules +} + // New creates and wires up a new API server. func New( cfg config.APIConfig, @@ -139,6 +147,7 @@ func (s *Server) authAdmin(h http.HandlerFunc) http.HandlerFunc { func (s *Server) routes() { s.mux.HandleFunc("GET /api/health", s.handleHealth) + s.mux.HandleFunc("GET /api/version", s.handleVersion) s.mux.HandleFunc("POST /api/auth/login", s.handleLogin) s.mux.HandleFunc("GET /api/auth/me", s.auth(s.handleMe)) s.mux.HandleFunc("POST /api/auth/logout", s.auth(s.handleLogout)) diff --git a/internal/api/version_handlers.go b/internal/api/version_handlers.go new file mode 100644 index 0000000..f293ca7 --- /dev/null +++ b/internal/api/version_handlers.go @@ -0,0 +1,12 @@ +package api + +import "net/http" + +// handleVersion liefert App- und Modulversionen. +// GET /api/version — öffentlich (kein Auth erforderlich). +func (s *Server) handleVersion(w http.ResponseWriter, r *http.Request) { + writeJSON(w, http.StatusOK, map[string]interface{}{ + "version": s.appVersion, + "modules": s.moduleVersions, + }) +}