Skip to content

Issue #220: Make document_id Optional in Document Item Creation Schema

Summary

Issue #220 addressed a validation bug where the API required document_id for creating document items, even though invoice numbers are now generated when the document is created. This caused validation failures when creating new invoices with items.

Status: ✅ COMPLETE - Schema updated, regression tests added, all tests passing.

Issues Identified

Required document_id During Item Creation

Problem: BaseDocumentItemSchema required document_id for all item creation operations - Location: schemas/src/DocumentItemSchema.ts:13 - Impact: New invoices with items could not be created because items didn't have a document_id yet - Affected Schemas: - CreateInvoiceItemSchema - CreateOfferItemSchema - CreateCreditNoteItemSchema

Original Code:

// BaseDocumentItemSchema - Line 13
document_id: z.string({ error: "document_id_required" }).uuid({ error: "invalid_document_id" }),

Root Cause Analysis

Workflow Change Impact

When the system was updated to generate invoice numbers at document creation time (instead of draft time), the validation schemas were not updated to reflect this change.

Previous Workflow: 1. Create draft invoice → Invoice number generated → document_id available 2. Add items with document_id

Current Workflow: 1. Create invoice with items (no document_id yet) 2. Document created → Invoice number generated → document_id assigned to items

Validation Mismatch

The CreateInvoiceItemSchema inherited the required document_id field from BaseDocumentItemSchema, causing validation to fail when items were created without a document_id.

Solution Implementation

Schema Changes

1. Updated Create Item Schemas

Made document_id optional and nullable in all Create schemas:

File: schemas/src/DocumentItemSchema.ts (lines 79-100)

// Helper schemas for creation/updates
// document_id is optional during creation since invoice numbers are generated when document is created
export const CreateInvoiceItemSchema = InvoiceItemSchema.omit({
  id: true,
  created_at: true,
}).extend({
  document_id: z.string({ error: "invalid_document_id" }).uuid({ error: "invalid_document_id" }).optional().nullable(),
});

export const CreateOfferItemSchema = OfferItemSchema.omit({
  id: true,
  created_at: true,
}).extend({
  document_id: z.string({ error: "invalid_document_id" }).uuid({ error: "invalid_document_id" }).optional().nullable(),
});

export const CreateCreditNoteItemSchema = CreditNoteItemSchema.omit({
  id: true,
  created_at: true,
}).extend({
  document_id: z.string({ error: "invalid_document_id" }).uuid({ error: "invalid_document_id" }).optional().nullable(),
});

Key Changes: - Used .extend() to override document_id validation - Changed from required to .optional().nullable() - Removed the "document_id_required" error message (not applicable for creation) - Added clarifying comment explaining why document_id is optional

Regression Tests

Added 4 Regression Tests

File: schemas/src/DocumentItemSchema.test.ts (lines 427-498)

Test Coverage: 1. CreateInvoiceItemSchema without document_id - Validates items can be created without document_id 2. CreateOfferItemSchema without document_id - Same for offer items 3. CreateCreditNoteItemSchema without document_id - Same for credit note items 4. Null document_id handling - Validates that null is accepted and properly handled

Example Test:

it("should validate CreateInvoiceItemSchema without document_id", () => {
  const createData = {
    type: ITEM_TYPE_INVOICE,
    name: "Test Item",
    quantity: 1,
    price_net: 100,
    product_category: "digital_service",
    tax_rate: 19,
  };

  const result = CreateInvoiceItemSchema.safeParse(createData);
  expect(result.success).toBe(true);
  if (result.success) {
    expect(result.data.document_id).toBeUndefined();
  }
});

Verification

Test Results

pnpm test DocumentItemSchema

Output:

✓ src/DocumentItemSchema.test.ts (57 tests) 9ms
  Test Files  1 passed (1)
       Tests  57 passed (57)

All tests passed, including the 4 new regression tests.

Build Verification

pnpm build

Output:

ESM Build success in 31ms
CJS Build success in 30ms
DTS Build success in 1789ms

TypeScript compilation successful - no type errors.

Impact Analysis

Schemas Affected

  • CreateInvoiceItemSchema - Can now accept items without document_id
  • CreateOfferItemSchema - Can now accept items without document_id
  • CreateCreditNoteItemSchema - Can now accept items without document_id
  • ℹ️ BaseDocumentItemSchema - Unchanged (document_id still required for complete items)
  • ℹ️ UpdateInvoiceItemSchema - Unchanged (document_id still required for updates)

API Impact

The API can now accept document creation payloads where items don't have a document_id, allowing the correct workflow: 1. Client sends document with items (no document_id in items) 2. API creates document (generates document_id) 3. API assigns document_id to all items 4. API saves items with proper document_id

Backward Compatibility

Fully backward compatible - Existing code that provides document_id during item creation will continue to work as before. The change only makes the field optional, not forbidden.

Files Modified

  1. schemas/src/DocumentItemSchema.ts
  2. Updated CreateInvoiceItemSchema (lines 81-86)
  3. Updated CreateOfferItemSchema (lines 88-93)
  4. Updated CreateCreditNoteItemSchema (lines 95-100)

  5. schemas/src/DocumentItemSchema.test.ts

  6. Added 4 regression tests (lines 427-498)
  • Issue #219: Dependency warnings (Sentry & magicast) - Resolved in parallel
  • Related to the invoice number generation workflow change

Lessons Learned

  1. Schema Synchronization: When changing business logic workflows, always review and update validation schemas accordingly
  2. Regression Testing: Adding regression tests for bug fixes prevents re-introduction of the same issue
  3. Documentation: Clear comments in code explain why certain validations are optional, helping future developers understand the intent
  4. Gradual Migration: Optional fields provide flexibility for transitional states in document creation workflows

Future Considerations

  • Consider adding validation at the API level to ensure document_id is properly assigned before items are persisted
  • Add integration tests that verify the full document creation workflow including item creation
  • Document the complete invoice creation flow in API documentation