quest-vorteq/TASKS.md
Lorentz bbcee034cb
Some checks failed
Build and Deploy / build (push) Failing after 3m6s
Build and Deploy / deploy (push) Has been skipped
feat(F-007): implement Better Auth with login and account request
Better Auth Configuration:
- Database adapter for PostgreSQL with custom schema mapping
- Email/password authentication enabled
- 7-day session expiration with 24-hour update frequency
- Custom field mappings for auth_user, auth_session, auth_account tables
- Server-side auth helpers: getSession(), requireAuth()
- Client-side React hooks: signIn, signOut, signUp, useSession

Authentication Pages:
- /login: Email/password login with error handling
- /forgot-password: Password reset request flow
- /account-request: New user registration form
  - Captures: name, email, phone, company, Epicor ID, message
  - Creates quest_account_request record for admin approval
  - Success confirmation with next steps

API Routes:
- /api/auth/[...all]: Better Auth handler for all auth operations
- /api/account-request: Account request submission endpoint

UI Components:
- Added Textarea component from shadcn/ui
- Form validation and loading states
- Toast notifications for user feedback
- Responsive card-based layouts

Session management and enhanced context (company, permissions) will be
added in F-008 middleware implementation.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-16 02:25:52 +00:00

22 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
  • Deps: F-007 | Est: 4 hrs

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
  • Breadcrumb component
  • Deps: F-007 | Est: 3 hrs

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)
  • Migrate alloc_request + alloc_request_detail
  • Migrate supporting tables (notifications, docs, email events, wave, paint)
  • Validation: count comparison, spot-check key records
  • Handle: IDENTITY → SERIAL, datetime2 → TIMESTAMPTZ, bit → BOOLEAN, nvarchar(MAX) → TEXT
  • Deps: F-005 | Est: 6 hrs

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

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
  • Deps: F-009, F-006 | Est: 6 hrs

C-002: Inventory Summary Views

  • /(portal)/inventory/page.tsx — category selector
  • /(portal)/inventory/[category]/page.tsx — summary data table
  • 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 (ALLV6 with count flag)
  • Data table with sorting, filtering, export to CSV
  • Click row → navigate to detail view
  • Deps: F-006, F-009 | Est: 12 hrs

C-003: Inventory Detail Views

  • /(portal)/inventory/[category]/details/page.tsx
  • Query params: part, plant, warehouse (for specific) or none (for all)
  • Service functions for each detail stored procedure (V6 and legacy)
  • Paint code display (from Epicor Part_UD table)
  • Part description with paint code lookup (getVorPartDescriptionFromPartNumberWithPaintCode)
  • On-hand quantity for specific lines
  • Data table with full column set
  • Back navigation to summary
  • Deps: C-002 | Est: 8 hrs

C-004: Order List

  • /(portal)/orders/page.tsx
  • Service: getTop100Orders(custId) using portal_Orders.sql
  • HDC/HDM exception handling (use portal_OrdersHDC view, map CustID)
  • Data table: Order Number, PO, Customer Part, Vorteq Part, Dates, Qty, Status
  • Click-through to order acknowledgement
  • Deps: F-006, F-009 | Est: 6 hrs

C-005: Order Acknowledgement Detail + PDF

  • /(portal)/orders/[id]/page.tsx
  • Service: getAcknowledgement(customer, poNumber?, orderNum?) using SalesOrder.sql
  • Detail view with all order line information
  • PDF export button (generate PDF server-side)
  • Deps: C-004 | Est: 6 hrs

C-006: Shipment List

  • /(portal)/shipments/page.tsx
  • Service: getTop100Shipments(custId, dbName) via portal_GetShipmentsV1
  • ShipToLoc formatting (replace , with line breaks)
  • Data table with shipment details
  • Click-through to BOL detail
  • Deps: F-006, F-009 | Est: 5 hrs

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

C-008: Coil Activity - Usage Report

  • /(portal)/coil-activity/usage/page.tsx
  • Date range picker (with validation)
  • Service: getCoilActivityUsage(custId, startDate, endDate) using portal_CoilActivityUsage.sql
  • Deduplication logic: only show OnHandQty for most recent DateUsed per LotNum
  • Zero weights → null display
  • Data table with full column set
  • Deps: F-006, F-009 | Est: 6 hrs

C-009: Coil Activity - Receipts Report

  • /(portal)/coil-activity/receipts/page.tsx
  • Date range picker
  • Service: getCoilActivityReceipts(custId, startDate, endDate)
  • VGL customer exception (use special SQL)
  • Data table with receipt columns
  • Deps: F-006, F-009 | Est: 4 hrs

C-010: Coil-by-Coil Report

  • /(portal)/coil-activity/coil-by-coil/page.tsx
  • Job number search input
  • Service: getCoilByCoil(jobNum, customer) using CoilByCoil.sql
  • Detail display
  • Deps: F-006 | Est: 3 hrs

C-011: Job Status by Plant

  • /(portal)/jobs/status/page.tsx
  • Service: getJobStatusByPlantByCustomer(custId, dbName) using JobStatusByPlantByCustomer.sql
  • Note: requires DBNAME cross-database parameter
  • Data table grouped by plant
  • Deps: F-006 | Est: 3 hrs

C-012: Job Traveler + PDF

  • /(portal)/jobs/[jobNum]/traveler/page.tsx
  • Service: getJobTraveler(jobNum) using jobTraveler.sql
  • Detailed routing/operations view
  • PDF export
  • Deps: F-006 | Est: 4 hrs

C-013: Shipment Request Cart Workflow

  • /(portal)/shipment-requests/page.tsx — list existing requests
  • /(portal)/shipment-requests/new/page.tsx — new request flow
  • /(portal)/shipment-requests/[id]/page.tsx — edit/view request
  • Step 1: Select ship-to address (from portal_CustomerShipToAddresses)
    • Sub-user filter: only '%NB HANDY%' addresses
  • Step 2: Add inventory items to cart
    • Browse available inventory, select items
    • Set quantity per line item
  • Step 3: Enter details (Order#, PO#, Release#, Pickup Date, Instructions, Email Recipients)
  • Submit: create ship_request + ship_request_detail records, send emails
  • Cancel: set IsCancelled=true, record canceller, send cancellation emails
  • Cart persistence: save progress to DB, show LastCartActivity
  • Confirmation page after submit
  • Deps: F-005, C-003 | Est: 12 hrs

C-014: Coil Allocation Request Cart Workflow

  • Mirror of C-013 but for allocation requests
  • Additional field: JobNum (from Epicor)
  • Uses alloc_request + alloc_request_detail tables
  • getCoilAllocationsByJobNumber() for allocation data
  • Deps: F-005, C-003 | Est: 8 hrs

C-015: Invoice Viewing (Customer)

  • /(portal)/invoices/page.tsx
  • Only visible if company CanAccessInvoices=true
  • List invoices from inv_upload_entry filtered by company
  • PDF download endpoint /api/invoices/:id/pdf
  • File serving from storage directory
  • Deps: F-005, F-009 | Est: 4 hrs

C-016: Notifications Display

  • Notification bell in header with unread count
  • Alert banner on dashboard for IsAlert=true notifications
  • Notification list view
  • Mark as read → create quest_user_notification_alert_read record
  • Deps: F-005, F-009 | Est: 3 hrs

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