Releases 1.33 + 1.34 — Pre-Implementation Decision Document
Every decision, field name, lifecycle, precision rule, and convention that must be resolved in the spec files before a single line of code is written. Derived from the Cross-Release Continuity Audit (42 findings across 61 spec files).
| Repo | Path | Type | Domain |
|---|---|---|---|
| appello-sdlc (16 files) | |||
| appello-sdlc | docs/uis-15-equipment-module.html | UIS | Equipment |
| appello-sdlc | docs/uis-15a-equipment-job-pl.html | UIS | Equipment P&L |
| appello-sdlc | docs/uis-15b-equipment-invoicing.html | UIS | Equipment Invoicing |
| appello-sdlc | docs/uis-15c-equipment-variable-rates.html | UIS | Equipment Rates |
| appello-sdlc | docs/uis-15d-equipment-maintenance-triggers.html | UIS | Maintenance |
| appello-sdlc | docs/uis-15e-equipment-search-mobile.html | UIS | Equipment Mobile |
| appello-sdlc | docs/uis-15f-daily-equipment-checklist.html | UIS | Equipment Checklist |
| appello-sdlc | docs/uis-15g-equipment-maintenance-scheduling.html | UIS | Maintenance |
| appello-sdlc | docs/uis-15h-equipment-timesheet-capture.html | UIS | Equipment Time |
| appello-sdlc | docs/plans/uis-15a-equipment-job-pl.html | Plan | Equipment P&L |
| appello-sdlc | docs/plans/uis-15b-equipment-invoicing.html | Plan | Equipment Invoicing |
| appello-sdlc | docs/plans/uis-15c-equipment-variable-rates.html | Plan | Equipment Rates |
| appello-sdlc | docs/plans/uis-15d-equipment-maintenance-triggers.html | Plan | Maintenance |
| appello-sdlc | docs/plans/uis-15e-equipment-search-mobile.html | Plan | Equipment Mobile |
| appello-sdlc | docs/plans/uis-15g-equipment-maintenance-scheduling.html | Plan | Maintenance |
| appello-sdlc | docs/plans/uis-15h-equipment-timesheet-capture.html | Plan | Equipment Time |
| appello-roadmap (25 files) | |||
| appello-roadmap | plans/LEM-1-labor-billable-rates.html | Plan | LEM |
| appello-roadmap | plans/LEM-2-equipment-billable-rates.html | Plan | LEM |
| appello-roadmap | plans/WO-2-line-item-tables.html | Plan | Work Orders |
| appello-roadmap | plans/WO-3a-schema-form-foundation.html | Plan | Work Orders |
| appello-roadmap | plans/WO-3b-line-item-editors.html | Plan | Work Orders |
| appello-roadmap | plans/WO-3d-wo-property-settings.html | Plan | Work Orders |
| appello-roadmap | plans/WO-4-detail-page.html | Plan | Work Orders |
| appello-roadmap | plans/WO-5-tm-log.html | Plan | Work Orders |
| appello-roadmap | plans/WO-6-mobile-list-detail.html | Plan | Work Orders |
| appello-roadmap | plans/WO-7-conversion.html | Plan | Work Orders |
| appello-roadmap | plans/WO-8a-stepped-form-wizard.html | Plan | Work Orders |
| appello-roadmap | plans/WO-8b-collect-signatures.html | Plan | Work Orders |
| appello-roadmap | plans/MAT-0-supply-chain-model.html | Plan | Material |
| appello-roadmap | plans/MAT-1-customer-po-entity.html | Plan | PO |
| appello-roadmap | plans/MAT-2a-lem-consumption-desktop.html | Plan | Material |
| appello-roadmap | plans/MAT-2b-lem-consumption-mobile.html | Plan | Material |
| appello-roadmap | plans/MAT-3-price-book-import.html | Plan | Procurement |
| appello-roadmap | plans/MAT-4-mobile-material-requests.html | Plan | Procurement |
| appello-roadmap | plans/MAT-5-supplier-po.html | Plan | Procurement |
| appello-roadmap | plans/MAT-6-receiving-workflow.html | Plan | Operations |
| appello-roadmap | plans/MAT-7-inventory-management.html | Plan | Operations |
| appello-roadmap | plans/MAT-8-vendor-credits.html | Plan | Operations |
| appello-roadmap | plans/MAT-9-discount-management.html | Plan | Procurement |
| appello-roadmap | release-1.33-timeline.html | Timeline | Release 1.33 |
| appello-roadmap | release-1.34-timeline.html | Timeline | Release 1.34 |
| appello (14 files) | |||
| appello | .cursor/plans/uis-17-material-management.html | UIS | Material |
| appello | .cursor/plans/uis-25-purchase-order-management.html | UIS | PO |
| appello | .cursor/plans/uis-25a-customer-po-management.html | UIS | Customer PO |
| appello | .cursor/plans/uis-25b-supplier-po-receiving.html | UIS | Supplier PO |
| appello | plan/clearstory-tm-workorders/uis/uis-20-tm-work-orders.html | UIS | Work Orders |
| appello | plan/clearstory-tm-workorders/uis/uis-20a-job-type-config.html | UIS | Job Config |
| appello | plan/clearstory-tm-workorders/uis/uis-20b-line-item-tables.html | UIS | Line Items |
| appello | plan/clearstory-tm-workorders/uis/uis-20c-create-edit-form.html | UIS | WO Form |
| appello | plan/clearstory-tm-workorders/uis/uis-20d-detail-page.html | UIS | WO Detail |
| appello | plan/clearstory-tm-workorders/uis/uis-20e-tm-log.html | UIS | WO Log |
| appello | plan/clearstory-tm-workorders/uis/uis-20f-co-log.html | UIS | CO Log |
| appello | plan/clearstory-tm-workorders/uis/uis-20g-conversion.html | UIS | Conversion |
| appello | plan/clearstory-tm-workorders/uis/uis-20h-mobile-creation.html | UIS | Mobile WO |
Decision (April 8 Meeting)
supplierCompanyId is clearer than supplierId, expectedDeliveryDate is clearer than deliveryDate (you may need both expected and actual). Do not rename fields for brevity. The spec’s more descriptive naming is preferred over shorter Prisma-style conventions.xxxById fields to xxxByUserId
CRITICAL-5
Decision
xxxByUserId pattern (createdByUserId, approvedByUserId, submittedByUserId). UIS uses xxxById which is ambiguous — “by” what? Always suffix with UserId.Fields to Rename
createdById → createdByUserIdupdatedById → updatedByUserIdapprovedById → approvedByUserIdsubmittedById → submittedByUserIdreceivedById → receivedByUserIdrequestedById → requestedByUserIduis-17-material-management.htmluis-25-purchase-order-management.htmluis-25b-supplier-po-receiving.htmlProduct model — use existing Material + MaterialGroup
CRITICAL-5
Decision
Material + MaterialGroup + MaterialAttribute architecture in production. Plan correctly extends these with ManufacturerProduct (manufacturer part numbers) and DistributorPrice (supplier pricing).uis-17-material-management.html — Remove/rewrite all Product model references to use Material and ManufacturerProduct@default(cuid()) and @default(nanoid()) from UIS specs
CRITICAL-5
Decision
cuid() generates 25-char IDs but the column is VarChar(21). The codebase generates IDs in application code using nanoid. Remove all @default() from ID fields in UIS specs.uis-17-material-management.html — Remove @default(cuid()) from model definitionsuis-25-purchase-order-management.html — Remove @default(nanoid())Decision (April 8 Meeting)
instanceId to ALL new models in Plan specs
SKIPPED
Decision (April 8 Meeting)
instanceId to any new models. Each Appello deployment serves exactly one company. The existing instanceId on legacy models is historical and does not need to be propagated to new models.Decision (April 8 Meeting)
Fields to Add Per Entity
MaterialConsumptionEntry: submittedAt, submittedByUserId, approvedAt, approvedByUserIdVendorCredit: approvedAt, approvedByUserId, appliedAt, appliedByUserId, voidedAt, voidedByUserId, creditDatePurchaseOrder: deferred until PO v1 PR merges (see A5)plans/MAT-2a-lem-consumption-desktop.html — Add consumption approval timestampsplans/MAT-8-vendor-credits.html — Add credit workflow timestampsplans/MAT-5-supplier-po.html — Deferred (PO v1 PR)Decision (April 8 Meeting)
vendorCredit.approve RBAC permission. Only Approved credits can be applied. Void reverses the job cost adjustment.plans/MAT-8-vendor-credits.html (Emma) — Use PropertyValue for status, add approval workflow, add 6 audit fields, add RBAC gateDecision (April 8 Meeting)
Decision (April 8 Meeting)
transferGroupId, costCodeId to InventoryMovement
DEFERRED
Decision (April 8 Meeting)
transferGroupId and costCodeId when inventory management is actively in scope and A10 has been resolved.isArchived + isDeleted — parent cascades to children
REVISED
Decision (April 8 Meeting)
isArchived + isDeleted fields. This is the existing Appello convention per Emma: “We generally put isArchived on line items. We do isArchived and isDeleted so that we can… if you archive the parent, it will archive the children, but we still have them.” Parent archive/delete cascades to children via application logic. This applies to: PurchaseOrderLineItem, ReceiptLineItem, VendorCreditLineItem, MaterialRequestItem, WorkOrderLaborItem, WorkOrderMaterialItem, WorkOrderEquipmentItem.isArchived + isDeleted fieldsdateOfWork vs multi-date Work Orders — use sub-model, not JSON
NEEDS RESEARCH
Decision (April 8 Meeting)
WorkOrderDate) instead of workDates Json for filterability. More research needed on how multi-date WO functionality should work end-to-end.plans/WO-3a-schema-form-foundation.html — Uses dateOfWorkuis-20h-mobile-creation.html — Uses workDates Json — needs to change to sub-modelDecision
InventoryItem is recalculated on each receipt as (existing qty × existing cost + received qty × receipt cost) / total qty.plans/MAT-7-inventory-management.html (Emma) — Document costing method explicitlyWorkOrderSigner into SignatureRequest
DEFERRED
Decision (April 8 Meeting)
WorkOrderOtherItem — use 3 line item types with nullable FK
REVISED • NEEDS CHRIS
Decision (April 8 Meeting)
WorkOrderOtherItem as a separate model. Each of the 3 existing line item types (WorkOrderLaborItem, WorkOrderMaterialItem, WorkOrderEquipmentItem) can function as an “other” item when the tied relationship FK is null. Emma: “Any of those three should be able to function as a work order other item that has no tied relationship and has a description and a value and a quantity rather than having a separate model.” If you give a labor ID or equipment ID, you don’t need the description. If you don’t pick a linked entity, you describe it freeform. Needs Chris review before finalizing.uis-20h-mobile-creation.html — Remove WorkOrderOtherItem modelplans/WO-2-line-item-tables.html — Document nullable FK = ad-hoc item patternplans/WO-8a-stepped-form-wizard.html — Merge Step 5 (“Other”) into the 3 existing stepsmanufacturerProductId to MaterialConsumptionEntry GraphQL type
SF-13
Decision
uis-17-material-management.html — Add manufacturerProductId to GraphQL consumption typeplans/MAT-2a-lem-consumption-desktop.html — Already has it in Prisma, confirm in GraphQLMaintenanceScheduleTemplate
REVISED
Decision (April 8 Meeting)
MaintenanceThreshold + MaintenanceLog + MaintenanceSchedule + DowntimeRecord in v1 scope. Drop only MaintenanceScheduleTemplate. Emma replaced the template concept with form attachments: “I got rid of that, and I said you can tie safety forms to it — like these are the four forms that you do when you do an oil change.” DowntimeRecord is important for tracking equipment availability metrics (e.g., VOR — Vehicles Off Road). This removes 1 model from scope, not 3 as originally proposed.docs/uis-15g-equipment-maintenance-scheduling.html — Remove MaintenanceScheduleTemplate only, keep Schedule + DowntimeRecorddocs/plans/uis-15g-equipment-maintenance-scheduling.html — Same"Pending"
SF-3
uis-17-material-management.html — Change default status from "Processing" to "Pending"errorLog uses Json? not String? @db.Text
SF-4
Json?. Structured error data (row number, column, error message per row) is more useful for displaying error tables in the UI than a raw text string.uis-17-material-management.html — Change errorLog String? @db.Text to errorLog Json?PartialSuccess
SF-5
Pending, Processing, Complete, PartialSuccess, Failed. UIS has PartialSuccess but omits Pending. Plan has Pending but omits PartialSuccess. Both are needed — PartialSuccess is essential for imports where some rows succeed and others fail.uis-17-material-management.html — Add Pending to status setplans/MAT-3-price-book-import.html — Add PartialSuccess to status setCanonical precision rules for all new models. These match the existing Prisma schema conventions (forecasts use Decimal(12,2), InvoiceLineItem uses Decimal(10,5) for quantity).
| Value Type | Precision | Rationale | Example Fields |
|---|---|---|---|
| Unit prices | Decimal(10, 2) | Standard money precision | unitPrice, unitCost, listPrice, rate |
| Quantities | Decimal(10, 4) | Unit conversion safety (m→ft, kg→lb, 2.5 rolls) | quantity, quantityReceived, quantityOnHand |
| Document totals | Decimal(12, 2) | Match forecast pattern, supports $99B | amount, totalAmount, extendedPrice |
| Percentages | Decimal(5, 2) | Standard percent precision | discountPercent, taxRate |
PurchaseOrder.amount from Decimal(10, 2) to Decimal(12, 2)
SF-1
plans/MAT-1-customer-po-entity.html — Change amount precisionplans/MAT-5-supplier-po.html — Change amount precisionuis-25-purchase-order-management.html — Change amount precisionVendorCredit.amount from Decimal(10, 2) to Decimal(12, 2)
SF-1
plans/MAT-8-vendor-credits.html — Change totalAmount precisionDecimal(10, 2) to Decimal(10, 4)
SF-15
Affected Models
PurchaseOrderLineItem.quantityMaterialConsumptionEntry.quantityMaterialRequestItem.quantityReceiptLineItem.quantityReceivedInventoryItem.quantityOnHand, minQuantity, maxQuantityInventoryMovement.quantityVendorCreditLineItem.quantityplans/MAT-*.html files with quantity fieldsuis-17-material-management.html, uis-25b-supplier-po-receiving.htmlDecimal(12, 2)
SF-1
Decimal(12, 2) (Emma’s Apr 7 fix), but the SQL CTE for P&L computation may still reference Decimal(10, 2) casts.docs/plans/uis-15a-equipment-job-pl.html — Check SQL CTE casts| Permission Group | view | create | edit | delete | approve | Source |
|---|---|---|---|---|---|---|
purchaseOrder | ✓ | ✓ | ✓ | ✓ | ✓ | SF-6 |
vendorCredit | ✓ | ✓ | ✓ | ✓ | ✓ | SF-6 |
pricing | ✓ | — | ✓ | — | — | SF-12 |
inventory | ✓ | ✓ | ✓ | ✓ | — | SF-6 |
purchaseOrder permission groupSF-6approve permission gates the Submitted → Approved transition. view supports ALL/OWN/DEPARTMENT scoping.plans/MAT-1-customer-po-entity.html, plans/MAT-5-supplier-po.html, uis-25-purchase-order-management.html, uis-25a-customer-po-management.html, uis-25b-supplier-po-receiving.htmlvendorCredit permission groupSF-6approve gates InReview → Approved. Credits directly affect job profitability.plans/MAT-8-vendor-credits.htmlpricing permission group (separate from material)SF-12pricing: { view, edit } from material: { view, edit }.plans/MAT-9-discount-management.html — Replace material.edit with pricing.editinventory permission groupSF-6plans/MAT-7-inventory-management.html, uis-17-material-management.html| Event | Notify Who | Channel | Currently Defined? |
|---|---|---|---|
| PO submitted for approval | Approvers (PO permission group) | In-app + email | No |
| PO approved | Creator | In-app | No |
| PO sent to supplier | Creator + job PM | In-app | No |
| Receiving completed | PO creator | In-app | No |
| Low stock alert | Inventory managers | In-app + email | No |
| Consumption submitted | Approvers | In-app | No |
| Credit submitted for review | Approvers | In-app + email | No |
| Credit approved | Creator | In-app | No |
| Material request submitted | Office material managers | In-app + email | MAT-4 |
| Material request fulfilled | Requester | In-app | No |
| Signature requested | Signer | WO-8b | |
| Maintenance threshold reached | Equipment managers | In-app + email | UIS-15D |
These are patterns/conventions that must be decided once and documented so every spec and every developer applies them consistently. They don’t require spec-level file changes — they’re documented here as the authoritative reference.
job-sites/[id]/... patternSF-7/job-sites/[id]/. This matches the existing mobile app structure. Affects: material consumption (/job-sites/[id]/material-consumption/new), material requests (/job-sites/[id]/material-request/new), WO creation, equipment time. Fix inconsistent patterns like /material-requests/new and /jobs/[jobId]/....uis-20h-mobile-creation.html, plans/WO-6-mobile-list-detail.html, plans/MAT-2b-lem-consumption-mobile.html, plans/MAT-4-mobile-material-requests.htmlDownloadablePDF/SF-8DownloadablePDF pattern. This matches existing Invoice, Estimate, and Work Order PDF patterns. UIS incorrectly placed PO PDF in the API (apps/api/src/templates/). Correct path: apps/frontend/src/components/DownloadablePDF/PurchaseOrder/SupplierPO.tsx.uis-25b-supplier-po-receiving.html — Fix PDF template locationDistributorDiscount > DistributorPrice.discountPercentSF-14DistributorDiscount (managed entity with date ranges and scope) takes precedence when present. DistributorPrice.discountPercent (per-row import value from CSV) is the fallback. Discount resolution: Product-specific > Category > Global.plans/MAT-9-discount-management.html — Document precedence cascade explicitlyeffectivePrice, extendedTotal). Use stored fields for values that need to be queried, sorted, or aggregated (PurchaseOrder.amount, VendorCredit.totalAmount). Stored values are set on create/update by the resolver.ListTableView includes an export action with CSV and PDF options. Use the existing export button pattern from Job List. Add to acceptance criteria for: WO Log, CO Log, PO List, Material Request Inbox, Inventory Stock Levels, Vendor Credit List.EmptyState componentNTH-3EmptyState component from @useanzen/ui with: icon (contextual), message, and action button (e.g., “Create First PO”). Check if EmptyState already exists in the UI library before building.{ success: [...], failed: [...] }NTH-4approveEquipmentTimeEntries, approveMaterialConsumptionEntries, upsertWorkOrderLineItems) return { success: [ids], failed: [{ id, error }] } with per-item error messages. Use prisma.$transaction() for all-or-nothing when appropriate.createdAt, updatedAt, createdByUserId, updatedByUserId. Entities with approval add: submittedAt, submittedByUserId, approvedAt, approvedByUserId. Use the existing AuditEntry pattern for change history on entities where it matters (v1.1).convert[Source]To[Target](sourceId: ID!): [Target]!. Pre-fills target from source line items. Used by: WO → Invoice (convertWorkOrderToInvoice), WO → Change Order (convertWorkOrderToChangeOrder). Future: Material Request → PO.GetListOptions with paginationNTH-17GetListOptions input type with pagination, sorting, and filtering. Construction companies accumulate thousands of records per entity. No unbounded arrays. Applies to: purchaseOrders, materialConsumptionEntries, inventoryMovements, vendorCredits, materialRequests, workOrders.AutoNumberService for WO, CPO, SPO, MR, VC, RCV prefixesNTH-9apps/api/src/models/AutoNumberService.ts. Input: { prefix: string, instanceId: string }. Output: next number string (e.g., WO-001, SPO-0042). Uses a counter table (AutoNumberCounter model) with @@unique([instanceId, prefix]). Handles padding, collision prevention via prisma.$transaction(). Configurable pad width per prefix.Prefixes
WO — Work OrdersCPO — Customer Purchase OrdersSPO — Supplier Purchase OrdersMR — Material RequestsVC — Vendor CreditsRCV — Receiving ReceiptsRepeatingLineItemEditor base componentNTH-8packages/ui/src/components/RepeatingLineItemEditor/. Props: columns (array of column defs with render, width, label), rows (data), onAdd, onRemove, onUpdate, showTotals, totalColumns. Used by: WO Labor Editor, WO Material Editor, WO Equipment Editor, PO Line Item Editor, VendorCredit Line Item Editor. Build before any feature-specific editors.JobFinancialSummaryService plugin/strategy refactorNTH-7JobFinancialSummaryService from a monolithic computation to a plugin/strategy pattern. Each cost source registers a “cost provider” function with signature: (jobId: string) => Promise<{ label: string, revenue: Decimal, cost: Decimal }>. The service aggregates all registered providers. Prevents merge conflicts when 5 features modify it in parallel.Cost Providers to Register
These are the canonical, final status lifecycles for every entity with a workflow. Each spec file must match these exactly.
Every implementation phase has been validated. Items marked with * are DEFERRED or SKIPPED per the April 8 meeting. Deferred items do not block the phase — they will be resolved when their blockers clear (PO v1 PR merge, Emma plan review, Chris review).
| Implementation Phase | Scope | Phase 0 Items Required |
|---|---|---|
| Phase 1: LEM Foundation | TradeLevelRate mod, 3 equipment rate models, desktop rate UI | D4 |
| Phase 2: T&M Work Orders | 8+ models, desktop CRUD/log/conversion, mobile wizard, WO PDF | A1*, A2, A6*, A7, A12, A13*, B1*, B2*, G1, G2, G4, G5, G6, G7, G10, G11, G12, H1, H2 |
| Phase 3: Equipment Module | 8 models, P&L, invoicing, maintenance, mobile QR/inspection | B4, D4, G1, G4, G5, G6, G12 |
| Phase 4: Material Foundation | 4 models, data migration, supply chain settings, consumption | A1*, A2, A3, A4, A5*, A6*, A7, A9*, B3, C1–C3, D1, D3, E1, F1, G1, G4, G5, G6, G8, G11, G12, H1, H3 |
| Phase 5: Procurement | 4 models, price book import, material requests, supplier PO, discounts | A5*, C1–C3, D3, E1, E3, G2, G3, G5, G6, G12, H1, H2 |
| Phase 6: Operations | 5 models, receiving, inventory, vendor credits, 3 JFS integrations | A8, A10*, A11*, A14, D1, D2, E2, E4, F1, G4, G5, G6, G7, G8, G9, G12, H2, H3 |
| Phase 7: Cross-Cutting | Shared components, services, mobile routes, pagination, testing | G1, G5, G6, G7, G10, G12, H1, H2, H3 |
MaterialAttributePrice, DistributorPrice) only covers cost (what the contractor pays). There was no mechanism for charge-out (what the customer pays). This gap has been closed by LEM-3: Material Billable Rates — a three-tier cascade (MaterialGroup.defaultMarkupPercent → Material.sellPriceOverride/markupPercentOverride → Job.materialMarkupPercent) that auto-calculates sell prices. All downstream specs (WO-2, WO-3, WO-7, MAT-2a) have been updated to use unitPrice (sell) and costPrice (cost) instead of unitCost.
| Owner | Files | Items | Notes |
|---|---|---|---|
| Emma (Plan specs) | appello-roadmap/plans/MAT-*.html, WO-*.html, LEM-*.html |
A7, A8, A14, B2, B3, C3, D1, D2, D3, E1–E4, F1, G3 | A9/A11 deferred, A6 skipped |
| Corey/AI (UIS specs) | appello/.cursor/plans/uis-*.html, appello/plan/clearstory-tm-workorders/uis/*.html |
A2, A3, A4, B2, C1, C2, D3, G1, G2 | A1/A6 skipped, A5/A10 deferred, B1 deferred |
| Emma (Equipment specs) | appello-sdlc/docs/*.html, appello-sdlc/docs/plans/*.html |
B4, D4 | B4 revised: keep Schedule + Downtime, drop Template only |
| Conventions (this doc) | No file changes — documented here | A12, A13, G4–G12, H1–H3 | A12 revised (line items DO get isArchived). A13 needs research. |
| Blocked / Deferred | Various | A5, A9, A10, A11, B1 | A5/A9: PO v1 PR. A10/A11: Emma MAT-7 review. B1: Emma WO-8b review. |
| Needs Chris Review | WO line item specs | B2 | 3 line item types with nullable FK pattern tentatively approved |