Compare commits
2 Commits
908b40aa1f
...
16c8edf7e9
| Author | SHA1 | Date | |
|---|---|---|---|
| 16c8edf7e9 | |||
| 2db6c0149b |
+57
-54
@@ -66,9 +66,6 @@ jobs:
|
|||||||
MINIMAX_BASE_URL: ${{ secrets.MINIMAX_BASE_URL }}
|
MINIMAX_BASE_URL: ${{ secrets.MINIMAX_BASE_URL }}
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Install rsync
|
|
||||||
run: sudo apt-get update && sudo apt-get install -y rsync
|
|
||||||
|
|
||||||
- name: Deploy
|
- name: Deploy
|
||||||
env:
|
env:
|
||||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||||
@@ -112,61 +109,67 @@ jobs:
|
|||||||
set -e
|
set -e
|
||||||
APP_DIR=/home/tyler/route-commerce
|
APP_DIR=/home/tyler/route-commerce
|
||||||
|
|
||||||
# Add server SSH host key if provided
|
# Setup SSH key
|
||||||
if [ -n "$SERVER_SSH_KEY" ]; then
|
|
||||||
mkdir -p ~/.ssh
|
mkdir -p ~/.ssh
|
||||||
echo "$SERVER_SSH_KEY" >> ~/.ssh/id_ed25519
|
echo "$SERVER_SSH_KEY" > ~/.ssh/id_ed25519
|
||||||
chmod 600 ~/.ssh/id_ed25519
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
ssh-keyscan route.crispygoat.com >> ~/.ssh/known_hosts 2>/dev/null
|
ssh-keyscan -H route.crispygoat.com >> ~/.ssh/known_hosts 2>/dev/null || true
|
||||||
fi
|
|
||||||
|
|
||||||
# Write production env file
|
# Test SSH connection
|
||||||
{
|
echo "Testing SSH connection..."
|
||||||
printf "DATABASE_URL=%s\n" "$DATABASE_URL"
|
ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no tyler@route.crispygoat.com "echo 'SSH OK' && hostname" || { echo "SSH FAILED"; exit 1; }
|
||||||
printf "NEXT_PUBLIC_SITE_URL=%s\n" "$NEXT_PUBLIC_SITE_URL"
|
|
||||||
printf "NEON_AUTH_BASE_URL=%s\n" "$NEON_AUTH_BASE_URL"
|
|
||||||
printf "NEON_AUTH_COOKIE_SECRET=%s\n" "$NEON_AUTH_COOKIE_SECRET"
|
|
||||||
printf "AUTH_SECRET=%s\n" "$AUTH_SECRET"
|
|
||||||
printf "AUTH_URL=%s\n" "$AUTH_URL"
|
|
||||||
printf "NEXT_PUBLIC_AUTH_URL=%s\n" "$NEXT_PUBLIC_AUTH_URL"
|
|
||||||
printf "GOOGLE_CLIENT_ID=%s\n" "$GOOGLE_CLIENT_ID"
|
|
||||||
printf "GOOGLE_CLIENT_SECRET=%s\n" "$GOOGLE_CLIENT_SECRET"
|
|
||||||
printf "ALLOW_DEV_LOGIN=%s\n" "$ALLOW_DEV_LOGIN"
|
|
||||||
printf "ADMIN_ALLOWED_EMAILS=%s\n" "$ADMIN_ALLOWED_EMAILS"
|
|
||||||
printf "NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=%s\n" "$NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY"
|
|
||||||
printf "STRIPE_SECRET_KEY=%s\n" "$STRIPE_SECRET_KEY"
|
|
||||||
printf "STRIPE_WEBHOOK_SECRET=%s\n" "$STRIPE_WEBHOOK_SECRET"
|
|
||||||
printf "STRIPE_PRICE_STARTER=%s\n" "$STRIPE_PRICE_STARTER"
|
|
||||||
printf "STRIPE_PRICE_FARM=%s\n" "$STRIPE_PRICE_FARM"
|
|
||||||
printf "STRIPE_PRICE_ENTERPRISE=%s\n" "$STRIPE_PRICE_ENTERPRISE"
|
|
||||||
printf "STRIPE_PRICE_HARVEST_REACH=%s\n" "$STRIPE_PRICE_HARVEST_REACH"
|
|
||||||
printf "STRIPE_PRICE_WHOLESALE_PORTAL=%s\n" "$STRIPE_PRICE_WHOLESALE_PORTAL"
|
|
||||||
printf "STRIPE_PRICE_WATER_LOG=%s\n" "$STRIPE_PRICE_WATER_LOG"
|
|
||||||
printf "STRIPE_PRICE_AI_TOOLS=%s\n" "$STRIPE_PRICE_AI_TOOLS"
|
|
||||||
printf "STRIPE_PRICE_SQUARE_SYNC=%s\n" "$STRIPE_PRICE_SQUARE_SYNC"
|
|
||||||
printf "STRIPE_PRICE_SMS_CAMPAIGNS=%s\n" "$STRIPE_PRICE_SMS_CAMPAIGNS"
|
|
||||||
printf "RESEND_API_KEY=%s\n" "$RESEND_API_KEY"
|
|
||||||
printf "FROM_EMAIL=%s\n" "$FROM_EMAIL"
|
|
||||||
printf "MINIO_ENDPOINT=%s\n" "$MINIO_ENDPOINT"
|
|
||||||
printf "MINIO_REGION=%s\n" "$MINIO_REGION"
|
|
||||||
printf "MINIO_ACCESS_KEY=%s\n" "$MINIO_ACCESS_KEY"
|
|
||||||
printf "MINIO_SECRET_KEY=%s\n" "$MINIO_SECRET_KEY"
|
|
||||||
printf "MINIO_PUBLIC_URL=%s\n" "$MINIO_PUBLIC_URL"
|
|
||||||
printf "MINIO_BUCKET_PRODUCTS=%s\n" "$MINIO_BUCKET_PRODUCTS"
|
|
||||||
printf "MINIO_BUCKET_BRAND_LOGOS=%s\n" "$MINIO_BUCKET_BRAND_LOGOS"
|
|
||||||
printf "MINIO_BUCKET_WATER_LOGS=%s\n" "$MINIO_BUCKET_WATER_LOGS"
|
|
||||||
printf "MINIMAX_API_KEY=%s\n" "$MINIMAX_API_KEY"
|
|
||||||
printf "MINIMAX_BASE_URL=%s\n" "$MINIMAX_BASE_URL"
|
|
||||||
printf "CRON_SECRET=%s\n" "$CRON_SECRET"
|
|
||||||
} > $APP_DIR/.env.production
|
|
||||||
|
|
||||||
# Sync build output and required files to server
|
# Write production env file on server
|
||||||
rsync -a --delete .next/ tyler@route.crispygoat.com:$APP_DIR/.next/
|
ssh tyler@route.crispygoat.com "mkdir -p $APP_DIR && cat > $APP_DIR/.env.production" << 'ENVEOF'
|
||||||
rsync -a --delete public/ tyler@route.crispygoat.com:$APP_DIR/public/
|
DATABASE_URL=$DATABASE_URL
|
||||||
rsync $APP_DIR/package.json tyler@route.crispygoat.com:$APP_DIR/
|
NEXT_PUBLIC_SITE_URL=$NEXT_PUBLIC_SITE_URL
|
||||||
rsync next.config.ts tyler@route.crispygoat.com:$APP_DIR/ 2>/dev/null || true
|
NEON_AUTH_BASE_URL=$NEON_AUTH_BASE_URL
|
||||||
|
NEON_AUTH_COOKIE_SECRET=$NEON_AUTH_COOKIE_SECRET
|
||||||
|
AUTH_SECRET=$AUTH_SECRET
|
||||||
|
AUTH_URL=$AUTH_URL
|
||||||
|
NEXT_PUBLIC_AUTH_URL=$NEXT_PUBLIC_AUTH_URL
|
||||||
|
GOOGLE_CLIENT_ID=$GOOGLE_CLIENT_ID
|
||||||
|
GOOGLE_CLIENT_SECRET=$GOOGLE_CLIENT_SECRET
|
||||||
|
ALLOW_DEV_LOGIN=$ALLOW_DEV_LOGIN
|
||||||
|
ADMIN_ALLOWED_EMAILS=$ADMIN_ALLOWED_EMAILS
|
||||||
|
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=$NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
|
||||||
|
STRIPE_SECRET_KEY=$STRIPE_SECRET_KEY
|
||||||
|
STRIPE_WEBHOOK_SECRET=$STRIPE_WEBHOOK_SECRET
|
||||||
|
STRIPE_PRICE_STARTER=$STRIPE_PRICE_STARTER
|
||||||
|
STRIPE_PRICE_FARM=$STRIPE_PRICE_FARM
|
||||||
|
STRIPE_PRICE_ENTERPRISE=$STRIPE_PRICE_ENTERPRISE
|
||||||
|
STRIPE_PRICE_HARVEST_REACH=$STRIPE_PRICE_HARVEST_REACH
|
||||||
|
STRIPE_PRICE_WHOLESALE_PORTAL=$STRIPE_PRICE_WHOLESALE_PORTAL
|
||||||
|
STRIPE_PRICE_WATER_LOG=$STRIPE_PRICE_WATER_LOG
|
||||||
|
STRIPE_PRICE_AI_TOOLS=$STRIPE_PRICE_AI_TOOLS
|
||||||
|
STRIPE_PRICE_SQUARE_SYNC=$STRIPE_PRICE_SQUARE_SYNC
|
||||||
|
STRIPE_PRICE_SMS_CAMPAIGNS=$STRIPE_PRICE_SMS_CAMPAIGNS
|
||||||
|
RESEND_API_KEY=$RESEND_API_KEY
|
||||||
|
FROM_EMAIL=$FROM_EMAIL
|
||||||
|
MINIO_ENDPOINT=$MINIO_ENDPOINT
|
||||||
|
MINIO_REGION=$MINIO_REGION
|
||||||
|
MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY
|
||||||
|
MINIO_SECRET_KEY=$MINIO_SECRET_KEY
|
||||||
|
MINIO_PUBLIC_URL=$MINIO_PUBLIC_URL
|
||||||
|
MINIO_BUCKET_PRODUCTS=$MINIO_BUCKET_PRODUCTS
|
||||||
|
MINIO_BUCKET_BRAND_LOGOS=$MINIO_BUCKET_BRAND_LOGOS
|
||||||
|
MINIO_BUCKET_WATER_LOGS=$MINIO_BUCKET_WATER_LOGS
|
||||||
|
MINIMAX_API_KEY=$MINIMAX_API_KEY
|
||||||
|
MINIMAX_BASE_URL=$MINIMAX_BASE_URL
|
||||||
|
CRON_SECRET=$CRON_SECRET
|
||||||
|
ENVEOF
|
||||||
|
|
||||||
# Install production deps and restart on server
|
# Sync build output to server using scp (no apt install needed)
|
||||||
ssh tyler@route.crispygoat.com "cd $APP_DIR && npm install --omit=dev && pm2 restart route-commerce || pm2 start npm --name route-commerce -- start -- -p 3100 && pm2 save"
|
echo "Copying .next/..."
|
||||||
|
scp -o ConnectTimeout=15 -o StrictHostKeyChecking=no -r .next/* tyler@route.crispygoat.com:$APP_DIR/.next/
|
||||||
|
echo "Copying public/..."
|
||||||
|
scp -o ConnectTimeout=15 -o StrictHostKeyChecking=no -r public/* tyler@route.crispygoat.com:$APP_DIR/public/
|
||||||
|
echo "Copying package.json..."
|
||||||
|
scp -o ConnectTimeout=15 -o StrictHostKeyChecking=no package.json tyler@route.crispygoat.com:$APP_DIR/
|
||||||
|
scp -o ConnectTimeout=15 -o StrictHostKeyChecking=no next.config.ts tyler@route.crispygoat.com:$APP_DIR/ 2>/dev/null || true
|
||||||
|
|
||||||
|
# Install deps and restart on server
|
||||||
|
echo "Installing deps and restarting PM2..."
|
||||||
|
ssh -o ConnectTimeout=15 -o StrictHostKeyChecking=no tyler@route.crispygoat.com "cd $APP_DIR && npm install --omit=dev && pm2 restart route-commerce || pm2 start npm --name route-commerce -- start -- -p 3100 && pm2 save"
|
||||||
|
|
||||||
echo "Deployed successfully"
|
echo "Deployed successfully"
|
||||||
|
|||||||
+125
@@ -0,0 +1,125 @@
|
|||||||
|
# Database Reference — Neon Postgres (Route Commerce)
|
||||||
|
|
||||||
|
## Core Auth
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `users` | id, name, email, email_verified, image, created_at |
|
||||||
|
| `sessions` | id, user_id, token, expires_at, ip_address, user_agent |
|
||||||
|
| `accounts` | id, user_id, provider_id, access_token, refresh_token |
|
||||||
|
| `verifications` | id, identifier, value, expires_at |
|
||||||
|
| `admin_users` | id, user_id, email, name, **role**, can_manage_* (15 flags), created_at |
|
||||||
|
| `admin_user_brands` | admin_user_id, brand_id, added_at, added_by |
|
||||||
|
|
||||||
|
> `role` values: `platform_admin`, `brand_admin`, `store_employee`
|
||||||
|
> Link a user to a brand via `admin_user_brands`, NOT a column on `admin_users`.
|
||||||
|
|
||||||
|
## Brands & Plans
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `brands` | id, name, slug, **plan_tier**, max_users, max_products, max_stops_monthly, stripe_* |
|
||||||
|
| `plans` | id, code, name, monthly_price_cents, max_users, max_products, max_stops_monthly, features |
|
||||||
|
| `add_ons` | id, code, name, monthly_price_cents, description |
|
||||||
|
| `brand_add_ons` | brand_id, add_on_id, stripe_subscription_id, status |
|
||||||
|
| `brand_features` | id, brand_id, feature_key, enabled, enabled_at |
|
||||||
|
| `brand_settings` | id, brand_id, legal_business_name, phone, email, logo_url, tagline, from_email, primary_color, custom_footer_text, etc. |
|
||||||
|
| `wholesale_settings` | id, brand_id, require_approval, min_order_amount, pickup_location, fob_location, from_email, invoice_business_name, last_invoice_number |
|
||||||
|
|
||||||
|
## Products & Media
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `products` | id, brand_id, name, description, sku, type, price_cents, inventory, unit, active, is_taxable, pickup_type, image_url |
|
||||||
|
| `product_images` | id, product_id, storage_key, position, alt_text |
|
||||||
|
| `wholesale_products` | id, brand_id, rc_product_id, name, unit_type, availability, qty_available, price_tiers (JSON) |
|
||||||
|
|
||||||
|
## Orders
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `orders` | id, brand_id, customer_id, stop_id, total_cents, status, fulfillment, customer_address, placed_at |
|
||||||
|
| `order_items` | id, order_id, product_id, quantity, price_cents, fulfillment |
|
||||||
|
| `stops` | id, brand_id, name, location, address, city, state, zip, date, time, cutoff_date, status, is_public |
|
||||||
|
| `shipments` | id, order_id, carrier, tracking_number, label_url, status, fedex_shipment_id |
|
||||||
|
| `shipping_settings` | id, brand_id, carrier, fedex_account_number, fedex_api_key, fedex_use_production |
|
||||||
|
| `user_carts` | id, brand_id, customer_id, items (JSON) |
|
||||||
|
| `abandoned_cart_recovery` | id, brand_id, customer_id, contact_email, sequence_step, status, next_email_at |
|
||||||
|
|
||||||
|
## Wholesale
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `wholesale_customers` | id, user_id, brand_id, company_name, contact_name, email, account_status, credit_limit, deposits_enabled |
|
||||||
|
| `wholesale_orders` | id, brand_id, customer_id, status, fulfillment_status, payment_status, subtotal, deposit_paid, balance_due, invoice_number |
|
||||||
|
| `wholesale_order_items` | id, wholesale_order_id, product_id, quantity, unit_price, line_total |
|
||||||
|
| `wholesale_deposits` | id, wholesale_order_id, amount, payment_method, reference |
|
||||||
|
| `wholesale_customer_product_pricing` | id, customer_id, product_id, custom_price_cents |
|
||||||
|
| `wholesale_notifications` | id, brand_id, customer_id, notification_type, channel, status, sent_at |
|
||||||
|
| `wholesale_webhook_settings` | id, brand_id, url, secret, enabled |
|
||||||
|
| `wholesale_sync_log` | id, brand_id, event_type, order_id, status |
|
||||||
|
|
||||||
|
## Communications (Harvest Reach)
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `communication_campaigns` | id, brand_id, name, subject, body_text, body_html, campaign_type, status, audience_rules (JSON), scheduled_at, sent_at |
|
||||||
|
| `communication_contacts` | id, brand_id, email, phone, first_name, last_name, email_opt_in, sms_opt_in, unsubscribed_at, tags |
|
||||||
|
| `communication_message_logs` | id, brand_id, campaign_id, contact_id, customer_email, delivery_method, subject, status |
|
||||||
|
| `communication_segments` | id, brand_id, name, rules (JSON) |
|
||||||
|
| `communication_templates` | id, brand_id, name, subject, body_text, body_html, template_type |
|
||||||
|
| `communication_settings` | id, brand_id, default_sender_email, email_provider |
|
||||||
|
| `welcome_email_sequence` | id, brand_id, contact_id, sequence_step, status, next_email_at |
|
||||||
|
|
||||||
|
## Customers
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `customers` | id, brand_id, primary_email, primary_phone, first_name, last_name, source |
|
||||||
|
| `customer_communication_preferences` | id, customer_id, email_opt_in, sms_opt_in |
|
||||||
|
|
||||||
|
## Time Tracking
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `time_tracking_workers` | id, brand_id, name, role, pin, active |
|
||||||
|
| `time_tracking_tasks` | id, brand_id, name, unit, sort_order, active |
|
||||||
|
| `time_tracking_logs` | id, brand_id, worker_id, task_id, clock_in, clock_out, lunch_break_minutes |
|
||||||
|
| `time_tracking_settings` | id, brand_id, pay_period_start_day, daily_overtime_threshold, weekly_overtime_threshold, overtime_multiplier |
|
||||||
|
| `time_tracking_notification_log` | id, brand_id, worker_id, notification_type, status, sent_at |
|
||||||
|
|
||||||
|
## Water Log
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `water_headgates` | id, brand_id, name, active |
|
||||||
|
| `water_irrigators` | id, brand_id, name, pin_hash, active |
|
||||||
|
| `water_sessions` | id, irrigator_id, expires_at |
|
||||||
|
| `water_log_entries` | id, brand_id, headgate_id, irrigator_id, measurement, unit, notes, logged_at |
|
||||||
|
| `water_alert_log` | id, brand_id, alert_type, headgate_id, message, sent_to |
|
||||||
|
|
||||||
|
## Integrations
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `square_sync_log` | id, brand_id, sync_type, direction, item_id, status |
|
||||||
|
| `square_sync_queue` | id, brand_id, sync_type, status, retry_count |
|
||||||
|
| `api_keys` | id, brand_id, name, key_hash, permissions (JSON), is_active |
|
||||||
|
| `payment_settings` | id, brand_id, provider, stripe_publishable_key, stripe_secret_key, square_access_token |
|
||||||
|
|
||||||
|
## Locations
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `locations` | id, brand_id, name, address, city, state, zip, active |
|
||||||
|
|
||||||
|
## Misc
|
||||||
|
| Table | Key Columns |
|
||||||
|
|---|---|
|
||||||
|
| `audit_logs` | id, user_id, brand_id, action, entity_type, entity_id, details (JSON) |
|
||||||
|
| `admin_action_logs` | id, admin_user_id, brand_id, action, target_type, target_id, metadata (JSON) |
|
||||||
|
| `operational_events` | id, brand_id, event_type, entity_type, actor_type, payload (JSON) |
|
||||||
|
| `referral_codes` | id, brand_id, referral_code, referrer_email, reward_type, reward_value |
|
||||||
|
| `referral_redemptions` | id, referral_code_id, brand_id, referred_user_id |
|
||||||
|
| `onboarding_progress` | id, brand_id, user_id, current_step, completed_steps (JSON) |
|
||||||
|
| `notification_preferences` | id, user_id, email_orders, email_marketing, sms_orders, etc. |
|
||||||
|
| `changelogs` | — |
|
||||||
|
| `changelog_reads` | id, user_id, changelog_id |
|
||||||
|
| `_migrations` | filename, applied_at |
|
||||||
|
|
||||||
|
## Schema Notes
|
||||||
|
- All timestamps use `TIMESTAMP WITH TIME ZONE` — timezone-aware
|
||||||
|
- No PostgreSQL ENUM types — statuses are plain TEXT
|
||||||
|
- Brand scoping enforced at application layer (SECURITY DEFINER RPCs), NOT via RLS
|
||||||
|
- `brands.slug` is the public storefront URL slug (e.g. `tuxedo`, `indian-river-direct`)
|
||||||
|
- `admin_users.user_id` links to `neon_auth.user` (managed by Neon Auth), NOT to `users` table
|
||||||
|
- The `users` table above is Neon Auth's internal table — do NOT write to it directly
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { config } from "dotenv";
|
||||||
|
config({ path: ".env.local" });
|
||||||
|
import pg from "pg";
|
||||||
|
|
||||||
|
const { Pool } = pg;
|
||||||
|
|
||||||
|
const TUXEDO = "64294306-5f42-463d-a5e8-2ad6c81a96de";
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
||||||
|
|
||||||
|
try {
|
||||||
|
// brand_settings
|
||||||
|
const bs = await pool.query(
|
||||||
|
`INSERT INTO brand_settings (brand_id, legal_business_name, phone, email, logo_url, tagline, from_email)
|
||||||
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||||
|
ON CONFLICT (brand_id) DO UPDATE SET legal_business_name = EXCLUDED.legal_business_name
|
||||||
|
RETURNING brand_id, legal_business_name`,
|
||||||
|
[TUXEDO, "Tuxedo Corn LLC", "970-555-0100", "info@tuxedocorn.com",
|
||||||
|
"/brand-logos/64294306-5f42-463d-a5e8-2ad6c81a96de/logo.png",
|
||||||
|
"Farm-Fresh Sweet Corn, Delivered", "orders@tuxedocorn.com"]
|
||||||
|
);
|
||||||
|
console.log("brand_settings:", bs.rows[0]);
|
||||||
|
|
||||||
|
// wholesale_settings
|
||||||
|
const ws = await pool.query(
|
||||||
|
`INSERT INTO wholesale_settings (brand_id, require_approval, pickup_location, fob_location, from_email)
|
||||||
|
VALUES ($1, true, $2, $3, $4)
|
||||||
|
ON CONFLICT (brand_id) DO UPDATE SET pickup_location = EXCLUDED.pickup_location
|
||||||
|
RETURNING brand_id, pickup_location`,
|
||||||
|
[TUXEDO, "59751 David Road, Olathe, CO 81425", "FOB Olathe, CO", "orders@tuxedocorn.com"]
|
||||||
|
);
|
||||||
|
console.log("wholesale_settings:", ws.rows[0]);
|
||||||
|
|
||||||
|
console.log("\nDone!");
|
||||||
|
} finally {
|
||||||
|
await pool.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((e) => { console.error(e.message); process.exit(1); });
|
||||||
Reference in New Issue
Block a user