Add rental system: listings, bookings, payments, payouts, reviews
Full rental marketplace with 6 categories (apartment, house, car, motorcycle, bicycle, ebike). Booking workflow: create → confirm → pay → active → complete → payout. Landlord dashboard, admin moderation, availability calendar, Stripe Connect payouts. 14 QA bugs found and fixed including validator schemas, API response types, HTTP methods. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "UserRole" AS ENUM ('USER', 'MODERATOR', 'ADMIN', 'SUPER_ADMIN');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ReportReason" AS ENUM ('SPAM', 'INAPPROPRIATE', 'SCAM', 'COUNTERFEIT', 'PROHIBITED_ITEM', 'HARASSMENT', 'OTHER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ReportStatus" AS ENUM ('OPEN', 'REVIEWING', 'RESOLVED', 'DISMISSED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ReportTargetType" AS ENUM ('LISTING', 'USER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SubscriptionTier" AS ENUM ('BASIC', 'PRO', 'BUSINESS');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "SubscriptionStatus" AS ENUM ('ACTIVE', 'CANCELLED', 'EXPIRED', 'PAST_DUE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PaymentType" AS ENUM ('LISTING_FEE', 'COMMISSION', 'PROMOTION', 'SUBSCRIPTION');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ModerationAction" AS ENUM ('APPROVED', 'REJECTED', 'WARNING', 'BAN', 'UNBAN', 'LISTING_DELETED', 'LISTING_FEATURED');
|
||||
|
||||
-- AlterEnum
|
||||
ALTER TYPE "ListingStatus" ADD VALUE 'PENDING_REVIEW';
|
||||
|
||||
-- AlterEnum
|
||||
-- This migration adds more than one value to an enum.
|
||||
-- With PostgreSQL versions 11 and earlier, this is not possible
|
||||
-- in a single migration. This can be worked around by creating
|
||||
-- multiple migrations, each migration adding only one value to
|
||||
-- the enum.
|
||||
|
||||
|
||||
ALTER TYPE "NotificationType" ADD VALUE 'LISTING_APPROVED';
|
||||
ALTER TYPE "NotificationType" ADD VALUE 'LISTING_REJECTED';
|
||||
ALTER TYPE "NotificationType" ADD VALUE 'MODERATION_WARNING';
|
||||
ALTER TYPE "NotificationType" ADD VALUE 'ACCOUNT_BANNED';
|
||||
ALTER TYPE "NotificationType" ADD VALUE 'ACCOUNT_UNBANNED';
|
||||
ALTER TYPE "NotificationType" ADD VALUE 'REPORT_RESOLVED';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Listing" ADD COLUMN "isFeatured" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "rejectionReason" TEXT,
|
||||
ADD COLUMN "reviewedAt" TIMESTAMP(3),
|
||||
ADD COLUMN "reviewedBy" TEXT;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Payment" ADD COLUMN "description" TEXT,
|
||||
ADD COLUMN "type" "PaymentType" NOT NULL DEFAULT 'LISTING_FEE';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ADD COLUMN "banReason" TEXT,
|
||||
ADD COLUMN "bannedAt" TIMESTAMP(3),
|
||||
ADD COLUMN "bannedBy" TEXT,
|
||||
ADD COLUMN "isBanned" BOOLEAN NOT NULL DEFAULT false,
|
||||
ADD COLUMN "role" "UserRole" NOT NULL DEFAULT 'USER';
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Report" (
|
||||
"id" TEXT NOT NULL,
|
||||
"reporterId" TEXT NOT NULL,
|
||||
"targetType" "ReportTargetType" NOT NULL,
|
||||
"targetId" TEXT NOT NULL,
|
||||
"reason" "ReportReason" NOT NULL,
|
||||
"description" TEXT,
|
||||
"status" "ReportStatus" NOT NULL DEFAULT 'OPEN',
|
||||
"resolvedBy" TEXT,
|
||||
"resolution" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Report_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PlatformConfig" (
|
||||
"id" TEXT NOT NULL,
|
||||
"listingFee" DOUBLE PRECISION NOT NULL DEFAULT 5.00,
|
||||
"commissionPercent" DOUBLE PRECISION NOT NULL DEFAULT 5.0,
|
||||
"autoApprove" BOOLEAN NOT NULL DEFAULT true,
|
||||
"maxImagesPerListing" INTEGER NOT NULL DEFAULT 6,
|
||||
"maxListingsFreeTier" INTEGER NOT NULL DEFAULT 5,
|
||||
"proPrice" DOUBLE PRECISION NOT NULL DEFAULT 9.99,
|
||||
"businessPrice" DOUBLE PRECISION NOT NULL DEFAULT 29.99,
|
||||
"promotionDayPrice" DOUBLE PRECISION NOT NULL DEFAULT 2.99,
|
||||
"blockedKeywords" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PlatformConfig_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Subscription" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"tier" "SubscriptionTier" NOT NULL DEFAULT 'BASIC',
|
||||
"status" "SubscriptionStatus" NOT NULL DEFAULT 'ACTIVE',
|
||||
"stripeSubscriptionId" TEXT,
|
||||
"currentPeriodEnd" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PromotedListing" (
|
||||
"id" TEXT NOT NULL,
|
||||
"listingId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"startDate" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"endDate" TIMESTAMP(3) NOT NULL,
|
||||
"amountPaid" DOUBLE PRECISION NOT NULL,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "PromotedListing_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ModerationLog" (
|
||||
"id" TEXT NOT NULL,
|
||||
"moderatorId" TEXT NOT NULL,
|
||||
"targetUserId" TEXT,
|
||||
"targetListingId" TEXT,
|
||||
"action" "ModerationAction" NOT NULL,
|
||||
"reason" TEXT,
|
||||
"details" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "ModerationLog_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Report_status_idx" ON "Report"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Report_targetType_targetId_idx" ON "Report"("targetType", "targetId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Subscription_userId_key" ON "Subscription"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Subscription_stripeSubscriptionId_key" ON "Subscription"("stripeSubscriptionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PromotedListing_listingId_key" ON "PromotedListing"("listingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "PromotedListing_isActive_endDate_idx" ON "PromotedListing"("isActive", "endDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ModerationLog_moderatorId_idx" ON "ModerationLog"("moderatorId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "ModerationLog_createdAt_idx" ON "ModerationLog"("createdAt");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Report" ADD CONSTRAINT "Report_reporterId_fkey" FOREIGN KEY ("reporterId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PromotedListing" ADD CONSTRAINT "PromotedListing_listingId_fkey" FOREIGN KEY ("listingId") REFERENCES "Listing"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PromotedListing" ADD CONSTRAINT "PromotedListing_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ModerationLog" ADD CONSTRAINT "ModerationLog_moderatorId_fkey" FOREIGN KEY ("moderatorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
Reference in New Issue
Block a user