Add application support teams with contacts
All checks were successful
CI / backend (push) Successful in 1m7s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 8s

Replaces the legacy supportteams/appowners pair: supportteams
(teamname unique, teamurl ServiceNow link) + supportteamcontacts
(multiple named contacts with SSO per team, the people you reach out
to), applications.supportteamid intact. Migration 7d18 migrates each
legacy team owner into a contact, drops appowners, and has a validated
downgrade. New /api/supportteams CRUD (admin writes, import-mode
timestamps, teamname lookup), Support card on application detail,
contacts column on the list, and a settings management page.
IMPORT-API.md mapping updated to the concrete endpoints.

658 tests pass; live dev migration applied (24 teams / 24 contacts);
fresh-install and downgrade round-trips verified on scratch DBs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-07-11 20:29:12 -04:00
parent 46e50c07ff
commit 7dae281993
18 changed files with 1095 additions and 172 deletions

View File

@@ -107,9 +107,9 @@ lookup-then-upsert loop (see section 5); rerunning any step is safe.
9. Notification types (`notifications/types`)
10. Per-plugin subtypes: computer types (from `pctype`), machine types,
printer types, network device types, measuring-tool types
11. Support teams + support-team contacts - see the DECIDED disposition in
section 4; import these BEFORE applications because
`applications.supportteamid` points at them
11. Support teams + support-team contacts (`supportteams`,
`supportteams/{id}/contacts` - see section 3.3); import these BEFORE
applications because `applications.supportteamid` points at them
12. Applications (`applications`) and their versions; import legacy `topics`
as applications too (KB links to applications, section 3)
2. **Assets, per type** (each creates the core Asset row plus its extension):
@@ -211,11 +211,19 @@ Note on communication types: the classic `comstypes.typename` values
seeded `communicationtypes.comtype`. They are created by the reference-data seed,
not imported per-row.
### 3.3 Applications, topics, installed apps
### 3.3 Support teams, applications, topics, installed apps
Support teams and their contacts import BEFORE applications, because
`applications.supportteamid` references a team. The legacy `appowners` table
is folded into contacts: each legacy `supportteams` row carries one
`appownerid`, so import that owner as ONE contact on the team (legacy
`appowner` -> `name`, `sso` -> `sso`).
| legacy table | target endpoint | field mapping | NK |
|---|---|---|---|
| `applications` | `POST /api/applications` | `appname`, `appdescription`, `supportteamid` (remapped, section 4), `isinstallable`, `applicationnotes`, `installpath`, `applicationlink`, `documentationpath`, `ishidden`, `isprinter`, `islicenced`, `image` | `appname` |
| `supportteams` | `POST /api/supportteams` | `teamname`, `teamurl` (ServiceNow group deep link) | `teamname` |
| `appowners` (via each team's `appownerid`) | `POST /api/supportteams/{supportteamid}/contacts` | `appowner` -> `name`, `sso` -> `sso`, `sortorder` (default 0) | (supportteamid, name) |
| `applications` | `POST /api/applications` | `appname`, `appdescription`, `supportteamid` (remap by team `teamname`, GET `/api/supportteams?teamname=...`), `isinstallable`, `applicationnotes`, `installpath`, `applicationlink`, `documentationpath`, `ishidden`, `isprinter`, `islicenced`, `image` | `appname` |
| `appversions` | `POST /api/applications/{appid}/versions` | `version`, `releasedate`, `notes` | `version` (per app) |
| `topics` | `POST /api/applications` | `topics` is a near-clone of `applications` and `knowledgebase.appid` points at it; import each distinct topic as an Application (`appname` = topic name), so KB links resolve against `applications` | `appname` |
| `installedapps` | `POST /api/computers/{computerid}/apps` | body `{appid, appversionid}`; resolve `machineid` -> the imported computer, `appid`/`appversionid` -> imported app + version | (computerid, appid) |
@@ -308,17 +316,6 @@ dispositions below are DECIDED, not open questions.
future design should favor per-field fleet-wide updates over per-machine
full-record imports.
### DECIDED: migrated into an upcoming model (do not build here)
- **`supportteams` and `appowners`** - WILL be migrated, but into a new
`supportteams` / `supportteamcontacts` model that is being built separately
immediately after this task. Legacy `supportteams` (teams, with `teamurl`)
becomes the teams table; legacy `appowners` becomes the contacts, linked to a
team via `supportteams.appownerid`. Import ordering: create teams and their
contacts BEFORE applications, because `applications.supportteamid` references
a team. Do not build these entities as part of the import work - just point
the two legacy tables at that upcoming target.
### DECIDED: skip (structure only or low value)
- **`compliance`, `compliancescans`** - 0 rows in `prodscratch`. No data to