Commit Graph

109 Commits

Author SHA1 Message Date
Scott Hatlen (CTR)
7e6cdc7f33 renaming osa -> mgmt 2026-04-08 13:34:51 -07:00
Scott Hatlen (CTR)
12b89c6866 fixing build issues 2026-04-08 13:25:48 -07:00
64089c039b Fix page scrolling when mouse is over sidebar
The sidebar nav section had no overflow containment, so scroll events
propagated to the page body causing the whole layout to scroll up
into blank space. Add overflow-y-auto for internal scrolling and
overscroll-contain to prevent propagation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:57:42 -07:00
d41056944e Split admin settings into Announcements, Billing, Notifications, Content, and System tabs
The single Settings tab was too long. Split into coherent groups:
- Announcements: alerts, bulletin board, MQTT diagnostics
- Billing: rate, billing day/notes, billing password, cost centers
- Notifications: SMTP status, email alert configuration
- Content: support resources, applications, downtime apps, agencies
- System: thresholds, work hours, downtime reminders, lifecycle
  rules (verification, unsponsored deletion, audit, auto-archive),
  security (session timeout, upload limit, PKCS12)

Settings form state is lifted into a shared useSettingsForm hook so
edits on any tab are saved together. Save button only appears when
there are unsaved changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:56:16 -07:00
a688fdfe02 Default admin users to Admin View tab on dashboard
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:52:15 -07:00
60b48972d5 Fix off-by-one in unsponsored deletion countdown
The countdown used floor division (timedelta.days / differenceInDays)
which truncates partial days. A user unsponsored at 2pm with a 7-day
window would immediately show 6 days remaining instead of 7. Switch
to ceiling division (math.ceil / Math.ceil) so any remaining time in
a day counts as a full day.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:50:38 -07:00
b893329bb3 Add billing tooltip to 'Paying for' line on project detail
Shows an info icon with tooltip explaining billing rules: users with
permissions longer than a day must be paid for, and the last project
to sponsor a user before the billing date pays. Only appears when the
billing count differs from the sponsored count.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:30:53 -07:00
e6b5c42334 Hide 'Paying for' when count matches sponsored count
The billing count line in the At a Glance card is redundant when it
equals the sponsored number. Only show it when they differ.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:27:52 -07:00
255643ec3b Add Projects and Teammates stat cards to personal dashboard
Adds two stat cards above the list cards on the user dashboard showing
project count and teammate count. Counts are derived from the
already-scoped useProjects and useMyTeammates hooks (row-level
filtered by KC permissions), not the admin stats endpoint.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 12:21:56 -07:00
c6af22a1e5 Add bulletin board channel for dashboard announcements
Adds a channel field (alert/bulletin) to announcements so the system
supports two distinct surfaces: short alert messages in the top bar
and longer-form bulletin posts on the user dashboard.

- Model: channel column (alert/bulletin, default alert) with migration
- Routes: channel filter on list/delete-all, channel field on create
- MQTT: publishes to sub-topics (mgmt/announcements/alert, .../bulletin)
- Frontend: useLiveAlerts (top bar), useLiveBulletins (dashboard),
  channel-aware MQTT subscriptions
- Admin: separate Alerts and Bulletin Board management sections
- Dashboard: AnnouncementsSection wired up with live bulletin feed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:40:06 -07:00
f0d1f2cf7c Add MQTT-backed real-time announcements replacing banner system
Replaces the static banner_messages setting with a full announcements
system backed by an MQTT broker (Mosquitto). Announcements are persisted
to a dedicated DB table for history/audit and pushed in real time via
MQTT-over-WebSocket to all connected browser clients.

- Mosquitto container in dev.sh and docker-compose.mqtt.yml overlay
- Backend: Announcement model, paho-mqtt client singleton, CRUD API
  with dual-write (DB + MQTT publish), mqtt-status health check,
  mqtt-config endpoint for frontend broker discovery
- Frontend: mqtt.js WebSocket client, useLiveAnnouncements hook that
  hydrates from REST then merges real-time MQTT events
- Admin UI: AnnouncementsSection with create/delete + expiry field,
  MqttDiagnosticsSection mirroring the Keycloak connectivity pipeline
- Helm chart: mqtt values, configmap, and secret entries for prod
- Data migration from banner_messages to announcements table

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 16:27:10 -07:00
74ab113aeb Move copy-email button to left of teammate name and fix alignment
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:55:24 -07:00
bce95d8150 Add personal dashboard with My Projects, Teammates, and Applications
- Dashboard toggle: VELA users see tabs (My Dashboard / Admin View),
  non-VELA users see only the personal dashboard
