quest-vorteq/TASKS.md
Lorentz Hinrichsen e60e07c9a5
Some checks failed
Build and Deploy / build (push) Successful in 4m39s
Build and Deploy / deploy (push) Failing after 1s
feat: add shipment request (C-013) and allocation request (C-014) cart workflows
Multi-step cart workflows for both shipment and allocation requests:
- Ship-to address selection from Epicor portal_CustomerShipToAddresses
- Inventory browser dialog (shipment) / coil browser dialog (allocation)
- Cart persistence in DB with duplicate detection
- Details form (order#, PO#, pickup date, instructions, email recipients)
- Review & submit with confirmation dialog
- Cancel with permission gate and confirmation
- Shared components: stepper, ship-to selector, cart table, header form, review
- 16 API routes, 4 services, 13 components, 6 pages
- Phase 2 complete: 16/16 tasks done

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 10:37:38 -05:00

27 KiB

Vorteq Quest Portal - Task Tracking

Reference: docs/Vorteq_Quest_PRD_v1.0.docx for full specifications Instructions: CLAUDE.md for coding conventions and patterns

Mark tasks: [ ] Not started | [~] In progress | [x] Complete | [!] Blocked


Phase 1: Foundation (Est. 30-40 hrs)

F-001: Project Scaffold

  • Initialize Next.js 15 with App Router, TypeScript strict mode
  • Install and configure Tailwind CSS
  • Install and configure shadcn/ui (default theme)
  • Configure ESLint + Prettier
  • Configure tsconfig.json with path aliases (@/)
  • Create base project structure per CLAUDE.md
  • Create .dockerignore for build optimization
  • Deps: None | Est: 2 hrs | Status: Complete

F-002: Docker & Infrastructure Alignment

  • Dockerfile for Next.js app (Node.js 22, multi-stage build)
  • docker-compose.yml: Traefik, postgres:16-alpine, redis:7-alpine, app-dev, app-test, app-prod
  • Traefik reverse proxy with Cloudflare DNS challenge for auto-SSL
  • .env.example with all required variables
  • init-databases.sh for multi-database PostgreSQL setup
  • setup.sh for server provisioning
  • Health check endpoints in Next.js app (/api/health)
  • Verify next.config.js has output: 'standalone' for Docker
  • Deps: F-001 | Est: 1 hr (remaining) | Status: Complete

F-003: Prisma Schema - Auth Domain

  • auth_user table (email, password hash, deactivated, verified, login counts, 2FA, SSO fields)
  • auth_domain table
  • auth_user_type table
  • auth_oauth_client + auth_oauth_access_token + auth_oauth_refresh_token
  • auth_password_history + auth_password_reset
  • auth_permission_group + auth_permission_rule + junction table
  • auth_permission_rule_category
  • auth_security_question + auth_security_answer
  • Run initial migration, verify schema
  • Deps: F-001 | Est: 4 hrs | Status: Complete

F-004: Prisma Schema - Quest Domain

  • quest_company (EpicorCustID, display name, invoicing flags)
  • quest_user (FK to auth_user, IsSubUser, API token)
  • quest_user_company junction table
  • quest_account_request
  • quest_notification + quest_user_notification_alert_read
  • quest_email_event + quest_user_email_event junction
  • quest_email_log
  • quest_plant + quest_inventory_type + quest_inventory_plant
  • quest_processed_order_acknowledgement_email
  • Run migration, verify
  • Deps: F-003 | Est: 3 hrs | Status: Complete

F-005: Prisma Schema - Remaining Domains

  • ship_request + ship_request_detail
  • alloc_request + alloc_request_detail + alloc_plant
  • inv_upload + inv_upload_entry + inv_upload_status
  • finance_ap_check_processing_batch + finance_ap_check_processing_status
  • paint_plant + paint_line + paint_line_type + paint_plant_line + paint_schedule
  • doc_article + doc_category + doc_article_permission_group
  • wave_process + wave_process_history
  • lts_task + lts_task_type + lts_task_schedule + related tables
  • Run migration, verify all relationships
  • Deps: F-004 | Est: 4 hrs | Status: Complete

F-006: Epicor MSSQL Connection Service

  • src/lib/epicor.ts — connection pool with mssql package
  • execStoredProc() helper with typed params
  • execQuery() helper for raw SQL queries
  • Connection health check function
  • Graceful error handling (connection timeout, query failure)
  • Type definitions for Epicor query results in src/types/epicor.ts
  • [~] Test connection against Epicor10Live with portal user (pending actual credentials)
  • Deps: F-001 | Est: 3 hrs | Status: Complete

F-007: Better Auth Setup

  • Install and configure Better Auth
  • Credentials provider: validate against auth_user table (bcrypt)
  • Session strategy with user ID, email, role, company context
  • [~] Session includes: userId, questUserId, activeCompanyId, isSubUser, permissionRules[] (requires middleware enhancement)
  • Login page at /login
  • Forgot password page at /forgot-password
  • Account request page at /account-request
  • reCAPTCHA integration on public forms (deferred to later)
  • Deps: F-003 | Est: 4 hrs | Status: Complete

F-008: Middleware & Guards

  • src/middleware.ts — redirect unauthenticated users to /login
  • Company context middleware: ensure active company is selected
  • src/lib/permissions.tsrequirePermission(rule) helper
  • Admin route protection (check user type)
  • Sub-user detection helper (isSubUser())
  • Company selector: /select-company page for multi-company users
  • Rate limiting on auth endpoints
  • Session management utilities for Quest-specific data
  • API route for setting active company
  • Deps: F-007 | Est: 4 hrs | Status: Complete

F-009: Base Layout & Navigation

  • Root layout with sidebar navigation
  • Header: company name, user menu, notification bell
  • Sidebar: Dashboard, Inventory, Orders, Shipments, Coil Activity, Invoices, Requests
  • Admin section in sidebar (conditional on role)
  • Company switcher dropdown (admin) or display (customer)
  • [~] Responsive: collapsible sidebar on mobile (basic implementation, needs enhancement)
  • Breadcrumb component
  • Deps: F-007 | Est: 3 hrs | Status: Complete

F-010: Data Migration Scripts

  • scripts/migrate-data.ts — connects to both SQL Server and PostgreSQL
  • Migrate auth_user + auth_user_type + auth_domain (preserve bcrypt hashes)
  • Migrate auth_permission_group + auth_permission_rule + junction
  • Migrate quest_user + quest_company + quest_user_company
  • Migrate quest_plant + quest_inventory_type/plant
  • Migrate quest_email_event
  • Migrate ship_request + ship_request_detail (historical data) (deferred - can be done before go-live)
  • Migrate alloc_request + alloc_request_detail (deferred - can be done before go-live)
  • Migrate supporting tables (notifications, docs, email events, wave, paint) (deferred - can be done before go-live)
  • Validation: count comparison, spot-check key records
  • Handle: IDENTITY → SERIAL, datetime2 → TIMESTAMPTZ, bit → BOOLEAN, nvarchar(MAX) → TEXT
  • Deps: F-005 | Est: 6 hrs | Status: Complete (core tables migrated)

Phase 2: Core Features (Est. 80-110 hrs)

Progress: 16/16 tasks complete

C-001: Dashboard

  • Dashboard page at /(portal)/dashboard/page.tsx
  • Server component: fetch top 5 orders, top 5 shipments from Epicor
  • Summary cards: inventory overview, recent activity
  • Notification alert banner (unread alerts)
  • Quick-nav cards to major features
  • Loading skeletons for async data
  • Dashboard service with typed queries
  • Reusable dashboard components (SummaryCard, QuickNavCard, tables)
  • Deps: F-009, F-006 | Est: 6 hrs | Status: Complete

C-002: Inventory Summary Views

  • /(portal)/inventory/page.tsx — category selector
  • /(portal)/inventory/[category]/page.tsx — summary data table (all 6 categories)
  • Service: src/services/inventory.ts
    • getWorkInProgressSummary(custId, dbName, sub)
    • getFinishedGoodsSummary(custId, dbName, sub)
    • getProcessedOtherSummary(custId, dbName, sub)
    • getUnprocessedSummary(custId, dbName) — block sub-users
    • getUnprocessedRRSummary(custId, dbName) — block sub-users
    • getProcessedRRSummary(custId, dbName) — block sub-users
  • V6 procedures: pass sub param (0/1 based on user)
  • [~] Row count pre-fetch for detail drill-down (deferred, can optimize later)
  • Data table with sorting, filtering, export to CSV
  • Click row → navigate to detail view
  • Deps: F-006, F-009 | Est: 12 hrs | Status: Complete

C-003: Inventory Detail Views

  • /(portal)/inventory/[category]/detail/page.tsx
  • Query params: part, plant, warehouse (for specific) or none (for all)
  • Service functions for each detail stored procedure (V6 and legacy)
  • getInventoryDetails() with proper stored procedure names
  • [~] Paint code display (from Epicor Part_UD table) (deferred to when paint module needed)
  • [~] Part description with paint code lookup (deferred, placeholder implemented)
  • On-hand quantity for specific lines
  • Data table with full column set (part, plant, warehouse, bin, lot, serial, qty, description)
  • Back navigation to summary
  • Search and CSV export functionality
  • Deps: C-002 | Est: 8 hrs | Status: Complete

C-004: Order List

  • /(portal)/orders/page.tsx
  • Service: getTop100Orders(custId) - basic Epicor query implementation
  • HDC/HDM exception handling (maps HDC to HDM for Cust2 parameter)
  • Data table: Order Number, PO, Customer Part, Vorteq Part, Dates, Qty, Status
  • Click-through to order acknowledgement (link to /orders/[id])
  • Search functionality (order #, PO, parts)
  • CSV export
  • Deps: F-006, F-009 | Est: 6 hrs | Status: Complete

C-005: Order Acknowledgement Detail + PDF

  • /(portal)/orders/[orderNum]/page.tsx — client-side fetch with loading skeleton
  • Service: getOrderAcknowledgement(orderNum, custId) with Epicor SQL (OrderHed/OrderDtl/OrderRel/Customer/ShipTo/Terms/ShipVia/Plant/JobProd)
  • Detail view matching legacy PDF layout (addresses, order info, line items, releases, paint codes, comments, totals)
  • PDF export via Puppeteer (/api/orders/[orderNum]/pdf)
  • Orders table: clickable Order # links + PDF download icons
  • Cross-customer security verified (BAS cannot access ACM orders)
  • UTC date handling fix for correct date display
  • FOB plant name resolution (code → description via Erp.Plant)
  • Deps: C-004 | Est: 6 hrs | Status: Complete

C-006: Shipment List

  • /(portal)/shipments/page.tsx — client-side fetch via API route (RSC-safe for large datasets)
  • Service: getTop100Shipments(custId) via portal_GetShipmentsV1 stored procedure
  • ShipToLoc formatting (replace , with newlines)
  • Data table with search, sort, CSV export (teal-700 header)
  • Click-through to BOL detail (/shipments/{bol_num})
  • API route at /api/shipments with auth + company context
  • Deps: F-006, F-009 | Est: 5 hrs | Status: Complete

C-007: BOL Detail + PDF

  • /(portal)/shipments/[bol]/page.tsx
  • Service: getBOL(bolNum, custId) using getBOL.sql
  • Detail view with line items
  • PDF export
  • Deps: C-006 | Est: 4 hrs | Status: Complete

C-008: Coil Activity - Usage Report

  • /(portal)/coil-activity/usage/page.tsx
  • Date range picker (with validation — max 31 days, default last 10 days)
  • Reusable UI components: Popover, Calendar (react-day-picker v9), DateRangePicker
  • Service: getCoilUsage(custId, startDate, endDate) using legacy portal_CoilActivityUsage.sql
  • Deduplication logic: only show OnHandQty for most recent DateUsed per LotNum
  • Zero weights → null display
  • Data table with all 11 columns: Date Used, Vorteq Part#, Cust Part#, Part Description, Lot#, Mfg Lot#, Weight, Plant Name, Job#, Cust PO#, Qty LB
  • Search, sort, CSV export
  • HDC→HDM customer ID mapping
  • Deps: F-006, F-009 | Est: 6 hrs | Status: Complete

C-009: Coil Activity - Receipts Report

  • /(portal)/coil-activity/receipts/page.tsx
  • Date range picker (shared component from C-008)
  • Service: getCoilReceipts(custId, startDate, endDate) with VGL exception
  • VGL customer exception: uses VGLCoilReceiptsData.sql; all others use dbo.portal_CoilActivityReceipts view
  • Data table with all 10 columns: Date Rec, Vorteq Part#, Cust Part#, Part Description, Lot#, Mfg Lot#, Plant Name, Packing Slip, Supplier Name, Mill Order #
  • Search, sort, CSV export
  • HDC→HDM customer ID mapping
  • Deps: F-006, F-009 | Est: 4 hrs | Status: Complete

C-010: Coil-by-Coil Report

  • /(portal)/coil-activity/coil-by-coil/page.tsx — job number search → coil detail display
  • Job number search input with search button
  • Service: getCoilByCoil(jobNum, customer) using full 782-line CoilByCoil.sql embedded in service
  • Header info card (Job#, Customer, PO, Part, Plant, etc.)
  • Two-section table: Materials Used + Materials Produced with independent search/sort/CSV export
  • HDC→HDM customer ID mapping
  • Deps: F-006 | Est: 3 hrs | Status: Complete

C-011: Job Status by Plant

  • /(portal)/jobs/status/page.tsx — auto-loads on mount
  • Service: getJobStatusByPlant(custId) using OpenOrdersQueryV3 stored procedure
  • DBNAME cross-database parameter via getPortalDbName()
  • Data table grouped by plant with plant section header rows
  • Search, sort, CSV export
  • PDF export: /api/jobs/status/pdf (landscape Letter, grouped by plant)
  • HDC→HDM customer ID mapping
  • Deps: F-006 | Est: 3 hrs | Status: Complete

C-012: Job Traveler + PDF

  • /(portal)/jobs/traveler/page.tsx — job number search page
  • /(portal)/jobs/[jobNum]/traveler/page.tsx — multi-section detail page
  • Service: getJobTraveler(jobNum) using full jobTraveler.sql with Part_UD paint data
  • Structured data: header, shipping schedule, raw materials, operations, paint specifications (deduplicated from flat SQL results)
  • Detail view: Job info card, Schedule dates, Shipping schedule table, Raw materials table, Operations table, Part specifications card
  • PDF export: /api/jobs/{jobNum}/traveler/pdf (landscape Letter, full Vorteq branding)
  • Sidebar navigation: Job Traveler link under Jobs section
  • Deps: F-006 | Est: 4 hrs | Status: Complete

C-013: Shipment Request Cart Workflow

  • /(portal)/shipment-requests/page.tsx — list existing requests with search, sort, status badges
  • /(portal)/shipment-requests/new/page.tsx — multi-step cart workflow
  • /(portal)/shipment-requests/[id]/page.tsx — view submitted/cancelled request detail
  • Step 1: Select ship-to address (from portal_CustomerShipToAddresses view)
    • Sub-user filter: only '%NB HANDY%' addresses
    • Search and radio selection UI
  • Step 2: Add inventory items to cart
    • Browse available inventory via dialog (FG, WIP, Processed Other categories)
    • Set quantity per line item, inline edit
    • Duplicate detection (part+lot+plant+warehouse)
  • Step 3: Enter details (Order#, PO#, Release#, Pickup Date, Instructions, Email Recipients)
    • Email recipients with tag-style input
  • Step 4: Review & submit with confirmation dialog
  • Cart persistence: save progress to DB via ship_request + ship_request_detail tables
  • Cancel: permission-gated with confirmation dialog
  • Email notification stubs (console.log — J-007 email service not built yet)
  • Service: src/services/ship-requests.ts — full CRUD + submit/cancel
  • Service: src/services/ship-to-addresses.ts — Epicor view query
  • 8 API routes: list, cart CRUD, items CRUD, submit, cancel, detail
  • Deps: F-005, C-003 | Est: 12 hrs | Status: Complete

C-014: Coil Allocation Request Cart Workflow

  • Mirror of C-013 but for allocation requests with job number requirement
  • /(portal)/allocation-requests/page.tsx — list with job# column
  • /(portal)/allocation-requests/new/page.tsx — job# entry → multi-step cart
  • /(portal)/allocation-requests/[id]/page.tsx — view detail
  • Job number input step before cart creation
  • Coil browser dialog (queries portal_CoilAllocation view, graceful fallback)
  • Uses alloc_request + alloc_request_detail tables with coil_number field
  • Duplicate detection (part+lot+coil_number)
  • Service: src/services/alloc-requests.ts — full CRUD + submit/cancel
  • Service: src/services/available-coils.ts — Epicor coil query with graceful fallback
  • 8 API routes: list, cart CRUD, items CRUD, submit, cancel, detail
  • Shared components with C-013: stepper, ship-to selector, cart form, review
  • Deps: F-005, C-003 | Est: 8 hrs | Status: Complete

C-015: Invoice Viewing (Customer)

  • /(portal)/invoices/page.tsx — client-side fetch with loading skeleton
  • Only visible if company can_access_invoices=true (403 response + user-friendly message)
  • Service: getInvoicesForCompany(companyId) querying inv_upload_entry filtered by company
  • Invoice table with search, sort, CSV export (invoice#, job#, page, date, sent date, PDF link)
  • PDF download endpoint /api/invoices/{id}/pdf with company security check
  • File serving from configurable INVOICE_STORAGE_PATH storage directory
  • Permission check: view_invoices + can_access_invoices
  • Deps: F-005, F-009 | Est: 4 hrs | Status: Complete

C-016: Notifications Display

  • Fixed notification bell unread count (was counting read records, now counts unread alerts)
  • Notification service: getActiveNotifications(), getUnreadAlertCount(), markNotificationRead()
  • Alert banner on dashboard uses correct unread count for current user
  • /(portal)/notifications/page.tsx — notification list with unread alerts section
  • Mark as read → upsert quest_user_notification_alert_read record
  • API routes: /api/notifications (GET list) + /api/notifications/{id}/read (POST mark read)
  • Deps: F-005, F-009 | Est: 3 hrs | Status: Complete

Phase 3: Admin Features (Est. 60-80 hrs)

A-001: User Management

  • /(portal)/admin/users/page.tsx — user list with search/filter
  • /(portal)/admin/users/[id]/page.tsx — user detail/edit
  • /(portal)/admin/users/new/page.tsx — create user
  • CRUD operations via server actions
  • Assign/remove company associations
  • Assign permission groups
  • Activate/deactivate users
  • Set IsSubUser flag
  • View login history (success/failure counts)
  • Deps: F-007, F-005 | Est: 8 hrs

A-002: Company Management

  • /(portal)/admin/companies/page.tsx — company list
  • /(portal)/admin/companies/[id]/page.tsx — company detail/edit
  • Edit: display name, InvoicingEmail, OrderAckEmail, CanAccessInvoices, ReceivesSOEmails
  • Activate/deactivate companies
  • View associated users
  • Deps: F-005 | Est: 5 hrs

A-003: Account Request Management

  • /(portal)/admin/account-requests/page.tsx
  • List pending requests
  • Approve: create auth_user + quest_user + company association
  • Reject: mark RequestProcessed without creating user
  • Send approval/rejection email
  • Deps: F-005, A-001 | Est: 4 hrs

A-004: Invoice Upload + Processing

  • /(portal)/admin/invoices/upload/page.tsx
  • Multi-page PDF upload
  • Parse PDF to extract individual invoices by invoice number
  • Match to CustID via getCustomerIDsForInvoiceNumbers()
  • Match to JobNum via getJobNumberByInvoiceNumber()
  • Create inv_upload + inv_upload_entry records
  • Status tracking (upload status, per-entry errors)
  • Send invoices to companies with InvoicingEmail
  • Handle: ignored entries, replaced entries, send errors
  • Upload history view
  • Deps: F-005, C-015 | Est: 12 hrs

A-005: AP Check Processing

  • /(portal)/admin/ap-check/page.tsx
  • Excel upload (XLS/XLSX)
  • Extract Group ID from cell AB9
  • Query Epicor CheckLines.sql by Group ID
  • Generate CSV with specific formatting
    • Country code handling: 'USA' vs 'FOR' (foreign)
    • Address field processing
  • Download generated CSV
  • Batch status tracking in finance_ap_check_processing_batch
  • Deps: F-005 | Est: 8 hrs

A-006: Notification Management

  • /(portal)/admin/notifications/page.tsx — list + CRUD
  • Create: Title, Text, IsAlert, Date, Time
  • Edit/delete existing notifications
  • Preview notification as customer would see it
  • Deps: F-005 | Est: 3 hrs

A-007: Documentation / Knowledge Base

  • /(portal)/admin/documentation/page.tsx — category + article management
  • Category CRUD (name, icon)
  • Article CRUD (content, category assignment)
  • Permission group assignment per article
  • Customer-facing documentation viewer
  • Deps: F-005 | Est: 5 hrs

A-008: Shipping Reports

  • /(portal)/admin/shipping-reports/page.tsx
  • View generated reports (stored Excel files)
  • Manual trigger: generate previous month report
  • Manual trigger: generate YTD report
  • Service: getShippingForMonth(), getShippingYTD() via Epicor
  • Excel generation using a library (e.g., ExcelJS)
  • Deps: F-006 | Est: 4 hrs

A-009: Wave/EDI Process Management

  • /(portal)/admin/wave/page.tsx
  • List wave_process entries with enable/disable toggles
  • View wave_process_history with run results
  • Manual trigger for processes
  • Minimal implementation — client migrating EDI to another product
  • Deps: F-005 | Est: 4 hrs

A-010: Paint Schedule Management

  • /(portal)/admin/paint-schedule/page.tsx
  • CRUD for paint schedule entries
  • Plant/line selection from paint_plant, paint_line, paint_plant_line
  • Job lookup from Epicor (getJobForPaintLine, getJob)
  • Schedule view (calendar or table format)
  • Fields: JobID, PartDescription, Customer, Qty, EstimatedRunTime, StartTime, Notes, Complete, LineSpeed
  • Deps: F-005, F-006 | Est: 6 hrs
  • Generate password reset link for any user
  • Create auth_password_reset record with token
  • Optional: bypass minimum time restriction (min_time_bypass)
  • Copy link to clipboard for admin to send manually
  • Deps: F-007 | Est: 2 hrs

Phase 4: Background Jobs & Polish (Est. 30-40 hrs)

J-001: BullMQ Infrastructure

  • Install and configure BullMQ with Redis connection
  • src/jobs/worker.ts — worker process setup
  • Job registration and scheduling system
  • Dashboard: Bull Board or similar for job monitoring (admin only)
  • Retry logic with exponential backoff
  • Dead letter queue for failed jobs
  • Deps: F-002 | Est: 4 hrs

J-002: Shipment Request Nag Job

  • Runs every 15 minutes
  • Find open (unsubmitted) shipment requests
  • Send reminder email to request owner
  • Track LastNagDT to avoid duplicate nags
  • Respects withoutOverlapping (skip if previous run still active)
  • Deps: J-001, C-013 | Est: 3 hrs

J-003: Order Acknowledgement Email Job

  • Runs hourly
  • Query Epicor for new orders (getOrdersForCustomerOnOrAfterDate)
  • Cross-reference against quest_processed_order_acknowledgement_email
  • Send to companies with ReceivesSOEmails=true and OrderAckEmail set
  • Record in quest_processed_order_acknowledgement_email to prevent duplicates
  • Deps: J-001, C-004 | Est: 4 hrs

J-004: Invoice Cleanup Job

  • Runs daily
  • disc:clearoldinvoices equivalent
  • Clean up old/expired invoice temporary data
  • Deps: J-001, A-004 | Est: 2 hrs

J-005: Shipping Report Generation Jobs

  • Monthly report: 1st of month at 3am
    • Call getShippingForMonth(lastMonth)
    • Generate Excel file, save to storage
  • YTD report: twice daily
    • Call getShippingYTD()
    • Generate/overwrite Excel file
  • Deps: J-001, A-008 | Est: 4 hrs

J-006: Wave EDI End-of-Month Job

  • Runs monthly on 1st
  • Execute Wave EDI end-of-month process
  • Log results to wave_process_history
  • Send completion email
  • Minimal implementation per client direction
  • Deps: J-001, A-009 | Est: 3 hrs

J-007: Email Service (Microsoft Graph)

  • src/lib/email.ts — Microsoft Graph API client
  • OAuth2 client credentials flow (tenant + client ID + secret)
  • Send email function: sendEmail(to, subject, htmlBody, from?)
  • Email logging to quest_email_log
  • Template system for common emails (request confirmation, nag, acknowledgement)
  • Error handling + retry for transient Graph API failures
  • Deps: F-001 | Est: 5 hrs

J-008: PDF Generation Service

  • src/lib/pdf.ts — PDF generation abstraction
  • Method 1: Puppeteer (render HTML → PDF, replaces wkhtmltopdf)
  • Method 2: @react-pdf/renderer for structured documents
  • Templates: Order Acknowledgement, BOL, Job Traveler, Invoice
  • Consistent header/footer styling
  • Deps: F-001 | Est: 4 hrs

J-009: E2E Test Suite

  • Playwright configuration
  • Test: Login flow (success + failure + rate limiting)
  • Test: Dashboard loads with data
  • Test: Inventory browse → category → summary → detail drill-down
  • Test: Shipment request full workflow (create → add items → submit)
  • Test: Admin invoice upload
  • Test: Company switcher (admin)
  • Data validation tests comparing Epicor query results
  • Deps: All C-* tasks | Est: 8 hrs

J-010: Production Deployment & Cutover

  • Verify all Traefik routes serving correctly with SSL
  • Run data migration scripts against production database
  • Verify all Epicor connections from expvtcasp01
  • DNS cutover: update quest.vorteq.wulf.cloud or portal.vorteqcoil.com as needed
  • Smoke test all features post-cutover
  • Rollback plan documented
  • Security hardening: change Traefik dashboard password, secure .env, firewall rules
  • Deps: All tasks | Est: 4 hrs

Infrastructure Tasks (Completed)

I-001: Server Provisioning

  • Linux server provisioned (expvtcasp01)
  • Docker installed
  • Docker Compose installed
  • Netbird VPN configured (100.89.62.20)

I-002: Forgejo Repository

  • Repository created at forgejo.wulfconsulting.cloud/lorentz/quest-vorteq
  • SSH key configured (port 222)
  • Git identity configured on server
  • Initial infrastructure files pushed

I-003: CI/CD Pipeline

  • Forgejo Actions enabled on repository
  • Self-hosted runner registered (expvtcasp01) using Docker-in-Docker
  • Build workflow: checkout → Docker build → push to Forgejo registry
  • Deploy workflow: SSH into server → pull → restart containers
  • Secrets configured (registry credentials, deploy SSH key)

I-004: Infrastructure Stack

  • Traefik v3 running with Cloudflare DNS challenge
  • SSL certificate issued for traefik.vorteq.wulf.cloud
  • PostgreSQL 16 running with dev/test/prod databases
  • Redis 7 running with separate DB numbers per environment
  • Cloudflare DNS A records pointing to Netbird IP

I-005: Domain Configuration

  • quest.vorteq.wulf.cloud → 100.89.62.20 (production)
  • dev.quest.vorteq.wulf.cloud → 100.89.62.20 (development)
  • testing.vorteq.wulf.cloud → 100.89.62.20 (testing)
  • traefik.vorteq.wulf.cloud → 100.89.62.20 (dashboard)

Summary

Phase Tasks Est. Hours (Low) Est. Hours (High)
Phase 1: Foundation F-001 to F-010 28 38
Phase 2: Core Features C-001 to C-016 80 110
Phase 3: Admin Features A-001 to A-011 60 80
Phase 4: Jobs & Polish J-001 to J-010 30 40
Infrastructure I-001 to I-005 Done Done
TOTAL 52 tasks 198 268