Feat default surface routing + fix startup hang (#4)
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Successful in 4s
CI/CD / test-go-pg (pull_request) Failing after 2m18s
CI/CD / test-sqlite (pull_request) Successful in 2m40s
CI/CD / build-and-deploy (pull_request) Has been skipped
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / test-frontend (pull_request) Successful in 4s
CI/CD / test-go-pg (pull_request) Failing after 2m18s
CI/CD / test-sqlite (pull_request) Successful in 2m40s
CI/CD / build-and-deploy (pull_request) Has been skipped
Default surface routing (v0.2.1): - `/` redirects to configurable default surface with fallback chain: configured → first enabled extension surface → /admin - Auto-sets default_surface on first extension surface install - Admin settings UI: Default Surface dropdown - disabledRedirect() and extension surface disabled redirect now go to /admin instead of / to prevent redirect loops Fix Gin route param conflict causing backend startup hang: - Team package settings routes used `:pkgId` while sibling routes used `:id` — Gin's radix tree entered infinite loop on conflicting param names. Unified to `:id`. Docker entrypoint hardening: - Health check timeout 10s → 60s - Stale backend process cleanup on restart - Crash detection (exit early if backend dies) Roadmap direction updates: - v0.3.0: Notes surface (Obsidian-style) replaces Editor surface - v0.4.0: MVP (was v0.5.0) — chat moved to post-MVP - No built-in auto-install — explicit install only Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -553,6 +553,18 @@ func (h *PackageHandler) InstallPackage(c *gin.Context) {
|
||||
log.Printf("[packages] %s: %d dependencies recorded", pkgID, len(deps))
|
||||
}
|
||||
|
||||
// v0.2.1: Auto-set default_surface when the first extension surface is installed.
|
||||
if (pkgType == "surface" || pkgType == "full") && pkgSource != "core" {
|
||||
if raw, err := h.stores.GlobalConfig.Get(c.Request.Context(), "default_surface"); err != nil || raw == nil {
|
||||
dflt := models.JSONMap{"id": pkgID}
|
||||
if setErr := h.stores.GlobalConfig.Set(c.Request.Context(), "default_surface", dflt, ""); setErr != nil {
|
||||
log.Printf("[packages] failed to auto-set default_surface to %s: %v", pkgID, setErr)
|
||||
} else {
|
||||
log.Printf("[packages] Auto-set default_surface to %s (first extension surface)", pkgID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"id": pkgID,
|
||||
"title": title,
|
||||
|
||||
@@ -26,10 +26,10 @@ func NewTeamPackageSettingsHandler(s store.Stores) *TeamPackageSettingsHandler {
|
||||
|
||||
// GetTeamPackageSettings returns the team-scoped settings for a package,
|
||||
// along with the overridable schema keys for the UI.
|
||||
// GET /api/v1/teams/:teamId/packages/:pkgId/settings
|
||||
// GET /api/v1/teams/:teamId/packages/:id/settings
|
||||
func (h *TeamPackageSettingsHandler) GetTeamPackageSettings(c *gin.Context) {
|
||||
teamID := c.Param("teamId")
|
||||
pkgID := c.Param("pkgId")
|
||||
pkgID := c.Param("id")
|
||||
|
||||
pkg, err := h.stores.Packages.Get(c.Request.Context(), pkgID)
|
||||
if err != nil || pkg == nil {
|
||||
@@ -60,10 +60,10 @@ func (h *TeamPackageSettingsHandler) GetTeamPackageSettings(c *gin.Context) {
|
||||
|
||||
// UpdateTeamPackageSettings saves team-scoped overrides for a package.
|
||||
// Non-overridable keys are stripped before saving.
|
||||
// PUT /api/v1/teams/:teamId/packages/:pkgId/settings
|
||||
// PUT /api/v1/teams/:teamId/packages/:id/settings
|
||||
func (h *TeamPackageSettingsHandler) UpdateTeamPackageSettings(c *gin.Context) {
|
||||
teamID := c.Param("teamId")
|
||||
pkgID := c.Param("pkgId")
|
||||
pkgID := c.Param("id")
|
||||
|
||||
pkg, err := h.stores.Packages.Get(c.Request.Context(), pkgID)
|
||||
if err != nil || pkg == nil {
|
||||
@@ -108,10 +108,10 @@ func (h *TeamPackageSettingsHandler) UpdateTeamPackageSettings(c *gin.Context) {
|
||||
}
|
||||
|
||||
// DeleteTeamPackageSettings removes team-scoped overrides for a package.
|
||||
// DELETE /api/v1/teams/:teamId/packages/:pkgId/settings
|
||||
// DELETE /api/v1/teams/:teamId/packages/:id/settings
|
||||
func (h *TeamPackageSettingsHandler) DeleteTeamPackageSettings(c *gin.Context) {
|
||||
teamID := c.Param("teamId")
|
||||
pkgID := c.Param("pkgId")
|
||||
pkgID := c.Param("id")
|
||||
|
||||
if err := h.stores.Packages.DeleteTeamSettings(c.Request.Context(), pkgID, teamID); err != nil {
|
||||
c.JSON(500, gin.H{"error": "failed to delete team settings"})
|
||||
|
||||
Reference in New Issue
Block a user