- My Projects card: scrollable list of user's projects with linked keys
- My Teammates card: deduplicated teammates across shared projects with
  email copy buttons and linked project keys/names
- Applications section: configurable app cards with icons, descriptions,
  and live status pills from proxied health check URLs
- Admin settings: Applications manager with image upload, drag-to-reorder,
  and audit logging
- Backend: GET /api/dashboard/my-teammates, GET/PUT /api/settings/applications,
  GET /api/dashboard/app-status with SSRF protection and input validation
- Seed data for Artifactory, Bitbucket, OpenShift, SRM, Black Duck,
  Coverity, and SwaggerHub

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 15:51:49 -07:00
91ea9a5f61 Add configurable billing notes setting
- Backend: add billing_notes setting with 5000 char limit
- Admin page: add textarea field under Project & User Defaults
- Project detail: display billing notes instead of placeholder text

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:42:45 -07:00
d763c57454 Add billing count to project detail and include sponsorship in user history
- Add billing_day_of_month setting (default: 1st) with admin UI field
- Add GET /api/projects/<key>/billing-count endpoint that computes
  currently sponsored + unsponsored users this project is liable for
- Display "Paying for X this month" below At a Glance cards on project detail
- Include sponsorship audit entries (sponsored/released) in user history query

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:39:37 -07:00
4ce8febdf4 Add configurable support resources with drag-to-reorder
- Backend: add support_resources JSON setting with GET/PUT endpoints
- Frontend: add useSupportResources hook and admin settings section
- Admin page: editable title/URL list with drag-and-drop reordering
- Project detail: replace hardcoded support links with dynamic settings

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 14:10:07 -07:00
4f5fb937f1 Add cost center name to project detail, status pills to list pages, and clickable project key on user detail
- Project detail: show cost center as "code - name" matching billing page format
- Projects list: add red "Unverified" pill that filters to overdue projects
- Users list: add red "Unsponsored" and amber "Delete Countdown" pills
- User detail: make project key column a clickable link to project detail

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:58:26 -07:00
Scott Hatlen (CTR)
b55185cd65 not using this import 2026-04-01 15:13:39 -07:00
bce35c6035 Fix Keycloak diagnostics showing green connectors when not connected
Connector lines between steps were green for skipped checks, making it
look like the chain succeeded even with no connection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:41:26 -07:00
5a70b62182 Shrink cost center settings table to show ~3 rows
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:33:24 -07:00
852686d123 Add delete all cost centers button on settings page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:32:21 -07:00
125f097df3 Fix cost center CSV upload by setting multipart/form-data header
The global axios instance defaults to application/json, which prevents
FormData from being sent correctly. Other file uploads already set the
header explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:28:19 -07:00
175f4159be Add cost center management with CSV upload and fuzzy search combobox
- New CostCenter model with CSV upload and manual add support
- Pipe-delimited CSV parsing extracts Cost Center and Code Name columns
- Upload preview shows which projects will lose their cost center
- Manual entries preserved across CSV re-uploads
- Fuzzy search combobox replaces text inputs on project form and billing page
- Cost center manager added to admin settings under Billing section
- Billing page: filter out archived projects, gate funding doc behind password
- Widen cost_center column from VARCHAR(10) to VARCHAR(50)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 11:25:11 -07:00
18e1215bc7 make project keys clickable links on billing page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 20:48:08 -07:00
7a0fa3172a Revert "fix billing page to not send or render data until password is verified"
This reverts commit b1a7770f64.
2026-03-31 20:41:14 -07:00
b1a7770f64 fix billing page to not send or render data until password is verified
Backend now returns an empty billing array when password is not verified,
preventing data exposure via developer tools. Frontend no longer renders
the table at all when locked — only the password card is shown.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 20:39:58 -07:00
4581e7f13f add Generate Report button to licenses page
Exports a CSV of all licenses with name, vendor, part number, cost,
purchase date, and expiration date. Generated client-side from the
already-fetched license data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:34:40 -07:00
596d2ee449 add Export CSV button for project members sponsorship table
New GET /api/projects/<key>/members/export endpoint returns a CSV with
name, email, sponsor_status, sponsor_project, last_login_at,
unsponsored_since, and days_until_deletion. Export button added to the
Users Associated with Project table toolbar on the project detail page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:32:15 -07:00
120a8e1955 add encrypted financial data from CSV uploads and password-gated billing page
Billing page now requires a shared password (separate from KC auth) to view any
data. Financial columns (Total, Spent, Available) populated from pipe-delimited
CSV uploads, parsed and stored encrypted (Fernet) in a new billing_data table.
Unmatched funding docs stored for auto-populate when projects get assigned matching
numbers. Admins set/reset the billing password from the Settings page with audit
logging and a gov-only access warning.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 14:18:07 -07:00
8c122d2685 replace funding document file with editable funding doc number and cost center fields
Funding document is now a text field (funding_doc_number) on the Project model
instead of a separate file-upload model. Both cost_center and funding_doc_number
are inline-editable on the billing page via PATCH /api/billing/<id>. Removed
FundingDocument model and all file upload/download/delete endpoints.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:27:35 -07:00
28f7777437 add Billing page with funding document management gated by VELA-mgmt-billing KC group
New billing domain: backend blueprint with Swagger-documented CRUD endpoints for
funding documents (one per project), FundingDocument model, billing_required
decorator checking VELA-mgmt-billing group membership. Frontend billing page with
DataTable (key, name, cost center, funding document upload/download/delete),
BillingRoute guard, hasBillingAccess in auth context. KC seed creates
VELA-mgmt-billing child group and adds Bill Billings (bill@bills.com) as a
billing-only test user.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:24:29 -07:00
89950b917f add government employee recommendation under PM field in project form
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:28:50 -07:00
d95f071af0 add switch-project hint to release sponsorship dialog
Link to user detail page as an alternative to releasing sponsorship,
so admins can transfer sponsorship to another project instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:24:05 -07:00
b65b9c328f restrict certs, licenses, and downtime to VELA/admin users
Add vela_or_admin_required decorator that gates access to hardcoded
admin or users with any VELA group membership. Applied to all cert,
license, and downtime API routes. Frontend sidebar hides these sections
and routes redirect non-VELA users to the dashboard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 11:23:28 -07:00
ab61f63e58 remove SQLite fallback, require PostgreSQL everywhere
- Remove sqlite DATABASE_URL from Dockerfile, docker-compose.yml, and
  Helm configmap; add Postgres service to base docker-compose
