5b1006d32162678d0e76f86c23b1121efe700a46
133
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5b1006d321 |
Merge pull request 'fix: ensure SSR always fetches fresh assets from database' (#9) from bugfix/ssr-asset-freshness into main
CI Pipeline / backend-test (push) Successful in 10m25s
CI Pipeline / frontend-test (push) Successful in 25s
CI Pipeline / backend-lint (push) Successful in 14s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / quality-gate (push) Successful in 2s
Reviewed-on: http://192.168.1.74:30008/kfj001/kmtnflower/pulls/9 |
||
|
|
1db84a384f |
fix(ssr): manually register engine manifest to fix 404 on all routes
CI Pipeline / frontend-test (push) Successful in 24s
CI Pipeline / backend-test (pull_request) Successful in 9m38s
CI Pipeline / frontend-test (pull_request) Successful in 23s
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 / backend-test (push) Successful in 9m49s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 3s
The Angular 21 builder generates angular-app-engine-manifest.mjs at build time but does NOT inject the import into server.mjs. Without manually importing and registering the manifest via ɵsetAngularAppEngineManifest, AngularNodeAppEngine fails with 'Angular app engine manifest is not set' and every request returns 404. This matches the exact issue reported in PR #14 on staging where nginx starts successfully but returns 'Not Found' for all paths. |
||
|
|
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.
|
||
|
|
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
|
||
|
|
c4e852684e |
fix: use bracket notation for process.env access (TS5.9 strict)
CI Pipeline / backend-test (push) Successful in 5m31s
CI Pipeline / frontend-build (push) Successful in 29s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / frontend-test (push) Successful in 23s
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 / frontend-build (pull_request) Successful in 29s
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. |
||
|
|
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 |
||
|
|
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> |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 / 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-lint (push) Successful in 9s
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 |
||
|
|
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
|
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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/
|
||
|
|
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> |
||
|
|
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
|
||
|
|
58267e8f59 |
feat(seo): Phase 2 — route-level metadata service and JSON-LD structured data
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
CI Pipeline / frontend-test (push) Successful in 28s
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). |
||
|
|
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 |
||
|
|
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
|
||
|
|
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
|
||
|
|
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
|
||
|
|
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. |
||
|
|
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' |
||
|
|
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. |
||
|
|
5484c761b4 |
fix: address reviewer feedback — dynamic sitemap/robots + wildcard CI branches
CI Pipeline / backend-test (push) Successful in 8m12s
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 (push) Successful in 28s
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' |
||
|
|
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
|
||
|
|
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 |
||
|
|
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 |
||
|
|
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> |
||
|
|
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. |
||
|
|
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
|
||
|
|
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 / 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-lint (push) Successful in 8s
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. |
||
|
|
85b3a4adc4 |
fix: add password_hash column migration and unit tests
CI Pipeline / backend-test (pull_request) Successful in 4m11s
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 / frontend-build (pull_request) Successful in 30s
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 |
||
|
|
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 / frontend-build (push) Successful in 31s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / frontend-test (pull_request) Successful in 26s
CI Pipeline / quality-gate (pull_request) Successful in 2s
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 |
||
|
|
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 / 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
CI Pipeline / backend-lint (pull_request) Successful in 11s
- 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 |
||
|
|
c74d905378 | fix(deps): add bcrypt to requirements.txt for CI test collection | ||
|
|
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). |
||
|
|
f29640eb47 |
Add admin user management API and frontend UI
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) |
||
|
|
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) |
||
|
|
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 |
||
|
|
a36fd92ad4 |
Merge pull request 'feat: add test framework, unit tests, and GitLab CI pipeline' (#1) from feature/tests-and-ci into main
Reviewed-on: http://192.168.1.74:30008/kfj001/kmtnflower/pulls/1 Reviewed-by: kfj001 <kfj001@gmail.com> |
||
|
|
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
|
||
|
|
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 |
||
|
|
80181cf4ed | fix(ci): remove duplicate .gitlab-ci.yml — project uses Gitea Actions, not GitLab CI | ||
|
|
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. |
||
|
|
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
|
||
|
|
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 |
||
|
|
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) |
||
|
|
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 |