Skip to content

Feature: Group discovered servers into Applications and query by App Identifier #21

@sugan0tech

Description

@sugan0tech

Summary

  • Add first-class "Applications" to group discovered servers, and expose APIs to manage apps and server membership. Support querying servers by app identifier.

Motivation

  • Today we can discover and list servers (/api/discover, /api/servers, /api/servers/{id}), but there is no way to organize them. Teams need logical groupings (apps) to view and operate on subsets of servers.

Proposal

  • Data model:

    • apps table: id (uuid), name (string, unique), identifier (slug, unique, indexed), description (text), created_at, updated_at.
    • Association: many-to-many between servers and apps via join table app_servers with columns: app_id, server_id (composite unique index). This preserves flexibility (a server can belong to multiple apps).
    • Alternative (simpler) option: add nullable app_id to Metadata (one app per server). Choose this if we want to start simple.
  • API endpoints (JSON over HTTP):

    • POST /api/apps — create app
      • Request: { "name": "Payments", "identifier": "payments", "description": "Prod payment service" }
      • Response: { "id": "<uuid>", "name": "...", "identifier": "...", "description": "..." }
    • GET /api/apps — list apps
    • GET /api/apps/{id} — get app by id
    • GET /api/apps/by-identifier/{identifier} — get app by identifier
    • POST /api/apps/{app_id}/servers — add servers to app
      • Request: { "server_ids": ["<uuid1>", "<uuid2>"] }
    • DELETE /api/apps/{app_id}/servers/{server_id} — remove server from app
    • Query servers by app:
      • GET /api/apps/{id}/servers OR GET /api/servers?app=<identifier> (either works; choose one and keep the other as an alias for convenience)
  • Storage changes (GORM):

    • Add models.App and models.AppServer (join) with migrations via AutoMigrate.
    • Storage methods: CreateApp, ListApps, GetAppByID, GetAppByIdentifier, AddServersToApp, RemoveServerFromApp, ListServersByAppID and/or ListServersByAppIdentifier.
  • UI (optional, separate PR):

    • Index page: show apps and counts.
    • App page: list member servers with links to server details.

Acceptance Criteria

  • Can create/list apps and retrieve an app by both id and identifier.
  • Can associate/disassociate servers with an app.
  • Can fetch servers for a given app using the app identifier (e.g., GET /api/servers?app=payments or GET /api/apps/by-identifier/payments/servers).
  • DB migrations run cleanly on fresh DB and existing DBs.
  • Basic error handling and 404/400/409 semantics implemented (e.g., duplicate identifier yields 409).

Open Questions

  • Do we need many-to-many or is one server limited to a single app? (Defaulting to many-to-many.)
  • Should app identifier be globally unique and immutable? (Recommend: yes.)

Tasks

  • Add models.App and (if many-to-many) models.AppServer.
  • Extend storage.Init to AutoMigrate new models.
  • Implement storage methods for apps and membership.
  • Add HTTP handlers and router routes for the endpoints above.
  • Add validation: non-empty name, slugified identifier, uniqueness checks.
  • Add list/filter handler for GET /api/servers?app=<identifier>.
  • Document new endpoints (see API docs issue).
  • Add lightweight tests for storage and handlers.

Notes

  • Keep request/response shapes consistent with existing JSON style.
  • Use UUIDs (same as server IDs) for app IDs.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions