Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

143 lines
5.2 KiB
Markdown

# PRD: Project Materials Drawer
## Problem Statement
Projects currently have a placeholder "Materials" button that opens a drawer displaying only an alert message: "Project materials are now owned by Billing." Users cannot manage materials (products) for projects, even though:
1. The backend infrastructure already exists (`listProjectMaterials`, `addProjectMaterial`, `deleteProjectMaterial`)
2. The data model is complete (`IProjectMaterial` interface, `project_materials` table)
3. Tickets have a fully functional materials card that users expect to work similarly for projects
This creates an inconsistent UX where materials work for tickets but not for projects.
## Goals
1. **Implement fully functional Project Materials Drawer** - Allow users to view, add, and delete materials for projects
2. **Maintain consistency with Ticket Materials** - Same interaction patterns, multi-currency support, and validation rules
3. **Use drawer layout** - As specified, materials management should be in a slide-out drawer (not an inline card like tickets)
## Non-Goals
- Bulk material operations (add multiple at once)
- Material editing (only add/delete, same as tickets)
- Export/import materials
- Material templates or presets
- Project-specific pricing overrides (uses service catalog prices)
## Architecture Compliance
### Package Location
**Keep in `@alga-psa/projects/components`** - Following the established pattern where `TicketMaterialsCard` lives in `@alga-psa/tickets`.
### Required Dependency Addition
Add `@alga-psa/billing` to `packages/projects/package.json`:
```json
"dependencies": {
"@alga-psa/billing": "*",
// ... existing deps
}
```
### Import Pattern (Same as TicketMaterialsCard)
```typescript
import {
listProjectMaterials,
addProjectMaterial,
deleteProjectMaterial,
searchServiceCatalogForPicker,
getServicePrices,
} from '@alga-psa/billing/actions';
```
## Target Users
- **MSP Administrators** - Managing project-based work for clients
- **Project Managers** - Tracking materials used on projects for billing
## User Flow
### Primary Flow: View Project Materials
1. User navigates to a project detail page
2. User clicks "Materials" button in project header
3. Drawer slides in from right showing materials list or empty state
### Secondary Flow: Add Material
1. User clicks "Add" button
2. Selects product, currency (if multi-currency), quantity
3. Optionally adds description
4. Clicks "Add Material" → material appears in list
### Secondary Flow: Delete Material
1. User clicks delete (trash icon) on unbilled material
2. Material removed, toast shown
## UX/UI Specification
### Drawer Layout
- **Width:** 560px (standard detail drawer width)
- **Position:** Right side slide-in
### Drawer Structure
```
┌─────────────────────────────────────┐
│ Materials [Add] │
├─────────────────────────────────────┤
│ [Add Form - when visible] │
├─────────────────────────────────────┤
│ Product | Qty | Rate | Total | Stat │
│ ─────────────────────────────────── │
│ Item 1 | 2 | $50 | $100 | Pend │
├─────────────────────────────────────┤
│ Unbilled (USD): $100.00 │
└─────────────────────────────────────┘
```
## Data Model (Existing)
```typescript
interface IProjectMaterial {
project_material_id: string;
project_id: string;
client_id: string;
service_id: string;
service_name?: string;
sku?: string | null;
quantity: number;
rate: number; // In cents
currency_code: string; // ISO 4217
description?: string | null;
is_billed: boolean;
// ... timestamps
}
```
## API/Actions (Existing in @alga-psa/billing/actions)
| Action | Purpose |
|--------|---------|
| `listProjectMaterials(projectId)` | Fetch materials with service_name/sku joined |
| `addProjectMaterial({...})` | Create material (rate in cents) |
| `deleteProjectMaterial(id)` | Delete if not billed |
| `searchServiceCatalogForPicker({...})` | Get products for dropdown |
| `getServicePrices(serviceId)` | Get multi-currency prices |
## Acceptance Criteria
- [ ] Drawer opens when "Materials" button clicked
- [ ] Materials displayed in table with all fields
- [ ] Add form with product picker, currency, quantity, description
- [ ] Successfully adds material and refreshes list
- [ ] Delete button removes unbilled materials
- [ ] Unbilled totals grouped by currency
- [ ] Warning when project has no client
- [ ] Error handling with toast notifications
## Files to Modify
1. `packages/projects/package.json` - Add `@alga-psa/billing` dependency
2. `packages/projects/src/components/ProjectMaterialsDrawer.tsx` - Complete implementation
## Reference Implementation
`packages/tickets/src/components/ticket/TicketMaterialsCard.tsx` - Follow this pattern exactly, adapted for drawer layout.