- Initialize Next.js 15 with App Router and TypeScript strict mode - Configure Tailwind CSS with shadcn/ui theme system - Install shadcn/ui components (button, card, input, table, etc.) - Set up ESLint and Prettier with automatic formatting - Configure path aliases (@/*) in tsconfig.json - Create full project structure per CLAUDE.md - Add health check endpoint at /api/health - Configure next.config.ts with output: 'standalone' for Docker - Set up Prisma with placeholder schema - Configure Vitest (unit) and Playwright (E2E) testing - Add VS Code settings for consistent development experience Build verification: TypeScript compilation, ESLint, and production build all pass. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
513 lines
22 KiB
Markdown
513 lines
22 KiB
Markdown
# 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
|
|
- [x] Initialize Next.js 15 with App Router, TypeScript strict mode
|
|
- [x] Install and configure Tailwind CSS
|
|
- [x] Install and configure shadcn/ui (default theme)
|
|
- [x] Configure ESLint + Prettier
|
|
- [x] Configure `tsconfig.json` with path aliases (`@/`)
|
|
- [x] Create base project structure per CLAUDE.md
|
|
- [x] Create `.dockerignore` for build optimization
|
|
- **Deps:** None | **Est:** 2 hrs | **Status:** ✅ Complete
|
|
|
|
### F-002: Docker & Infrastructure Alignment
|
|
- [x] `Dockerfile` for Next.js app (Node.js 22, multi-stage build)
|
|
- [x] `docker-compose.yml`: Traefik, postgres:16-alpine, redis:7-alpine, app-dev, app-test, app-prod
|
|
- [x] Traefik reverse proxy with Cloudflare DNS challenge for auto-SSL
|
|
- [x] `.env.example` with all required variables
|
|
- [x] `init-databases.sh` for multi-database PostgreSQL setup
|
|
- [x] `setup.sh` for server provisioning
|
|
- [x] Health check endpoints in Next.js app (`/api/health`)
|
|
- [x] 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
|
|
|
|
### 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
|
|
|
|
### 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
|
|
|
|
### 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
|
|
- **Deps:** F-001 | **Est:** 3 hrs
|
|
|
|
### 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[]
|
|
- [ ] Login page at `/login`
|
|
- [ ] Forgot password page at `/forgot-password`
|
|
- [ ] Account request page at `/account-request`
|
|
- [ ] reCAPTCHA integration on public forms
|
|
- **Deps:** F-003 | **Est:** 4 hrs
|
|
|
|
### F-008: Middleware & Guards
|
|
- [ ] `src/middleware.ts` — redirect unauthenticated users to /login
|
|
- [ ] Company context middleware: ensure active company is selected
|
|
- [ ] `src/lib/permissions.ts` — `requirePermission(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
|
|
|
|
### A-011: Admin Password Reset Links
|
|
- [ ] 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
|
|
- [x] Linux server provisioned (expvtcasp01)
|
|
- [x] Docker installed
|
|
- [x] Docker Compose installed
|
|
- [x] Netbird VPN configured (100.89.62.20)
|
|
|
|
### I-002: Forgejo Repository
|
|
- [x] Repository created at `forgejo.wulfconsulting.cloud/lorentz/quest-vorteq`
|
|
- [x] SSH key configured (port 222)
|
|
- [x] Git identity configured on server
|
|
- [x] Initial infrastructure files pushed
|
|
|
|
### I-003: CI/CD Pipeline
|
|
- [x] Forgejo Actions enabled on repository
|
|
- [x] Self-hosted runner registered (`expvtcasp01`) using Docker-in-Docker
|
|
- [x] Build workflow: checkout → Docker build → push to Forgejo registry
|
|
- [x] Deploy workflow: SSH into server → pull → restart containers
|
|
- [x] Secrets configured (registry credentials, deploy SSH key)
|
|
|
|
### I-004: Infrastructure Stack
|
|
- [x] Traefik v3 running with Cloudflare DNS challenge
|
|
- [x] SSL certificate issued for `traefik.vorteq.wulf.cloud`
|
|
- [x] PostgreSQL 16 running with dev/test/prod databases
|
|
- [x] Redis 7 running with separate DB numbers per environment
|
|
- [x] Cloudflare DNS A records pointing to Netbird IP
|
|
|
|
### I-005: Domain Configuration
|
|
- [x] `quest.vorteq.wulf.cloud` → 100.89.62.20 (production)
|
|
- [x] `dev.quest.vorteq.wulf.cloud` → 100.89.62.20 (development)
|
|
- [x] `testing.vorteq.wulf.cloud` → 100.89.62.20 (testing)
|
|
- [x] `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** |
|