Skip to content

Commit b4f5ad4

Browse files
committed
fix: definitive RLS - 4 policies per table (no FOR ALL overlap), zero permissive duplicates; add ADMIN_GUIDE.md; remove superseded SQL files
1 parent b7fc188 commit b4f5ad4

File tree

5 files changed

+720
-931
lines changed

5 files changed

+720
-931
lines changed

ADMIN_GUIDE.md

Lines changed: 330 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,330 @@
1-
# 🦅 Admin Guidance · Obsidian Operations
2-
**Access:** `https://dinacosmetic.store/admin`
3-
4-
## 🎭 Admin Role Activation
5-
1. Sign up on the storefront with your email.
6-
2. Go to **Supabase Dashboard > Table Editor > profiles**.
7-
3. Find your user ID and change `role` from `user` to `admin`.
8-
4. Refresh the admin portal.
9-
10-
## 📦 Merchandise Management
11-
- **Dashboard:** Track total luxury sales, recent volume, and low stock alerts.
12-
- **Stock:** Inventory is **Atomic**. If you sell 1 unit, the system locks the database row to prevent overselling.
13-
- **Pricing:** Validated server-side during checkout.
14-
15-
## 🎨 Visual Curation (Frontend)
16-
- Navigate to **Admin > Customization**.
17-
- Change the **Hero Masterpiece** title and subtitle.
18-
- Updates apply instantly to the homepage via Next.js server actions.
19-
20-
## 📜 Order Ledger
21-
- View all paid sessions synced from Stripe.
22-
- Click a Reference Number to enter the fulfillment workflow.
23-
24-
## ⚠️ Security Protocols
25-
- Never share your `SUPABASE_SERVICE_ROLE_KEY`. It allows full DB bypass.
26-
- The `/admin` route is protected by both Next.js middleware and Supabase RLS policies (Double-lock).
1+
# DINA COSMETIC — Admin & Deployment Guide
2+
3+
> **The Obsidian Palace** · LMXEngine · Built on Next.js 15 + Supabase + Stripe
4+
5+
---
6+
7+
## Table of Contents
8+
9+
1. [What Was Built](#1-what-was-built)
10+
2. [Admin Portal — Features & How to Use](#2-admin-portal--features--how-to-use)
11+
3. [Database Setup](#3-database-setup)
12+
4. [Environment Variables](#4-environment-variables)
13+
5. [Deploy to Vercel](#5-deploy-to-vercel)
14+
6. [Post-Deploy Checklist](#6-post-deploy-checklist)
15+
7. [Storefront Routes](#7-storefront-routes)
16+
8. [Architecture Notes](#8-architecture-notes)
17+
18+
---
19+
20+
## 1. What Was Built
21+
22+
### Storefront (`/`)
23+
| Route | Description |
24+
|---|---|
25+
| `/` | Homepage with hero, featured products, collections teaser |
26+
| `/shop` | Full product catalogue with real-time Supabase updates |
27+
| `/collections` | Curated vault index — links dynamically to DB categories |
28+
| `/collections/[slug]` | Individual collection page — filtered by category slug |
29+
| `/product/[slug]` | Single product detail with variants & add-to-cart |
30+
| `/account` | Customer order history and profile |
31+
| `/login` | Supabase Auth email/password + magic link |
32+
| `/cart` | Shopping bag drawer (client component) |
33+
| `/checkout` | Stripe Checkout session redirect |
34+
| `/checkout/success` | Post-payment confirmation page |
35+
| `/about` | Brand story page |
36+
| `/contact` | Contact form (Resend) |
37+
38+
### Admin Portal (`/admin`)
39+
| Route | Description |
40+
|---|---|
41+
| `/admin` | **Command Center** — live stats dashboard |
42+
| `/admin/products` | Product list with inline actions |
43+
| `/admin/products/new` | Create product with image upload |
44+
| `/admin/products/[id]` | Edit product details, images, stock |
45+
| `/admin/orders` | Order fulfilment table with status controls |
46+
| `/admin/categories` | Category management |
47+
| `/admin/users` | Customer directory |
48+
| `/admin/settings` | Site settings and frontend content editor |
49+
50+
### API Routes (`/app/api`)
51+
| Route | Description |
52+
|---|---|
53+
| `/api/checkout` | Creates Stripe Checkout session (server-side) |
54+
| `/api/webhooks/stripe` | Receives and verifies Stripe events |
55+
56+
---
57+
58+
## 2. Admin Portal — Features & How to Use
59+
60+
### Accessing Admin
61+
62+
1. Log in at `/login` with your admin email
63+
2. Your `profiles.role` must be `'admin'` in Supabase
64+
3. Navigate to `/admin` — non-admin users are redirected to `/`
65+
66+
> **To make an account admin:** In Supabase → Table Editor → `profiles` → find your row → set `role` to `admin`
67+
68+
---
69+
70+
### Command Center Dashboard (`/admin`)
71+
72+
**Live stats refreshed on every page load:**
73+
- **Total Revenue** — sum of all `paid` orders
74+
- **Orders** — total order count
75+
- **Low Stock** — products with `inventory < 5`
76+
- **Customers** — total registered users
77+
78+
**Quick Actions grid:**
79+
- → New Product
80+
- → View Orders
81+
- → Manage Categories
82+
- → Site Settings
83+
84+
**Low Stock Alerts panel** — top 5 products by lowest inventory, click to edit
85+
86+
**Recent Transactions table** — last 8 orders with status badges and amounts
87+
88+
---
89+
90+
### Product Management (`/admin/products`)
91+
92+
#### Creating a Product
93+
1. Click **"New Product"** or go to `/admin/products/new`
94+
2. Fill in:
95+
- **Name** (required)
96+
- **Description**
97+
- **Price** (in USD, e.g. `49.99`)
98+
- **Stock / Inventory** quantity
99+
- **Category** — dropdown populated from DB
100+
- **Images** — drag & drop upload to Supabase Storage
101+
- **Active** toggle — only active products appear in the store
102+
3. Click **Save** — page revalidates instantly
103+
104+
#### Editing a Product
105+
1. Click any product row → `/admin/products/[id]`
106+
2. Same form, pre-filled with existing data
107+
3. Upload new images or remove old ones
108+
4. Save — changes reflect on storefront immediately (ISR revalidation)
109+
110+
#### Deleting a Product
111+
- Delete button on the product list row
112+
- Product is removed from DB and storefront
113+
114+
---
115+
116+
### Order Fulfilment (`/admin/orders`)
117+
118+
**Status values:** `pending``paid``shipped``delivered` | `cancelled` | `refunded`
119+
120+
**Workflow:**
121+
1. Order arrives as `pending` when checkout starts
122+
2. Stripe webhook (`/api/webhooks/stripe`) marks it `paid` automatically
123+
3. Admin manually marks `shipped` after generating a label
124+
4. Shippo label generation available via the order detail action button
125+
5. Tracking number is stored and visible to the customer in `/account`
126+
127+
**Important:** Orders are **immutable after payment** per security rules. Status can advance but items cannot be changed.
128+
129+
---
130+
131+
### Category Management (`/admin/categories`)
132+
133+
- Add categories with `name`, `slug`, `description`, `image_url`
134+
- Slug must be URL-safe (e.g. `skincare`, `lip-collection`)
135+
- Categories appear in shop filter and `/collections/[slug]` pages
136+
- Deleting a category does **not** delete products (FK set to NULL)
137+
138+
---
139+
140+
### Site Settings (`/admin/settings`)
141+
142+
Edits content stored in `site_settings` and `frontend_content` tables:
143+
- Hero headline and subtitle
144+
- Store name and tagline
145+
- **Kill Switch** — set `store_enabled` to `false` to show a maintenance page
146+
147+
---
148+
149+
## 3. Database Setup
150+
151+
### Run in Supabase SQL Editor
152+
153+
> **Supabase → SQL Editor → New Query → Paste → Run**
154+
155+
**Use `DATABASE_FINAL.sql`** — this is the single source of truth. It:
156+
- Adds all missing columns to existing tables
157+
- Creates `variants`, `site_settings`, `frontend_content` tables
158+
- Sets exactly **4 RLS policies per table** (SELECT / INSERT / UPDATE / DELETE)
159+
- Uses `(select auth.uid())` pattern — zero performance warnings
160+
- Creates all indexes, triggers, and the `admin_sales_stats` view
161+
- Seeds default settings
162+
163+
### Make Yourself Admin
164+
165+
After running the SQL and creating your account:
166+
```sql
167+
UPDATE public.profiles
168+
SET role = 'admin'
169+
WHERE email = 'your@email.com';
170+
```
171+
172+
### Storage Bucket
173+
174+
The SQL creates the `product-images` bucket automatically. Configure storage policies via:
175+
> **Supabase → Storage → product-images → Policies**
176+
177+
Add:
178+
- `SELECT`: `true` (public read)
179+
- `INSERT/UPDATE/DELETE`: `(select role from profiles where id = auth.uid()) = 'admin'`
180+
181+
---
182+
183+
## 4. Environment Variables
184+
185+
Create `.env.local` (never commit this file):
186+
187+
```env
188+
# Supabase
189+
NEXT_PUBLIC_SUPABASE_URL=https://zsahskxejgbrvfhobfyp.supabase.co
190+
NEXT_PUBLIC_SUPABASE_ANON_KEY=sb_publishable_...
191+
SUPABASE_SERVICE_ROLE_KEY=eyJ...
192+
193+
# Stripe
194+
STRIPE_SECRET_KEY=sk_live_...
195+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...
196+
STRIPE_WEBHOOK_SECRET=whsec_...
197+
198+
# Email (Resend)
199+
RESEND_API_KEY=re_...
200+
201+
# Shipping (Shippo)
202+
SHIPPO_API_KEY=shippo_live_...
203+
204+
# App
205+
NEXT_PUBLIC_SITE_URL=https://dinacosmetic.store
206+
```
207+
208+
### Vercel Environment Variables
209+
210+
Add all of the above to:
211+
> **Vercel → Project → Settings → Environment Variables**
212+
213+
Set for **Production**, **Preview**, and **Development**.
214+
215+
---
216+
217+
## 5. Deploy to Vercel
218+
219+
### First Deployment
220+
221+
```bash
222+
# Install Vercel CLI (if not installed)
223+
npm i -g vercel
224+
225+
# From project root
226+
vercel --prod
227+
```
228+
229+
Or connect via GitHub:
230+
1. Go to [vercel.com/new](https://vercel.com/new)
231+
2. Import `lead-matrix/LMXEngine`
232+
3. Framework: **Next.js** (auto-detected)
233+
4. Add all environment variables
234+
5. Deploy
235+
236+
### Subsequent Deploys
237+
238+
```bash
239+
git push origin main
240+
```
241+
Vercel auto-deploys on every push to `main`.
242+
243+
### Stripe Webhook (Production)
244+
245+
After deploying, register your webhook:
246+
1. [Stripe Dashboard → Webhooks](https://dashboard.stripe.com/webhooks)
247+
2. Add endpoint: `https://dinacosmetic.store/api/webhooks/stripe`
248+
3. Events to listen for:
249+
- `checkout.session.completed`
250+
- `payment_intent.succeeded`
251+
- `payment_intent.payment_failed`
252+
4. Copy the **Signing secret** → set as `STRIPE_WEBHOOK_SECRET` in Vercel
253+
254+
### Supabase Auth Redirect URLs
255+
256+
In **Supabase → Authentication → URL Configuration**:
257+
- **Site URL:** `https://dinacosmetic.store`
258+
- **Redirect URLs:**
259+
```
260+
https://dinacosmetic.store/**
261+
http://localhost:3000/**
262+
```
263+
264+
---
265+
266+
## 6. Post-Deploy Checklist
267+
268+
```
269+
□ DATABASE_FINAL.sql run successfully in Supabase SQL Editor
270+
□ Admin account role set to 'admin' in profiles table
271+
□ All environment variables added to Vercel
272+
□ Stripe webhook registered with correct endpoint
273+
□ Supabase Auth redirect URLs configured
274+
□ product-images storage bucket is public
275+
□ Test: Create a product via /admin/products/new
276+
□ Test: Place a test order with Stripe test card 4242 4242 4242 4242
277+
□ Test: Verify webhook fires and order status changes to 'paid'
278+
□ Test: /admin Command Center shows correct stats
279+
□ Test: /collections loads categories from DB
280+
□ Test: /collections/[slug] filters products correctly
281+
```
282+
283+
---
284+
285+
## 7. Storefront Routes
286+
287+
### Customer Flow
288+
```
289+
/ → /shop → /product/[slug] → (add to cart) → /checkout → /checkout/success
290+
→ (Stripe webhook fires)
291+
→ Order marked 'paid'
292+
→ Confirmation email sent
293+
```
294+
295+
### Auth Flow
296+
```
297+
/login → Supabase Auth → redirect to /account (or previous page)
298+
/account → view orders, update profile
299+
```
300+
301+
---
302+
303+
## 8. Architecture Notes
304+
305+
### Security
306+
- All pricing calculated **server-side** — client never submits prices
307+
- Stripe webhook verified with `STRIPE_WEBHOOK_SECRET` signature
308+
- Admin routes protected by middleware + server-side role check
309+
- `SUPABASE_SERVICE_ROLE_KEY` only used in server components and API routes
310+
- RLS enabled on all tables with zero policy conflicts
311+
312+
### Performance
313+
- Product lists use `revalidate = 60` (ISR — fresh every 60s)
314+
- Admin dashboard is fully dynamic (no cache)
315+
- All `auth.uid()` calls use `(select auth.uid())` pattern (single eval per query)
316+
- Exactly 4 RLS policies per table (no redundant evaluation)
317+
- Indexed columns: `is_active`, `category_id`, `inventory`, `slug`, `status`, `created_at`
318+
319+
### Real-time
320+
- `ProductGrid` subscribes to Supabase Realtime — product updates appear instantly
321+
- Admin orders page refreshes on status change
322+
323+
### Image Uploads
324+
- Stored in Supabase Storage `product-images` bucket (public CDN)
325+
- Uploaded via drag-and-drop in `ImageUpload` component
326+
- `next/image` used throughout with `sizes` attribute for responsive loading
327+
328+
---
329+
330+
*Last updated: 2026-02-26 · LMXEngine / DINA COSMETIC*

0 commit comments

Comments
 (0)