WellNuo/backend/scripts/MIGRATION_INSTRUCTIONS.html
Sergei e1b32560ff Add Node.js backend with Stripe integration and admin panel
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>
2025-12-19 09:49:24 -08:00

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>