Move web UI from /ui/ to /web/ path prefix

The web UI is now mounted at /web/ (previously /ui/) — cmd/server/main.go
wraps web.Server.Handler with http.StripPrefix("/web", ...), so
internal/web's own routes stay unprefixed (/, /login, /logout,
/shares/..., /static/...) and only the outer mux adds the prefix. All
templates, redirects, and cookie paths updated accordingly. The root '/'
route reverts to the original unauthenticated welcome page (linking to
/web/), and /cal/, /card/, /files/ are unaffected.

Also gitignore the bin/ build output directory.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-08-19 07:29:32 +02:00
co-authored by Copilot
parent ab3c7f44d5
commit 4dba55c807
15 changed files with 58 additions and 52 deletions
+9 -6
View File
@@ -4,7 +4,7 @@ A self-hosted CalDAV, CardDAV, and WebDAV server written in Go, backed by a
filesystem store, with calendar/address book sharing grants tracked in a
small SQLite database. HTTP Basic Auth (bcrypt) with per-user isolated
collections. A small server-rendered web UI (templ + Tailwind + htmx) at
`/ui/` lets users log in and manage their shares.
`/web/` lets users log in and manage their shares.
## Build, test, lint
@@ -120,10 +120,13 @@ Test files: `internal/store/store_test.go`, `internal/webdav/handler_test.go`,
the caldav/carddav backends query the shares tables on every request
(no caching), changes take effect immediately without restarting the
server.
- `internal/web` — the web UI, mounted at `/ui/` in `cmd/server/main.go`
(`web.NewServer(cfg, st, dbase, logger).Handler(webstatic.FS())`),
entirely separate from `internal/auth`'s Basic Auth: logins go through
`/ui/login` (username/password checked against `cfg.Users` the same way
- `internal/web` — the web UI, mounted at `/web/` in `cmd/server/main.go`
(`mux.Handle("/web/", http.StripPrefix("/web", web.NewServer(cfg, st,
dbase, logger).Handler(webstatic.FS())))`, so `Server.Handler`'s own
routes are all unprefixed — `/login`, `/`, `/shares/...` — and only the
outer mux adds the `/web` prefix), entirely separate from `internal/auth`'s
Basic Auth: logins go through
`/web/login` (username/password checked against `cfg.Users` the same way
Basic Auth does, via bcrypt) and issue an opaque random session token
stored in the `web_sessions` SQLite table (`db.CreateSession`/
`SessionUser`/`DeleteSession`, see `internal/db/sessions.go`), set as an
@@ -135,7 +138,7 @@ Test files: `internal/store/store_test.go`, `internal/webdav/handler_test.go`,
(`SharesOfCalendar`/`SharesOfAddressBook`) and what's shared with them
(`CalendarsSharedWith`/`AddressBooksSharedWith`). `internal/web/shares.go`
handles POST (create/update share) and DELETE (revoke) at
`/ui/shares/{calendar,addressbook}`, re-rendering just the affected
`/web/shares/{calendar,addressbook}`, re-rendering just the affected
resource card for htmx's `hx-swap="outerHTML"`; it always checks
`ownsResource` first so a user can only share resources actually
configured for their own account (never someone else's, even via a