Commit Graph
131 Commits
Author SHA1 Message Date
DevOps QA 89cac854ae fix: use full nginx.conf instead of conf.d snippet to avoid directive nesting error
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / backend-lint (pull_request) Successful in 10s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-test (push) Successful in 5m1s
CI Pipeline / frontend-test (push) Successful in 29s
CI Pipeline / backend-test (pull_request) Successful in 4m48s
CI Pipeline / frontend-test (pull_request) Successful in 24s
CI Pipeline / quality-gate (push) Successful in 2s
Alpine nginx includes conf.d/*.conf inside the http{} block, but our
template contained map/log_format directives and a server{} block that
conflicted with the include structure. Switched to a complete standalone
nginx.conf with proper user/events/http nesting.
2026-08-07 14:47:48 +00:00
DevOps QA 8f0adf9299 fix: add gettext to Alpine image for envsubst in entrypoint
CI Pipeline / frontend-test (push) Successful in 24s
CI Pipeline / backend-lint (push) Successful in 12s
CI Pipeline / backend-test (pull_request) Successful in 5m48s
CI Pipeline / frontend-build (pull_request) Successful in 29s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-test (push) Successful in 5m46s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / frontend-test (pull_request) Successful in 22s
CI Pipeline / backend-lint (pull_request) Successful in 8s
2026-08-07 06:38:28 +00:00
DevOps QA c4e852684e fix: use bracket notation for process.env access (TS5.9 strict)
CI Pipeline / backend-test (push) Successful in 5m31s
CI Pipeline / frontend-test (push) Successful in 23s
CI Pipeline / frontend-build (push) Successful in 29s
CI Pipeline / frontend-build (pull_request) Successful in 29s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / backend-test (pull_request) Successful in 5m42s
CI Pipeline / frontend-test (pull_request) Successful in 24s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / quality-gate (push) Successful in 2s
- src/main.server.ts: process.env['SSR_API_BASE_URL'] instead of
  process.env.SSR_API_BASE_URL to satisfy TS4111 index signature rule.
- server.spec.ts: update corresponding test assertions to match new syntax.
2026-08-07 06:03:02 +00:00
robot 328d067d97 fix: ensure SSR always fetches fresh assets from database
CI Pipeline / backend-test (push) Successful in 5m31s
CI Pipeline / frontend-test (push) Successful in 23s
CI Pipeline / frontend-build (push) Failing after 27s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / backend-test (pull_request) Successful in 5m24s
CI Pipeline / frontend-test (pull_request) Successful in 23s
CI Pipeline / frontend-build (pull_request) Failing after 27s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
Root cause: Dockerfile copied only browser/ to nginx; server/server.mjs
was built but never deployed or executed. Prerender baked DEFAULT_CONFIG
into static HTML with no API at build time, causing stale content on
every initial paint.

Changes:
- Dockerfile: serve stage uses node:22-alpine, installs nginx via apk,
  copies both browser/ and server/ bundles from build stage
- docker-entrypoint.sh: starts Angular SSR Node process on port 4200,
  waits for readiness, exports SSR_API_BASE_URL, then exec nginx
- nginx.conf.template: adds upstream ssr_backend block (127.0.0.1:4200),
  proxies / to SSR backend, static assets served directly with 1y cache
- app.server.routes.ts: all routes switched from RenderMode.Prerender
  to RenderMode.Server for zero stale content
- server.ts: removed dead prerender code (PRERENDERED_ROUTES,
  isPrerenderedRoute, allowStaticRouteRender)
- main.server.ts: injects SSR-aware apiBaseUrl via APP_CONFIG
  (reads SSR_API_BASE_URL env var)
- server.spec.ts: updated 5 test suites + added 5 new suites (31 tests)
  covering server.ts cleanup, RenderMode.Server, entrypoint lifecycle,
  Dockerfile build, nginx upstream proxy, and API URL injection
- vitest.config.ts: added server.spec.ts to include pattern

Request flow: Browser -> nginx (port 80) -> SSR server (port 4200)
-> Angular SSR -> HttpClient -> localhost:80/api/station-config
-> nginx proxies to api:8000 -> fresh data rendered in HTML
2026-08-07 05:33:40 +00:00
kfj001 2ece38e52d Merge pull request 'feat(seo): Phase 3 — preload LCP image and reduce APP_INITIALIZER blocking' (#8) from feat/seo-phase3-optimizations into main
CI Pipeline / frontend-test (push) Successful in 24s
CI Pipeline / backend-lint (push) Successful in 11s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / backend-test (push) Successful in 9m10s
CI Pipeline / quality-gate (push) Successful in 3s
Reviewed-on: http://192.168.1.74:30008/kfj001/kmtnflower/pulls/8
Reviewed-by: kfj001 <kfj001@gmail.com>
2026-08-06 21:08:51 -07:00
kfj001 c4e2dc5b9f Merge pull request 'feat: add SSR and prerendering support' (#7) from feat/ssr-prerendering into main
CI Pipeline / backend-test (push) Successful in 9m9s
CI Pipeline / frontend-test (push) Successful in 26s
CI Pipeline / backend-lint (push) Successful in 11s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / frontend-build (push) Successful in 32s
Reviewed-on: kfj001/kmtnflower#7
2026-08-06 21:06:48 -07:00
robot e2356954ef feat(seo): Phase 3 — preload LCP image and reduce APP_INITIALIZER blocking
CI Pipeline / backend-test (push) Successful in 10m9s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / frontend-test (push) Successful in 30s
CI Pipeline / frontend-test (pull_request) Successful in 25s
CI Pipeline / frontend-build (pull_request) Successful in 41s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / backend-test (pull_request) Successful in 10m30s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / quality-gate (pull_request) Successful in 3s
- Add <link rel="preload"> for hero background image (LCP element) in index.html
- Remove blocking APP_INITIALIZER for config.json and station config loading
- Config loads now fire asynchronously in App.ngOnInit() (browser only)
- SSR/prerender renders instantly with default config — no network wait
- Improves LCP, Time to First Byte, and initial paint for SEO
2026-08-06 21:29:30 +00:00
Hermes Agent a8b6e65831 fix(ssr): enable static route rendering and fix self-import in server.ts
CI Pipeline / backend-test (push) Successful in 9m12s
CI Pipeline / frontend-test (push) Successful in 24s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / frontend-test (pull_request) Successful in 23s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-test (pull_request) Successful in 10m0s
- Add AngularAppEngine.ɵallowStaticRouteRender flag so the engine serves
  prerendered static HTML from disk instead of falling back to SSR
- Rename default export to named const (requestHandler) to avoid self-import
  loop when the module is the entry point
- Use requestHandler directly in the main-module listener instead of
  importing './server.js' which caused TS2307 resolution failure
2026-08-06 18:10:39 +00:00
Hermes Agent 63bc2fb22d fix(ssr): remove broken dynamic import and lazy-init engine
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-test (pull_request) Successful in 5m24s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / backend-test (push) Successful in 5m39s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / frontend-test (pull_request) Successful in 22s
CI Pipeline / quality-gate (push) Successful in 2s
- Replace await import('./main.server.js') with lazy getEngine()
  (original path was wrong — main.server.ts lives in src/, not root)
- AngularNodeAppEngine handles manifest registration internally;
  no manual bootstrap import needed
- Add npm scripts: build:ssr, build:prerender, serve:ssr:radio-station
- Add PRERENDER.md build documentation

Verified: clean build prerenders all 5 routes, 54 tests pass
2026-08-06 16:38:27 +00:00
Hermes Agent e95a158d57 fix(ssr): apply theme CSS vars during SSR and enable client hydration
CI Pipeline / backend-test (push) Successful in 9m4s
CI Pipeline / frontend-test (push) Successful in 24s
CI Pipeline / backend-lint (push) Successful in 14s
CI Pipeline / backend-test (pull_request) Successful in 9m17s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / backend-lint (pull_request) Successful in 10s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / frontend-build (push) Successful in 32s
CI Pipeline / frontend-test (pull_request) Successful in 24s
CI Pipeline / quality-gate (push) Successful in 2s
- ThemeService: remove isPlatformBrowser guard so CSS custom properties
  are applied during SSR/prerender — server-rendered HTML now carries the
  correct color scheme and gradients (fixes missing colors on test site).

- main.ts: add provideClientHydration() so Angular preserves the server-
  rendered DOM on the client instead of destroying and rebuilding it
  (fixes jarring full-page reload between static and dynamic versions).

- Tests: update theme.service.spec.ts to match new behaviour, expand
  coverage with gradient tests and empty-value handling (9 tests).
  Fix structured-data.component.spec.ts import paths. All 54 tests pass.
2026-08-06 03:24:57 +00:00
robot 2d26269c1a fix: align @angular/platform-server and @angular/ssr versions with Angular core
CI Pipeline / backend-test (push) Successful in 11m37s
CI Pipeline / frontend-build (push) Successful in 32s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / quality-gate (pull_request) Successful in 3s
CI Pipeline / frontend-test (push) Successful in 37s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / backend-test (pull_request) Successful in 11m59s
CI Pipeline / frontend-test (pull_request) Successful in 24s
CI Pipeline / frontend-build (pull_request) Successful in 33s
CI Pipeline / backend-lint (pull_request) Successful in 12s
The SSR packages were pinned to ^21.2.19 and ^21.2.20 which had
strict peer dependency requirements conflicting with @angular/common
at ^21.2.0. This caused npm ci (used in CI) to fail with peer
dependency resolution errors.

Aligned both packages to ^21.2.0 to match the rest of the Angular
core packages, and regenerated package-lock.json.
2026-08-05 22:11:05 +00:00
robot 0bde1cfc75 fix(tests): load JIT compiler before router imports in seo.service.spec
CI Pipeline / frontend-build (push) Failing after 10s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / frontend-build (pull_request) Failing after 19s
CI Pipeline / quality-gate (pull_request) Successful in 3s
CI Pipeline / backend-lint (pull_request) Successful in 11s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / backend-test (push) Successful in 14m20s
CI Pipeline / frontend-test (push) Failing after 14s
CI Pipeline / backend-test (pull_request) Successful in 11m56s
CI Pipeline / frontend-test (pull_request) Failing after 22s
The PlatformLocation static initializer in @angular/common/router
requires @angular/compiler to be loaded first. Move the compiler
import before any Angular router/common imports so the JIT facade
is available when the module loads.
2026-08-05 21:24:52 +00:00
robot a783626f34 feat: add SSR and prerendering support
CI Pipeline / backend-test (push) Successful in 10m24s
CI Pipeline / frontend-build (push) Failing after 23s
CI Pipeline / backend-lint (push) Successful in 12s
CI Pipeline / backend-test (pull_request) Successful in 10m45s
CI Pipeline / frontend-build (pull_request) Failing after 12s
CI Pipeline / backend-lint (pull_request) Successful in 13s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / quality-gate (pull_request) Successful in 3s
CI Pipeline / frontend-test (push) Failing after 19s
CI Pipeline / frontend-test (pull_request) Failing after 20s
- Install @angular/ssr and @angular/platform-server (v21.2.x)
- Create server entry point (server.ts) and server bootstrap (main.server.ts)
- Add server routes config (app.server.routes.ts) with 5 prerendered routes:
  /, /about, /schedule, /events, /contact
- Update angular.json with server/ssr/prerender build configuration
- Add prerender-routes.txt for build-time static route generation
- Fix SSR compatibility:
  - App component: guard DOM access with isPlatformBrowser
  - StructuredDataComponent: skip head manipulation on server
  - ThemeService: skip CSS variable application on server
  - ShowService/EventService: return empty arrays on API failure
    (graceful fallback during prerender with no backend)
- Prerendered output verified: 5 static HTML routes in dist/
2026-08-05 20:22:43 +00:00
kfj001 fdbc1d78da Merge pull request 'feat(seo): Phase 2 — route-level metadata service and JSON-LD structured data' (#6) from feat/seo-phase2-metadata-structured-data into main
CI Pipeline / backend-test (push) Successful in 8m29s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / frontend-build (push) Successful in 32s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / quality-gate (push) Successful in 3s
Reviewed-on: http://192.168.1.74:30008/kfj001/kmtnflower/pulls/6
Reviewed-by: kfj001 <kfj001@gmail.com>
2026-08-05 11:18:48 -07:00
robot c61162bff4 fix(seo): use bracket notation for Record index signature properties (TS4111)
CI Pipeline / backend-test (push) Successful in 5m10s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / quality-gate (push) Successful in 1s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-test (pull_request) Successful in 5m11s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / frontend-build (push) Successful in 29s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / frontend-test (pull_request) Successful in 28s
CI Pipeline / frontend-build (pull_request) Successful in 30s
2026-08-05 10:32:04 +00:00
robot 58267e8f59 feat(seo): Phase 2 — route-level metadata service and JSON-LD structured data
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / frontend-build (push) Failing after 29s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-test (push) Successful in 5m16s
CI Pipeline / backend-test (pull_request) Successful in 5m5s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / frontend-build (pull_request) Failing after 29s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
Add SeoService for dynamic metadata management:
- Per-route document titles (e.g., 'KMountain Flower Radio — About')
- Meta descriptions from station config per route
- Canonical URLs, Open Graph tags, Twitter Card tags
- Input sanitization (HTML stripping, URL validation, attribute escaping)
- noindex robots directives for /login and /admin routes
- Centralized router watcher (zero per-component boilerplate)

Add StructuredDataService + StructuredDataComponent for JSON-LD:
- Organization schema (NCBOrganization) site-wide with contact info
- WebSite schema with publisher info
- WebPage schema per-route with breadcrumbs
- Dynamic Event schema on /events page
- RadioSeason schema on /schedule page

Wire up SeoService.watchRouter() in app-root ngOnInit.
Wire up StructuredDataComponent in app-root template.
Wire up EventsComponent and ScheduleComponent to feed data to
StructuredDataService for dynamic schema injection.

Includes full test suite for SeoService (22 tests).
2026-08-05 10:12:55 +00:00
kfj001 2716765223 Merge pull request 'Updates the generation means of robots.txt and sitemap.xml to be based off siteconfig's website param.' (#5) from bugfix/fix_API_robots_txt into main
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / backend-test (push) Successful in 7m40s
CI Pipeline / frontend-build (push) Successful in 29s
CI Pipeline / frontend-test (push) Successful in 28s
Reviewed-on: kfj001/kmtnflower#5
2026-08-04 22:15:22 -07:00
kfj001 4b123025e4 Updates the generation means of robots.txt and sitemap.xml to be based off siteconfig's website param.
CI Pipeline / frontend-build (push) Successful in 32s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / backend-test (pull_request) Successful in 11m42s
CI Pipeline / frontend-test (pull_request) Successful in 31s
CI Pipeline / frontend-build (pull_request) Successful in 32s
CI Pipeline / backend-lint (pull_request) Successful in 12s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / quality-gate (pull_request) Successful in 3s
CI Pipeline / backend-test (push) Successful in 10m0s
2026-08-04 20:33:25 -07:00
robot 55be42ed99 Merge pull request 'fix(seo): comprehensive SEO improvements per expert audit' (#4) from fix/seo-improvements into main
CI Pipeline / backend-test (push) Successful in 10m13s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / frontend-test (push) Successful in 29s
CI Pipeline / backend-lint (push) Successful in 11s
CI Pipeline / quality-gate (push) Successful in 4s
2026-08-04 20:03:55 -07:00
kfj001 70bf1830b2 Merge branch 'main' into fix/seo-improvements
CI Pipeline / backend-test (push) Successful in 10m12s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / frontend-test (pull_request) Successful in 28s
CI Pipeline / backend-test (pull_request) Successful in 10m11s
CI Pipeline / frontend-build (pull_request) Successful in 31s
CI Pipeline / backend-lint (pull_request) Successful in 10s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 3s
2026-08-04 19:31:36 -07:00
Hermes Agent 58a25370b9 fix(seo): add admin UI for social media URLs
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / backend-lint (push) Successful in 11s
CI Pipeline / backend-test (pull_request) Successful in 10m43s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / frontend-build (pull_request) Successful in 32s
CI Pipeline / backend-test (push) Successful in 10m42s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / backend-lint (pull_request) Successful in 10s
CI Pipeline / quality-gate (pull_request) Successful in 4s
CI Pipeline / frontend-test (pull_request) Successful in 28s
Addresses reviewer feedback: social media fields (Facebook, Twitter/X, Instagram, YouTube) were added to the backend and frontend interfaces but had no admin UI for station owners to configure them.

Added a 'Social Media' section to the station config form with four URL inputs that persist via the existing station-config API.
2026-08-05 00:27:18 +00:00
Hermes Agent 3687e91f7f test(seo): add unit tests for sitemap export and API endpoints
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / backend-test (pull_request) Successful in 10m26s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / backend-test (push) Successful in 10m37s
CI Pipeline / frontend-test (push) Successful in 29s
CI Pipeline / frontend-build (push) Successful in 32s
CI Pipeline / frontend-test (pull_request) Successful in 28s
CI Pipeline / frontend-build (pull_request) Successful in 31s
CI Pipeline / backend-lint (pull_request) Successful in 11s
CI Pipeline / quality-gate (pull_request) Successful in 2s
- test_sitemap_export.py: 19 tests covering SEOMAP_ROUTES constants,
  build_sitemap_xml() output structure, XML validity, trailing slash
  handling, and build_robots_txt() rules + sitemap reference
- test_sitemap_api.py: 7 tests covering /sitemap.xml and /robots.txt
  endpoint status codes, content types, content validation, and
  auth-gated /regenerate endpoint

Addresses reviewer REQUEST_CHANGES: 'This needs a unit test' and
'Unit test for this type too'
2026-08-04 22:01:22 +00:00
Hermes Robot 3dead2921a fix: switch sitemap/robots to dynamic generation + Nginx proxy
CI Pipeline / frontend-test (push) Successful in 29s
CI Pipeline / backend-test (pull_request) Successful in 8m56s
CI Pipeline / frontend-build (pull_request) Successful in 32s
CI Pipeline / backend-lint (pull_request) Successful in 11s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / quality-gate (pull_request) Successful in 3s
CI Pipeline / backend-test (push) Successful in 8m58s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / frontend-test (pull_request) Successful in 28s
The reviewer noted the static sitemap.xml had a hardcoded domain in a
white-label app.  Instead of writing files to disk, we now serve
sitemap.xml and robots.txt as dynamic API endpoints that read
KMTN_WEBSITE_URL at runtime.

- Nginx proxies /sitemap.xml and /robots.txt to the backend API so
  search crawlers reach them at root paths.
- Removed the startup filesystem-write that would fail in Docker
  (backend can't write to Nginx container's static dir).
- Simplified sitemap_export.py to pure generation functions (no I/O).
- Added /api/sitemap/regenerate admin endpoint for consistency.
2026-08-04 20:06:00 +00:00
Hermes Robot 5484c761b4 fix: address reviewer feedback — dynamic sitemap/robots + wildcard CI branches
CI Pipeline / backend-test (push) Successful in 8m12s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / frontend-build (push) Successful in 32s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / backend-test (pull_request) Successful in 8m43s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / frontend-test (pull_request) Successful in 29s
CI Pipeline / frontend-build (pull_request) Successful in 32s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / quality-gate (push) Successful in 3s
- CI workflow: replace hardcoded branch list with ['**'] wildcard so
  pipeline runs on every branch push, not just 4 named branches.

- Sitemap/robots.txt: moved from static files to dynamic generation.
  New sitemap_export.py module (follows theme_export.py pattern) uses
  KMTN_WEBSITE_URL to generate tenant-aware sitemap.xml and robots.txt
  on app startup. Atomic writes to STATIC_FILES_DIR so Nginx serves them.

- Added /api/sitemap endpoint with /status (public) and /regenerate
  (admin-only) for runtime control.

Addresses reviewer comments on PR #4:
  1. 'more general way to ensure this runs on any branch on push'
  2. 'whitelabel app - this file may need to be dynamically generated'
2026-08-04 19:54:48 +00:00
Hermes Agent a7d994a122 chore: remove pytest artifacts from commit
CI Pipeline / backend-test (pull_request) Successful in 4m35s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / backend-test (push) Successful in 4m26s
CI Pipeline / frontend-build (push) Successful in 30s
2026-08-04 10:40:37 +00:00
Hermes Agent e3a742b708 fix(seo): add RouterLinkWithHref imports + default social media fields
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / frontend-build (push) Successful in 29s
CI Pipeline / backend-test (pull_request) Successful in 4m19s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / backend-test (push) Successful in 4m24s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / frontend-build (pull_request) Successful in 30s
- Import RouterLinkWithHref in footer and events components (required for queryParams binding on <a>)
- Add social media fields to DEFAULT_CONFIG in station-config.service.ts
2026-08-04 10:32:47 +00:00
Hermes Agent bea1c97e88 fix(seo): comprehensive SEO improvements per expert audit
CI Pipeline / backend-test (pull_request) Successful in 4m20s
CI Pipeline / frontend-build (pull_request) Failing after 29s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / frontend-test (push) Successful in 26s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 1s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / backend-test (push) Successful in 4m22s
CI Pipeline / frontend-build (push) Failing after 28s
- Add public/robots.txt (allow all, disallow /admin and /login, reference sitemap)
- Add public/sitemap.xml (5 public routes with change frequencies and priorities)
- Fix heading hierarchy: h2 -> h1 on about, schedule, events, contact pages
- Remove dead footer href="#" links:
  - Volunteer/Corporate Giving/Planned Giving -> routerLink to /contact with subject query param
  - Social media links -> conditional on config().social_* fields (hidden when empty)
- Fix logo ARIA: add aria-hidden="true" to decorative logo in about page divider
- Add social_facebook, social_twitter, social_instagram, social_youtube to:
  - StationConfig DB model + startup migration
  - StationConfigResponse and StationConfigUpdate schemas
  - Frontend StationConfig TypeScript interface
- Fix events "Learn More" dead link -> routerLink to /contact
2026-08-04 10:19:24 +00:00
kfj001 da02687260 Merge pull request 'fix(seo): use h1 as primary heading on about, schedule, events, and contact pages' (#3) from fix/seo-heading-hierarchy into main
CI Pipeline / backend-test (push) Successful in 4m24s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / frontend-build (push) Successful in 29s
CI Pipeline / quality-gate (push) Successful in 2s
Reviewed-on: kfj001/kmtnflower#3
Reviewed-by: kfj001 <kfj001@gmail.com>
2026-08-04 02:54:18 -07:00
robot b7e67fa244 fix(seo): use h1 as primary heading on about, schedule, events, and contact pages
CI Pipeline / backend-test (pull_request) Successful in 4m38s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / frontend-test (pull_request) Successful in 31s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / quality-gate (pull_request) Successful in 1s
Each public page now has exactly one <h1> element for proper semantic
heading hierarchy:
- About: 'About [Station Name]' (h1), with subsection h2s for History/Team
- Schedule: 'Program Schedule' (h1)
- Events: 'Upcoming Events' (h1)
- Contact: 'Get in Touch' (h1)

The home page hero component already used <h1>, as did login and admin.
2026-08-04 09:26:48 +00:00
robot 65af2824a9 Merge pull request 'feat: admin user management API, multi-admin roles, and conditional bootstrap login' (#2) from feature/multi-admin-roles into main
CI Pipeline / backend-test (push) Successful in 8m7s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / frontend-build (push) Successful in 33s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / quality-gate (push) Successful in 2s
2026-07-31 14:24:16 -07:00
Hermes Agent 433bdef5d0 fix(auth): remove redundant startup bootstrap user creation
CI Pipeline / backend-test (push) Successful in 4m59s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / frontend-test (push) Successful in 32s
CI Pipeline / backend-test (pull_request) Successful in 5m2s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / backend-lint (pull_request) Successful in 7s
CI Pipeline / quality-gate (push) Successful in 2s
The login endpoint already provisions the first admin user on demand
with a proper password_hash. The startup block in main.py created the
user without a password_hash, causing the login endpoint to see
has_admins=True and reject bootstrap credentials with 403.

Fix: remove the startup user-creation block so the login endpoint's
bootstrap path runs first and provisions the user correctly.
2026-07-31 18:28:26 +00:00
robot 85b3a4adc4 fix: add password_hash column migration and unit tests
CI Pipeline / backend-test (pull_request) Successful in 4m11s
CI Pipeline / frontend-build (pull_request) Successful in 30s
CI Pipeline / backend-test (push) Successful in 4m5s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 11s
CI Pipeline / frontend-test (pull_request) Successful in 26s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
- Add users.password_hash to _migrate_add_missing_columns pending list
- Skip tables that don't exist yet (prevents crash on fresh DB)
- Handle nullable columns (no DEFAULT clause) in ALTER TABLE
- Fix SQLite column type (use sql_type instead of hardcoded TEXT)
- Update migrate_roles.py to create schema columns/tables before seeding roles
- Add unit tests for migration: adds column, nullable, idempotent, no-op
2026-07-31 08:10:05 +00:00
robot 210da72e03 fix(frontend): add missing 'new' to EventEmitter instantiations
CI Pipeline / backend-test (push) Successful in 4m24s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / backend-test (pull_request) Successful in 4m18s
CI Pipeline / frontend-build (pull_request) Successful in 32s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / frontend-test (pull_request) Successful in 26s
The Angular production build was failing with TS2348 errors because
EventEmitter<void>() was used without the 'new' keyword. This is not
valid TypeScript — EventEmitter is a constructor class, not a callable
value.

Fixes:
- src/app/admin/admin-users-tab.component.ts: added 'new' to saved and
  closed EventEmitter properties
2026-07-31 05:39:04 +00:00
Hermes Agent f8a04dba1a fix(ci): add frontend production build step to catch Angular build failures
CI Pipeline / backend-test (push) Successful in 7m58s
CI Pipeline / frontend-test (push) Successful in 29s
CI Pipeline / backend-test (pull_request) Successful in 7m49s
CI Pipeline / frontend-test (pull_request) Successful in 29s
CI Pipeline / frontend-build (pull_request) Failing after 30s
CI Pipeline / backend-lint (pull_request) Successful in 11s
CI Pipeline / quality-gate (push) Successful in 3s
CI Pipeline / quality-gate (pull_request) Successful in 3s
CI Pipeline / frontend-build (push) Failing after 31s
CI Pipeline / backend-lint (push) Successful in 9s
- Add 'frontend-build' job that runs 'npx ng build --configuration production'
- Wire frontend-build into quality-gate dependencies
- Include feature/multi-admin-roles in CI push branches
- Build failures now fail the pipeline instead of being silently missed
2026-07-30 23:50:20 +00:00
Hermes Agent c74d905378 fix(deps): add bcrypt to requirements.txt for CI test collection
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / backend-test (pull_request) Successful in 4m2s
CI Pipeline / frontend-test (pull_request) Successful in 30s
CI Pipeline / quality-gate (pull_request) Successful in 3s
2026-07-30 10:36:21 +00:00
Hermes Agent ffbc19f16f fix(auth): only block bootstrap login when admin users exist
The previous check counted ALL users (func.count(User.id)), which
incorrectly blocked bootstrap login if any non-admin user (e.g.,
Google OAuth sign-in) already existed. The fix queries specifically
for admin users using the legacy is_admin flag OR the admin role
assignment in user_roles.

Also add tests for the non-admin-user-only scenario and fix the
stale test_non_admin_user_cannot_login_as_admin assertion (401
not 403 — bootstrap path is still active when no admin exists).
2026-07-30 09:44:42 +00:00
Hermes Agent f29640eb47 Add admin user management API and frontend UI
CI Pipeline / backend-test (pull_request) Failing after 22s
CI Pipeline / frontend-test (pull_request) Successful in 31s
CI Pipeline / backend-lint (pull_request) Successful in 9s
CI Pipeline / quality-gate (pull_request) Successful in 2s
Backend:
- /api/admin/users: GET list, POST create, PUT update, DELETE
- Admin users can be added with email, display name, and password
- Self-deletion and last-admin deletion are blocked
- Admin role auto-assigned on creation

Frontend:
- AdminUsersTabComponent: list + add/delete admin users
- AdminUserService: HTTP client for admin user CRUD
- AdminUser interface
- 'Admins' tab added to admin dashboard

Tests:
- 10 new tests for admin user management endpoints
- 140 total tests pass (130 original + 10 new)
2026-07-30 07:41:23 +00:00
Hermes Agent f22802658e feat: add conditional bootstrap login + 23 admin login tests
- Add hash_password/verify_password to app/auth.py using bcrypt
- Fix /login to reject bootstrap creds (403) when admin users exist
- Add normal password-based login path for existing admin users
- Eagerly load User.roles to avoid lazy-load outside async session
- Fix test_user_models.py VARCHAR assertion (SQLAlchemy 2.0 uses 'string')
- Use shared-cache SQLite in conftest for endpoint-level tests
- Add 23 tests covering all 3 required scenarios plus edge cases:
  1. Bootstrap login with hardcoded creds when no admins → PASS (200)
  2. Bootstrap login with hardcoded creds when admins exist → FAIL (403)
  3. Password login for existing admin with hashed password → PASS (200)
- All 130 tests pass (107 existing + 23 new)
2026-07-30 06:35:52 +00:00
Hermes Agent 0eca079f28 feat: add role-based admin support for multiple admin users
- Add Role model and user_roles association table (many-to-many)
- Add password_hash column to User model (nullable, for future bcrypt)
- Keep is_admin boolean for backward compatibility
- Add is_admin_effective property: true if legacy is_admin OR 'admin' role
- Update auth dependency (get_current_admin_user) to use is_admin_effective
- Update bootstrap login to auto-create 'admin' role and assign on login
- Update Google OAuth login to use is_admin_effective for token creation
- Add migrate_roles.py: idempotent migration script to backfill roles
- Add unit tests for Role, User, association table, and is_admin_effective
2026-07-30 04:54:30 +00:00
kfj001 a36fd92ad4 Merge pull request 'feat: add test framework, unit tests, and GitLab CI pipeline' (#1) from feature/tests-and-ci into main
CI Pipeline / frontend-test (push) Successful in 26s
CI Pipeline / backend-test (push) Successful in 12s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
Reviewed-on: http://192.168.1.74:30008/kfj001/kmtnflower/pulls/1
Reviewed-by: kfj001 <kfj001@gmail.com>
2026-07-29 15:40:30 -07:00
robot 4e7ba7adea fix(tests): mock os.path.exists for GeoLite2 tests so reader initialization succeeds
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / backend-test (push) Successful in 12s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / backend-test (pull_request) Successful in 12s
CI Pipeline / frontend-test (pull_request) Successful in 26s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 2s
2026-07-29 22:17:09 +00:00
robot da3cd5b2ed fix: address PR review feedback
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / backend-test (pull_request) Failing after 14s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-test (push) Failing after 12s
CI Pipeline / frontend-test (push) Successful in 34s
- Remove .gitlab-ci.yml (duplicative with Gitea Actions workflow)
- Add lookup_geo() unit tests with mocked MaxMind reader (4 tests)
- Expand README.md Testing section with backend/frontend/CI docs
- Add CLAUDE.md with test framework documentation
2026-07-29 20:22:41 +00:00
robot 80181cf4ed fix(ci): remove duplicate .gitlab-ci.yml — project uses Gitea Actions, not GitLab CI 2026-07-29 20:11:25 +00:00
CI Bot d7075b163a fix(ci): remove upload-artifact@v4 step incompatible with Gitea Actions
CI Pipeline / backend-test (push) Successful in 12s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / backend-test (pull_request) Successful in 12s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (push) Successful in 2s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / frontend-test (pull_request) Successful in 27s
The actions/upload-artifact@v4 step fails on Gitea with:
  GHESNotSupportedError: @actions/artifact v2.0.0+ not supported on GHES.

Coverage is already enforced via --cov-fail-under=10 in the test step,
so the artifact upload was redundant anyway.
2026-07-29 18:32:52 +00:00
robot 0771a07478 ci: add Gitea Actions workflow for CI pipeline
CI Pipeline / frontend-test (push) Successful in 2m29s
CI Pipeline / backend-test (pull_request) Failing after 15s
CI Pipeline / frontend-test (pull_request) Successful in 27s
CI Pipeline / quality-gate (pull_request) Successful in 3s
CI Pipeline / backend-test (push) Failing after 3m18s
CI Pipeline / backend-lint (push) Successful in 11s
CI Pipeline / backend-lint (pull_request) Successful in 10s
CI Pipeline / quality-gate (push) Successful in 3s
2026-07-29 15:51:18 +00:00
kfj001 96e6742676 feat: initialize frontend unit test framework with Vitest
- Add vitest ^4.0.8, jsdom, @vitest/coverage-v8 to devDependencies
- Configure vitest.config.ts for jsdom environment with src/**/*.spec.ts pattern
- Simplify test-setup.ts (no TestBed needed for standalone unit tests)
- Add example spec file src/app/app.spec.ts (5 tests) covering App component logic
- Add npm scripts: test:unit, test:unit:watch, test:unit:coverage
- Verified: 5/5 frontend tests pass, 86/86 backend pytest tests still pass
2026-07-29 11:17:27 +00:00
kfj001 eae0bffc89 ci: add branch trigger rules and improve quality gate
- Add rules to trigger pipeline on push to main/develop branches
- Separate stages: test, lint, build, gate
- Quality gate explicitly depends on backend-test passing
- Remove hardcoded DB credentials from CI variables
- Fix frontend-test before_script (remove hardcoded CI_PROJECT_PATH)
2026-07-29 11:16:16 +00:00
Hermes Agent 501df79e5c feat: add test framework, unit tests, and GitLab CI pipeline
- Add pytest config in backend/pyproject.toml with asyncio mode and coverage
- Add backend/requirements-test.txt with pytest, pytest-cov, pytest-asyncio, aiosqlite
- Write 86 backend unit tests covering auth (JWT tokens), schemas (Pydantic
  models), config (Settings env overrides), log_parser (log parsing, IP
  resolution, geo data), models (SQLAlchemy table definitions + column
  defaults), and theme export
- Add Vitest config for Angular frontend (vitest.config.ts, src/test-setup.ts)
- Add .gitlab-ci.yml with stages: backend-test, frontend-test, backend-lint,
  docker-build, and quality-gate
- CI enforces 10% minimum coverage threshold for backend
2026-07-29 08:34:42 +00:00
kfj001 8d233b17a5 Updated media player filter. Updated larger hero image size. 2026-07-20 19:14:33 -07:00
kfj001 39b3e633a6 Fixes security issue: potential remote Path Traversal via File Upload 2026-07-19 05:55:58 +00:00