- Remove SQLite persistence PVC, usePostgres helper, and conditional
  volume/strategy logic from Helm chart
- Remove dual-dialect branches in run.py (keep Postgres-only SQL)
- Remove SQLite backup endpoint and frontend button
- Add Postgres container to dev.sh alongside Keycloak
- Update config.py default to postgresql://
- Update .env.example files, README, CLAUDE.md, and notes
- Tests remain on in-memory SQLite for speed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:46:32 -07:00
358d8d5dcc fix dashboard expiring items: remove limit(3) and add scrollable overflow
- Remove hardcoded .limit(3) on expiring licenses/certs query so all
  expiring items are returned
- Increase scroll container to max-h-[220px] to show ~3 items with
  partial 4th visible as scroll hint

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 10:34:40 -07:00
df8a8233bc add PKCS7 import, private key editing, drag-and-drop, and cert table fixes
- Add PKCS#7 (P7B/P7C) parsing support for cert import
- Allow adding/updating private keys on existing certs via PUT endpoint
- Add drag-and-drop file reading on private key textarea in cert form
- Truncate long issuer names in certs table column (max 200px)
- Fix certs table not refreshing after create/import/update/delete
- Add .p7b/.p7c to import dialog accepted file extensions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 09:23:36 -07:00
45321873f3 add per-project permissions on user detail, fix KC sync consistency
User detail page shows expandable accordion rows with permission
pills (e.g. mgmt-write, bitbucket-read) per project, scoped to
viewer access. "Manage" link directs to project groups tab.

Group member add/remove routes now write UserPermission rows
immediately (DB-first pattern), matching the rest of the codebase.
KC sync does full delete+rebuild per project to eliminate orphaned
and duplicate rows. Startup dedup migration cleans existing data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 16:03:47 -07:00
a2ad513d63 add license quantity field and sponsorship release warning dialog
License form shows seat/device count when type is Per Seat or Per
Device. Release sponsorship button now shows a confirmation dialog
warning that the user will be disabled in Keycloak and their account
deleted after the configurable unsponsored deletion period.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:13:18 -07:00
70b1d25b31 add downtime reminders, required fields, audit name fix, project filters, show-all rows
- Daily email reminders for unresolved downtime entries with configurable
  time and max days via admin settings (background worker thread)
- Downtime form: enclave, scope, and planned/unplanned now required
- Audit log resolves entity names from details when entities are deleted
  instead of showing "Deleted (ID: X)"
