Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
# Copy this file to .env and fill in values
# Copy this file to .env and fill in values.
# NOTE: .env is git-ignored. NEVER commit real credentials to this
# open-source repository — anyone can read them.

# The port the server listens on. Render overrides this automatically.
PORT=5000
NODE_ENV=development

# Optional — if omitted, the app falls back to in-memory storage
# --- MongoDB ---
# If omitted, the app falls back to in-memory storage (demo only).
# Get a free cluster at https://www.mongodb.com/cloud/atlas
MONGODB_URI=mongodb://localhost:27017/quick-teams
# After creating your cluster, add "0.0.0.0/0" to Network Access so
# your deployed server can connect from anywhere.
MONGODB_URI=mongodb+srv://<db_user>:<db_password>@<cluster>.mongodb.net/<db_name>?appName=<app>

# --- CORS (optional, recommend setting for production) ---
# Comma-separated list of origins allowed to call the API.
# Leave empty to allow same-origin requests only.
# Example: CORS_ORIGIN=https://teamup.onrender.com,https://teamup.example.com
# CORS_ORIGIN=
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ jobs:
- name: Syntax check server & client JS
run: |
node --check server.js
node --check dashboard.js
node --check script.js
node --check public/dashboard.js
node --check public/script.js
node --check scripts/seedData.js
node --check scripts/seed.js
node --check utils/parser.js
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ node_modules/

# Environment variables
.env
*.env
!*.env.example

# Logs
logs
Expand Down
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: node server.js
47 changes: 45 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,48 @@ curl "http://localhost:5000/api/search/teammates?skills=Machine%20Learning"

---

## 🌍 Deploying for Production

Teamup is a full-stack Node/Express app with a MongoDB database and file uploads, so it needs a
**real server host** (not GitHub Pages, which only serves static files). Good options that offer a
free tier: **Render**, **Railway**, or **Fly.io**.

### Prerequisites

1. **MongoDB Atlas** must accept connections from the deployed server. In Atlas →
**Network Access** → add **`0.0.0.0/0`** (allow from anywhere). Keep strong credentials and store
them only in the host's environment variables — never in the repo.
2. Your code is on GitHub (e.g. `github.com/KRISHNA-24BCS127/Teamup`).

### Deploy on Render (recommended)

1. Push this repository to GitHub.
2. Create an account at [render.com](https://render.com) → **New → Web Service** → connect the repo
(or use **New → Blueprint** with the included [`render.yaml`](render.yaml)).
3. Configure the service:
- **Build command:** `npm install`
- **Start command:** `npm start`
- **Environment variables:**
- `MONGODB_URI` = your Atlas connection string, e.g.
`mongodb+srv://<user>:<password>@<cluster>.mongodb.net/<dbname>?appName=<app>`
- `CORS_ORIGIN` = your deployed URL, e.g. `https://teamup.onrender.com`
4. Deploy. Render gives you a public `https://your-service.onrender.com` URL.

> `Procfile` and `render.yaml` are included so the platform knows how to run the app.

### 🛡️ Production security notes

- **Never commit `.env` or `atlas-credentials.env`.** They are git-ignored. `.env.example` is the
safe template — fill in your real values only in the host's secret store.
- The server now serves **only the `public/` folder** as static assets. This prevents exposing
source files, `server.js`, or credentials that the old `express.static(__dirname)` setup leaked.
- CORS is restricted to the domains in `CORS_ORIGIN`. Leave it unset for same-origin use.
- For real production auth you should replace the demo SHA-256 password hashing with **bcrypt/argon2**
and stored uploaded resumes in cloud storage (the current `uploads/` disk storage is wiped on every
redeploy and is only suitable for parsing temp files).

---

## 📁 Project Structure

```
Expand All @@ -142,8 +184,9 @@ Teamup/
│ └── parser.js
├── uploads/ # Temporary upload storage (.gitkeep only)
├── server.js # Application server & API controller
├── *.html # Landing, login, signup, dashboard pages
└── *.js # Client-side logic
├── public/ # Static frontend served by Express (HTML/CSS/JS/images)
├── Procfile # Platform start command (node server.js)
└── render.yaml # Render blueprint for deployment
```

---
Expand Down
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
26 changes: 26 additions & 0 deletions render.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Blueprint for deploying Teamup on Render.
# Docs: https://render.com/docs/yaml-spec
# Usage: connect your GitHub repo on Render and select "Blueprint" (render.yaml).
# IMPORTANT: set REAL values for MONGODB_URI and CORS_ORIGIN in the Render
# dashboard AFTER creating the service — never commit real secrets to git.

services:
- type: web
name: teamup
runtime: node
plan: free
buildCommand: npm install
startCommand: node server.js
healthCheckPath: /api/health
autoDeploy: true
envVars:
- key: NODE_ENV
value: production
- key: PORT
value: 10000
# Filled in the Render dashboard (secret): mongodb+srv://<user>:<pass>@cluster...
- key: MONGODB_URI
sync: false
# Comma-separated allowed origins, e.g. https://teamup.onrender.com
- key: CORS_ORIGIN
sync: false
48 changes: 39 additions & 9 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,41 @@ const upload = multer({ dest: "uploads/" });

const app = express();

// Middleware
app.use(cors());
// Security middleware (production-safe defaults)
// - Stops Express from advertising its version (X-Powered-By)
// - Adds basic hardening headers; tuned to work with the static frontend
app.disable("x-powered-by");
app.use((req, res, next) => {
res.setHeader("X-Content-Type-Options", "nosniff");
res.setHeader("X-Frame-Options", "DENY");
res.setHeader("Referrer-Policy", "no-referrer");
res.setHeader("Permissions-Policy", "camera=(), microphone=(), geolocation=()");
return next();
});

// CORS — restrict to allowed origins when CORS_ORIGIN is set (comma-separated).
// Defaults to allowing the same-origin requests (no header needed) plus any
// explicitly configured origins. For production, set CORS_ORIGIN to your domain(s).
const allowedOrigins = (process.env.CORS_ORIGIN || "")
.split(",")
.map((o) => o.trim())
.filter(Boolean);
app.use(
cors({
origin: (origin, callback) => {
// Allow requests without an Origin (same-origin, curl, server-to-server)
if (!origin) return callback(null, true);
if (allowedOrigins.length === 0 || allowedOrigins.includes(origin)) {
return callback(null, true);
}
return callback(new Error("Not allowed by CORS"));
},
})
);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, "/")));
// Serve ONLY the public/ folder — never the project root (protects .env, source, etc.)
app.use(express.static(path.join(__dirname, "public")));

// Ensure uploads directory exists
if (!fs.existsSync(path.join(__dirname, "uploads"))) {
Expand Down Expand Up @@ -612,12 +642,12 @@ app.get("/api/db-status", authenticateUser, async (req, res) => {
// -------------------------------------------------------------
// HTML Page Serving
// -------------------------------------------------------------
app.get("/", (req, res) => res.sendFile(path.join(__dirname, "index.html")));
app.get("/login", (req, res) => res.sendFile(path.join(__dirname, "login.html")));
app.get("/signup", (req, res) => res.sendFile(path.join(__dirname, "signup.html")));
app.get("/dashboard", (req, res) => res.sendFile(path.join(__dirname, "dashboard.html")));
app.get("/about", (req, res) => res.sendFile(path.join(__dirname, "about.html")));
app.get("/db-status", (req, res) => res.sendFile(path.join(__dirname, "db-status.html")));
app.get("/", (req, res) => res.sendFile(path.join(__dirname, "public", "index.html")));
app.get("/login", (req, res) => res.sendFile(path.join(__dirname, "public", "login.html")));
app.get("/signup", (req, res) => res.sendFile(path.join(__dirname, "public", "signup.html")));
app.get("/dashboard", (req, res) => res.sendFile(path.join(__dirname, "public", "dashboard.html")));
app.get("/about", (req, res) => res.sendFile(path.join(__dirname, "public", "about.html")));
app.get("/db-status", (req, res) => res.sendFile(path.join(__dirname, "public", "db-status.html")));

// 404 Fallback for unknown API routes
app.use("/api", (req, res) => {
Expand Down
Loading