Add Equipment Module: DHEquipment service, DHEquipmentPortal, Discord bot, and Admin integration#271
Open
tmnyhbs wants to merge 15 commits into
Open
Conversation
- Port equipment list, detail, add/edit modal, and CRUD JS from PA1 into DHEquipmentPortal/templates/index.html (loadEquipment, renderEquipGrid, openEquipDetail, openEquipModal, renderAttrEditor, saveEquipment, deleteEquipment, location image helpers) - Add equipment section HTML: toolbar, area filter, status filters, equip grid, detail offcanvas, add/edit modal with attr editor - Fix bridge networking for all three portals in docker-compose.yaml (remove network_mode: host, add dh_network + DH_API_BASE_URL) - Add dhequipmentportal entry to docker-compose.dev.yml with dev auth env vars and DH_EQUIP_API_BASE_URL - Add CLAUDE.md and .gitignore for DHEquipmentPortal - Remove config.ini.example files replaced by env-var configuration - Add uv.lock files for DHEquipmentPortal, DHDiscordBot, DHEquipment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Areas section fully ported: list table, detail offcanvas, add/edit modal with all metadata fields (website, host_name, host_contact, email, discord) - Add .detail-section-label and .gitignore *.ini to complete the section - Wire AUTH_MODE env var into dhequipmentportal in docker-compose.yaml so dev mode can be enabled via .env without touching the compose file Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Repair Tickets: list table with multi-select status/priority filters,
create/edit modal with work log timeline and add-entry form, optimistic
locking via version field, all CRUD wired to /api/tickets[/{id}[/worklog]]
- Equipment Groups: collapsible group cards, create/edit modal with
multi-select equipment picker, CRUD wired to /api/equipment-groups
- Lazy-load allEquipment in ticket and group modals so pickers work
even if the Equipment section hasn't been visited first
- Fix CSP font-src to include cdn.jsdelivr.net so Bootstrap Icons
woff2 fonts load (fixes squares rendering in place of icons)
- Add ticket/badge/worklog/group-card CSS using theme custom properties
- Fix groups section using canChange('equipment.groups') instead of
PA1's can('groups.manage')
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ortal
- Shared calendar engine: calRenderDayWeek, calRenderMonth, nav label helpers
- Scheduling: day/week/month/list view toggle, equipment filter, Book Time modal,
15-min minimum / 24-hour maximum duration validation, /api/schedules integration
- Authorization sessions: tiles/list/calendar views, filter bar (upcoming/past/mine),
enroll/unenroll via /api/auth-sessions/{id}/enroll, create/edit/delete modal,
enrollment list with member names in detail modal
- Calendar CSS: grid, event chips, month cells, now-line, session-card badges
- All currentUser refs replaced with MEMBER_ID; API paths prefixed with /api/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Section UI: day/week/month/list/schedules view toggle with cal nav bar,
status legend badges, summary stats area, and permission-gated New Schedule button
- Schedules tab: lists all maintenance schedules with recurrence info, priority badge,
edit/delete per-row; lazy-loads equipment and groups if not yet fetched
- Events list/calendar: maps due_date to calendar slot, colors events by status
(pending=yellow, in_progress=cyan, overdue=red, completed=green, skipped=grey),
patches inline styles after calRenderDayWeek since shared engine uses classes
- Event detail modal: shows status, due date, equipment, priority, estimated time,
recurrence description, linked ticket (clickable to open ticket detail), completion
notes textarea; Start/Complete/Skip action buttons gated by canChange
- Checklist support: renders checklist_items as checkboxes, toggles checklist_state
via PATCH /api/maintenance/events/{id} without closing the modal
- Schedule modal: title, description, target type toggle (equipment/group), recurrence
interval + type, priority, estimated minutes; populates selects lazily
- API paths: /api/maintenance/events, /api/maintenance/schedules (no summary endpoint)
- can('maintenance.manage') added to bridge → canChange('equipment.maintenance')
- IDs are integers; parseInt used throughout for ID comparisons and payloads
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces the stub settingsContent div with a two-tab interface gated on
canChange('equipment.config'). Notifications tab has three sub-tabs:
Channels (email/push SMTP/VAPID config), Events (per-event channel matrix
for 8 equipment-specific events), and Webhooks (generic + Discord, with
event filter, enable toggle, and HMAC secret). All three sub-tabs read/write
via GET/PUT /api/config/notifications. Export tab renders a card grid for
six entities (equipment, areas, tickets, groups, schedules,
maintenance_schedules) and downloads client-side JSON→CSV with a timestamped
filename. PA1's import, JSON snapshot, role routing, and all non-equipment
panels are intentionally excluded.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add POST /v1/equipment/upload endpoint to DHEquipment service; stores
images in RustFS (S3-compatible) with auto bucket creation and
public-read bucket policy on first use
- Add GET /v1/equipment/media/{key} endpoint to proxy stored images
back through the service layer
- Add POST /api/upload and GET /api/media/<key> proxy routes to the
equipment portal; /api/media serves images same-origin so they render
correctly when the portal is accessed through a reverse proxy/tunnel
- Fix CSRF error handler to return JSON 400 for requests carrying
X-CSRFToken header (multipart uploads were getting 302 redirects)
- Gitignore CLAUDE.md
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Upload endpoint now accepts images, documents (PDF/Word/Excel/PPT/CSV),
and video up to 250 MB (was image-only at 10 MB)
- Added DELETE /v1/equipment/media/{key} endpoint to remove files from RustFS
- Added GET /api/areas/<id> proxy route (was missing)
- Added DELETE /api/media/<key> proxy route in Flask portal
- Upload proxy timeout raised to 300s; media proxy to 60s
- Flask MAX_CONTENT_LENGTH set to 260 MB; nginx client_max_body_size raised to 260m
- Attachment sections added to equipment, ticket, area, and group modals
- Shared JS attachment module: upload, render, remove (with S3 deletion)
- Schema: attachments JSONB DEFAULT '[]' added to areas and equipment_groups
- Migration: pg/sql/migrate_attachments.sql for existing databases
- db.py: update_area and update_equipment_group now handle attachments column
- Administrator and SuperAdmin roles updated with full equipment.* permissions
- Fixed invalid bcrypt placeholder hashes for dev-equipment-portal and dev-discord-bot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- notifications.py: New webhook dispatcher that fires on equipment events
(ticket opened/closed/status changed, equipment status changed, maintenance
started/completed/overdue). Reads config from equipment_config table, respects
per-event webhook toggle, supports Discord embeds and generic signed JSON.
Fixes Cloudflare 1010 block with DiscordBot User-Agent.
- Webhook settings UI: Discord message style editor (content, title prefix,
embed color picker with per-event defaults, footer, description template
with {field} variable substitution). Real server-side test send via
/api/webhook-test with style preview.
- Electrical fields: Voltage, amperage, phase, plug type, notes, and circuit
breaker (panel, breaker #, location, notes) added to equipment add/edit modal.
Detail panel shows Electrical section when data is present. Equipment cards
show a compact ⚡ badge with voltage/amperage/panel summary.
- nginx.conf: Fix persistent 500s after container restarts. Switched all
proxy_pass directives to use variables with explicit rewrites, forcing
per-request DNS re-resolution via Docker's resolver (127.0.0.11, TTL 5s).
Removed upstream blocks that cached IPs at startup.
- dhservices.py: Token fetch retries once on 502/503/504 and connection errors
to absorb transient gateway unavailability during container startup races.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Move notifications config from DHEquipmentPortal settings into a new Equipment Module section in DHAdminPortal (Notifications + Module Toggles tabs); DHAdmin proxies to DHEquipment API with its own token - Add module toggle switches in Equipment Module panel to enable/disable Maintenance, Scheduling, and Authorizations modules; DHEquipmentPortal hides disabled module nav items on load - Add open tickets table to DHEquipmentPortal dashboard (status: open/in_progress/on_hold) with priority badges and click-through - Remove export tab, routes, and JS from DHEquipmentPortal - Add 03-seed_equipment.sql template for areas, equipment, and groups - Wire DHEquipment credentials into DHAdminPortal via config.ini, config.py, and docker-compose env vars (dev uses dev-equipment-portal) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Settings in DHEquipmentPortal now shows a redirect card pointing to DHAdminPortal's Equipment Module panel instead of rendering the notifications config locally. DH_ADMIN_BASE_URL env var controls the link target (defaults to http://localhost:5001). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove push notification channel (VAPID config) from both portals - Merge Webhooks tab content into the Channels tab; webhooks render below email config separated by a divider, no separate tab needed - Remove push column from Events matrix; email and webhook remain - _renderNotifWebhooks prefers notif-webhooks-container so add/remove webhook actions re-render in place within the Channels tab Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds a full equipment management module to Deep Harbor, built and tested against
dev(rebased as of 2026-05-12). It introduces three new components and extends the existing Admin Portal:code/services/DHEquipment/) — FastAPI service with its own PostgreSQL schema, OAuth2 client-credentials auth, and a notifications/webhook dispatch enginecode/DHEquipmentPortal/) — Flask SPA portal (similar in structure to DHAdminPortal/DHMemberPortal) for day-to-day equipment managementcode/external/DHDiscordBot/) — Discord bot that surfaces equipment events and ticket updates into channelsWhat the Equipment Module covers
Networking
Follows the existing
docker-compose.dev.ymlpattern: production services usenetwork_mode: host; the dev overlay resets all new services to bridge networking and routes inter-container calls throughhttp://gateway/dh/equipment. No changes to existing service networking.Database
pg/sql/migrate_equipment.sql— migration script for adding the equipment schema to an existing databasepg/db-init/03-seed_equipment.sql— template seed file (placeholder rows, not pre-filled) for dev bootstrappingareas,equipment,equipment_groups,equipment_group_members,repair_tickets,ticket_work_log,maintenance_schedules,maintenance_events,equipment_schedules,equip_auth_sessions,equip_auth_enrollments,equipment_config,equipment_attachmentsoauth2_usersentries fordev-equipment-portalanddev-discord-botTest plan
docker compose -f docker-compose.yaml -f docker-compose.dev.yml up --build -dstarts cleanly with no errorshttp://localhost:5003, dev login works