feat: establish auth listing and image vertical slices

Includes MFA-capable authentication, session and CSRF security, password recovery, listing lifecycle and ownership rules, inventory image metadata, local ImageStorage, migrations, tests, and implementation status documentation. Verification: npm test (62 passing) and integration suite (14 passing).
This commit is contained in:
2026-09-08 17:32:03 -04:00
commit c728016dec
128 changed files with 9788 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import {
LISTING_STATUS,
canPublishListing,
createListing,
transitionListingStatus,
} from '../../src/modules/listings/domain/listing.js';
test('creates a draft listing with the required public offer fields', () => {
const listing = createListing({
inventoryItemId: 'inventory-item-id',
productName: ' Charizard ex ',
categoryId: 'category-id',
conditionId: 'condition-id',
askingPriceMinor: 2499,
imageCount: 2,
notes: ' Near mint ',
});
assert.deepEqual(listing, {
inventoryItemId: 'inventory-item-id',
productName: 'Charizard ex',
categoryId: 'category-id',
conditionId: 'condition-id',
askingPriceMinor: 2499,
imageCount: 2,
status: LISTING_STATUS.DRAFT,
notes: 'Near mint',
});
});
test('requires the publication prerequisites before a listing can be made available', () => {
const valid = {
productName: 'Charizard ex',
categoryId: 'category-id',
conditionId: 'condition-id',
inventoryItemId: 'inventory-item-id',
askingPriceMinor: 2499,
imageCount: 2,
};
assert.doesNotThrow(() => canPublishListing(valid));
assert.throws(
() => canPublishListing({ ...valid, askingPriceMinor: 0 }),
(error) => error.code === 'LISTING_REQUIREMENTS_NOT_MET',
);
assert.throws(
() => canPublishListing({ ...valid, imageCount: 0 }),
(error) => error.code === 'LISTING_REQUIREMENTS_NOT_MET',
);
assert.throws(
() => canPublishListing({ ...valid, inventoryStatus: 'SOLD' }),
(error) => error.code === 'LISTING_INVENTORY_UNAVAILABLE' && error.statusCode === 409,
);
assert.throws(
() => canPublishListing({ ...valid, inventoryStatus: 'ARCHIVED' }),
(error) => error.code === 'LISTING_INVENTORY_UNAVAILABLE',
);
});
test('allows only status transitions permitted by the listing lifecycle', () => {
assert.equal(transitionListingStatus(LISTING_STATUS.DRAFT, LISTING_STATUS.AVAILABLE), LISTING_STATUS.AVAILABLE);
assert.throws(
() => transitionListingStatus(LISTING_STATUS.DRAFT, LISTING_STATUS.ARCHIVED),
/Listing status cannot transition from DRAFT to ARCHIVED/,
);
assert.equal(transitionListingStatus(LISTING_STATUS.CLOSED, LISTING_STATUS.ARCHIVED), LISTING_STATUS.ARCHIVED);
});