- Projects list: agency and service columns with faceted filters
- All data tables: "All" option in rows-per-page dropdown

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 15:05:13 -07:00
b60d03ea14 add dynamic filtered count pills to list page titles
Count badges next to Users, Licenses, and Certificates titles now
reflect the filtered row count from TanStack Table, updating live
with search and faceted filters. Added onFilteredCountChange callback
to the shared DataTable component.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:31:55 -07:00
a86e816d96 add row-level actions: disable user, archive licenses/certs
Users list gets a disable/enable button per row (admin-only).
Licenses and certs lists get archive/unarchive buttons per row
(VELA write/admin only). All use confirmation dialogs and existing
backend endpoints with proper permission gating.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:23:21 -07:00
d15bd88fee add dashboard pills for unverified projects, expiring licenses/certs
Projects card shows red "Unverified" pill linking to filtered project
list with new Verified column and faceted filter. License and cert
cards show amber "Expiring" pills alongside existing red "Expired"
pills. Added amber badge color to StatCard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 14:04:16 -07:00
d88a48b08e add configurable verification interval with audit logging
Replaces hardcoded 30-day verification window with a configurable
setting (default 90 days). Changes to any settings are now audit
logged with from/to values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 13:47:38 -07:00
dca541be61 add audit log page, multi-select project assignment, and status banner
- Full audit log page (VELA-only) with search, filters, and pagination
- Sidebar nav item gated on global_role (VELA users)
- User detail "Add to Project" now supports multi-select with checkboxes
- Status banner system: admin-configurable messages in topbar with
  info/warning/critical types, cycling, dismiss, and expand for long text
- Banner management UI in admin settings page
- Fix table overflow in audit log with min-w-0 on app shell

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 16:48:35 -07:00
5a9814626d add CSV import/export for group management
Backend:
- GET /api/projects/<key>/groups/export — CSV download of all group memberships
- POST /api/projects/<key>/groups/import-preview — dry-run with diff preview
- POST /api/projects/<key>/groups/import — apply import via KC queue
- Flexible CSV parsing: supports email,group / name,group / full format
- User matching by email first, name fallback, ambiguous match detection

Frontend:
- Export/Import CSV buttons in group management header
- Import dialog with drag-and-drop upload, preview with color-coded results
- Export requires read access, import requires write/admin

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 12:25:43 -07:00
fc3bfdd299 make Keycloak the primary login method, local login as break-glass
- Keycloak SSO button is now the prominent primary action on the login page
- Local username/password form hidden behind collapsible "Admin access" toggle
- Falls back to username/password form when Keycloak is not configured
- Rename container to mgmt-keycloak, backup filename to mgmt-backup

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 12:13:39 -07:00
e782392ec8 fix TypeScript build errors breaking container image build
- Remove unused displayName variable in keycloak-discrepancy-section
- Add missing san property to Cert interface
- Fix null assignability in downtime-form Select handlers
- Fix DialogTrigger asChild -> render prop for base-ui compatibility
- Exclude test files from tsconfig.app.json to avoid vitest type leakage
- Fix type assertion in users-columns test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 11:30:55 -07:00
6a2cc72d88 Fix resolve not sticking: heal stale UserPermission IDs and stop scroll jump
- After push_to_keycloak membership resolve, update any UserPermission
  rows with stale keycloak_user_id to match the user's current KC ID.
  This was the root cause: resolve added user to KC by their current ID,
  but the discrepancy scan still saw the old ID in UserPermission.
- Remove removeQueries/invalidateQueries from resolve hooks — wiping the
  cache caused the UI to unmount to "Not yet scanned" and re-mount,
  jumping to the top. The component's refetch() already handles refresh.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 19:37:26 -07:00
b931111928 Fix KC discrepancy detection, caching, and make UI helpdesk-friendly
Backend:
- Fix scanned_at date format (was double timezone: +00:00Z)
- Fix membership discrepancies: walk child groups (mirrors sync logic),
  deduplicate with set arithmetic, fix per-child exception handling
- Filter group comparison to top-level KC groups only (skip child groups
  that some KC versions return in flat list)
- Resolve user names from KC user list instead of showing raw UUIDs
- Add Cache-Control: no-store on all API responses to prevent browser
  from serving stale data after mutations
- Add max=1000 pagination param to get_group_members

Frontend:
- Replace jargon badges: Local Only → Missing in KC, KC Only →
  Missing locally, Mismatch → Out of sync
- Rewrite membership rows: show user name/email instead of UUIDs,
  plain-English descriptions instead of two-column diff layout
- Remove staleTime from discrepancy query, use removeQueries instead
  of invalidateQueries to ensure fresh data after resolve

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 15:48:43 -07:00