Skip to content

Commit

Permalink
Merge branch 'localsupabase' into deployed
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexVOiceover committed Jul 29, 2024
2 parents b673c81 + d67f133 commit c826a55
Show file tree
Hide file tree
Showing 19 changed files with 499 additions and 90 deletions.
66 changes: 40 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,51 @@
# NisaInvest-TFB-BE

There are a few important considerations and modifications we need to make to ensure it works well with Vercel's serverless environment. Here's what you need to know:
This backend project is designed to work with Vercel's serverless environment. Here's a quick guide to get you started:

Vercel and Express:
* Vercel primarily supports serverless functions, which means we need to adapt our Express app to work in this environment.
* File Structure: We'll need to modify our file structure slightly to work with Vercel's conventions.
* Serverless Function: We'll create a serverless function that wraps our Express app.
## Deployment

NISAINVEST-TFB-BE/
├── api/
│ └── index.ts
├── src/
│ ├── app.ts //Here we set the express server and its middleware
│ └── (other source files)
├── package.json
├── tsconfig.json
└── vercel.json
### Vercel Setup
- Adapt the Express app for serverless functions
- Modify file structure to match Vercel's conventions
- Create a serverless function wrapping the Express app

### Environment Variables
- **Development**: Use `.env` file
CORS_ORIGIN=http://localhost:3000
- **Production**: Set in Vercel dashboard
CORS_ORIGIN=https://your-frontend-domain.com

Vercel (Production):
On Vercel, you'll set environment variables through their dashboard or CLI. These will be available in your code via process.env without needing to use dotenv.
### Deployment Command
```npx vercel --prod```
Backend URL: https://nisa-invest-tfb-be.vercel.app/

In your .env file for development:
```CopyCORS_ORIGIN=http://localhost:3000```
### Local Development
#### Supabase Commands
##### Start local instance:
```npx supabase start```
##### Stop local instance:
```npx supabase stop```
##### Reset local DB:
```npx supabase db reset```
##### Access local Supabase Studio:
```http://localhost:54323/project/default```

In Vercel's dashboard or CLI, set the same variable:
```CopyCORS_ORIGIN=https://your-frontend-domain.com```
### Supabase Remote Setup

Production Environment (Vercel):
Vercel automatically sets NODE_ENV to production in its deployment environment. You don't need to set this manually.
1) Generate access token at https://app.supabase.com
2) Set environment variable:
```export SUPABASE_ACCESS_TOKEN=your_new_token_here```

To redeploy:
npx vercel --prod
3) Link with remote DB:
```npx supabase link --project-ref xzzacivebczssoporkmz```


### Reset Remote DB (Caution: Will reseed)
```npx supabase db reset --linked```

### Best Practices

* Keep environment variables secure
* Test thoroughly before deploying
* Monitor logs in Vercel dashboard for issues

The backend will be accessible on:
https://nisa-invest-tfb-be.vercel.app/
7 changes: 2 additions & 5 deletions api/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { VercelRequest, VercelResponse } from '@vercel/node';
import app from '../src/app';
import config from '../src/config/config';

// Load environment variables from .env file in development
if (process.env.NODE_ENV !== 'production') {
require('dotenv').config();
}
console.log('Current environment:', process.env.NODE_ENV);
console.log('Current environment:', config.nodeEnv);

export default function (req: VercelRequest, res: VercelResponse) {
app(req, res);
Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
"@supabase/supabase-js": "^2.44.4",
"@vercel/node": "^3.2.7",
"cors": "^2.8.5",
"express": "^4.19.2"
"express": "^4.19.2",
"knex": "^3.1.0",
"sqlite3": "^5.1.7"
},
"scripts": {
"start": "node dist/src/app.js",
Expand All @@ -20,6 +22,7 @@
"cross-env": "^7.0.3",
"dotenv": "^16.4.5",
"nodemon": "^3.1.4",
"supabase": "^1.187.8",
"typescript": "^5.5.4",
"vercel": "^35.2.1"
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
16 changes: 16 additions & 0 deletions seeds/users_goals.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
user_id,goal_id,assigned_at,due_date,status,completed_at
1,26,2023-07-01T10:00:00Z,2023-12-31T23:59:59Z,in_progress,
1,30,2023-07-02T11:30:00Z,2023-11-30T23:59:59Z,completed,2023-10-15T14:45:00Z
1,35,2023-07-03T09:15:00Z,2024-01-31T23:59:59Z,not_done,
1,41,2023-07-04T14:00:00Z,2023-12-15T23:59:59Z,in_progress,
1,45,2023-07-05T16:45:00Z,2024-02-29T23:59:59Z,not_done,
2,28,2023-07-06T08:30:00Z,2023-10-31T23:59:59Z,completed,2023-09-30T18:20:00Z
2,33,2023-07-07T13:00:00Z,2024-03-31T23:59:59Z,in_progress,
2,38,2023-07-08T11:45:00Z,2023-12-31T23:59:59Z,not_done,
2,43,2023-07-09T10:30:00Z,2024-01-15T23:59:59Z,in_progress,
3,25,2023-07-10T15:15:00Z,2023-11-30T23:59:59Z,completed,2023-11-15T09:30:00Z
3,31,2023-07-11T09:45:00Z,2024-02-28T23:59:59Z,in_progress,
3,37,2023-07-12T14:30:00Z,2023-12-31T23:59:59Z,not_done,
4,24,2023-07-13T11:00:00Z,2023-10-31T23:59:59Z,completed,2023-10-20T16:45:00Z
4,29,2023-07-14T16:30:00Z,2024-01-31T23:59:59Z,in_progress,
5,27,2023-07-15T10:45:00Z,2023-12-15T23:59:59Z,not_done,
53 changes: 24 additions & 29 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,43 @@ import cors from 'cors'
import userRoutes from './routes/users'
import goalRoutes from './routes/goals'
import quoteRoutes from './routes/quotes'
import dotenv from 'dotenv'
dotenv.config()
import config from './config/config'; // This is file to extract environment variables, use eg. config.port
import config from './config/config'


const app = express();
const app = express()

// CORS setup
const corsOptions = {
origin: process.env.CORS_ORIGIN || '*',
optionsSuccessStatus: 200,

origin: config.corsOrigin,
optionsSuccessStatus: 200,
}

// CORS OPTIONS
// app.use(cors(corsOptions))
app.use(cors())
app.use(cors(corsOptions))
app.use(express.json())

// Routes
app.use('/users', userRoutes)
app.use('/goals', goalRoutes)
app.use('/quotes', quoteRoutes)

const port = process.env.PORT || 3000

// Check if both result the same. Delete this first option
if (process.env.NODE_ENV !== 'production') {
app.listen(port, () => {
console.log(
`Server running in ${process.env.NODE_ENV} mode on http://localhost:${port}`
)
})
};


if (process.env.NODE_ENV !== 'production') {
app.listen(config.port, () => {
console.log(
`Server running in ${config.port} mode on http://localhost:${config.port}`
);
});
if (config.nodeEnv !== 'production') {
const server = app.listen(config.port, () => {
console.log(
`Server running in ${config.nodeEnv} mode on http://localhost:${config.port}`
)
})

server.on('error', (e: NodeJS.ErrnoException) => {
if (e.code === 'EADDRINUSE') {
console.log('Address in use, retrying...')
setTimeout(() => {
server.close()
server.listen(config.port)
}, 1000)
} else {
console.error('Server error:', e.message)
}
})
}

export default app
export default app
24 changes: 13 additions & 11 deletions src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ import dotenv from 'dotenv';
dotenv.config();

interface Config {
port: number;
corsOrigin: string;
nodeEnv: string;
supabaseUrl: string;
supabaseAnonKey: string;
port: number;
corsOrigin: string;
nodeEnv: string;
supabaseUrl: string;
supabaseAnonKey: string;
}

const isProd = process.env.NODE_ENV === 'production';

const config: Config = {
port: parseInt(process.env.PORT || '3000', 10),
corsOrigin: process.env.CORS_ORIGIN || 'http://localhost:3000',
nodeEnv: process.env.NODE_ENV || 'development',
supabaseUrl: process.env.SUPABASE_URL || '',
supabaseAnonKey: process.env.SUPABASE_ANON_KEY || '',
port: parseInt(process.env.PORT || '3000', 10),
corsOrigin: process.env.CORS_ORIGIN || '*',
nodeEnv: process.env.NODE_ENV || 'development',
supabaseUrl: isProd ? process.env.PROD_SUPABASE_URL! : process.env.LOCAL_SUPABASE_URL!,
supabaseAnonKey: isProd ? process.env.PROD_SUPABASE_ANON_KEY! : process.env.LOCAL_SUPABASE_ANON_KEY!,
};

export default config;
export default config;
2 changes: 1 addition & 1 deletion src/routes/goals.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from 'express';
import { supabase } from '../supabaseClient';
import supabase from '../supabaseClient';

const router = express.Router();

Expand Down
18 changes: 12 additions & 6 deletions src/routes/quotes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from 'express'
import { supabase } from '../supabaseClient'
import supabase from '../supabaseClient'

const router = express.Router()

Expand Down Expand Up @@ -38,13 +38,19 @@ function shuffleArray<T>(array: T[]): T[] {
router.get('/random', async (req, res) => {
try {
const { date, count } = req.query
const parsedDate = new Date(date as string)
const parsedCount = parseInt(count as string) || 1

if (isNaN(parsedDate.getTime())) {
return res.status(400).json({ error: 'Invalid date format' })
let parsedDate: Date

if (date) {
parsedDate = new Date(date as string)
if (isNaN(parsedDate.getTime())) {
return res.status(400).json({ error: 'Invalid date format' })
}
} else {
parsedDate = new Date() // Use today's date if no date is provided
}

const parsedCount = parseInt(count as string) || 1

const { data, error } = await supabase
.from('quotes')
.select('*')
Expand Down
2 changes: 1 addition & 1 deletion src/routes/users.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express from 'express';
import { supabase } from '../supabaseClient';
import supabase from '../supabaseClient';

const router = express.Router();

Expand Down
17 changes: 9 additions & 8 deletions src/supabaseClient.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { createClient } from '@supabase/supabase-js'
import dotenv from 'dotenv'
import config from './config/config'

dotenv.config()
console.log('NODE_ENV:', config.nodeEnv)
console.log('Supabase URL:', config.supabaseUrl)
console.log('Supabase Key:', config.supabaseAnonKey ? '**hidden**' : 'undefined')

const supabaseUrl = process.env.SUPABASE_URL!
const supabaseAnonKey = process.env.SUPABASE_ANON_KEY!

if (!supabaseUrl || !supabaseAnonKey) {
throw new Error('Supabase URL and Anon Key are required')
if (!config.supabaseUrl || !config.supabaseAnonKey) {
throw new Error('Supabase URL or Key is missing. Check your environment variables.')
}

export const supabase = createClient(supabaseUrl, supabaseAnonKey)
const supabase = createClient(config.supabaseUrl, config.supabaseAnonKey)

export default supabase
4 changes: 4 additions & 0 deletions supabase/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Supabase
.branches
.temp
.env
Loading

0 comments on commit c826a55

Please sign in to comment.