Merge: pull latest main into bottom-nav branch
This commit is contained in:
@@ -24,16 +24,36 @@ func handleAppointmentsCalendarPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// handleSettingsPage serves the unified settings page with tabs for
|
||||
// Profil / Benachrichtigungen / CalDAV. The active tab is picked client-side
|
||||
// from ?tab=<name> so switching tabs doesn't round-trip.
|
||||
// Profil / Benachrichtigungen / CalDAV / Dezernat. The active tab is picked
|
||||
// client-side from ?tab=<name> so switching tabs doesn't round-trip.
|
||||
func handleSettingsPage(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, "dist/settings.html")
|
||||
}
|
||||
|
||||
// handleSettingsCalDAVRedirect keeps /settings/caldav working for
|
||||
// bookmarks and any external links while the canonical URL moves to
|
||||
// /settings?tab=caldav. 301 Moved Permanently — browsers cache the hop
|
||||
// so the redirect only costs once per bookmark.
|
||||
func handleSettingsCalDAVRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/settings?tab=caldav", http.StatusMovedPermanently)
|
||||
// settingsTabAliases maps every supported /settings/<slug> deep-link to its
|
||||
// canonical ?tab=<name> value the client TS understands. Both the German tab
|
||||
// IDs (profil/benachrichtigungen/dezernat) and intuitive English aliases
|
||||
// (profile/notifications/department) are accepted so bookmarks, smoke tests,
|
||||
// and manually-typed URLs all land on the right tab.
|
||||
var settingsTabAliases = map[string]string{
|
||||
"profil": "profil",
|
||||
"profile": "profil",
|
||||
"benachrichtigungen": "benachrichtigungen",
|
||||
"notifications": "benachrichtigungen",
|
||||
"caldav": "caldav",
|
||||
"dezernat": "dezernat",
|
||||
"department": "dezernat",
|
||||
}
|
||||
|
||||
// handleSettingsTabRedirect turns /settings/<slug> into /settings?tab=<canonical>
|
||||
// as 301 Moved Permanently. Unknown slugs fall back to the bare /settings page
|
||||
// (the client picks the default tab) so a typo doesn't 404.
|
||||
func handleSettingsTabRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
slug := r.PathValue("tab")
|
||||
canonical, ok := settingsTabAliases[slug]
|
||||
if !ok {
|
||||
http.Redirect(w, r, "/settings", http.StatusMovedPermanently)
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, "/settings?tab="+canonical, http.StatusMovedPermanently)
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ func Register(mux *http.ServeMux, client *auth.Client, giteaAPIToken string, svc
|
||||
|
||||
// Settings
|
||||
protected.HandleFunc("GET /settings", gateOnboarded(handleSettingsPage))
|
||||
protected.HandleFunc("GET /settings/caldav", handleSettingsCalDAVRedirect)
|
||||
protected.HandleFunc("GET /settings/{tab}", handleSettingsTabRedirect)
|
||||
|
||||
// Catch-all 404 — runs for any authenticated path that no more-specific
|
||||
// pattern claimed. Renders the chromed shell with HTTP 404 (Bug 9 from
|
||||
|
||||
@@ -28,6 +28,9 @@ func registerLegacyRedirects(mux *http.ServeMux) {
|
||||
"/parteien": "/parties",
|
||||
"/gerichte": "/courts",
|
||||
"/glossar": "/glossary",
|
||||
// Memorable aliases — sidebar uses the canonical path but users
|
||||
// type these from memory and would otherwise hit the 404 chrome.
|
||||
"/whatsnew": "/changelog",
|
||||
}
|
||||
for oldPrefix, newPrefix := range prefixes {
|
||||
mux.Handle("GET "+oldPrefix, redirectPrefix(oldPrefix, newPrefix))
|
||||
|
||||
53
tests/smoke-auth-2026-04-26-cleanup.md
Normal file
53
tests/smoke-auth-2026-04-26-cleanup.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Smoke Cleanup Delta — 2026-04-26 (post t-paliad-038/039/040)
|
||||
|
||||
Original report: `tests/smoke-auth-2026-04-25.md` (10 bugs).
|
||||
This is a delta report — only changes since the original. No URL grid replay.
|
||||
|
||||
Tester: `tester@hlc.de` (admin), Playwright headless against `https://paliad.de`.
|
||||
|
||||
## What shipped
|
||||
|
||||
| Task | Branch | Merge | What |
|
||||
|---|---|---|---|
|
||||
| t-paliad-038 | `mai/brunel/projects-detail-rename` | d81da4b | `/projects/{id}` notfound + German DOM/URL leftovers in `projects-detail` |
|
||||
| t-paliad-039 | `mai/brunel/urgent-deadlines-id` | f782ef7 | `/deadlines/{id}` notfound, `/deadlines` "Invalid Date", `/appointments/{id}` notfound |
|
||||
| (no task #) | `mai/brunel/footer-tool-by-flexsiebels` | 3ff982c | Footer "Nur für internen Gebrauch" → "ein Werkzeug von flexsiebels.de" |
|
||||
| (no task #) | `mai/brunel/project-tabs-nil-empty` | b4a409a | `/projects/{id}` tabs blank — list services returned JSON `null` → client `.length` crash |
|
||||
| t-paliad-040 | `mai/brunel/smoke-cleanup-batch-2` | 3a1eb07 | `/whatsnew` alias + `/settings/{tab}` deep-link redirects |
|
||||
|
||||
## Bug status
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Bug 1** (`/projects/{id}` SSR notfound while API 200) — t-paliad-038. `parseAkteID` was checking the German URL prefix; renamed to `parseProjectID` reading `/projects/{id}`. Confirmed via Playwright: project chrome + tabs render.
|
||||
- **Bug 7** (`/whatsnew` bare 404) — t-paliad-040. 301 → `/changelog` via `internal/handlers/redirects.go`. Confirmed: `curl -sI /whatsnew` → 301 Location: /changelog.
|
||||
- **Bug 8** (`/settings` tab deep-link 404) — t-paliad-040. Replaced single CalDAV-only handler with generic `/settings/{tab}` redirector. Map accepts both German tab IDs (`profil`, `benachrichtigungen`, `dezernat`) and English aliases (`profile`, `notifications`, `department`); unknown slugs fall back to `/settings` (default tab) instead of 404. Confirmed in Playwright as logged-in admin: `/settings/notifications` → `/settings?tab=benachrichtigungen` and the "Benachrichtigungen" tab is active. Same for `/settings/dezernat`, `/settings/profile`, `/settings/department`.
|
||||
- **Bug 9** (404 has no chrome) — already shipped in t-paliad-037. Verified still in place: `/garbage` returns 404 with sidebar + footer + "Zurück zum Dashboard" CTA.
|
||||
- **`/deadlines/{id}` notfound** (caught after smoke ran) — t-paliad-039. `parseFristID` checked `/fristen` URL prefix; renamed to `parseDeadlineID` reading `/deadlines`. Same class as Bug 1.
|
||||
- **`/deadlines` "Invalid Date"** (caught after smoke ran) — t-paliad-039. `fmtDate` blindly appended `T00:00:00` to API dates; API now returns full ISO datetime. Guarded with `iso.length === 10` / `iso.slice(0, 10)`.
|
||||
- **`/projects/{id}` tabs blank** (m reported after t-paliad-038) — empty list services returned JSON `null` (sqlx scan into `var rows []T` leaves nil slice; `encoding/json` marshals nil slice as `null`). Fixed at the source for 9 services (`party`, `project`, `deadline`, `appointment`, `note`, `checklist_instance`, `team`, `department` + their `WithProject` variants); client also coerces with `?? []`.
|
||||
|
||||
### Skipped (documented)
|
||||
|
||||
- **Bug 10** (login form 401 console replay) — **not fixable from JS**. Reproduced cleanly: a failed `/api/login` with the wrong password emits the exact one-line console error `[ERROR] Failed to load resource: the server responded with a status of 401`. That message is generated by the browser's network stack itself, not by `login.ts` (which has no `console.error` call — it shows the error in the form via `showError`). The only "fixes" available either compromise the security pattern (return HTTP 200 with `{ok: false}` body so 4xx never appears) or don't actually suppress the browser log (4xx → 4xx, status code change doesn't help). Brief explicitly authorised the skip ("If this turns out to be a non-trivial yak-shave, skip it"). Severity is low; the form UX itself works correctly.
|
||||
|
||||
### Still open from original report
|
||||
|
||||
- **Bug 2** — same root cause as Bug 1 / Bug `/deadlines/{id}` / Bug `/appointments/{id}` (German URL prefix in `parse*ID`). All three now fixed in t-paliad-038 + t-paliad-039.
|
||||
- **Bug 3** — `/projects` 500 (RLS function bodies) — already fixed in t-paliad-036 (migration 021).
|
||||
- **Bugs 4 / 5 / 6** — i18n leaks, `/api/departments` 500, dashboard activity — already fixed in t-paliad-037.
|
||||
- **Bugs not numbered above** (none) — original report had Bugs 1–10; all addressed.
|
||||
|
||||
## What's still off (post-fix smoke)
|
||||
|
||||
- **None blocking.** One known cosmetic: the browser's auto-emitted "Failed to load resource: 401" on a wrong-password login attempt (Bug 10) is unavoidable without changing the auth response shape. Documented above.
|
||||
- **Console clean** on the canonical pages I exercised: `/dashboard`, `/projects`, `/projects/{id}` (history/parties/deadlines/appointments/team), `/deadlines`, `/deadlines/{id}`, `/appointments`, `/appointments/{id}`, `/settings`, `/settings/notifications`, `/settings/dezernat`, `/changelog`, `/whatsnew`. No JS errors.
|
||||
- **Footer copy** — confirmed live: "© 2026 Paliad — ein Werkzeug von flexsiebels.de" on `/dashboard` and the marketing index.
|
||||
|
||||
## Verdict
|
||||
|
||||
**Clean.** All actionable items from the original 2026-04-25 smoke report are fixed (8/10) or explicitly deferred with rationale (Bug 10). No new regressions surfaced during verification. Ready for the next smoke pass.
|
||||
|
||||
## Out of scope (deferred — m to decide)
|
||||
|
||||
- **`Hogan Lovells` → dynamic `FIRM_NAME` constant** — m requested it, head asked to hold for architectural sign-off. WIP draft exists in `git stash` on this worker; can be revived as its own task.
|
||||
Reference in New Issue
Block a user