You are the senior engineer reviewing a proposed feature for...
Prompt
You are the senior engineer reviewing a proposed feature for REbuilder, a customer-facing Realtor database-rebuild service operated by Velocity Builders LLC. Your job is to turn a flawed intake-to-processing implementation into a small, production-worthy design. Prioritize correctness, maintainability, and customer trust over impressive-sounding architecture. This is a self-contained engineering exercise. You do not have access to the real repository. Do not invent existing files, claim you inspected the codebase, or claim you executed tests. PRODUCT CONTEXT A customer: 1. Opens a personalized intake page. 2. Provides identity/contact information and privacy consent. 3. Uploads a lifetime MLS production report. 4. Uploads a current CRM export. 5. Pays $199 USD. 6. Receives a rebuilt/enriched database after processing. Payment and uploads can happen in either order. Customers may leave and return. ASSUMED TECHNICAL ENVIRONMENT For this exercise, assume: - TypeScript and Next.js. - PostgreSQL. - Private object storage for uploaded files. - A payment provider that sends signed webhooks. - An external background-job queue with at-least-once delivery. - A multi-tenant application. These are exercise assumptions, not statements about the real repository. BUSINESS RULES An initial rebuild may be queued only when ALL of these are true: - The server has verified a successful $199 USD payment for this order. - Privacy consent has been recorded. - The currently selected MLS upload has passed validation. - The currently selected CRM upload has passed validation. Additional rules: - “Uploaded” is not the same as “validated.” - Two MLS files do not substitute for one MLS file and one CRM file. - A browser redirect, query parameter, or client-supplied flag is not proof of payment. - Before queueing, replacing an upload makes the new revision authoritative. A late validation callback for the old revision must not approve the new revision. - Once queued, the rebuild is bound to immutable file revisions. For this MVP, reject replacement uploads after queueing. Reruns are out of scope. - Each order may create at most one initial logical rebuild. - Duplicate webhooks, simultaneous requests, and queue redelivery must not create additional logical rebuilds. - A delayed or duplicate payment webhook must not move a running or completed rebuild backward to “queued.” - Failed rebuilds must not be automatically recreated by the intake gate. - Users must not access another tenant’s orders, files, or status. - Raw client records must not appear in application logs or public file URLs. FLAWED IMPLEMENTATION The following APIs are illustrative pseudocode, not a real database SDK. async function finishIntake(input: { orderId: string; paymentSuccess?: boolean; }) { if (input.paymentSuccess) { await db.setPaid(input.orderId); } const order = await db.getOrder(input.orderId); const files = await db.listUploads(input.orderId); if (order.paid && files.length >= 2) { await queue.publish({ orderId: input.orderId }); await db.setStatus(input.orderId, "queued"); } return { message: "Your rebuild is underway!" }; } YOUR TASK Review this implementation and propose the smallest robust replacement. Do not redesign the entire product or introduce unrelated infrastructure. Include the following: 1. FAILURE ANALYSIS Identify the highest-impact defects. Explain the concrete failure each could cause. Prioritize data exposure, unauthorized processing, duplicate processing, lost work, and misleading customer status. Do not merely list generic “best practices.” 2. EXECUTABLE CORE LOGIC Implement a pure TypeScript function: evaluateIntake(snapshot: IntakeSnapshot): IntakeView Use these input types: type FileState = | "missing" | "uploaded" | "validating" | "valid" | "invalid"; type Lifecycle = | "intake" | "queued" | "running" | "completed" | "failed"; type IntakeSnapshot = { payment: "unpaid" | "paid"; consentRecorded: boolean; mls: FileState; crm: FileState; lifecycle: Lifecycle; }; Define IntakeView yourself, but it must contain: - canQueue: boolean - blockers: an array of machine-readable blocker codes - statusLabel: customer-facing text - nextAction: customer-facing text Requirements: - For an intake-stage order, report every unmet prerequisite, not just the first. - Use a deterministic blocker order: PAYMENT, CONSENT, MLS, CRM. - canQueue is true only for lifecycle="intake" with every prerequisite met. - For queued/running/completed/failed, canQueue must be false and the displayed lifecycle must not regress. - Distinguish missing, validating, and invalid files in the customer-facing explanation. - Do not imply work has started just because prerequisites are complete. - Do not invent turnaround-time promises. The function evaluates an authoritative server snapshot. It does not authenticate requests, verify payments, write database records, or publish jobs. Explain briefly where those responsibilities belong. Include table-driven tests for the function. Make them executable rather than merely describing what someone should test. 3. DURABLE QUEUEING DESIGN Provide: - A minimal PostgreSQL schema sketch with the important uniqueness constraints. - Transaction pseudocode for safely creating the initial rebuild. - How payment events and file-validation callbacks update authoritative state. - How tenant ownership is enforced for customer requests and how provider events are bound to the correct order. - How the selected file revisions are protected against replacement/queueing races. - How work reliably reaches the external queue despite a crash. - How a worker handles duplicate messages and crash/retry recovery. Clearly distinguish runnable TypeScript from illustrative SQL or pseudocode. Naming an “idempotency key” is not sufficient. State what it identifies, where uniqueness is enforced, and what happens during concurrent requests. Do not assume publishing to an external queue is atomic with a PostgreSQL transaction. Do not claim exactly-once message delivery. Distinguish one logical rebuild from message delivery and execution attempts, including any limits around external enrichment side effects. 4. ADVERSARIAL CASES For each case below, state: - Whether a new logical rebuild is created. - What the customer should see, or whether access is denied. - Which safeguard makes the result reliable. Unless stated otherwise, consent is recorded, lifecycle is "intake," and events belong to the correct tenant. A. Payment is verified; MLS is valid; CRM is missing. B. Payment is verified; two MLS files are valid; there is no CRM file. C. Both required files are valid, but payment is unverified. The browser submits paymentSuccess=true. D. Payment is verified; both files have uploaded successfully but neither has passed validation. E. Payment and both files are valid, but privacy consent is absent. F. All prerequisites are met. Two requests attempt to queue simultaneously while the same payment webhook is delivered three times. G. MLS revision 1 was valid. The customer replaces it with revision 2, which is still validating. A delayed “valid” callback arrives for revision 1. All other prerequisites are met. H. The queue accepts a message, but the publisher crashes before recording successful delivery. Delivery is retried. I. An authenticated user from tenant B supplies a valid order ID belonging to tenant A. J. A rebuild is already running when an old successful-payment webhook is redelivered. 5. CUSTOMER HANDOFF Write the exact short customer-facing status message and primary action for: - Paid, but CRM export missing. - Paid, with both files still validating. - All prerequisites met, but queueing has not yet committed. - Rebuild durably queued, but not running. - Rebuild running. - Rebuild failed. Make the distinction between “we have your payment,” “we are checking your files,” “your rebuild is queued,” and “your rebuild is running” unmistakable. 6. IMPLEMENTATION JUDGMENT Finish with: - The smallest sensible implementation sequence. - The three most important integration tests beyond the pure-function tests. - Any assumptions or unresolved decisions. Do not ask clarifying questions. State reasonable assumptions and proceed. Keep the response under 2,500 words, including code. Spend the space on concrete logic, failure handling, and customer clarity—not introductory commentary.