fabrica-e-commerce 0.1.17 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/deps.js CHANGED
@@ -2,29 +2,22 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import process from 'node:process';
4
4
  import { commandExists, runCommand, runCommandCapture } from './system.js';
5
- import { kv, section, endSections, spinner, subBox, log } from './ui.js';
5
+ import { kv, kvSuccess, kvFail, section, endSections, spinner, subBox, log, logInfo, logWarn, divider, orange, dimOrange, bold, dim, green, red, cyan, yellow } from './ui.js';
6
6
 
7
- function isTermux() {
8
- return process.platform === 'android' ||
9
- (process.platform === 'linux' && (process.env.TERMUX_VERSION || process.env.PREFIX?.includes('com.termux')));
7
+ export function isTermux() {
8
+ return (
9
+ process.platform === 'android' ||
10
+ (process.platform === 'linux' &&
11
+ (process.env.TERMUX_VERSION || process.env.PREFIX?.includes('com.termux')))
12
+ );
10
13
  }
11
14
 
12
- async function runPrivileged(command, args, options = {}) {
13
- if (process.platform === 'win32' || isTermux()) return runCommand(command, args, options);
14
- if (await commandExists('sudo')) return runCommand('sudo', [command, ...args], options);
15
- return runCommand(command, args, options);
15
+ function platform() {
16
+ if (isTermux()) return 'termux';
17
+ return process.platform; // win32 | linux | darwin
16
18
  }
17
19
 
18
- function runPrivilegedShell(script, options = {}) {
19
- return runCommand('bash', ['-c', script], options);
20
- }
21
-
22
- const DEPENDENCIES = [
23
- { name: 'git', label: 'Git', check: () => checkWithPathRefresh('git'), install: installGit, manualUrl: 'https://git-scm.com/downloads' },
24
- { name: 'gh', label: 'GitHub CLI (gh)', check: () => checkWithPathRefresh('gh'), install: installGithubCli, manualUrl: 'https://github.com/cli/cli#installation' },
25
- { name: 'vercel', label: 'Vercel CLI (via npx)', check: checkVercelCli, install: warmVercelCli, manualUrl: 'https://vercel.com/docs/cli' },
26
- ];
27
-
20
+ // ── PATH helpers ──────────────────────────────────────────────────────────────
28
21
  function addToPathIfDirectory(directory) {
29
22
  if (!directory || !fs.existsSync(directory)) return;
30
23
  const current = process.env.PATH || '';
@@ -47,7 +40,10 @@ function refreshWindowsToolPaths() {
47
40
  addToPathIfDirectory(pf && path.join(pf, 'nodejs'));
48
41
  }
49
42
 
50
- async function checkWithPathRefresh(cmd) { refreshWindowsToolPaths(); return commandExists(cmd); }
43
+ async function checkWithPathRefresh(cmd) {
44
+ refreshWindowsToolPaths();
45
+ return commandExists(cmd);
46
+ }
51
47
 
52
48
  async function runFirstSuccessful(candidates, options = {}) {
53
49
  for (const [cmd, args] of candidates) {
@@ -57,6 +53,7 @@ async function runFirstSuccessful(candidates, options = {}) {
57
53
  return { code: 1, stdout: '', stderr: 'All fallback commands failed' };
58
54
  }
59
55
 
56
+ // ── Vercel ────────────────────────────────────────────────────────────────────
60
57
  async function checkVercelCli() {
61
58
  refreshWindowsToolPaths();
62
59
  const r = await runFirstSuccessful([
@@ -78,12 +75,19 @@ async function warmVercelCli() {
78
75
  await runCommand('npm', ['install', '-g', 'vercel@latest'], { allowFailure: true });
79
76
  }
80
77
 
78
+ // ── Git ───────────────────────────────────────────────────────────────────────
81
79
  async function installGit() {
82
80
  refreshWindowsToolPaths();
83
- const p = process.platform;
84
- if (isTermux()) return runCommand('pkg', ['install', '-y', 'git'], { allowFailure: true });
81
+ const p = platform();
82
+
83
+ if (p === 'termux') {
84
+ return runCommand('pkg', ['install', '-y', 'git'], { allowFailure: true });
85
+ }
85
86
  if (p === 'linux') {
86
- if (await commandExists('apt-get')) { await runPrivileged('apt-get', ['update'], { allowFailure: true }); return runPrivileged('apt-get', ['install', '-y', 'git'], { allowFailure: true }); }
87
+ if (await commandExists('apt-get')) {
88
+ await runPrivileged('apt-get', ['update', '-qq'], { allowFailure: true });
89
+ return runPrivileged('apt-get', ['install', '-y', 'git'], { allowFailure: true });
90
+ }
87
91
  if (await commandExists('dnf')) return runPrivileged('dnf', ['install', '-y', 'git'], { allowFailure: true });
88
92
  if (await commandExists('yum')) return runPrivileged('yum', ['install', '-y', 'git'], { allowFailure: true });
89
93
  if (await commandExists('pacman')) return runPrivileged('pacman', ['-Sy', '--noconfirm', 'git'], { allowFailure: true });
@@ -95,30 +99,44 @@ async function installGit() {
95
99
  return runCommand('xcode-select', ['--install'], { allowFailure: true });
96
100
  }
97
101
  if (p === 'win32') {
98
- if (await commandExists('winget')) { await runCommand('winget', ['install', '--id', 'Git.Git', '-e', '--source', 'winget'], { allowFailure: true }); refreshWindowsToolPaths(); return; }
99
- if (await commandExists('choco')) { await runCommand('choco', ['install', 'git', '-y'], { allowFailure: true }); refreshWindowsToolPaths(); }
102
+ if (await commandExists('winget')) {
103
+ await runCommand('winget', ['install', '--id', 'Git.Git', '-e', '--source', 'winget', '--silent'], { allowFailure: true });
104
+ refreshWindowsToolPaths();
105
+ return;
106
+ }
107
+ if (await commandExists('choco')) {
108
+ await runCommand('choco', ['install', 'git', '-y'], { allowFailure: true });
109
+ refreshWindowsToolPaths();
110
+ }
100
111
  }
101
112
  }
102
113
 
114
+ // ── GitHub CLI ────────────────────────────────────────────────────────────────
103
115
  async function installGithubCli() {
104
116
  refreshWindowsToolPaths();
105
- const p = process.platform;
106
- if (isTermux()) return runCommand('pkg', ['install', '-y', 'gh'], { allowFailure: true });
117
+ const p = platform();
118
+
119
+ if (p === 'termux') {
120
+ return runCommand('pkg', ['install', '-y', 'gh'], { allowFailure: true });
121
+ }
107
122
  if (p === 'linux') {
108
123
  if (await commandExists('apt-get')) {
109
- const direct = await (await commandExists('sudo')
110
- ? runCommandCapture('sudo', ['apt-get', 'install', '-y', 'gh'])
111
- : runCommandCapture('apt-get', ['install', '-y', 'gh']));
124
+ // Try direct first (gh is in Ubuntu 22.04+ repos)
125
+ const direct = await runCommandCapture('apt-get', ['install', '-y', 'gh']);
112
126
  if (direct.code === 0) return;
127
+ // Fall back to GitHub's official APT repo
113
128
  const pre = (await commandExists('sudo')) ? 'sudo ' : '';
114
- await runPrivilegedShell([
115
- 'set -e', `${pre}apt-get update`, `${pre}apt-get install -y curl ca-certificates gnupg`,
129
+ await runCommand('bash', ['-c', [
130
+ 'set -e',
131
+ `${pre}apt-get update -qq`,
132
+ `${pre}apt-get install -y curl ca-certificates gnupg`,
116
133
  `${pre}mkdir -p -m 755 /etc/apt/keyrings`,
117
134
  `curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | ${pre}tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null`,
118
135
  `${pre}chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg`,
119
136
  `echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | ${pre}tee /etc/apt/sources.list.d/github-cli.list > /dev/null`,
120
- `${pre}apt-get update`, `${pre}apt-get install -y gh`,
121
- ].join(' && '), { allowFailure: true });
137
+ `${pre}apt-get update -qq`,
138
+ `${pre}apt-get install -y gh`,
139
+ ].join(' && ')], { allowFailure: true });
122
140
  return;
123
141
  }
124
142
  if (await commandExists('dnf')) return runPrivileged('dnf', ['install', '-y', 'gh'], { allowFailure: true });
@@ -130,45 +148,135 @@ async function installGithubCli() {
130
148
  if (await commandExists('brew')) return runCommand('brew', ['install', 'gh'], { allowFailure: true });
131
149
  }
132
150
  if (p === 'win32') {
133
- if (await commandExists('winget')) { await runCommand('winget', ['install', '--id', 'GitHub.cli', '-e', '--source', 'winget'], { allowFailure: true }); refreshWindowsToolPaths(); return; }
134
- if (await commandExists('choco')) { await runCommand('choco', ['install', 'gh', '-y'], { allowFailure: true }); refreshWindowsToolPaths(); }
151
+ if (await commandExists('winget')) {
152
+ await runCommand('winget', ['install', '--id', 'GitHub.cli', '-e', '--source', 'winget', '--silent'], { allowFailure: true });
153
+ refreshWindowsToolPaths();
154
+ return;
155
+ }
156
+ if (await commandExists('choco')) {
157
+ await runCommand('choco', ['install', 'gh', '-y'], { allowFailure: true });
158
+ refreshWindowsToolPaths();
159
+ }
135
160
  }
136
161
  }
137
162
 
163
+ async function runPrivileged(command, args, options = {}) {
164
+ const p = platform();
165
+ if (p === 'win32' || p === 'termux') return runCommand(command, args, options);
166
+ if (await commandExists('sudo')) return runCommand('sudo', [command, ...args], options);
167
+ return runCommand(command, args, options);
168
+ }
169
+
170
+ // ── dependency table ──────────────────────────────────────────────────────────
171
+ const DEPENDENCIES = [
172
+ {
173
+ name: 'git',
174
+ label: 'Git',
175
+ description: 'Version control — clones the storefront repo',
176
+ check: () => checkWithPathRefresh('git'),
177
+ install: installGit,
178
+ manualUrl: 'https://git-scm.com/downloads',
179
+ termuxPkg: 'git',
180
+ },
181
+ {
182
+ name: 'gh',
183
+ label: 'GitHub CLI',
184
+ description: 'Creates your GitHub repo and manages auth',
185
+ check: () => checkWithPathRefresh('gh'),
186
+ install: installGithubCli,
187
+ manualUrl: 'https://github.com/cli/cli#installation',
188
+ termuxPkg: 'gh',
189
+ },
190
+ {
191
+ name: 'vercel',
192
+ label: 'Vercel CLI',
193
+ description: 'Deploys the storefront to Vercel cloud',
194
+ check: checkVercelCli,
195
+ install: warmVercelCli,
196
+ manualUrl: 'https://vercel.com/docs/cli',
197
+ termuxPkg: null, // via npx only
198
+ },
199
+ ];
200
+
201
+ // ── ensureDependencies (shared) ───────────────────────────────────────────────
138
202
  export async function ensureDependencies({ autoInstall = true, names } = {}) {
139
203
  const targets = names ? DEPENDENCIES.filter((d) => names.includes(d.name)) : DEPENDENCIES;
140
204
  const results = [];
141
205
  for (const dep of targets) {
142
- const spin = spinner(`Checking ${dep.label}`);
206
+ const spin = spinner(`Checking ${dep.label}…`);
143
207
  let present = await dep.check();
144
- if (present) { spin.succeed(`${dep.label} found`); results.push({ ...dep, present, installed: false }); continue; }
145
- spin.fail(`${dep.label} missing`);
208
+ if (present) {
209
+ spin.succeed(`${green(dep.label)} is ready`);
210
+ results.push({ ...dep, present, installed: false });
211
+ continue;
212
+ }
213
+ spin.fail(`${dep.label} not found`);
146
214
  if (!autoInstall) { results.push({ ...dep, present: false, installed: false }); continue; }
147
- const installSpin = spinner(`Installing ${dep.label}`);
148
- await dep.install();
149
- present = await dep.check();
150
- if (present) installSpin.succeed(`${dep.label} installed`);
151
- else installSpin.fail(`${dep.label} could not be installed automatically`);
215
+
216
+ const p = platform();
217
+ if (p === 'termux' && dep.termuxPkg === null) {
218
+ // Vercel on Termux — npx-only, attempt inline
219
+ const wSpin = spinner(`Warming Vercel CLI via npx (Termux)…`);
220
+ await dep.install();
221
+ present = await dep.check();
222
+ if (present) wSpin.succeed(`Vercel CLI ready via npx`);
223
+ else wSpin.fail(`Vercel CLI not available — use: npx vercel`);
224
+ } else {
225
+ const installSpin = spinner(`Auto-installing ${dep.label}…`);
226
+ await dep.install();
227
+ present = await dep.check();
228
+ if (present) installSpin.succeed(`${green(dep.label)} installed successfully`);
229
+ else installSpin.fail(`${red(dep.label)} could not be installed automatically`);
230
+ }
152
231
  results.push({ ...dep, present, installed: present });
153
232
  }
154
233
  return results;
155
234
  }
156
235
 
236
+ // ── vins command ──────────────────────────────────────────────────────────────
157
237
  export async function vinsCommand() {
158
- section('Fabrica dependency check (vins)');
159
- kv('Platform', isTermux() ? 'Termux/Android' : process.platform);
238
+ const p = platform();
239
+ const platformLabel = p === 'termux' ? 'Termux / Android' : p === 'win32' ? 'Windows' : p === 'darwin' ? 'macOS' : 'Linux';
240
+
241
+ section('System info');
242
+ kv('Platform', platformLabel);
243
+ kv('Node.js', process.version);
244
+ kv('Arch', process.arch);
245
+ if (p === 'termux') {
246
+ logInfo('Termux detected — using pkg for native installs, npx for Node tools');
247
+ }
248
+
249
+ section('Checking dependencies');
160
250
  const results = await ensureDependencies();
161
251
 
162
- section('Summary');
163
- const summaryLines = [];
252
+ section('Dependency summary');
253
+ divider();
164
254
  let allGood = true;
165
255
  for (const dep of results) {
166
- summaryLines.push(`${dep.label}: ${dep.present ? '✓ OK' : '✗ MISSING — install manually'}`);
167
- if (!dep.present) { allGood = false; summaryLines.push(` Manual: ${dep.manualUrl}`); }
256
+ if (dep.present) {
257
+ kvSuccess(dep.label, dep.description);
258
+ } else {
259
+ kvFail(dep.label, `Missing — ${dep.description}`);
260
+ allGood = false;
261
+ }
168
262
  }
169
- subBox(summaryLines, { isError: !allGood });
170
- if (allGood) log('All dependencies ready. Run: fabrica build');
171
- else log('Some deps could not be installed. See links above.');
263
+ divider();
264
+
265
+ const missing = results.filter((d) => !d.present);
266
+ if (missing.length) {
267
+ logWarn(`${missing.length} dependency(ies) could not be installed automatically`);
268
+ for (const dep of missing) {
269
+ if (p === 'termux' && dep.termuxPkg) {
270
+ log(`Install ${dep.label}: ${cyan(`pkg install ${dep.termuxPkg}`)}`);
271
+ } else {
272
+ log(`Install ${dep.label}: ${cyan(dep.manualUrl)}`);
273
+ }
274
+ }
275
+ log('Then re-run: fabrica vins');
276
+ } else {
277
+ log(green('All dependencies ready — run: fabrica build'));
278
+ }
279
+
172
280
  endSections();
173
281
  if (!allGood) process.exitCode = 1;
174
282
  return results;
package/src/sql.js CHANGED
@@ -1,24 +1,234 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // SCHEMA
3
+ // ─────────────────────────────────────────────────────────────────────────────
1
4
  export const SCHEMA_SQL = `
2
5
  CREATE EXTENSION IF NOT EXISTS pgcrypto;
3
- CREATE TABLE IF NOT EXISTS public.site_content (id text NOT NULL, content jsonb NOT NULL, updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT site_content_pkey PRIMARY KEY (id));
4
- CREATE TABLE IF NOT EXISTS public.collections (id text NOT NULL, name text NOT NULL, description text NOT NULL, image_url text NOT NULL, item_count_label text NOT NULL, sort_order integer NOT NULL DEFAULT 0, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT collections_pkey PRIMARY KEY (id));
5
- CREATE TABLE IF NOT EXISTS public.products (id text NOT NULL, name text NOT NULL, price numeric NOT NULL CHECK (price >= 0), main_image_url text NOT NULL, gallery_image_urls text[] NOT NULL DEFAULT '{}', category_label text, description text NOT NULL, details text[] NOT NULL DEFAULT '{}', sizes text[] NOT NULL DEFAULT '{}', section text NOT NULL DEFAULT 'general' CHECK (section = ANY (ARRAY['general','new_arrivals','best_sellers'])), collection_ids text[] NOT NULL DEFAULT '{}', sort_order integer NOT NULL DEFAULT 0, is_active boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT products_pkey PRIMARY KEY (id));
6
- CREATE TABLE IF NOT EXISTS public.app_users (id uuid NOT NULL DEFAULT gen_random_uuid(), email text NOT NULL UNIQUE, first_name text NOT NULL, last_name text NOT NULL, phone text NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT app_users_pkey PRIMARY KEY (id));
7
- CREATE TABLE IF NOT EXISTS public.saved_addresses (id uuid NOT NULL DEFAULT gen_random_uuid(), user_id uuid NOT NULL, label text NOT NULL, first_name text NOT NULL, last_name text NOT NULL, phone text NOT NULL, address text NOT NULL, apartment text, city text NOT NULL, state text NOT NULL, zip_code text NOT NULL, country text NOT NULL DEFAULT 'India', is_default boolean NOT NULL DEFAULT false, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT saved_addresses_pkey PRIMARY KEY (id), CONSTRAINT saved_addresses_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.app_users(id));
8
- CREATE TABLE IF NOT EXISTS public.order_policies (id boolean NOT NULL DEFAULT true CHECK (id = true), shipping_amount numeric NOT NULL DEFAULT 15 CHECK (shipping_amount >= 0), free_shipping_threshold numeric NOT NULL DEFAULT 200 CHECK (free_shipping_threshold >= 0), tax_rate numeric NOT NULL DEFAULT 8 CHECK (tax_rate >= 0), automatic_shipping_enabled boolean NOT NULL DEFAULT false, shippo_from_name text NOT NULL DEFAULT '', shippo_from_company text NOT NULL DEFAULT '', shippo_from_street1 text NOT NULL DEFAULT '', shippo_from_street2 text NOT NULL DEFAULT '', shippo_from_city text NOT NULL DEFAULT '', shippo_from_state text NOT NULL DEFAULT '', shippo_from_zip text NOT NULL DEFAULT '', shippo_from_country text NOT NULL DEFAULT 'IN', shippo_from_phone text NOT NULL DEFAULT '', shippo_from_email text NOT NULL DEFAULT '', shippo_from_is_residential boolean NOT NULL DEFAULT false, shippo_parcel_length numeric NOT NULL DEFAULT 10 CHECK (shippo_parcel_length > 0), shippo_parcel_width numeric NOT NULL DEFAULT 10 CHECK (shippo_parcel_width > 0), shippo_parcel_height numeric NOT NULL DEFAULT 4 CHECK (shippo_parcel_height > 0), shippo_parcel_weight numeric NOT NULL DEFAULT 1 CHECK (shippo_parcel_weight > 0), shippo_parcel_distance_unit text NOT NULL DEFAULT 'in' CHECK (shippo_parcel_distance_unit = ANY (ARRAY['in','cm'])), shippo_parcel_mass_unit text NOT NULL DEFAULT 'lb' CHECK (shippo_parcel_mass_unit = ANY (ARRAY['lb','oz','g','kg'])), shippo_label_file_type text NOT NULL DEFAULT 'PDF_4x6' CHECK (shippo_label_file_type = ANY (ARRAY['PNG','PNG_2.3x7.5','PDF','PDF_2.3x7.5','PDF_4x6','PDF_4x8','PDF_A4','PDF_A5','PDF_A6','ZPLII'])), active_theme_name text DEFAULT 'default', updated_at timestamptz NOT NULL DEFAULT now(), show_ticker boolean NOT NULL DEFAULT true, section_styles jsonb NOT NULL DEFAULT '{"homeHero":"video"}', CONSTRAINT order_policies_pkey PRIMARY KEY (id));
9
- CREATE TABLE IF NOT EXISTS public.coupons (code text NOT NULL, label text NOT NULL, coupon_type text NOT NULL CHECK (coupon_type = ANY (ARRAY['universal','one_time'])), discount_type text NOT NULL CHECK (discount_type = ANY (ARRAY['percent','amount'])), discount_value numeric NOT NULL CHECK (discount_value >= 0), active boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT coupons_pkey PRIMARY KEY (code));
10
- CREATE TABLE IF NOT EXISTS public.orders (id text NOT NULL, user_id uuid, user_email text NOT NULL, status text NOT NULL DEFAULT 'placed' CHECK (status = ANY (ARRAY['placed','packed','in_transit','delivered'])), payment_method text NOT NULL CHECK (payment_method = ANY (ARRAY['cod','razorpay'])), payment_verified boolean NOT NULL DEFAULT false, razorpay_payment_id text, coupon_code text, shipping_address jsonb NOT NULL, totals jsonb NOT NULL, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT orders_pkey PRIMARY KEY (id), CONSTRAINT orders_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.app_users(id), CONSTRAINT orders_coupon_code_fkey FOREIGN KEY (coupon_code) REFERENCES public.coupons(code));
11
- CREATE TABLE IF NOT EXISTS public.order_items (id uuid NOT NULL DEFAULT gen_random_uuid(), order_id text NOT NULL, product_id text, product_name text NOT NULL, product_image text, size text NOT NULL, quantity integer NOT NULL CHECK (quantity > 0), unit_price numeric NOT NULL CHECK (unit_price >= 0), line_total numeric NOT NULL CHECK (line_total >= 0), created_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT order_items_pkey PRIMARY KEY (id), CONSTRAINT order_items_order_id_fkey FOREIGN KEY (order_id) REFERENCES public.orders(id), CONSTRAINT order_items_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id));
12
- CREATE TABLE IF NOT EXISTS public.themes (id uuid NOT NULL DEFAULT gen_random_uuid(), name text NOT NULL UNIQUE, label text NOT NULL, colors jsonb NOT NULL, is_active boolean NOT NULL DEFAULT true, created_at timestamptz NOT NULL DEFAULT now(), updated_at timestamptz NOT NULL DEFAULT now(), CONSTRAINT themes_pkey PRIMARY KEY (id));
6
+
7
+ CREATE TABLE IF NOT EXISTS public.site_content (
8
+ id text NOT NULL,
9
+ content jsonb NOT NULL,
10
+ updated_at timestamptz NOT NULL DEFAULT now(),
11
+ CONSTRAINT site_content_pkey PRIMARY KEY (id)
12
+ );
13
+
14
+ CREATE TABLE IF NOT EXISTS public.collections (
15
+ id text NOT NULL,
16
+ name text NOT NULL,
17
+ description text NOT NULL,
18
+ image_url text NOT NULL,
19
+ item_count_label text NOT NULL,
20
+ sort_order integer NOT NULL DEFAULT 0,
21
+ created_at timestamptz NOT NULL DEFAULT now(),
22
+ updated_at timestamptz NOT NULL DEFAULT now(),
23
+ CONSTRAINT collections_pkey PRIMARY KEY (id)
24
+ );
25
+
26
+ CREATE TABLE IF NOT EXISTS public.products (
27
+ id text NOT NULL,
28
+ name text NOT NULL,
29
+ price numeric NOT NULL CHECK (price >= 0),
30
+ main_image_url text NOT NULL,
31
+ gallery_image_urls text[] NOT NULL DEFAULT '{}',
32
+ category_label text,
33
+ description text NOT NULL,
34
+ details text[] NOT NULL DEFAULT '{}',
35
+ sizes text[] NOT NULL DEFAULT '{}',
36
+ section text NOT NULL DEFAULT 'general' CHECK (section = ANY (ARRAY['general','new_arrivals','best_sellers'])),
37
+ collection_ids text[] NOT NULL DEFAULT '{}',
38
+ sort_order integer NOT NULL DEFAULT 0,
39
+ is_active boolean NOT NULL DEFAULT true,
40
+ created_at timestamptz NOT NULL DEFAULT now(),
41
+ updated_at timestamptz NOT NULL DEFAULT now(),
42
+ CONSTRAINT products_pkey PRIMARY KEY (id)
43
+ );
44
+
45
+ CREATE TABLE IF NOT EXISTS public.app_users (
46
+ id uuid NOT NULL DEFAULT gen_random_uuid(),
47
+ email text NOT NULL UNIQUE,
48
+ first_name text NOT NULL,
49
+ last_name text NOT NULL,
50
+ phone text NOT NULL,
51
+ created_at timestamptz NOT NULL DEFAULT now(),
52
+ updated_at timestamptz NOT NULL DEFAULT now(),
53
+ CONSTRAINT app_users_pkey PRIMARY KEY (id)
54
+ );
55
+
56
+ CREATE TABLE IF NOT EXISTS public.saved_addresses (
57
+ id uuid NOT NULL DEFAULT gen_random_uuid(),
58
+ user_id uuid NOT NULL,
59
+ label text NOT NULL,
60
+ first_name text NOT NULL,
61
+ last_name text NOT NULL,
62
+ phone text NOT NULL,
63
+ address text NOT NULL,
64
+ apartment text,
65
+ city text NOT NULL,
66
+ state text NOT NULL,
67
+ zip_code text NOT NULL,
68
+ country text NOT NULL DEFAULT 'India',
69
+ is_default boolean NOT NULL DEFAULT false,
70
+ created_at timestamptz NOT NULL DEFAULT now(),
71
+ updated_at timestamptz NOT NULL DEFAULT now(),
72
+ CONSTRAINT saved_addresses_pkey PRIMARY KEY (id),
73
+ CONSTRAINT saved_addresses_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.app_users(id)
74
+ );
75
+
76
+ CREATE TABLE IF NOT EXISTS public.order_policies (
77
+ id boolean NOT NULL DEFAULT true CHECK (id = true),
78
+ shipping_amount numeric NOT NULL DEFAULT 15 CHECK (shipping_amount >= 0),
79
+ free_shipping_threshold numeric NOT NULL DEFAULT 200 CHECK (free_shipping_threshold >= 0),
80
+ tax_rate numeric NOT NULL DEFAULT 8 CHECK (tax_rate >= 0),
81
+ automatic_shipping_enabled boolean NOT NULL DEFAULT false,
82
+ shippo_from_name text NOT NULL DEFAULT '',
83
+ shippo_from_company text NOT NULL DEFAULT '',
84
+ shippo_from_street1 text NOT NULL DEFAULT '',
85
+ shippo_from_street2 text NOT NULL DEFAULT '',
86
+ shippo_from_city text NOT NULL DEFAULT '',
87
+ shippo_from_state text NOT NULL DEFAULT '',
88
+ shippo_from_zip text NOT NULL DEFAULT '',
89
+ shippo_from_country text NOT NULL DEFAULT 'IN',
90
+ shippo_from_phone text NOT NULL DEFAULT '',
91
+ shippo_from_email text NOT NULL DEFAULT '',
92
+ shippo_from_is_residential boolean NOT NULL DEFAULT false,
93
+ shippo_parcel_length numeric NOT NULL DEFAULT 10 CHECK (shippo_parcel_length > 0),
94
+ shippo_parcel_width numeric NOT NULL DEFAULT 10 CHECK (shippo_parcel_width > 0),
95
+ shippo_parcel_height numeric NOT NULL DEFAULT 4 CHECK (shippo_parcel_height > 0),
96
+ shippo_parcel_weight numeric NOT NULL DEFAULT 1 CHECK (shippo_parcel_weight > 0),
97
+ shippo_parcel_distance_unit text NOT NULL DEFAULT 'in' CHECK (shippo_parcel_distance_unit = ANY (ARRAY['in','cm'])),
98
+ shippo_parcel_mass_unit text NOT NULL DEFAULT 'lb' CHECK (shippo_parcel_mass_unit = ANY (ARRAY['lb','oz','g','kg'])),
99
+ shippo_label_file_type text NOT NULL DEFAULT 'PDF_4x6' CHECK (shippo_label_file_type = ANY (ARRAY['PNG','PNG_2.3x7.5','PDF','PDF_2.3x7.5','PDF_4x6','PDF_4x8','PDF_A4','PDF_A5','PDF_A6','ZPLII'])),
100
+ active_theme_name text DEFAULT 'default',
101
+ updated_at timestamptz NOT NULL DEFAULT now(),
102
+ show_ticker boolean NOT NULL DEFAULT true,
103
+ section_styles jsonb NOT NULL DEFAULT '{"homeHero":"video"}',
104
+ CONSTRAINT order_policies_pkey PRIMARY KEY (id)
105
+ );
106
+
107
+ CREATE TABLE IF NOT EXISTS public.coupons (
108
+ code text NOT NULL,
109
+ label text NOT NULL,
110
+ coupon_type text NOT NULL CHECK (coupon_type = ANY (ARRAY['universal','one_time'])),
111
+ discount_type text NOT NULL CHECK (discount_type = ANY (ARRAY['percent','amount'])),
112
+ discount_value numeric NOT NULL CHECK (discount_value >= 0),
113
+ active boolean NOT NULL DEFAULT true,
114
+ created_at timestamptz NOT NULL DEFAULT now(),
115
+ updated_at timestamptz NOT NULL DEFAULT now(),
116
+ CONSTRAINT coupons_pkey PRIMARY KEY (code)
117
+ );
118
+
119
+ CREATE TABLE IF NOT EXISTS public.orders (
120
+ id text NOT NULL,
121
+ user_id uuid,
122
+ user_email text NOT NULL,
123
+ status text NOT NULL DEFAULT 'placed' CHECK (status = ANY (ARRAY['placed','packed','in_transit','delivered'])),
124
+ payment_method text NOT NULL CHECK (payment_method = ANY (ARRAY['cod','razorpay'])),
125
+ payment_verified boolean NOT NULL DEFAULT false,
126
+ razorpay_payment_id text,
127
+ coupon_code text,
128
+ shipping_address jsonb NOT NULL,
129
+ totals jsonb NOT NULL,
130
+ created_at timestamptz NOT NULL DEFAULT now(),
131
+ updated_at timestamptz NOT NULL DEFAULT now(),
132
+ CONSTRAINT orders_pkey PRIMARY KEY (id),
133
+ CONSTRAINT orders_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.app_users(id),
134
+ CONSTRAINT orders_coupon_code_fkey FOREIGN KEY (coupon_code) REFERENCES public.coupons(code)
135
+ );
136
+
137
+ CREATE TABLE IF NOT EXISTS public.order_items (
138
+ id uuid NOT NULL DEFAULT gen_random_uuid(),
139
+ order_id text NOT NULL,
140
+ product_id text,
141
+ product_name text NOT NULL,
142
+ product_image text,
143
+ size text NOT NULL,
144
+ quantity integer NOT NULL CHECK (quantity > 0),
145
+ unit_price numeric NOT NULL CHECK (unit_price >= 0),
146
+ line_total numeric NOT NULL CHECK (line_total >= 0),
147
+ created_at timestamptz NOT NULL DEFAULT now(),
148
+ CONSTRAINT order_items_pkey PRIMARY KEY (id),
149
+ CONSTRAINT order_items_order_id_fkey FOREIGN KEY (order_id) REFERENCES public.orders(id),
150
+ CONSTRAINT order_items_product_id_fkey FOREIGN KEY (product_id) REFERENCES public.products(id)
151
+ );
152
+
153
+ CREATE TABLE IF NOT EXISTS public.themes (
154
+ id uuid NOT NULL DEFAULT gen_random_uuid(),
155
+ name text NOT NULL UNIQUE,
156
+ label text NOT NULL,
157
+ colors jsonb NOT NULL,
158
+ is_active boolean NOT NULL DEFAULT true,
159
+ created_at timestamptz NOT NULL DEFAULT now(),
160
+ updated_at timestamptz NOT NULL DEFAULT now(),
161
+ CONSTRAINT themes_pkey PRIMARY KEY (id)
162
+ );
13
163
  `;
164
+
165
+ // ─────────────────────────────────────────────────────────────────────────────
166
+ // SEED — full mock data from uploaded SQL files
167
+ // ─────────────────────────────────────────────────────────────────────────────
14
168
  export const SEED_SQL = `
15
- INSERT INTO public.collections (id, name, description, image_url, item_count_label, sort_order) VALUES ('contemporary','Contemporary Collection','Modern cuts and innovative styling for the forward-thinking gentleman.','/thudarum-sky-blue-blazer.jpg','10 items',30),('evening','Evening Collection','Luxurious velvet and satin pieces designed to make a statement at formal occasions.','/thudarum-navy-velvet-blazer.jpg','6 items',40),('executive','Executive Collection','Bold, sophisticated pieces for the modern power dresser.','/thudarum-burgundy-evening-suit.jpg','12 items',10),('heritage','Heritage Collection','Classic tailoring with timeless appeal.','/thudarum-green-check-blazer.jpg','8 items',20) ON CONFLICT (id) DO NOTHING;
16
- INSERT INTO public.products (id,name,price,main_image_url,gallery_image_urls,category_label,description,details,sizes,section,collection_ids,sort_order,is_active) VALUES ('classic-taupe-double-breasted-suit','Classic Taupe Double-Breasted Suit',1289.00,'/thudarum-taupe-suit-hero.jpg',ARRAY['/thudarum-taupe-suit-detail.jpg'],'Suits','An impeccably tailored double-breasted suit in refined taupe wool.',ARRAY['100% Italian wool','Double-breasted closure'],ARRAY['38','40','42','44'],'new_arrivals',ARRAY['executive','contemporary'],10,true),('navy-velvet-double-breasted-jacket','Navy Velvet Double-Breasted Jacket',1195.00,'/thudarum-navy-velvet-blazer.jpg',ARRAY['/thudarum-navy-velvet-detail.jpg'],'Blazers','A luxurious navy velvet jacket with elevated texture.',ARRAY['Italian cotton velvet','Evening-ready finish'],ARRAY['38','40','42','44'],'best_sellers',ARRAY['evening'],20,true) ON CONFLICT (id) DO NOTHING;
17
- INSERT INTO public.coupons (code,label,coupon_type,discount_type,discount_value,active) VALUES ('WELCOME10','Welcome 10%','universal','percent',10.00,true) ON CONFLICT (code) DO NOTHING;
18
- INSERT INTO public.order_policies (id, shipping_amount, free_shipping_threshold, tax_rate, active_theme_name, show_ticker, section_styles) VALUES (true,15.00,200.00,8.00,'default',true,'{"homeHero":"video"}') ON CONFLICT (id) DO NOTHING;
19
- INSERT INTO public.themes (name,label,colors,is_active) VALUES ('default','Minimalist White','{"background":"oklch(0.985 0 0)","foreground":"oklch(0.145 0 0)","primary":"oklch(0.205 0 0)"}',true),('golden','Light Golden','{"background":"oklch(0.98 0.01 70)","foreground":"oklch(0.25 0.08 50)","primary":"oklch(0.70 0.18 62)"}',true),('midnight','Midnight Dark','{"background":"oklch(0.15 0.02 240)","foreground":"oklch(0.98 0.01 240)","primary":"oklch(0.6 0.15 250)"}',true) ON CONFLICT (name) DO NOTHING;
20
- INSERT INTO public.site_content (id,content) VALUES ('site','{"brandName":"FABRICA","tickerMessages":["FREE SHIPPING ON ORDERS OVER ₹200","30-DAY RETURNS","HOST YOUR OWN STORE IN MINUTES"]}'),('home','{"heroTitle":"Launch Your Store","heroSubtitle":"Discover powerful tools crafted for the modern merchant","bestSellersTitle":"Best Sellers","collectionsTitle":"Collections","newArrivalsTitle":"New Arrivals"}') ON CONFLICT (id) DO NOTHING;
169
+ -- Themes
170
+ INSERT INTO public.themes (id, name, label, colors, is_active) VALUES
171
+ ('36c8ea36-0aa5-4100-b0c4-d61c6b9bccd3','crimson','Crimson Elegance','{"muted":"oklch(0.96 0.02 20)","accent":"oklch(0.6 0.15 30)","border":"oklch(0.9 0.05 20)","primary":"oklch(0.5 0.18 25)","secondary":"oklch(0.95 0.03 20)","background":"oklch(0.98 0.01 20)","foreground":"oklch(0.2 0.05 20)","primary_foreground":"oklch(0.98 0.01 20)"}',true),
172
+ ('48234595-c916-4e52-a1d7-5dc489fec14d','golden','Light Golden','{"muted":"oklch(0.88 0.08 70)","accent":"oklch(0.75 0.18 62)","border":"oklch(0.90 0.10 70)","primary":"oklch(0.70 0.18 62)","secondary":"oklch(0.85 0.12 70)","background":"oklch(0.98 0.01 70)","foreground":"oklch(0.25 0.08 50)","primary_foreground":"oklch(0.96 0.12 75)"}',true),
173
+ ('7f33e885-6629-4f6b-8dde-382efa03698c','default','Minimalist White','{"muted":"oklch(0.97 0 0)","accent":"oklch(0.97 0 0)","border":"oklch(0.922 0 0)","primary":"oklch(0.205 0 0)","secondary":"oklch(0.97 0 0)","background":"oklch(0.985 0 0)","foreground":"oklch(0.145 0 0)","primary_foreground":"oklch(0.985 0 0)"}',true),
174
+ ('bcf786ec-a658-4e9f-9115-0067fc313a34','peachy','Peachy Delight','{"muted":"oklch(0.901 0.012 162.023)","accent":"oklch(0.888 0.061 5.752)","border":"oklch(0.85 0.02 0)","primary":"oklch(0.816 0.086 9.042)","secondary":"oklch(0.888 0.061 5.752)","background":"oklch(0.95 0.01 162)","foreground":"oklch(0.35 0.03 0)","primary_foreground":"oklch(0.98 0.01 0)"}',true),
175
+ ('c3f4dba4-17db-47d6-9e84-315425d78e91','midnight','Midnight Dark','{"muted":"oklch(0.2 0.03 240)","accent":"oklch(0.7 0.1 200)","border":"oklch(0.3 0.05 240)","primary":"oklch(0.6 0.15 250)","secondary":"oklch(0.25 0.05 240)","background":"oklch(0.15 0.02 240)","foreground":"oklch(0.98 0.01 240)","primary_foreground":"oklch(0.98 0.01 240)"}',true),
176
+ ('d132bca7-872e-475c-adfc-1f8b2e9e271c','ocean','Ocean Deep','{"muted":"oklch(0.9 0.03 220)","accent":"oklch(0.6 0.12 200)","border":"oklch(0.8 0.06 220)","primary":"oklch(0.5 0.15 220)","secondary":"oklch(0.85 0.05 220)","background":"oklch(0.95 0.02 220)","foreground":"oklch(0.2 0.08 220)","primary_foreground":"oklch(0.98 0.01 220)"}',true),
177
+ ('dab26fe5-31e9-4748-b82a-15d3b91c5af1','forest','Forest Nature','{"muted":"oklch(0.92 0.03 140)","accent":"oklch(0.5 0.12 150)","border":"oklch(0.85 0.05 140)","primary":"oklch(0.4 0.1 140)","secondary":"oklch(0.9 0.05 140)","background":"oklch(0.97 0.01 140)","foreground":"oklch(0.2 0.05 140)","primary_foreground":"oklch(0.98 0.01 140)"}',true),
178
+ ('fd49d578-a0a1-44a9-9d83-93dcec092dc8','lavender','Lavender Mist','{"muted":"oklch(0.94 0.03 290)","accent":"oklch(0.75 0.15 300)","border":"oklch(0.88 0.06 290)","primary":"oklch(0.7 0.12 290)","secondary":"oklch(0.92 0.05 290)","background":"oklch(0.96 0.02 290)","foreground":"oklch(0.3 0.08 290)","primary_foreground":"oklch(0.98 0.01 290)"}',true)
179
+ ON CONFLICT (name) DO UPDATE SET label=EXCLUDED.label, colors=EXCLUDED.colors, updated_at=now();
180
+
181
+ -- Collections
182
+ INSERT INTO public.collections (id, name, description, image_url, item_count_label, sort_order) VALUES
183
+ ('contemporary','Contemporary Collection','Modern cuts and innovative styling for the forward-thinking gentleman.','/thudarum-sky-blue-blazer.jpg','10 items',30),
184
+ ('evening','Evening Collection','Luxurious velvet and satin pieces designed to make a statement at formal occasions.','/thudarum-navy-velvet-blazer.jpg','6 items',40),
185
+ ('executive','Executive Collection','Bold, sophisticated pieces for the modern power dresser. Featuring rich textures and commanding colors.','/thudarum-burgundy-evening-suit.jpg','12 items',10),
186
+ ('heritage','Heritage Collection','Classic tailoring with timeless appeal. Traditional patterns reimagined for contemporary elegance.','/thudarum-green-check-blazer.jpg','8 items',20)
187
+ ON CONFLICT (id) DO NOTHING;
188
+
189
+ -- Products
190
+ INSERT INTO public.products (id,name,price,main_image_url,gallery_image_urls,category_label,description,details,sizes,section,collection_ids,sort_order,is_active) VALUES
191
+ ('burgundy-blazer-cream-trousers','Burgundy Blazer with Cream Trousers',985.00,'/thudarum-burgundy-blazer-combo.jpg',ARRAY['/thudarum-burgundy-combo-detail.jpg','/thudarum-burgundy-combo-side.jpg'],'Separates','A striking burgundy blazer combination with cream trousers for a polished statement look.',ARRAY['Premium wool construction','Double-breasted design','Gold-tone buttons','Tailored separates'],ARRAY['38','40','42','44','46','48'],'best_sellers',ARRAY['executive','evening'],10,true),
192
+ ('camel-trench-coat','Camel Trench Coat',645.00,'/camel-trench-coat-elegant.jpg',ARRAY['/minimalist-fashion-studio-elegant-clothing.jpg'],'Outerwear','A refined camel trench coat with a versatile silhouette for smart everyday dressing.',ARRAY['Water-resistant cotton blend','Belted waist','Classic storm flap'],ARRAY['S','M','L','XL'],'general',ARRAY['heritage','contemporary'],20,true),
193
+ ('classic-taupe-double-breasted-suit','Classic Taupe Double-Breasted Suit',1289.00,'/thudarum-taupe-suit-hero.jpg',ARRAY['/thudarum-taupe-suit-detail.jpg','/thudarum-taupe-suit-side.jpg'],'Suits','An impeccably tailored double-breasted suit in refined taupe wool with peak lapels and matching trousers.',ARRAY['100% Italian wool','Double-breasted closure','Peak lapels','Complete with trousers'],ARRAY['38','40','42','44','46','48'],'new_arrivals',ARRAY['executive','contemporary'],10,true),
194
+ ('elegant-black-wool-trousers','Elegant Black Wool Trousers',325.00,'/elegant-black-wool-trousers.jpg',ARRAY[],'Trousers','A foundational black wool trouser with a sharp line and versatile formal appeal.',ARRAY['Wool blend','Pressed front crease','Tailored waistband'],ARRAY['30','32','34','36','38'],'general',ARRAY[],30,true),
195
+ ('heritage-green-check-blazer','Heritage Green Check Blazer',895.00,'/thudarum-green-check-blazer.jpg',ARRAY['/thudarum-green-check-detail.jpg','/thudarum-green-check-side.jpg'],'Blazers','A distinguished houndstooth blazer with classic green patterning, refined tailoring, and gold-tone buttons.',ARRAY['Premium wool houndstooth','Double-breasted design','Gold-tone buttons','Made in England'],ARRAY['38','40','42','44','46','48'],'new_arrivals',ARRAY['heritage'],20,true),
196
+ ('luxe-burgundy-evening-suit','Luxe Burgundy Evening Suit',1545.00,'/thudarum-burgundy-evening-suit.jpg',ARRAY['/thudarum-burgundy-suit-detail.jpg','/thudarum-burgundy-suit-side.jpg'],'Suits','A sophisticated burgundy suit designed for elevated evening occasions with a timeless tailored silhouette.',ARRAY['Fine Italian wool','Double-breasted style','Tone-on-tone buttons','Full suit ensemble'],ARRAY['38','40','42','44','46','48'],'new_arrivals',ARRAY['executive','evening'],30,true),
197
+ ('minimalist-white-linen-shirt','Minimalist White Linen Shirt',245.00,'/minimalist-white-linen-shirt-fashion.jpg',ARRAY['/ivory-silk-blouse-minimal.jpg'],'Shirts','A clean white linen shirt designed for effortless layering and warm-weather polish.',ARRAY['Premium linen','Relaxed tailored fit','Breathable finish'],ARRAY['S','M','L','XL'],'general',ARRAY['contemporary'],10,true),
198
+ ('modern-slate-blazer-set','Modern Slate Blazer Set',1095.00,'/thudarum-slate-blazer-set.jpg',ARRAY['/thudarum-slate-blazer-detail.jpg','/thudarum-slate-blazer-side.jpg'],'Separates','A sophisticated slate blazer set that blends timeless tailoring with modern styling.',ARRAY['Premium wool blend','Double-breasted design','Classic buttons','Made in England'],ARRAY['38','40','42','44','46','48'],'best_sellers',ARRAY['contemporary'],40,true),
199
+ ('navy-velvet-double-breasted-jacket','Navy Velvet Double-Breasted Jacket',1195.00,'/thudarum-navy-velvet-blazer.jpg',ARRAY['/thudarum-navy-velvet-detail.jpg','/thudarum-navy-velvet-side.jpg'],'Blazers','A luxurious navy velvet jacket with elevated texture and refined eveningwear presence.',ARRAY['Italian cotton velvet','Double-breasted style','Silver-tone buttons','Evening-ready finish'],ARRAY['38','40','42','44','46','48'],'best_sellers',ARRAY['evening'],20,true),
200
+ ('refined-gray-double-breasted-suit','Refined Gray Double-Breasted Suit',1345.00,'/thudarum-gray-suit-refined.jpg',ARRAY['/thudarum-gray-suit-detail.jpg','/thudarum-gray-suit-side.jpg'],'Suits','A modern gray double-breasted suit with a clean profile and professional finish.',ARRAY['Super 120s wool','Double-breasted closure','Peak lapels','Complete suit'],ARRAY['38','40','42','44','46','48'],'best_sellers',ARRAY['executive','contemporary'],30,true),
201
+ ('sky-blue-textured-blazer','Sky Blue Textured Blazer',795.00,'/thudarum-sky-blue-blazer.jpg',ARRAY['/thudarum-sky-blue-detail.jpg','/thudarum-sky-blue-side.jpg'],'Blazers','A contemporary sky blue blazer with subtle texture, sharp tailoring, and distinctive button details.',ARRAY['Textured wool blend','Double-breasted cut','Gold button details','Made in Italy'],ARRAY['38','40','42','44','46','48'],'new_arrivals',ARRAY['contemporary'],40,true)
202
+ ON CONFLICT (id) DO NOTHING;
203
+
204
+ -- Coupons
205
+ INSERT INTO public.coupons (code, label, coupon_type, discount_type, discount_value, active) VALUES
206
+ ('WELCOME10','Welcome 10%','universal','percent',10.00,true)
207
+ ON CONFLICT (code) DO NOTHING;
208
+
209
+ -- Order policies
210
+ INSERT INTO public.order_policies (id, shipping_amount, free_shipping_threshold, tax_rate, automatic_shipping_enabled, shippo_from_name, shippo_from_company, shippo_from_street1, shippo_from_street2, shippo_from_city, shippo_from_state, shippo_from_zip, shippo_from_country, shippo_from_phone, shippo_from_email, shippo_from_is_residential, shippo_parcel_length, shippo_parcel_width, shippo_parcel_height, shippo_parcel_weight, shippo_parcel_distance_unit, shippo_parcel_mass_unit, shippo_label_file_type, active_theme_name, show_ticker, section_styles) VALUES
211
+ (true, 15.00, 200.00, 8.00, true, 'FABRICA', 'SPARROW AI SOLUTIONS', '20 W 34th St', 'New York', 'New York', 'NY', '10001', 'US', '8852099490', 'sparrowaisolutions@gmail.com', false, 10.00, 10.00, 4.00, 1.00, 'in', 'lb', 'PDF_4x6', 'default', true, '{"homeHero":"video"}')
212
+ ON CONFLICT (id) DO NOTHING;
213
+
214
+ -- Site content
215
+ INSERT INTO public.site_content (id, content) VALUES
216
+ ('site', '{"brandName":"FABRICA","tickerMessages":["FREE SHIPPING ON ORDERS OVER \u20b9200","30-DAY RETURNS","HOST YOUR OWN STORE IN MINUTES"]}'),
217
+ ('home', '{"heroTitle":"Launch Your Store","heroSubtitle":"Discover powerful tools crafted for the modern merchant","heroVideoUrl":"https://www.youtube.com/embed/u9FEg5qur14?autoplay=1&mute=1&loop=1&playlist=u9FEg5qur14&controls=0&showinfo=0&rel=0&modestbranding=1&playsinline=1","footerTagline":"Contemporary commerce for the independent entrepreneur.","bestSellersTitle":"Best Sellers","collectionsTitle":"Collections","newArrivalsTitle":"New Arrivals"}'),
218
+ ('about', '{"values":[{"title":"Craftsmanship","description":"Every feature is constructed with meticulous attention to detail by skilled engineers who take pride in their work."},{"title":"Quality","description":"We source only the finest open-source tools and frameworks, ensuring reliability and speed in every build."},{"title":"Timelessness","description":"Our designs transcend fleeting trends, offering interfaces that remain elegant and relevant season after season."}],"ctaTitle":"Experience Fabrica","heroTitle":"About Fabrica","storyTitle":"Our Story","valuesTitle":"Our Values","heroImageUrl":"/thudarum-burgundy-evening-suit.jpg","heroSubtitle":"Building seamless commerce tools for the modern entrepreneur","storyImageUrl":"/thudarum-taupe-suit-detail.jpg","ctaDescription":"Discover our latest platform of meticulously crafted storefronts and dashboards designed for the modern merchant.","storyParagraphs":["Founded with a vision to redefine modern e-commerce, Fabrica represents the perfect marriage of powerful infrastructure and intuitive design.","Every feature in our platform is meticulously crafted using proven technology and assembled by engineers who have honed their expertise over decades.","Our storefronts and admin tools are designed for the discerning merchant who appreciates quality, understands branding, and values a platform that will remain powerful and relevant for years to come."]}'),
219
+ ('collections', '{"title":"Collections","description":"Explore our curated collections, each telling a unique story of style, craftsmanship, and modern elegance.","featuredTitle":"Crafted for Excellence","featuredDescription":"Each collection is carefully curated to offer distinctive pieces that complement your personal style."}'),
220
+ ('shop', '{"title":"All Products"}'),
221
+ ('page:contact', '{"body":["Reach out to our support team for help."],"title":"Contact","contact":{"email":"support@fabrica.com","phone":"+91 00000 00000","facebook":"https://facebook.com/fabricahq","whatsapp":"https://wa.me/910000000000","instagram":"https://instagram.com/fabricahq"},"description":"Contact us"}'),
222
+ ('page:privacy', '{"body":["We respect your privacy and protect your data."],"title":"Privacy Policy","description":"Privacy information"}'),
223
+ ('page:returns', '{"body":["30-day return policy for unworn items."],"title":"Returns","description":"Returns information"}'),
224
+ ('page:shipping', '{"body":["Complimentary shipping rules are controlled from Admin Policies."],"title":"Shipping","description":"Shipping information"}'),
225
+ ('page:terms', '{"body":["By using this site, you agree to our terms."],"title":"Terms of Service","description":"Terms information"}')
226
+ ON CONFLICT (id) DO UPDATE SET content=EXCLUDED.content, updated_at=now();
21
227
  `;
228
+
229
+ // ─────────────────────────────────────────────────────────────────────────────
230
+ // STORAGE POLICIES
231
+ // ─────────────────────────────────────────────────────────────────────────────
22
232
  export const STORAGE_POLICIES_SQL = `
23
233
  INSERT INTO storage.buckets (id, name, public) VALUES ('pic', 'pic', true) ON CONFLICT (id) DO NOTHING;
24
234
  DO $$ BEGIN CREATE POLICY "pic_select_all" ON storage.objects FOR SELECT USING (bucket_id = 'pic'); EXCEPTION WHEN duplicate_object THEN NULL; END $$;
@@ -26,4 +236,5 @@ DO $$ BEGIN CREATE POLICY "pic_insert_all" ON storage.objects FOR INSERT WITH CH
26
236
  DO $$ BEGIN CREATE POLICY "pic_update_all" ON storage.objects FOR UPDATE USING (bucket_id = 'pic'); EXCEPTION WHEN duplicate_object THEN NULL; END $$;
27
237
  DO $$ BEGIN CREATE POLICY "pic_delete_all" ON storage.objects FOR DELETE USING (bucket_id = 'pic'); EXCEPTION WHEN duplicate_object THEN NULL; END $$;
28
238
  `;
239
+
29
240
  export const FULL_SQL = `${SCHEMA_SQL}\n${SEED_SQL}\n${STORAGE_POLICIES_SQL}`;