Backend features: - Express.js API server - Supabase database integration - Stripe Checkout for payments ($249 kit + $9.99/mo premium) - Stripe webhooks for payment events - Admin panel with order management - Auth middleware with JWT - Email service via Brevo API endpoints: - /api/stripe/* - Payment processing - /api/webhook/stripe - Stripe webhooks - /api/admin/* - Admin operations - /function/well-api/api - Legacy API proxy Database migrations: - orders, subscriptions, push_tokens tables Schemes updated: - Removed updatedAt from all schemes - Updated credentials section with live values - Added Stripe configuration details 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
171 lines
6.3 KiB
HTML
171 lines
6.3 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ru">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>WellNuo Database Migration</title>
|
|
<style>
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; background: #1a1a2e; color: #eee; }
|
|
h1 { color: #4ade80; }
|
|
.step { background: #16213e; padding: 20px; border-radius: 12px; margin: 20px 0; border-left: 4px solid #4ade80; }
|
|
.step h2 { margin-top: 0; color: #60a5fa; }
|
|
pre { background: #0f0f23; padding: 15px; border-radius: 8px; overflow-x: auto; font-size: 13px; line-height: 1.4; }
|
|
code { font-family: 'SF Mono', Monaco, 'Courier New', monospace; }
|
|
.copy-btn { background: #4ade80; color: #000; border: none; padding: 10px 20px; border-radius: 6px; cursor: pointer; font-weight: 600; margin-top: 10px; }
|
|
.copy-btn:hover { background: #22c55e; }
|
|
a { color: #60a5fa; }
|
|
.success { background: #065f46; padding: 15px; border-radius: 8px; margin: 20px 0; }
|
|
.warning { background: #854d0e; padding: 15px; border-radius: 8px; margin: 20px 0; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>WellNuo Database Migration</h1>
|
|
|
|
<div class="step">
|
|
<h2>Step 1: Open Supabase SQL Editor</h2>
|
|
<p>Go to: <a href="https://supabase.com/dashboard/project/bfzizknbxbsfrffqityf/sql/new" target="_blank">
|
|
https://supabase.com/dashboard/project/bfzizknbxbsfrffqityf/sql/new
|
|
</a></p>
|
|
</div>
|
|
|
|
<div class="step">
|
|
<h2>Step 2: Copy and Run This SQL</h2>
|
|
<p>Click the button to copy, then paste in SQL Editor and click "Run":</p>
|
|
<pre><code id="sql-code">-- WellNuo Orders & Subscriptions Schema
|
|
-- Compatible with existing database structure
|
|
|
|
-- ============ ORDERS TABLE ============
|
|
CREATE TABLE IF NOT EXISTS orders (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
order_number VARCHAR(50) UNIQUE NOT NULL,
|
|
user_id INTEGER REFERENCES person_details(user_id),
|
|
|
|
-- Beneficiary info (stored directly, not FK)
|
|
beneficiary_name VARCHAR(255),
|
|
beneficiary_address TEXT,
|
|
beneficiary_phone VARCHAR(50),
|
|
|
|
-- Stripe
|
|
stripe_session_id VARCHAR(255),
|
|
stripe_customer_id VARCHAR(255),
|
|
stripe_subscription_id VARCHAR(255),
|
|
|
|
-- Order details
|
|
status VARCHAR(50) DEFAULT 'paid' CHECK (status IN ('paid', 'preparing', 'shipped', 'delivered', 'installed', 'canceled')),
|
|
amount_total INTEGER NOT NULL, -- in cents
|
|
currency VARCHAR(3) DEFAULT 'usd',
|
|
|
|
-- Shipping
|
|
shipping_address JSONB,
|
|
shipping_name VARCHAR(255),
|
|
tracking_number VARCHAR(255),
|
|
carrier VARCHAR(50),
|
|
estimated_delivery DATE,
|
|
|
|
-- Items
|
|
items JSONB NOT NULL DEFAULT '[]',
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
shipped_at TIMESTAMPTZ,
|
|
delivered_at TIMESTAMPTZ
|
|
);
|
|
|
|
-- Index for faster queries
|
|
CREATE INDEX IF NOT EXISTS idx_orders_user_id ON orders(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_orders_status ON orders(status);
|
|
CREATE INDEX IF NOT EXISTS idx_orders_created_at ON orders(created_at DESC);
|
|
|
|
-- ============ SUBSCRIPTIONS TABLE ============
|
|
CREATE TABLE IF NOT EXISTS subscriptions (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
user_id INTEGER REFERENCES person_details(user_id),
|
|
deployment_id INTEGER REFERENCES deployments(deployment_id),
|
|
|
|
-- Stripe
|
|
stripe_subscription_id VARCHAR(255) UNIQUE,
|
|
stripe_customer_id VARCHAR(255),
|
|
|
|
-- Plan
|
|
plan VARCHAR(50) DEFAULT 'free' CHECK (plan IN ('free', 'premium')),
|
|
status VARCHAR(50) DEFAULT 'active' CHECK (status IN ('active', 'past_due', 'canceled', 'unpaid')),
|
|
|
|
-- Billing period
|
|
current_period_start TIMESTAMPTZ,
|
|
current_period_end TIMESTAMPTZ,
|
|
canceled_at TIMESTAMPTZ,
|
|
|
|
-- Timestamps
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_subscriptions_user_id ON subscriptions(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_subscriptions_status ON subscriptions(status);
|
|
|
|
-- ============ PUSH TOKENS TABLE ============
|
|
CREATE TABLE IF NOT EXISTS push_tokens (
|
|
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
|
|
user_id INTEGER REFERENCES person_details(user_id),
|
|
token TEXT NOT NULL,
|
|
platform VARCHAR(20) CHECK (platform IN ('ios', 'android', 'web')),
|
|
device_id VARCHAR(255),
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
|
|
UNIQUE(user_id, token)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_push_tokens_user_id ON push_tokens(user_id);
|
|
|
|
-- ============ UPDATED_AT TRIGGER ============
|
|
CREATE OR REPLACE FUNCTION update_updated_at_column()
|
|
RETURNS TRIGGER AS $$
|
|
BEGIN
|
|
NEW.updated_at = NOW();
|
|
RETURN NEW;
|
|
END;
|
|
$$ language 'plpgsql';
|
|
|
|
-- Drop triggers if exist and recreate
|
|
DROP TRIGGER IF EXISTS update_orders_updated_at ON orders;
|
|
CREATE TRIGGER update_orders_updated_at BEFORE UPDATE ON orders
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
DROP TRIGGER IF EXISTS update_subscriptions_updated_at ON subscriptions;
|
|
CREATE TRIGGER update_subscriptions_updated_at BEFORE UPDATE ON subscriptions
|
|
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
|
|
|
-- ============ TEST INSERT ============
|
|
-- Insert a test order to verify everything works
|
|
INSERT INTO orders (order_number, user_id, beneficiary_name, beneficiary_address, status, amount_total, items)
|
|
VALUES ('WN-TEST-0001', NULL, 'Test Beneficiary', '123 Test St', 'paid', 25899, '[{"type": "starter_kit", "name": "WellNuo Starter Kit", "price": 24900}, {"type": "subscription", "name": "Premium Monthly", "price": 999}]')
|
|
ON CONFLICT (order_number) DO NOTHING;</code></pre>
|
|
<button class="copy-btn" onclick="copySQL()">Copy SQL to Clipboard</button>
|
|
</div>
|
|
|
|
<div class="step">
|
|
<h2>Step 3: Verify Tables Created</h2>
|
|
<p>After running, you should see:</p>
|
|
<ul>
|
|
<li><strong>orders</strong> - Table for storing orders</li>
|
|
<li><strong>subscriptions</strong> - Table for managing subscriptions</li>
|
|
<li><strong>push_tokens</strong> - Table for push notification tokens</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="success">
|
|
<strong>After migration:</strong> The admin panel at <a href="https://wellnuo.smartlaunchhub.com/admin" target="_blank">https://wellnuo.smartlaunchhub.com/admin</a> should work fully!
|
|
</div>
|
|
|
|
<script>
|
|
function copySQL() {
|
|
const sql = document.getElementById('sql-code').textContent;
|
|
navigator.clipboard.writeText(sql).then(() => {
|
|
alert('SQL copied to clipboard!');
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|