Skip to content

Commit 16fcf5b

Browse files
initial commit - full stack project
0 parents  commit 16fcf5b

9 files changed

Lines changed: 262 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: CI/CD
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build-backend:
11+
runs-on: ubuntu-latest
12+
defaults:
13+
run:
14+
working-directory: backend
15+
steps:
16+
- uses: actions/checkout@v4
17+
- uses: actions/setup-node@v4
18+
with:
19+
node-version: 20
20+
cache: npm
21+
cache-dependency-path: backend/package-lock.json
22+
- run: npm install
23+
- run: npm run build
24+
25+
build-frontend:
26+
runs-on: ubuntu-latest
27+
defaults:
28+
run:
29+
working-directory: frontend
30+
steps:
31+
- uses: actions/checkout@v4
32+
- uses: actions/setup-node@v4
33+
with:
34+
node-version: 20
35+
cache: npm
36+
cache-dependency-path: frontend/package-lock.json
37+
- run: npm install
38+
- run: npm run build
39+
env:
40+
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
41+
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY }}

README.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# EcomCloud — Multi-Tenant E-Commerce Platform
2+
3+
## Project Structure
4+
5+
```
6+
ecomcloud/
7+
├── backend/ # NestJS API
8+
├── frontend/ # Next.js 14 Dashboard
9+
├── supabase-schema.sql
10+
├── docker-compose.yml
11+
└── .github/workflows/ci.yml
12+
```
13+
14+
## Quick Start
15+
16+
### 1. Supabase Setup
17+
1. Create a project at https://supabase.com
18+
2. Go to SQL Editor → New Query
19+
3. Paste and run `supabase-schema.sql`
20+
4. Copy your `SUPABASE_URL` and `SUPABASE_SERVICE_ROLE_KEY` from Project Settings → API
21+
22+
### 2. Backend
23+
```bash
24+
cd backend
25+
cp .env.example .env
26+
# Fill in your .env values
27+
npm install
28+
npm run start:dev
29+
```
30+
API runs on http://localhost:4000
31+
Swagger docs at http://localhost:4000/api/docs
32+
33+
### 3. Frontend
34+
```bash
35+
cd frontend
36+
cp .env.example .env
37+
# Fill in your .env values
38+
npm install
39+
npm run dev
40+
```
41+
Dashboard runs on http://localhost:3000
42+
43+
### 4. Docker (optional)
44+
```bash
45+
cp backend/.env.example backend/.env
46+
cp frontend/.env.example frontend/.env
47+
# Fill in both .env files
48+
docker-compose up --build
49+
```
50+
51+
## Default Admin Login
52+
- Email: admin@ecomcloud.com
53+
- Password: admin123
54+
55+
56+
57+
## Scrrnshots
58+
59+
## 🔐 Login Page
60+
61+
<p align="center">
62+
<img src="assets/login.png" width="600"/>
63+
</p>
64+
65+
## 🏠 Home Page
66+
67+
<p align="center">
68+
<img src="assets/home.png" width="600"/>
69+
</p>
70+
71+
## 🛒 Store Page
72+
73+
<p align="center">
74+
<img src="assets/store.png" width="600"/>
75+
</p>
76+
77+
78+
79+
80+
81+
82+
83+
84+
85+
86+
## Environment Variables
87+
88+
### backend/.env
89+
| Variable | Description |
90+
|---|---|
91+
| SUPABASE_URL | Your Supabase project URL |
92+
| SUPABASE_SERVICE_ROLE_KEY | Service role key (not anon key) |
93+
| JWT_SECRET | Any long random string |
94+
| STRIPE_SECRET_KEY | Stripe secret key (sk_test_...) |
95+
| PORT | API port (default 4000) |
96+
| FRONTEND_URL | Frontend URL for CORS |
97+
98+
### frontend/.env
99+
| Variable | Description |
100+
|---|---|
101+
| NEXT_PUBLIC_API_URL | Backend URL (http://localhost:4000) |
102+
| NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY | Stripe publishable key (pk_test_...) |
103+
104+
## API Endpoints
105+
106+
| Method | Endpoint | Description |
107+
|---|---|---|
108+
| POST | /auth/register | Register user / store |
109+
| POST | /auth/login | Login, get JWT |
110+
| GET | /dashboard/overview | Stats overview |
111+
| GET | /dashboard/revenue-chart | 7-day revenue |
112+
| GET | /dashboard/recent-orders | Last 10 orders |
113+
| GET | /tenants | List tenants |
114+
| GET | /tenants/:id/stats | Tenant stats |
115+
| GET | /tenants/:id/products | List products |
116+
| POST | /tenants/:id/products | Create product |
117+
| PUT | /tenants/:id/products/:pid | Update product |
118+
| DELETE | /tenants/:id/products/:pid | Delete product |
119+
| GET | /tenants/:id/orders | List orders |
120+
| POST | /tenants/:id/orders | Create order + Stripe intent |
121+
| POST | /tenants/:id/orders/:oid/confirm | Confirm payment |
122+
| PUT | /tenants/:id/orders/:oid/status | Update status |
123+
124+
## User Roles
125+
- **admin** — sees all stores, all orders, all analytics
126+
- **store_owner** — sees only their own store's data
127+
128+

assets/home.png

73.9 KB
Loading

assets/login.png

503 KB
Loading

assets/store.png

73.9 KB
Loading

backend

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 62361fb38feea44a279ab81c1ee9dd060f2ecab4

docker-compose.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
version: '3.9'
2+
services:
3+
backend:
4+
build: ./backend
5+
ports:
6+
- '4000:4000'
7+
env_file:
8+
- ./backend/.env
9+
restart: unless-stopped
10+
11+
frontend:
12+
build: ./frontend
13+
ports:
14+
- '3000:3000'
15+
env_file:
16+
- ./frontend/.env
17+
depends_on:
18+
- backend
19+
restart: unless-stopped

frontend

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit d75ca8fee11f13c5e3defb1d0b31e758ea8189bb

supabase-schema.sql

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
create extension if not exists "uuid-ossp";
2+
3+
create table if not exists tenants (
4+
id uuid primary key default uuid_generate_v4(),
5+
name text not null,
6+
owner_id uuid,
7+
logo_url text,
8+
created_at timestamptz default now()
9+
);
10+
11+
create table if not exists users (
12+
id uuid primary key default uuid_generate_v4(),
13+
email text unique not null,
14+
password_hash text not null,
15+
name text not null,
16+
role text not null default 'store_owner',
17+
tenant_id uuid references tenants(id) on delete set null,
18+
created_at timestamptz default now()
19+
);
20+
21+
alter table tenants
22+
add constraint fk_tenant_owner
23+
foreign key (owner_id) references users(id) on delete set null;
24+
25+
create table if not exists categories (
26+
id uuid primary key default uuid_generate_v4(),
27+
tenant_id uuid not null references tenants(id) on delete cascade,
28+
name text not null,
29+
created_at timestamptz default now()
30+
);
31+
32+
create table if not exists products (
33+
id uuid primary key default uuid_generate_v4(),
34+
tenant_id uuid not null references tenants(id) on delete cascade,
35+
category_id uuid references categories(id) on delete set null,
36+
name text not null,
37+
description text,
38+
price numeric(10,2) not null default 0,
39+
stock integer not null default 0,
40+
image_url text,
41+
created_at timestamptz default now(),
42+
updated_at timestamptz
43+
);
44+
45+
create table if not exists orders (
46+
id uuid primary key default uuid_generate_v4(),
47+
tenant_id uuid not null references tenants(id) on delete cascade,
48+
user_id uuid references users(id) on delete set null,
49+
customer_email text not null,
50+
status text not null default 'pending',
51+
total numeric(10,2) not null default 0,
52+
stripe_payment_intent_id text,
53+
line_items jsonb not null default '[]',
54+
created_at timestamptz default now(),
55+
updated_at timestamptz
56+
);
57+
58+
create index if not exists idx_products_tenant on products(tenant_id);
59+
create index if not exists idx_orders_tenant on orders(tenant_id);
60+
create index if not exists idx_orders_status on orders(status);
61+
create index if not exists idx_users_tenant on users(tenant_id);
62+
63+
create or replace function decrement_stock(p_product_id uuid, p_qty integer)
64+
returns void language plpgsql as $$
65+
begin
66+
update products set stock = greatest(stock - p_qty, 0), updated_at = now() where id = p_product_id;
67+
end;
68+
$$;
69+
70+
insert into users (id, email, password_hash, name, role)
71+
values (uuid_generate_v4(), 'admin@ecomcloud.com', '$2a$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj4J/HS.iK8i', 'Super Admin', 'admin')
72+
on conflict (email) do nothing;

0 commit comments

Comments
 (0)