diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ccb0ac7 --- /dev/null +++ b/.env.example @@ -0,0 +1,10 @@ +# Database Configuration +# For local development with Docker Compose +DATABASE_URL=postgres://studybuddy:studybuddy@localhost:5432/studybuddy + +# Server Port +PORT=3030 + +# Force database sync (drops all tables and recreates them) +# Set to true to reset the database on server start +FORCE_SYNC=false diff --git a/README.md b/README.md index 25475b9..493ba15 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ Visit http://study-hero.herokuapp.com/ to use the app. You will need to create a **PLEASE NOTE** this is not a production product. Your account and its contents may be viewed, removed or altered without warning. DO NOT use this app for research that is not backed up nor to store any private or personally identifiable information. +## Local Development + +Want to run StudyBuddy locally or contribute to the project? See [SETUP.md](./SETUP.md) for detailed instructions on setting up your local development environment with PostgreSQL. + ## About Created by Tyler Monaghan ([GitHub](https://www.github.com/tymonaghan), [Portfolio](https://portfolio.tylermonaghan.dev)) for Async Week Project at Fullstack Academy diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..f0d94ce --- /dev/null +++ b/SETUP.md @@ -0,0 +1,218 @@ +# StudyBuddy Local Development Setup + +This guide will help you set up StudyBuddy for local development with a PostgreSQL database. + +## Prerequisites + +- [Node.js](https://nodejs.org/) (v14 or higher recommended) +- [Docker](https://www.docker.com/get-started) and Docker Compose (for local PostgreSQL) +- Git + +## Quick Start + +### 1. Clone the Repository + +```bash +git clone https://github.com/tymonaghan/studybuddy.git +cd studybuddy +``` + +### 2. Install Dependencies + +```bash +npm install +``` + +### 3. Set Up Environment Variables + +Copy the example environment file and customize it if needed: + +```bash +cp .env.example .env +``` + +The default `.env.example` is configured to work with the Docker Compose setup. If you're using a different PostgreSQL setup, update the `DATABASE_URL` in your `.env` file. + +### 4. Start PostgreSQL Database + +Using Docker Compose (recommended): + +```bash +docker-compose up -d +``` + +This will start a PostgreSQL container with: +- Database name: `studybuddy` +- Username: `studybuddy` +- Password: `studybuddy` +- Port: `5432` + +To stop the database: + +```bash +docker-compose down +``` + +To stop and remove all data: + +```bash +docker-compose down -v +``` + +### 5. Seed the Database + +Populate the database with initial test data: + +```bash +npm run seed +``` + +This will create: +- Test users (jimmy, ricky, bluey) +- Sample projects +- Sample sources + +### 6. Start the Application + +For development with hot reloading: + +```bash +npm run start:dev +``` + +This will: +- Start webpack in watch mode for frontend changes +- Start nodemon for backend changes +- The app will be available at `http://localhost:3030` + +For production mode: + +```bash +npm run build +npm start +``` + +## Database Management + +### Viewing Database Contents + +Connect to the PostgreSQL database: + +```bash +docker exec -it studybuddy-postgres psql -U studybuddy -d studybuddy +``` + +Useful PostgreSQL commands: +- `\dt` - List all tables +- `\d table_name` - Describe a table +- `SELECT * FROM "Users";` - View all users +- `\q` - Quit + +### Resetting the Database + +To completely reset the database: + +1. Set `FORCE_SYNC=true` in your `.env` file, OR +2. Run the seed script which forces a sync: + +```bash +npm run seed +``` + +### Manual PostgreSQL Setup + +If you prefer not to use Docker, install PostgreSQL locally: + +1. Install PostgreSQL for your operating system +2. Create a database named `studybuddy`: + ```bash + createdb studybuddy + ``` +3. Update your `.env` file with your local PostgreSQL connection string: + ``` + DATABASE_URL=postgres://your_username@localhost:5432/studybuddy + ``` + +## Testing + +Run tests with the test database: + +```bash +npm run test:dev +``` + +## Available Scripts + +- `npm run build` - Build the frontend bundle +- `npm start` - Start the server in production mode +- `npm run start:dev` - Start the server in development mode with hot reloading +- `npm run start-webpack` - Start only the webpack dev server +- `npm run seed` - Seed the database with test data +- `npm test` - Run tests with remote test database +- `npm run test:dev` - Run tests with local test database + +## Troubleshooting + +### Database Connection Issues + +If you see database connection errors: + +1. **Check if PostgreSQL is running:** + ```bash + docker ps + ``` + You should see the `studybuddy-postgres` container running. + +2. **Check database health:** + ```bash + docker-compose logs postgres + ``` + +3. **Verify connection string:** + Make sure your `.env` file has the correct `DATABASE_URL`. + +4. **Restart the database:** + ```bash + docker-compose restart + ``` + +### Port Already in Use + +If port 5432 or 3030 is already in use: + +- **For PostgreSQL (5432):** Stop other PostgreSQL instances or change the port in `docker-compose.yml` +- **For the app (3030):** Change the `PORT` variable in your `.env` file + +### Module Not Found Errors + +If you see module not found errors: + +```bash +rm -rf node_modules package-lock.json +npm install +``` + +## Project Structure + +``` +studybuddy/ +├── app/ # React frontend components +├── public/ # Static files +├── server/ # Express backend +│ ├── db/ # Database models and configuration +│ └── ... # API routes +├── tests/ # Test files +├── .env.example # Example environment variables +├── docker-compose.yml # Docker configuration for PostgreSQL +├── package.json # Node dependencies and scripts +└── start.js # Application entry point +``` + +## Next Steps + +- Create a user account at `http://localhost:3030` +- Create a project +- Add sources to your project +- Take notes on your sources + +For more information, see the main [README.md](./README.md). diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..276f218 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,21 @@ +services: + postgres: + image: postgres:14-alpine + container_name: studybuddy-postgres + restart: unless-stopped + environment: + POSTGRES_DB: studybuddy + POSTGRES_USER: studybuddy + POSTGRES_PASSWORD: studybuddy + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U studybuddy -d studybuddy"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres_data: diff --git a/package-lock.json b/package-lock.json index 222029d..01753b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "body-parser": "^1.19.1", "bootstrap": "^5.1.3", "chalk": "^4.1.2", + "dotenv": "^17.2.3", "express": "^4.17.2", "jsonwebtoken": "^8.5.1", "nodemon": "^2.0.15", @@ -3667,6 +3668,18 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dottie": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", @@ -11428,6 +11441,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "17.2.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz", + "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==" + }, "dottie": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", diff --git a/package.json b/package.json index dfe7bb7..e6f86f9 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "body-parser": "^1.19.1", "bootstrap": "^5.1.3", "chalk": "^4.1.2", + "dotenv": "^17.2.3", "express": "^4.17.2", "jsonwebtoken": "^8.5.1", "nodemon": "^2.0.15", diff --git a/server/db/database.js b/server/db/database.js index ce16379..d7ed93e 100644 --- a/server/db/database.js +++ b/server/db/database.js @@ -1,16 +1,32 @@ const Sequelize = require("sequelize"); -const db = new Sequelize( - process.env.DATABASE_URL || "postgres://localhost:5432/studybuddy", - { - dialectOptions: { - // this dialectOptions section is required for the heroku postgres add-on to connect - ssl: { - rejectUnauthorized: false, - }, +const databaseUrl = process.env.DATABASE_URL || "postgres://studybuddy:studybuddy@localhost:5432/studybuddy"; + +// Determine if we need SSL (for Heroku and other production databases) +// Parse the URL to properly check the hostname +let isProduction = process.env.NODE_ENV === 'production'; +try { + const url = new URL(databaseUrl); + // Check if hostname ends with amazonaws.com (matches RDS hosts) + isProduction = isProduction || url.hostname.endsWith('.amazonaws.com'); +} catch (err) { + // If URL parsing fails, fall back to NODE_ENV check only + console.warn('Warning: Unable to parse DATABASE_URL for SSL detection:', err.message); +} + +const config = { + logging: false, +}; + +// Only add SSL config for production databases +if (isProduction) { + config.dialectOptions = { + ssl: { + rejectUnauthorized: false, }, - logging: false, - } -); + }; +} + +const db = new Sequelize(databaseUrl, config); module.exports = db; diff --git a/start.js b/start.js index 8cdddc0..383dc4d 100644 --- a/start.js +++ b/start.js @@ -1,3 +1,4 @@ +require('dotenv').config(); const { db } = require("./server/db"); const app = require("./server");