Розробка краудфандинговой платформи
Краудфандингова платформа — це не просто «сайт зі сторінкою оплати». Це система управління кампаніями, збором коштів, виплатами творцям, комунікацією з спонсорами і дотриманням вимог законодавства про платежі. Різниця між робочим продуктом і списком фіч — в деталях реалізації кожної з цих частин.
Моделі фінансування
Перш ніж проектувати схему даних, потрібно визначитися з моделлю:
All-or-Nothing (AON) — кошти списуються тільки при досягненні цілі. Kickstarter-модель. Технічно складніша: потрібна pre-authorization (холдирування) або відкладений capture.
Keep-it-All (KIA) — кошти списуються одразу, творець отримує все незалежно від цілі. Indiegogo-модель. Простіша в реалізації, але юридично вимагає чіткого описання умов повернення.
Гібридна — ціль фіксована, але при перевищенні відкриваються stretch goals. Найскладніший варіант з точки зору логіки стану кампанії.
Схема даних
CREATE TABLE campaigns (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
creator_id UUID NOT NULL REFERENCES users(id),
title VARCHAR(200) NOT NULL,
slug VARCHAR(200) UNIQUE NOT NULL,
description TEXT,
goal_amount NUMERIC(15,2) NOT NULL,
currency CHAR(3) NOT NULL DEFAULT 'RUB',
model VARCHAR(20) NOT NULL CHECK (model IN ('aon','kia','hybrid')),
status VARCHAR(20) NOT NULL DEFAULT 'draft'
CHECK (status IN ('draft','active','funded','failed','cancelled')),
starts_at TIMESTAMPTZ NOT NULL,
ends_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE pledges (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
campaign_id UUID NOT NULL REFERENCES campaigns(id),
backer_id UUID NOT NULL REFERENCES users(id),
amount NUMERIC(15,2) NOT NULL,
reward_id UUID REFERENCES rewards(id),
status VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending','authorized','captured','refunded','failed')),
payment_intent VARCHAR(200),
captured_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE rewards (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
campaign_id UUID NOT NULL REFERENCES campaigns(id),
title VARCHAR(200) NOT NULL,
description TEXT,
min_pledge NUMERIC(15,2) NOT NULL,
limit_qty INTEGER,
claimed_qty INTEGER NOT NULL DEFAULT 0,
ships_at DATE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_pledges_campaign_status
ON pledges(campaign_id, status)
WHERE status IN ('authorized','captured');







