59 Commits
Author SHA1 Message Date
Hermes Robot c5d80f4caa feat(ssr): spider-only SSR — serve CSR shell for regular users
CI Pipeline / backend-test (push) Successful in 12m23s
CI Pipeline / frontend-test (push) Successful in 24s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / backend-test (pull_request) Successful in 17m40s
CI Pipeline / frontend-test (pull_request) Successful in 24s
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 3s
CI Pipeline / quality-gate (pull_request) Successful in 3s
Add spider detection gate to SSR server so that search engine
crawlers get full server-side rendering with fresh API data,
while regular users receive the static CSR app shell from disk.

- backend/app/spider_detection.py: Python spider detection module
- spider_detection.ts: TypeScript mirror of spider detection patterns
- server.ts: SSR gate — isSpider() check before dispatching to
  Angular SSR engine; non-spiders get static index.html
- server.spec.ts: Added spider detection unit tests
- tsconfig.app.json: Include spider_detection.ts in compilation
- backend/app/models.py: Fix SQLAlchemy FK resolution (user_models import)
2026-08-08 17:48:37 +00:00
kfj001 4b123025e4 Updates the generation means of robots.txt and sitemap.xml to be based off siteconfig's website param.
CI Pipeline / backend-test (push) Successful in 10m0s
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
2026-08-04 20:33:25 -07:00
Hermes Agent 3687e91f7f test(seo): add unit tests for sitemap export and API endpoints
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 / backend-lint (push) Successful in 10s
CI Pipeline / backend-test (pull_request) Successful in 10m26s
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 (push) Successful in 3s
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 / backend-test (push) Successful in 8m58s
CI Pipeline / frontend-test (push) Successful in 29s
CI Pipeline / frontend-build (push) Successful in 31s
CI Pipeline / backend-lint (push) Successful in 10s
CI Pipeline / backend-test (pull_request) Successful in 8m56s
CI Pipeline / frontend-test (pull_request) Successful in 28s
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
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 / 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 Pipeline / quality-gate (pull_request) Successful in 2s
- 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 / 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 (push) Successful in 4m26s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 9s
2026-08-04 10:40:37 +00:00
Hermes Agent e3a742b708 fix(seo): add RouterLinkWithHref imports + default social media fields
CI Pipeline / backend-test (push) Successful in 4m24s
CI Pipeline / backend-lint (pull_request) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 2s
CI Pipeline / frontend-test (push) Successful in 28s
CI Pipeline / frontend-build (push) Successful in 29s
CI Pipeline / backend-lint (push) Successful in 9s
CI Pipeline / backend-test (pull_request) Successful in 4m19s
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
- 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-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 / backend-test (push) Successful in 4m22s
CI Pipeline / frontend-test (push) Successful in 26s
CI Pipeline / frontend-build (push) Failing after 28s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / quality-gate (pull_request) Successful in 1s
- 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
Hermes Agent 433bdef5d0 fix(auth): remove redundant startup bootstrap user creation
CI Pipeline / backend-test (push) Successful in 4m59s
CI Pipeline / frontend-test (push) Successful in 32s
CI Pipeline / frontend-build (push) Successful in 30s
CI Pipeline / backend-lint (push) Successful in 8s
CI Pipeline / backend-test (pull_request) Successful in 5m2s
CI Pipeline / frontend-test (pull_request) Successful in 27s
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
CI Pipeline / quality-gate (pull_request) 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 (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 / backend-test (pull_request) Successful in 4m11s
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
2026-07-31 08:10:05 +00:00
Hermes Agent c74d905378 fix(deps): add bcrypt to requirements.txt for CI test collection
CI Pipeline / backend-test (pull_request) Successful in 4m2s
CI Pipeline / frontend-test (pull_request) Successful in 30s
CI Pipeline / backend-lint (pull_request) Successful in 9s
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
robot 4e7ba7adea fix(tests): mock os.path.exists for GeoLite2 tests so reader initialization succeeds
CI Pipeline / backend-test (push) Successful in 12s
CI Pipeline / frontend-test (push) Successful in 27s
CI Pipeline / backend-lint (push) Successful in 9s
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 (push) Successful in 2s
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-test (push) Failing after 12s
CI Pipeline / frontend-test (push) Successful in 34s
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
- 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
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 39b3e633a6 Fixes security issue: potential remote Path Traversal via File Upload 2026-07-19 05:55:58 +00:00
kfj001 a4093e86b1 fixes generated image download 2026-07-08 23:18:07 -07:00
kfj001 57198cd671 Fixes build results console log screen 2026-07-08 20:32:00 -07:00
kfj001 2c66a802c0 incorporates and implements mobile build service functionality. 2026-07-08 15:02:22 -07:00
Your Name 9e3ee75bd4 fixes for double nginx forward scenarios 2026-07-07 09:17:34 +00:00
Your Name 8cd54459ec Adds website theme serialization system 2026-07-06 06:52:18 +00:00
kfj001 ba99e88303 updates service api endpoints to allow for nginx forwarding with ssh 2026-07-04 21:10:36 +00:00
kfj001 7a04fa7c84 sets default admin creds in docker compose. first pass remote builder feature 2026-07-04 18:40:29 +00:00
kfj001 d2ab2240d5 transforms landing, about and schedule page content to data driven 2026-07-01 03:24:30 +00:00
kfj001 fd7b1f2861 Updated geodatabase info 2026-06-30 21:51:09 +00:00
kfj001 e6c5ca1ee3 Updated gitignore - adds 'city' geodata (really country) 2026-06-30 21:48:48 +00:00
kfj001 6db3bf9853 fixes db init for production 2026-06-30 21:37:55 +00:00
kfj001 9b8d4c0f01 layout changes with media player and negative spacing at top of screen. updated sqlalchemy init for postgres deployment 2026-06-30 21:06:35 +00:00
kfj001 87c9b0b8ab better color control 2026-06-30 03:52:00 +00:00
kfj001 f62f8188bf additional colors under admin control 2026-06-29 22:31:37 +00:00
kfj001 ee79662e5d adds color themeing support to the site 2026-06-29 21:23:51 +00:00
kfj001 8ef1ac12c7 bug fixes for local deployment model 2026-06-28 14:37:24 -07:00
kfj001 621e8bd7b6 buildable docker compose 2026-06-28 13:23:00 -07:00
kfj001 de70005b39 dockerfile fixed to include geo db 2026-06-28 12:14:25 +00:00
kfj001 db2ebd23fb adjusts display issues of world map on admin dash 2026-06-28 08:29:32 +00:00
kfj001 77d1c04d86 Adds visitor dashboard and related features 2026-06-28 06:41:23 +00:00
kfj001 fd61246ceb fixes small gap between navbar and media player on mobile 2026-06-26 02:19:36 +00:00
kfj001 1fe6833428 bugfix on data model 2026-06-26 00:21:58 +00:00
kfj001 4bb21f70ed new app store links feature 2026-06-25 08:24:45 +00:00
kfj001 d9b0964f07 new media player functionality 2026-06-25 06:09:28 +00:00
kfj001 2295f841c9 Adds Underwriter's carousel and admin features 2026-06-23 06:50:08 +00:00
kfj001 9b95bef9c6 Retires Support/donation/tiers page in favor of simple configurable link 2026-06-23 00:30:47 +00:00
kfj001 3b61a131c1 database driven image uploader and storage service model 2026-06-22 19:29:06 +00:00
kfj001 76894061c5 more changes 2026-06-22 05:43:27 +00:00
kfj001 9049b066ba Remove Programs tab and all supporting code
The Programs feature is superseded by Shows, which provides a more
flexible model with schedule slots. This commit removes all Programs
code across frontend and backend:

Frontend:
- Delete admin-program-form component (ts/html/scss)
- Delete program.service.ts and program.ts interface
- Remove Programs tab, form modal, and all CRUD logic from admin
  component (ts + html)

Backend:
- Delete programs API router
- Remove Program ORM model and ProgramCreate/Update/Response schemas
- Remove programs router registration from main.py
- Remove Program from seed data, seed helpers, and truncate/reset
2026-06-22 05:42:43 +00:00
kfj001 eb9a00f21a Adds the new shows admin screen and drives schedule from it 2026-06-22 04:19:51 +00:00
kfj001 e627fe3637 New programming screen 2026-06-21 21:55:55 +00:00