feat(marketplace): sell/cancel Standard RIs on AWS Marketplace (closes #292)#808
feat(marketplace): sell/cancel Standard RIs on AWS Marketplace (closes #292)#808cristim wants to merge 12 commits into
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughImplements AWS RI Marketplace listing and cancellation end-to-end: new auth actions, DB schema and store methods, EC2 client ops, API handlers/routes, frontend API wrappers and History UI buttons with confirm flows, and test/mock updates. ChangesAWS RI Marketplace Listing Implementation
Sequence Diagram(s)sequenceDiagram
participant User as User (Browser)
participant History as History UI
participant FrontendAPI as Frontend API
participant Router as API Router
participant Handler as Marketplace Handler
participant EC2 as AWS EC2
participant DB as PostgreSQL
User->>History: Click "Sell on Marketplace"
History->>History: Show pricing confirm modal
User->>History: Confirm price & AWS fee
History->>FrontendAPI: createMarketplaceListing(purchaseId, schedule)
FrontendAPI->>Router: POST /purchases/{id}/marketplace-list
Router->>Handler: validateMarketplaceListRequest + marketplaceList
Handler->>Handler: Check session, purchase, offering_class, RBAC
Handler->>Handler: Compute remaining months & price schedule
Handler->>EC2: CreateReservedInstancesListing
EC2-->>Handler: listing_id, listing_state
Handler->>DB: UpdatePurchaseHistoryListing(listing_id, listing_state)
DB-->>Handler: success
Handler-->>Router: MarketplaceListResponse
Router-->>FrontendAPI: listing_id, listing_state, price_schedule
FrontendAPI-->>History: MarketplaceListResult
History->>History: Show success toast
History->>History: Reload history & show "Cancel listing" button
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
frontend/src/history.ts (1)
610-624:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDon't let retry-lineage markup suppress marketplace actions.
Line 610 returns as soon as lineage exists, so a completed Standard RI with
retry_attempt_n > 0never reaches Lines 617-623. That hides Sell/Cancel for successful retry descendants, even though they're still eligible completed purchases.Suggested direction
- if (lineage.length > 0) { - return lineage.join(' '); - } - - // Completed Standard RI rows: offer Sell on Marketplace (issue `#292`). - // The button is placed here (after lineage links) so it does not - // interfere with the Retry / Approve / Cancel affordances above. - if (p.purchase_id) { - if (canCancelMarketplaceListing(p)) { - return `<button type="button" class="btn-link history-marketplace-cancel-btn" data-marketplace-cancel-id="${escapeHtml(p.purchase_id)}">Cancel listing ${escapeHtml(p.listing_id || '')}</button>`; - } - if (canSellOnMarketplace(p)) { - return `<button type="button" class="btn-link history-marketplace-sell-btn" data-marketplace-sell-id="${escapeHtml(p.purchase_id)}">Sell on Marketplace</button>`; - } - } + const trailingActions: string[] = []; + if (p.purchase_id) { + if (canCancelMarketplaceListing(p)) { + trailingActions.push( + `<button type="button" class="btn-link history-marketplace-cancel-btn" data-marketplace-cancel-id="${escapeHtml(p.purchase_id)}">Cancel listing ${escapeHtml(p.listing_id || '')}</button>`, + ); + } else if (canSellOnMarketplace(p)) { + trailingActions.push( + `<button type="button" class="btn-link history-marketplace-sell-btn" data-marketplace-sell-id="${escapeHtml(p.purchase_id)}">Sell on Marketplace</button>`, + ); + } + } + + if (lineage.length > 0 || trailingActions.length > 0) { + return [...lineage, ...trailingActions].join(' '); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@frontend/src/history.ts` around lines 610 - 624, The early return when lineage.length > 0 prevents the marketplace buttons from being rendered for completed retry descendants; update the logic in the function handling the history row so that when lineage exists you append (or merge) the marketplace button markup instead of returning immediately — locate the lineage handling and the marketplace block using lineage, p.purchase_id, canCancelMarketplaceListing, canSellOnMarketplace and escapeHtml; either move the marketplace block above the return or build a combined string (lineage.join(' ') + marketplaceMarkup) so Sell on Marketplace / Cancel listing buttons are included for eligible purchases.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/src/history.ts`:
- Around line 914-943: The flow skips the required pricing modal: after the
initial confirmDialog in the '.history-marketplace-sell-btn' click handler, open
the RI pricing/pricing-schedule modal (e.g., call a new or existing
showMarketplacePricingModal / showPricingModal function) to display the RI
summary, default per-month price schedule and 12% fee breakdown and allow the
user to adjust/select schedule types (use the schedule types exposed by
frontend/src/api/purchases.ts via api.getPricingSchedules or similar). Only if
the user confirms the pricing modal proceed to call
api.createMarketplaceListing(id); preserve the existing UI state handling
(disable/enable sameRowActions(btn) and call loadHistory() on success) and
handle errors exactly as existing catch blocks do.
- Around line 474-496: canSellOnMarketplace currently omits the required
remaining-term check; update the function (canSellOnMarketplace(p:
HistoryPurchase)) to return false unless the purchase has at least one month
remaining before maturity by inspecting the appropriate remaining-term field on
p (e.g., p.remaining_term, p.remaining_months, or p.termRemaining depending on
the model) and parsing/coercing string values to numbers if needed; add this
gate alongside the existing status/offering_class/listing_state checks so
matured Standard RIs (remaining < 1) do not show the Sell button.
In `@internal/api/handler_marketplace.go`:
- Line 147: The code currently maps every AWS marketplace error to HTTP 502 via
NewClientError("AWS marketplace listing failed: "+err.Error()) which incorrectly
classifies client-side validation/precondition failures; update the handlers in
internal/api/handler_marketplace.go to inspect the returned AWS error (check for
awserr.Error or smithy.APIError / error with Code() and/or HTTPStatusCode()
methods) and map its actual HTTP-level or SDK error code to an appropriate
status (e.g., 4xx for validation/precondition/auth errors, 409 for conflict, 404
for not found, 401/403 for auth/perm, otherwise 502 for server-side), then call
NewClientError with that mapped status and the error message; apply the same
change to the other occurrence that currently returns 502 so client-correctable
errors are propagated with the correct 4xx status.
- Around line 151-156: When UpdatePurchaseHistoryListing(...) fails after AWS
listing creation (the block using purchaseID, result.ListingID, result.State),
do not silently return success; instead treat it as an error: attempt a
compensating rollback of the created listing (call the appropriate marketplace
delete/cleanup method for result.ListingID), log both the DB error and the
rollback outcome, and return an internal error to the API caller; apply the same
change for the other occurrence referenced (the block around lines 207-209) so
DB persistence failures never yield a successful response while external state
exists.
- Around line 117-118: The default listing price uses row.Term as the remaining
months, which overprices older reservations; instead compute remainingMonths as
the actual remaining term (e.g., row.RemainingTerm or row.Term - row.UsedMonths,
or derive from start/end dates and now) and pass that into
resolveMarketplacePriceSchedule when body.PriceSchedule is empty; update the
code around the schedule assignment (the call to resolveMarketplacePriceSchedule
and the local variable schedule) to use this computed remainingMonths and apply
the same fix to the other occurrence referenced (lines ~299-310).
In
`@internal/database/postgres/migrations/000060_purchase_history_marketplace_listing.up.sql`:
- Around line 15-18: The migration for table purchase_history adds
offering_class, listing_id, and listing_state but omits required marketplace
columns needed for lifecycle persistence; update the ALTER TABLE statement in
the migration to also ADD COLUMN IF NOT EXISTS listed_at TIMESTAMP WITH TIME
ZONE, listing_price_schedule JSONB (or appropriate type),
listing_proceeds_received NUMERIC (or appropriate money type), and
listing_fee_paid NUMERIC so the poller/sale path (references: table
purchase_history and columns offering_class, listing_id, listing_state) can
persist listing timestamps, price schedules, proceeds, and fees; ensure
nullability and default behavior match existing schema conventions.
In `@providers/aws/services/ec2/client.go`:
- Around line 970-979: Ensure the code never returns an empty ListingID: when
building MarketplaceListingResult (using variables listingID and
listing.ReservedInstancesListingId and listing.Status) validate that
aws.ToString(listing.ReservedInstancesListingId) yields a non-empty string and,
if empty, return a clear error instead of MarketplaceListingResult{ListingID:
"", ...}; apply the same validation & error-return logic in the other similar
blocks (the code paths referenced around the other two snippets) so downstream
handlers never persist an empty ListingID.
---
Outside diff comments:
In `@frontend/src/history.ts`:
- Around line 610-624: The early return when lineage.length > 0 prevents the
marketplace buttons from being rendered for completed retry descendants; update
the logic in the function handling the history row so that when lineage exists
you append (or merge) the marketplace button markup instead of returning
immediately — locate the lineage handling and the marketplace block using
lineage, p.purchase_id, canCancelMarketplaceListing, canSellOnMarketplace and
escapeHtml; either move the marketplace block above the return or build a
combined string (lineage.join(' ') + marketplaceMarkup) so Sell on Marketplace /
Cancel listing buttons are included for eligible purchases.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b216fad4-4a77-4b3b-be24-d77f8f3b76d4
📒 Files selected for processing (24)
frontend/src/api/index.tsfrontend/src/api/purchases.tsfrontend/src/history.tsfrontend/src/types.tsinternal/analytics/collector_test.gointernal/api/handler.gointernal/api/handler_marketplace.gointernal/api/mocks_test.gointernal/api/router.gointernal/auth/service_group_test.gointernal/auth/service_test.gointernal/auth/types.gointernal/auth/types_test.gointernal/config/interfaces.gointernal/config/store_postgres.gointernal/config/store_postgres_pgxmock_test.gointernal/config/types.gointernal/database/postgres/migrations/000060_purchase_history_marketplace_listing.down.sqlinternal/database/postgres/migrations/000060_purchase_history_marketplace_listing.up.sqlinternal/mocks/stores.gointernal/purchase/mocks_test.gointernal/scheduler/scheduler_test.gointernal/server/test_helpers_test.goproviders/aws/services/ec2/client.go
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Fixed the compile/type issues (missing MockEC2Client methods for the extended EC2API interface), addressed the 7 CR findings (6 were already in prior commits and verified against HEAD; the Describe/Cancel empty-listing-ID fallback is now applied), and resolved the pre-commit failures (gocyclo on marketplaceList via extracting validateMarketplaceListRequest, and the stale permissions.generated.ts codegen) in 03ab7f5. @coderabbitai review |
|
(ᴗ˳ᴗ) ✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
All 8 CodeRabbit findings from the 2026-05-28 review are resolved in commits a3cfc89 to 03ab7f5. Verification summary: frontend/src/history.ts
internal/api/handler_marketplace.go
internal/database/postgres/migrations/000060_...
providers/aws/services/ec2/client.go
Tests: @coderabbitai review |
|
(ᴗ˳ᴗ) ✅ Actions performedReview triggered.
|
|
All 7 CR findings from the 2026-05-28 review (plus the outside-diff lineage composability note) are resolved and confirmed in the 2026-06-01T19:33 incremental review. No new findings were raised in that review pass. Verification summary: 7 inline threads - all confirmed LGTM by CR at 2026-06-01T19:33:
Outside-diff finding (lineage composability - history.ts:610-624): already fixed in the same commit range. trailingActions array is built before lineage join at history.ts:624-635 so retry descendants with eligible listings get Sell/Cancel buttons. Build and tests pass: go build ./... clean, go test ./internal/api/... 1355 passed, go test ./providers/aws/services/ec2/... 39 passed. @coderabbitai review |
|
(ᴗ˳ᴗ) ✅ Actions performedReview triggered.
|
|
Rebased on Conflict resolution:
Verification:
All previous CR findings from the 2026-05-28 pass remain addressed (no logic changes to marketplace handlers, history.ts, ec2 client, or migration). The outside-diff-range note ( @coderabbitai review |
|
The clean build + 3292 tests passing + frontend Jest green across all touched packages is a solid confidence signal. Triggering a fresh incremental review now to cover the rebase commits. (ᴗ˳ᴗ) 🧠 Learnings used✅ Actions performedReview triggered.
|
|
Rebased The prior round's 7 CR findings were addressed in the branch history:
Note: @coderabbitai review |
|
(ᴗ˳ᴗ) 🧠 Learnings used✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/api/handler_marketplace.go`:
- Around line 401-412: The default price schedule is using the full upfrontCost
instead of the prorated remaining upfront; update
resolveMarketplacePriceSchedule to accept the original term (e.g., add a
parameter originalTerm int64 or float64) and compute upfrontRemaining :=
upfrontCost * (float64(remainingMonths) / float64(originalTerm)), then set
totalValue := upfrontRemaining + (monthlyCost * float64(remainingMonths)) and
continue with listPrice := totalValue * 0.95 and clamping to >=0; also update
the call site in marketplaceList to pass row.Term into
resolveMarketplacePriceSchedule so the function has the original term available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a47024a4-0465-406d-b1b1-370d84820e04
📒 Files selected for processing (25)
frontend/src/api/index.tsfrontend/src/api/purchases.tsfrontend/src/history.tsfrontend/src/permissions.generated.tsfrontend/src/types.tsinternal/analytics/collector_test.gointernal/api/handler.gointernal/api/handler_marketplace.gointernal/api/mocks_test.gointernal/api/router.gointernal/auth/service_group_test.gointernal/auth/types.gointernal/auth/types_test.gointernal/config/interfaces.gointernal/config/store_postgres.gointernal/config/store_postgres_pgxmock_test.gointernal/config/types.gointernal/database/postgres/migrations/000060_purchase_history_marketplace_listing.down.sqlinternal/database/postgres/migrations/000060_purchase_history_marketplace_listing.up.sqlinternal/mocks/stores.gointernal/purchase/mocks_test.gointernal/scheduler/scheduler_test.gointernal/server/test_helpers_test.goproviders/aws/services/ec2/client.goproviders/aws/services/ec2/client_test.go
💤 Files with no reviewable changes (15)
- internal/auth/types_test.go
- internal/database/postgres/migrations/000060_purchase_history_marketplace_listing.down.sql
- providers/aws/services/ec2/client_test.go
- internal/database/postgres/migrations/000060_purchase_history_marketplace_listing.up.sql
- internal/server/test_helpers_test.go
- internal/config/interfaces.go
- internal/scheduler/scheduler_test.go
- internal/purchase/mocks_test.go
- internal/auth/service_group_test.go
- internal/auth/types.go
- internal/config/store_postgres_pgxmock_test.go
- internal/mocks/stores.go
- internal/config/types.go
- providers/aws/services/ec2/client.go
- internal/config/store_postgres.go
✅ Files skipped from review due to trivial changes (1)
- frontend/src/permissions.generated.ts
🚧 Files skipped from review as they are similar to previous changes (7)
- internal/api/mocks_test.go
- internal/api/router.go
- internal/api/handler.go
- frontend/src/types.ts
- frontend/src/api/purchases.ts
- frontend/src/history.ts
- frontend/src/api/index.ts
|
Pushed a follow-up fix: extracted @coderabbitai review |
|
(ᴗ˳ᴗ) 🧠 Learnings used✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Pushed Gap 1 (BLOCKER) - compile against current base: RESOLVED. Gap 2 (BLOCKER) - multi-count partial-listing: FIXED. Gap 3 (BLOCKER) - zero handler tests: ADDED. Gap 4 (SCOPE) - dead poller columns: DESCOPED. Verification: |
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Rebased on feat/multicloud-web-frontend. Resolved conflicts in:
All prior CR findings were already addressed. Requesting fresh review pass. @coderabbitai review |
|
(ᴗ˳ᴗ) 🧠 Learnings used✅ Action performedReview finished.
|
…end (closes #292) Add sell-on-Marketplace support for Standard Reserved Instances: - migration 000060: add offering_class, listing_id, listing_state to purchase_history - auth: sell-any and sell-own actions; sell-own added to DefaultUserPermissions - config: extend PurchaseHistoryRecord, StoreInterface with GetPurchaseHistoryByPurchaseID + UpdatePurchaseHistoryListing - ec2 client: CreateReservedInstancesListing, DescribeReservedInstancesListings, CancelReservedInstancesListing - api: handler_marketplace.go with marketplaceList/Cancel, authorizeSessionSell (sell-any/sell-own RBAC), default price schedule (95% of residual value) - router: POST /api/purchases/{id}/marketplace-list + /marketplace-cancel routes - all tests updated for the new interface methods and permission count
…tend (closes #292) Add Sell on Marketplace / Cancel listing buttons to purchase history rows: - types.ts: extend HistoryPurchase with offering_class, listing_id, listing_state - api/purchases.ts: createMarketplaceListing + cancelMarketplaceListing; re-export from api/index.ts - history.ts: canSellOnMarketplace / canCancelMarketplaceListing predicates; renderActionCell renders Sell/Cancel buttons for Standard RI completed rows; wireRowActionHandlers wires confirm-dialog + API + toast + reload for both buttons
- canSellOnMarketplace: gate on remaining term >= 1 month computed from purchase timestamp + total term; matured Standard RIs no longer show Sell - sell click handler: open pricing/schedule modal before calling createMarketplaceListing so users see RI summary, default list price, and 12% fee breakdown before confirming - lineage actions cell: build trailingActions[] first then combine with lineage[] so Sell/Cancel buttons render on retry-descendant rows
- Compute actual remaining months from purchase timestamp and total term via computeRemainingMonths; removes overpricing of older RIs in the default price schedule (was using full contract term) - Map AWS errors via mapAWSMarketplaceError: inspect smithy.APIError code and fault; client-fault errors return 4xx instead of blanket 502 - On DB failure after successful listing creation, attempt compensating rollback via CancelMarketplaceListing to prevent AWS/DB desync; return internal error rather than false success to the caller - Same DB-failure fix for cancel handler: return error on UpdatePurchaseHistoryListing failure so the caller knows the state is out of sync
Add listed_at, listing_price_schedule, listing_proceeds_received, and listing_fee_paid columns for marketplace settlement tracking. All nullable, consistent with existing offering_class/listing_id/listing_state nullability. Down migration updated to drop the new columns.
…isting Return an error when AWS returns a listing with an empty ReservedInstancesListingId rather than propagating a blank ID that would silently make rollback and describe calls fail.
Repair the stalled marketplace sell/cancel work: - Add the three missing marketplace methods to MockEC2Client so the ec2 package compiles against the extended EC2API interface (CreateReservedInstancesListing, DescribeReservedInstancesListings, CancelReservedInstancesListing). - Extract validateMarketplaceListRequest from marketplaceList to bring its cyclomatic complexity back under the gocyclo threshold. - Regenerate frontend/src/permissions.generated.ts to include the new sell-own:purchases permission (pre-commit codegen check). - Harden Describe/Cancel marketplace paths to fall back to the caller-supplied listing ID when AWS omits ReservedInstancesListingId, so downstream persistence never stores an empty ID (CR finding).
After rebasing onto feat/multicloud-web-frontend, base PR #258 made PurchaseHistoryRecord.MonthlyCost a *float64 (nullable). The marketplace default price-schedule path passed it as a float64. Dereference it nil-safely at the call site, treating an absent monthly breakdown as a zero recurring contribution to residual value (per the nullable-not-zero convention: nil means "no breakdown recorded", which contributes nothing to the residual list price).
queryPurchaseHistory reached cyclomatic complexity 11 (budget 10) after the nullable marketplace columns (offering_class, listing_id, listing_state) and the nullable monthly_cost handling were added to the per-row scan. Pull the scan plus nullable-column reconciliation into scanPurchaseHistoryRow so the parent function drops back under the limit. Behavior is unchanged.
…lt schedule When the caller omits a price schedule, the default was computing total value as (full_upfront + recurring * remaining_months). For an older RI this overprices the upfront component because only (remaining/original) of the upfront has not yet been amortized. Change to: upfront_remaining = upfront_cost * (remaining / original_term) total_value = upfront_remaining + recurring * remaining_months Pass row.Term as originalTerm through resolveMarketplacePriceSchedule. Addresses CR finding on handler_marketplace.go.
…columns (closes #292 partial) Address adversarial-review gaps on the RI Marketplace sell/cancel PR: - Multi-count fix: CreateMarketplaceListing now lists every RI in the row (purchase_history.count) instead of a hardcoded InstanceCount=1, so a row of N Standard RIs lists all N. The EC2 client rejects a non-positive count before the outbound call; the handler passes row.Count (floored at 1 for legacy rows). Adds EC2 client tests for create (multi-count + guards), describe, and cancel via the SDK mock. - Tests: add handler_marketplace_test.go covering convertible -> 400, sell-own allow + deny (account scoping), duplicate active listing -> 409, AWS error mapping (client fault -> 400, server/unknown -> 502), DB-failure compensating rollback, and default-schedule proration math. - Descope poller: migration 000060 keeps only the columns the implemented flow reads/writes (offering_class, listing_id, listing_state). The settlement/poller columns (listed_at, listing_price_schedule, listing_proceeds_received, listing_fee_paid) are removed so the schema never carries columns nothing populates; they land with the poller in the #292 follow-up (#966). - Repair a stale Session.Role="admin" reference in a pre-existing purchases test (removed in the group-only auth migration) so the api test package compiles after rebasing onto the current base.
000060 is taken by 000060_cleanup_universal_plans on base.
Summary
offering_class,listing_id,listing_statecolumns topurchase_historyPOST /api/purchases/{id}/marketplace-listandPOST /api/purchases/{id}/marketplace-cancelroutes withsell-any/sell-ownRBAC (mirroring the cancel/retry/approve family);sell-ownadded toDefaultUserPermissions; default price schedule is 95% of residual value (upfront + monthly * remaining months); EC2 API:CreateReservedInstancesListing,DescribeReservedInstancesListings,CancelReservedInstancesListinglisting_state == "active"; confirm-dialog + API call + toast + reload click handlers; all API types exported fromapi/index.tsTest plan
go test ./...- all 4966 tests pass across 38 packagesnpm testinfrontend/- all 2142 frontend tests passnpm run build- compiles with no TS errorsoffering_class=standardand verify "Sell on Marketplace" button appears; click it and confirm the API call is dispatchedlisting_state=activeand cancels correctlysell-ownusers can only sell RIs in their allowed accounts;sell-anyusers can sell anyScope / descope
This PR ships listing creation and cancellation for Standard RIs. Two parts of #292 are intentionally descoped to keep it landable and are tracked in follow-up #966:
active -> closed/sold transition, realized proceeds, AWS fee actually charged).Because the poller is not implemented, migration 000060 was reduced to only the columns the implemented flow reads/writes (
offering_class,listing_id,listing_state). The settlement/poller columns (listed_at,listing_price_schedule,listing_proceeds_received,listing_fee_paid) were removed so the schema never carries columns nothing populates; they will land with the poller in #966.Closes #292 partially; remainder tracked in #966.
Summary by CodeRabbit