feat: WeKan ticketing source

- wekan connector: board id as project key, cards assigned to the
  consultant's WeKan username (assignees with member fallback), archived
  cards skipped, client-side modifiedAt since-filtering, username/password
  login with token reuse (or pre-issued token), case-insensitive identity
- fake-WeKan unit tests: factory validation, test-connection, fetch
  filtering, key listing, token reuse
- admin customer wizard: WeKan option + credential fields
- OpenAPI enum + credential shapes, README identity mapping docs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
etalon
2026-06-12 21:15:34 +02:00
parent 6265ffa894
commit f3897907a3
11 changed files with 516 additions and 6 deletions
+17
View File
@@ -71,6 +71,23 @@ func NewConnector(t domain.TicketingType, baseURL, projectKey string, creds Cred
return nil, fmt.Errorf("youtrack requires permanentToken")
}
return &youtrackConnector{baseURL: baseURL, projectKey: projectKey, token: creds["permanentToken"]}, nil
case domain.TicketingWekan:
hasLogin := creds["username"] != "" && creds["password"] != ""
hasToken := creds["token"] != ""
if !hasLogin && !hasToken {
return nil, fmt.Errorf("wekan requires username+password (or a pre-issued token)")
}
if baseURL == "" {
return nil, fmt.Errorf("wekan requires baseUrl")
}
if projectKey == "" {
return nil, fmt.Errorf("wekan requires projectKey (the board id)")
}
return &wekanConnector{
baseURL: baseURL, boardID: projectKey,
username: creds["username"], password: creds["password"],
token: creds["token"],
}, nil
case domain.TicketingDemo:
return &demoConnector{projectKey: projectKey}, nil
default: