# Software Development Specification (Revised)

## 1. Introduction  
The project delivers a ready-to-run RESTful API built with Node.js, Express, and MongoDB.

Key capabilities  
1. User management with role-based access control  
2. Stateless authentication via short-lived JWT access tokens and long-lived refresh tokens  
3. Third-party OAuth (Facebook, Google) and traditional email/password login  
4. Password-reset workflow with e-mail delivery  
5. Production-grade boilerplate including error handling, logging, documentation, and automated testing

---

## 2. Functional Requirements

### 2.1 Configuration  
The application reads and validates environment variables from `.env` (checked against `.env.example`).

Required variables  
* `PORT` – HTTP listening port  
* `NODE_ENV` – `development` / `test` / `production`  
* `MONGO_URI` – MongoDB connection string (production / dev)  
* `MONGO_URI_TESTS` – MongoDB connection string for the test suite  
* `JWT_SECRET` – HMAC secret for signing JWTs  
* `JWT_EXPIRATION_MINUTES` – lifetime of an access token (minutes)  
* `EMAIL_HOST`, `EMAIL_PORT`, `EMAIL_USERNAME`, `EMAIL_PASSWORD` – SMTP credentials

Note – The runtime configuration property `jwtExpirationInterval` is populated from `JWT_EXPIRATION_MINUTES`.

### 2.2 Server Lifecycle  
1. Read and validate env vars  
2. Establish MongoDB connection  
3. Start HTTP listener on `PORT`  
4. Log successful startup via `config/logger.js`

### 2.3 Authentication & Authorization  

| Action | Endpoint | Method | Auth | Description | Input Validation |
|--------|----------|--------|------|-------------|------------------|
| Register | `/v1/auth/register` | POST | public | Create account | `email`, `password` (6–128 chars) |
| Login | `/v1/auth/login` | POST | public | Issue new tokens | `email`, `password` |
| OAuth login | `/v1/auth/facebook`, `/v1/auth/google` | POST | public | Exchange third-party `access_token` for local tokens | `access_token` |
| Refresh token | `/v1/auth/refresh-token` | POST | public | Exchange refresh token for new access token | `email`, `refreshToken` |
| Send reset link | `/v1/auth/send-password-reset` | POST | public | E-mail reset link | `email` |
| Reset password | `/v1/auth/reset-password` | POST | public | Update password using reset token | `email`, `password`, `resetToken` |

Authorization rules  
* Access tokens are Bearer JWTs.  
* `ADMIN` role may operate on any user.  
* `LOGGED_USER` may only operate on itself (unless `ADMIN`).  
* Middleware chain: `passport.authenticate('jwt')` → role guard.

### 2.4 User Management  

| Action | Endpoint | Method | Required Role |
|--------|----------|--------|---------------|
| List users | `/v1/users` | GET | `ADMIN` |
| Create user | `/v1/users` | POST | `ADMIN` |
| Get own profile | `/v1/users/profile` | GET | authenticated |
| Get user by id | `/v1/users/:userId` | GET | same user \| `ADMIN` |
| Replace user | `/v1/users/:userId` | PUT | same user \| `ADMIN` |
| Update user | `/v1/users/:userId` | PATCH | same user \| `ADMIN` |
| Delete user | `/v1/users/:userId` | DELETE | same user \| `ADMIN` |

Query parameters: `page`, `perPage`, `name`, `email`, `role`.

### 2.5 Email Delivery  
* SMTP transport configured with `EMAIL_*` vars  
* Templates: `passwordReset`, `passwordChange`  
* Password-reset mail includes `passwordResetUrl` containing reset token

### 2.6 Documentation & Status  
* `GET /v1/docs` – generated API docs  
* `GET /v1/status` – simple health check (`OK`)

---

## 3. Non-Functional Requirements  
Performance Stateless JWT auth; MongoDB indexes on token fields  
Scalability Horizontally scalable; application instances are stateless  
Security bcrypt password hashing (10 rounds; 1 in tests), Helmet headers, assumed HTTPS, CORS enabled  
Maintainability Layered folder structure (config, middleware, services, models, controllers, routes)  
Logging Console in non-production, file logs (`combined.log`, `error.log`) in production  
Testing Mocha, Chai, Supertest with unit and integration suites  
Constraints Node ≥ 8

---

## 4. Data Structures and Models

### 4.1 User (`users` collection)

Field | Type | Rules
----- | ---- | -----
email | String | unique, lowercase, regex, required
password | String | bcrypt hash, 6–128, required
name | String | ≤128
services.facebook / services.google | String | OAuth IDs
role | Enum `user` \| `admin` | default `user`
picture | String |
timestamps | `createdAt`, `updatedAt`

### 4.2 RefreshToken (`refresh_tokens` collection)

Field | Type | Notes
----- | ---- | -----
token | String (indexed) | `<userId>.<80-hex>` (40 random bytes → 80-char hex)
userId | ObjectId → User | required
userEmail | String | required
expires | Date | +30 days

### 4.3 PasswordResetToken (`password_reset_tokens` collection)

Field | Type | Notes
----- | ---- | -----
resetToken | String (indexed) | `<userId>.<80-hex>` (40 random bytes → 80-char hex)
userId | ObjectId → User | required
userEmail | String | required
expires | Date | +2 hours

### 4.4 JWT Payload
```
{
  exp: <unix seconds>,   // expiry = now + JWT_EXPIRATION_MINUTES
  iat: <unix seconds>,   // issued at
  sub: <userId>          // subject
}
```

---

## 5. Algorithms and Logic

### 5.1 Registration  
```
if user with email exists → 409
hash password
create user document
generate accessToken (JWT)
create refresh token document (expires +30d)
return {token, user}
```

### 5.2 Login  
```
find user by email
if user missing OR bcrypt.compare(password) fails → 401
generateTokenResponse(user)
```

### 5.3 OAuth Login  
```
call provider API using received access_token
normalize provider response → {service,id,email,name,picture}
User.oAuthLogin():
  search by services.<service> id OR email
  if found → update missing fields
  else → create user with random uuid password
generateTokenResponse(user)
```

### 5.4 Token Refresh  
```
find & remove RefreshToken by email + token
if not found OR expired → 401
issue new accessToken and new refreshToken
return response
```

### 5.5 Password Reset Flow  
Send link  
```
find user by email → if none → 401
create PasswordResetToken (+2h)
send email with token
```
Reset  
```
find & remove PasswordResetToken by email + token
if not found OR expired → 401
update user.password (bcrypt hash)
send confirmation email
```

### 5.6 Authorization Middleware (pseudo)  
```
passport.authenticate('jwt')
if !user OR role check fails → 403
attach req.user and continue
```

---

## 6. Interface Definitions

### 6.1 HTTP API  
See Functional Requirement tables.

Common headers  
* `Content-Type: application/json`  
* `Authorization: Bearer <accessToken>` (when required)

### 6.2 Internal Services  
* `authProviders.facebook(token)` → normalized user info  
* `authProviders.google(token)` → normalized user info  
* `emailProvider.sendPasswordReset(resetTokenDoc)`  
* `emailProvider.sendPasswordChangeEmail(user)`

### 6.3 Config Modules  
`config/vars.js` exports  
```
{
  env,
  port,
  jwtSecret,
  jwtExpirationInterval, // derived from JWT_EXPIRATION_MINUTES
  mongo: { uri },
  logs,
  emailConfig: { host, port, username, password }
}
```
`config/logger.js` exports Winston logger with `stream.write()` for Morgan.

---

## 7. Error Handling and Validation

* Request validation via `express-validation` (Joi schemas)  
* Middleware `error.converter` transforms unknown errors to `APIError`  
* `error.handler` JSON format: `{code, message, errors?, stack?}`; stack returned only in development  
* 404 handled by `error.notFound`  
* HTTP status codes follow `http-status` enum  
* Unique-email conflicts mapped to 409 (`User.checkDuplicateEmail`)

---

## 8. Technical Dependencies

Category | Packages
-------- | --------
Web | express
Database | mongoose, MongoDB
Auth | passport, passport-jwt, passport-http-bearer, jsonwebtoken, bcryptjs
Validation | joi, express-validation
Logging | winston, morgan
Config | dotenv-safe, cross-env
Email | nodemailer, email-templates
Utilities | lodash, moment-timezone, uuid, axios, bluebird
Security / headers | helmet, cors, compression, method-override
Testing | mocha, chai, chai-as-promised, sinon, supertest, nyc
Process mgr | pm2
Docs | apidoc

---

## 9. Testing and Validation

Strategy  
* Unit tests: models, services  
* Integration tests: all API routes (`/tests/integration`)  
* Test DB: `MONGO_URI_TESTS`, `NODE_ENV=test`  
* Coverage via `nyc` (HTML + text + Coveralls)

Representative cases  
1. Registration success & duplicate e-mail conflict  
2. Login (success / wrong password / invalid input)  
3. JWT expiry using Sinon timers  
4. Role enforcement (`ADMIN` vs regular)  
5. Refresh token (valid / invalid / expired)  
6. Entire password-reset flow  
7. CRUD operations with permission checks

---

## 10. Deployment and Configuration

### 10.1 Environment Files  
`.env` – real values  
`.env.example` – template including `MONGO_URI_TESTS`

### 10.2 NPM/Yarn Scripts  
Command | Purpose
------- | -------
`yarn dev` | start with nodemon  
`yarn start` | production via pm2  
`yarn validate` | lint + tests  
`yarn docs` | generate API docs  
`docker:dev / docker:prod / docker:test` | compose variants

### 10.3 PM2  
`pm2 start ./src/index.js` (or `pm2-docker` inside containers)

### 10.4 Logging  
* `combined.log` and `error.log` in project root  
* Console logging when `NODE_ENV !== 'production'`

### 10.5 Database  
* URI from `MONGO_URI` (or `MONGO_URI_TESTS` in tests)  
* Mongoose options: `useNewUrlParser`, `useUnifiedTopology`, `useCreateIndex`, `keepAlive`, `useFindAndModify=false`

### 10.6 Email  
* SMTP based on `EMAIL_*`  
* `transporter.verify()` executed at startup; errors are logged

### 10.7 Build & Runtime Requirements  
* Node.js 8+  
* Yarn  
* Accessible MongoDB instance  
* SMTP server for e-mails

---