# ๐Ÿ” Express, AWS Lambda ๋ฐ Dynamo DB๋ฅผ ์ด์šฉํ•œ ๋กœ๊ทธ์ธ ๋ฐฑ์—”๋“œ

๋ฐœํ–‰: (2025๋…„ 12์›” 20์ผ ์˜ค์ „ 02:27 GMT+9)
8 min read
์›๋ฌธ: Dev.to

Source: Dev.to

Puffer

Node.js์™€ Express๋กœ ๊ตฌ์ถ•๋œ ์ธ์ฆ ๋ฐ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๊ฒฌ๊ณ ํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ๋ฐฑ์—”๋“œ API์ž…๋‹ˆ๋‹ค. ๋ณด์•ˆ ๋กœ๊ทธ์ธ/ํšŒ์›๊ฐ€์ž…, ์—ญํ•  ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋ฉฐ AWS DynamoDB, Stripe, Brevo์™€ ์›ํ™œํ•˜๊ฒŒ ํ†ตํ•ฉ๋ฉ๋‹ˆ๋‹ค.

โœจ ๊ธฐ๋Šฅ

  • ๐Ÿ” ์ธ์ฆ ์‹œ์Šคํ…œ โ€“ JWT ํ† ํฐ์„ ์ด์šฉํ•œ ์•ˆ์ „ํ•œ ์‚ฌ์šฉ์ž ๋“ฑ๋ก ๋ฐ ๋กœ๊ทธ์ธ
  • ๐Ÿ‘ฅ ์—ญํ•  ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด โ€“ 4๋‹จ๊ณ„ ์—ญํ•  ์‹œ์Šคํ…œ (User, Agent, Master, Super Admin)
  • ๐Ÿ”’ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณด์•ˆ โ€“ ์•ˆ์ „ํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅ์„ ์œ„ํ•œ Bcrypt ํ•ด์‹œ
  • ๐Ÿ“Š DynamoDB ํ†ตํ•ฉ โ€“ AWS DynamoDB๋ฅผ ์ด์šฉํ•œ NoSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…
  • ๐Ÿ’ณ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ โ€“ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ Stripe ํ†ตํ•ฉ
  • ๐Ÿ“ง ์ด๋ฉ”์ผ ์„œ๋น„์Šค โ€“ ์ด๋ฉ”์ผ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜์„ ์œ„ํ•œ Brevo ํ†ตํ•ฉ
  • ๐Ÿš€ ์„œ๋ฒ„๋ฆฌ์Šค ์ค€๋น„ โ€“ AWS Lambda ํ•จ์ˆ˜๋กœ ๋ฐฐํฌ ๊ฐ€๋Šฅ
  • ๐Ÿ›ก๏ธ ๋ณด์•ˆ ๋ฏธ๋“ค์›จ์–ด โ€“ JWT ์ธ์ฆ ๋ฐ ์ธ๊ฐ€ ๋ฏธ๋“ค์›จ์–ด
  • ๐Ÿ“ ์ž…๋ ฅ ๊ฒ€์ฆ โ€“ ํšŒ์›๊ฐ€์ž… ๋ฐ ๋กœ๊ทธ์ธ ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•œ ์š”์ฒญ ๊ฒ€์ฆ
  • ๐Ÿ—๏ธ MVC ์•„ํ‚คํ…์ฒ˜ โ€“ ๋ชจ๋ธ, ๋ทฐ, ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ†ตํ•œ ๋ช…ํ™•ํ•œ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ

๐Ÿ› ๏ธ ๊ธฐ์ˆ  ์Šคํƒ

๊ตฌ์„ฑ ์š”์†Œ๊ธฐ์ˆ 
๋Ÿฐํƒ€์ž„Node.js
ํ”„๋ ˆ์ž„์›ŒํฌExpress.js
๋ฐ์ดํ„ฐ๋ฒ ์ด์ŠคAWS DynamoDB
์ธ์ฆJWT (JSON Web Tokens)
๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹ฑbcryptjs
๊ฒฐ์ œStripe
์ด๋ฉ”์ผBrevo (formerly Sendinblue)
๋ฐฐํฌServerless (AWS Lambda compatible)

๐Ÿ“‹ ํ•„์ˆ˜ ์กฐ๊ฑด

  • Node.js (v14 ์ด์ƒ)
  • npm ๋˜๋Š” yarn
  • AWS ๊ณ„์ • (DynamoDB์šฉ)
  • Stripe ๊ณ„์ • (๊ฒฐ์ œ ์ฒ˜๋ฆฌ์šฉ)
  • Brevo ๊ณ„์ • (์ด๋ฉ”์ผ ์„œ๋น„์Šค์šฉ)

๐Ÿš€ ์„ค์น˜

1. ์ €์žฅ์†Œ ๋ณต์ œ

git clone https://github.com/puffer-git/login-dynamo-db.git
cd login-dynamo-db

2. ์˜์กด์„ฑ ์„ค์น˜

npm install

3. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์„ค์ •

๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์— .env ํŒŒ์ผ์„ ๋งŒ๋“ค๊ณ  ๋‹ค์Œ ๋ณ€์ˆ˜๋ฅผ ์„ค์ •ํ•˜์„ธ์š”:

# Server Configuration
ENVIRONMENT=development
PORT=4000

# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
JWT_EXPIRES_IN=7d

# AWS DynamoDB Configuration
AWSREGION=us-east-1
AWSENDPOINT=https://dynamodb.us-east-1.amazonaws.com
AWSACCESSKEYID=your-aws-access-key-id
AWSSECRETKEY=your-aws-secret-access-key

# Stripe Configuration (optional)
STRIPE_SECRET_KEY=your-stripe-secret-key

# Brevo Configuration (optional)
BREVO_API_KEY=your-brevo-api-key

4. DynamoDB ํ…Œ์ด๋ธ” ์„ค์ •

users ๋ผ๋Š” ์ด๋ฆ„์˜ DynamoDB ํ…Œ์ด๋ธ”์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ƒ์„ฑํ•˜์„ธ์š”:

  • Partition Key: id (String)
  • Pointโ€‘inโ€‘time recovery: ํ™œ์„ฑํ™” (ํ”„๋กœ๋•์…˜์—์„œ๋Š” ๊ถŒ์žฅ)

๐Ÿƒ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์‹คํ–‰

๊ฐœ๋ฐœ ๋ชจ๋“œ

npm run dev

์„œ๋ฒ„๋Š” http://localhost:4000์—์„œ ์ž๋™ ์žฌ๋กœ๋“œ๊ฐ€ ํ™œ์„ฑํ™”๋œ ์ƒํƒœ๋กœ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ๋•์…˜ ๋ชจ๋“œ

npm start

์„œ๋ฒ„๋ฆฌ์Šค ๋ฐฐํฌ

ENVIRONMENT=production์ผ ๋•Œ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ AWS Lambda ๋ฐฐํฌ์— ์ ํ•ฉํ•œ ์„œ๋ฒ„๋ฆฌ์Šค ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.

๐Ÿ“š API ๋ฌธ์„œ

๊ธฐ๋ณธ URL

  • ๊ฐœ๋ฐœ: http://localhost:4000
  • ํ”„๋กœ๋•์…˜: ๋ฐฐํฌ๋œ ์—”๋“œํฌ์ธํŠธ

์ธ์ฆ ์—”๋“œํฌ์ธํŠธ

์ƒˆ ์‚ฌ์šฉ์ž ๋“ฑ๋ก

POST /auth/signup
Content-Type: application/json

{
  "player_name": "johndoe",
  "email": "john@example.com",
  "password": "securePassword123",
  "name": "John Doe"   // optional
}

์‘๋‹ต (201 Created)

{
  "success": true,
  "message": "User created successfully",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}

์˜ค๋ฅ˜ ์‘๋‹ต

  • 409 Conflict โ€“ ํ”Œ๋ ˆ์ด์–ด ์ด๋ฆ„ ๋˜๋Š” ์ด๋ฉ”์ผ์ด ์ด๋ฏธ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค
  • 400 Bad Request โ€“ ๊ฒ€์ฆ ์˜ค๋ฅ˜
  • 500 Internal Server Error โ€“ ์„œ๋ฒ„ ์˜ค๋ฅ˜

๋กœ๊ทธ์ธ

POST /auth/login
Content-Type: application/json

{
  "identifier": "johndoe",   // Can be email or player_name
  "password": "securePassword123"
}

์‘๋‹ต (200 OK)

{
  "success": true,
  "message": "Login successful",
  "data": {
    "user": {
      "role": "user",
      "player_name": "johndoe",
      "email": "john@example.com",
      "name": "John Doe"
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
  }
}

์˜ค๋ฅ˜ ์‘๋‹ต

  • 401 Unauthorized โ€“ ์ธ์ฆ ์ •๋ณด๊ฐ€ ์œ ํšจํ•˜์ง€ ์•Š์Œ
  • 400 Bad Request โ€“ ๊ฒ€์ฆ ์˜ค๋ฅ˜
  • 500 Internal Server Error โ€“ ์„œ๋ฒ„ ์˜ค๋ฅ˜

์ธ์ฆ ํ—ค๋”

๋ณดํ˜ธ๋œ ๋ผ์šฐํŠธ์—์„œ๋Š” Authorization ํ—ค๋”์— JWT ํ† ํฐ์„ ํฌํ•จํ•˜์„ธ์š”:

Authorization: Bearer <token>

๐Ÿ—๏ธ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ

login-dynamo-db/
โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ constants/
โ”‚   โ”‚   โ”œโ”€โ”€ roles.js          # Role definitions and hierarchy
โ”‚   โ”‚   โ””โ”€โ”€ tables.js         # DynamoDB table configurations
โ”‚   โ”œโ”€โ”€ controllers/
โ”‚   โ”‚   โ””โ”€โ”€ auth/
โ”‚   โ”‚       โ”œโ”€โ”€ login/
โ”‚   โ”‚       โ”‚   โ”œโ”€โ”€ login.js
โ”‚   โ”‚       โ”‚   โ””โ”€โ”€ loginValidation.js
โ”‚   โ”‚       โ””โ”€โ”€ signup/
โ”‚   โ”‚           โ”œโ”€โ”€ signup.js
โ”‚   โ”‚           โ””โ”€โ”€ signupValidation.js
โ”‚   โ”œโ”€โ”€ db/
โ”‚   โ”‚   โ”œโ”€โ”€ dynamoClient.js   # DynamoDB client configuration
โ”‚   โ”‚   โ””โ”€โ”€ index.js          # Database exports
โ”‚   โ”œโ”€โ”€ middleware/
โ”‚   โ”‚   โ””โ”€โ”€ auth.js
โ”‚   โ””โ”€โ”€ ... (other folders/files)
โ”œโ”€โ”€ config/
โ”‚   โ””โ”€โ”€ ... (configuration files)
โ”œโ”€โ”€ routes/
โ”‚   โ””โ”€โ”€ ... (route definitions)
โ”œโ”€โ”€ services/
โ”‚   โ””โ”€โ”€ ... (business logic, e.g., Stripe, Brevo)
โ”œโ”€โ”€ tests/
โ”‚   โ””โ”€โ”€ ... (unit/integration tests)
โ”œโ”€โ”€ .env.example
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ README.md

์ถ”๊ฐ€ ๊ตฌ์กฐ:

โ”œโ”€โ”€ app/
โ”‚   โ”œโ”€โ”€ middleware/
โ”‚   โ”‚   โ””โ”€โ”€ auth.js               # Authentication & authorization middleware
โ”‚   โ”œโ”€โ”€ models/
โ”‚   โ”‚   โ”œโ”€โ”€ BaseModel.js           # Base model for DynamoDB operations
โ”‚   โ”‚   โ””โ”€โ”€ UserModel.js           # User model with business logic
โ”‚   โ”œโ”€โ”€ routes/
โ”‚   โ”‚   โ”œโ”€โ”€ auth.js                # Authentication routes
โ”‚   โ”‚   โ””โ”€โ”€ index.js               # Route aggregator
โ”‚   โ”œโ”€โ”€ utils/
โ”‚   โ”‚   โ””โ”€โ”€ userUtils.js           # User utility functions
โ”‚   โ””โ”€โ”€ index.js                   # Express app configuration
โ”œโ”€โ”€ index.js                       # Application entry point
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ README.md

๐Ÿ” ์—ญํ•  ์‹œ์Šคํ…œ

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ 4๋‹จ๊ณ„ ์—ญํ•  ๊ณ„์ธต์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

  • USER โ€“ ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์—ญํ•  (๊ธฐ๋ณธ๊ฐ’)
  • AGENT โ€“ ์—์ด์ „ํŠธ ์ˆ˜์ค€ ๊ถŒํ•œ
  • MASTER โ€“ ๋งˆ์Šคํ„ฐ ์ˆ˜์ค€ ๊ถŒํ•œ
  • SUPER_ADMIN โ€“ ์ตœ๊ณ  ์ˆ˜์ค€ ์ ‘๊ทผ ๊ถŒํ•œ

์—ญํ• ์€ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ํ†ตํ•ด ํ™•์ธ๋ฉ๋‹ˆ๋‹ค:

  • authenticate โ€“ JWT ํ† ํฐ ๊ฒ€์ฆ
  • authorize(roles) โ€“ ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ์—ญํ• ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธ
  • requireMinimumRole(role) โ€“ ์‚ฌ์šฉ์ž๊ฐ€ ์ตœ์†Œ ์—ญํ•  ์ˆ˜์ค€์„ ์ถฉ์กฑํ•˜๋Š”์ง€ ํ™•์ธ

๐Ÿงช ๊ฐœ๋ฐœ

์ฝ”๋“œ ์Šคํƒ€์ผ

  • ๊ธฐ์กด ์ฝ”๋“œ ํŒจํ„ด์„ ๋”ฐ๋ฅด์„ธ์š”.
  • ์˜๋ฏธ ์žˆ๋Š” ๋ณ€์ˆ˜ ๋ฐ ํ•จ์ˆ˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
  • ํ•จ์ˆ˜์— JSDoc ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
  • ํ•จ์ˆ˜๋Š” ํ•˜๋‚˜์˜ ๋ชฉ์ ์— ์ง‘์ค‘ํ•˜๋„๋ก ์œ ์ง€ํ•˜์„ธ์š”.

์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€

  1. ๊ธฐ๋Šฅ ๋ธŒ๋žœ์น˜๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”:

    git checkout -b feature/your-feature-name
  2. MVC ์•„ํ‚คํ…์ฒ˜๋ฅผ ๋”ฐ๋ฅด์„ธ์š”:

    • Models โ†’ app/models/
    • Controllers โ†’ app/controllers/
    • Routes โ†’ app/routes/
    • Middleware โ†’ app/middleware/
  3. ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋Œ€ํ•œ ๊ฒ€์ฆ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

  4. ๋ช…ํ™•ํ•œ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”.

  5. ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.

  6. ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๋ฅผ ์ œ์ถœํ•˜์„ธ์š”.

๐Ÿค ๊ธฐ์—ฌ

Contributions are welcome! Please follow these steps:

  1. Fork the repository.

  2. Create your feature branch:

    git checkout -b feature/AmazingFeature
  3. Commit your changes:

    git commit -m 'Add some AmazingFeature'
  4. Push to the branch:

    git push origin feature/AmazingFeature
  5. Open a Pull Request.

๊ธฐ์—ฌ ๊ฐ€์ด๋“œ๋ผ์ธ

  • Write clear, readable code. โ†’ ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ€๋…์„ฑ ์ข‹์€ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”.
  • Add comments for complex logic. โ†’ ๋ณต์žกํ•œ ๋กœ์ง์—๋Š” ์ฃผ์„์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
  • Follow the existing code structure. โ†’ ๊ธฐ์กด ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ๋”ฐ๋ฅด์„ธ์š”.
  • Test your changes before submitting. โ†’ ์ œ์ถœํ•˜๊ธฐ ์ „์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”.
  • Update documentation if needed. โ†’ ํ•„์š”ํ•˜๋ฉด ๋ฌธ์„œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜์„ธ์š”.

๐Ÿ“ ๋ผ์ด์„ ์Šค

์ด ํ”„๋กœ์ ํŠธ๋Š” MIT ๋ผ์ด์„ ์Šค์— ๋”ฐ๋ผ ๋ผ์ด์„ ์Šค๊ฐ€ ๋ถ€์—ฌ๋ฉ๋‹ˆ๋‹ค โ€“ ์ž์„ธํ•œ ๋‚ด์šฉ์€ LICENSE ํŒŒ์ผ์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

๐Ÿ“ง ์—ฐ๋ฝ์ฒ˜

๊ฐœ๋ฐœ์ž: Puffer

๐Ÿ™ Acknowledgments

  • Express.js ๋กœ ๊ตฌ์ถ•
  • AWS DynamoDB ๋กœ ๊ตฌ๋™๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
  • Stripe ๋กœ ๊ฒฐ์ œ ์ฒ˜๋ฆฌ
  • Brevo ๋กœ ์ด๋ฉ”์ผ ์„œ๋น„์Šค

โญ๏ธ ์ง€์›

์ด ํ”„๋กœ์ ํŠธ๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๋ณ„ํ‘œ๋ฅผ ๋ˆŒ๋Ÿฌ ์ฃผ์„ธ์š”!

Back to Blog

๊ด€๋ จ ๊ธ€

๋” ๋ณด๊ธฐ ยป

์ฐฝ๊ณ  ํ™œ์šฉ์— ๋Œ€ํ•œ ์ข…ํ•ฉ ๊ฐ€์ด๋“œ

์†Œ๊ฐœ ์ฐฝ๊ณ ๋Š” ๊ทผ๋ณธ์ ์œผ๋กœ 3โ€‘D ๋ฐ•์Šค์ผ ๋ฟ์ž…๋‹ˆ๋‹ค. Utilisation์€ ์‹ค์ œ๋กœ ๊ทธ ๋ฐ•์Šค๋ฅผ ์–ผ๋งˆ๋‚˜ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”์ง€๋ฅผ ์ธก์ •ํ•˜๋Š” ์ง€ํ‘œ์ž…๋‹ˆ๋‹ค. While logistics c...

CinemaSins: ๋ ˆ๋“œ ์›์˜ ๋ชจ๋“  ์ž˜๋ชป์„ 18๋ถ„ ์ด๋‚ด์—

๊ฐœ์š”: โ€œEverything Wrong With Red One in 18 Minutes Or Lessโ€๋Š” ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ํ”Œ๋กฏ์˜ ํœด๊ฐ€ ๋ธ”๋ก๋ฒ„์Šคํ„ฐ์— ์ถ•์ œ์ ์ธ ๋ฐ˜์ „์„ ๊ฐ€ํ•˜๋ฉฐ, ๋ชจ๋“  โ€œsinโ€์„ ์ฐจ๋ก€๋กœ ๋‚˜์—ดํ•œ๋‹ค.

1์–ต ๊ฐœ์˜ ์‹ฌ์žฅ ๋ฐ•๋™ ์ˆ˜์ง‘: ํŒŒ์‚ฐ ์—†์ด Wearable Tech ํ™•์žฅ

โ€œContinuousโ€์˜ ์ˆ˜ํ•™ ์ˆซ์ž์— ๋Œ€ํ•ด ํ˜„์‹ค์ ์œผ๋กœ ์ด์•ผ๊ธฐํ•ด๋ด…์‹œ๋‹ค. ์žฅ์น˜๊ฐ€ 1์ดˆ์— ํ•œ ๋ฒˆ, ์ฆ‰ 1 Hz๋กœ ํ•˜ํŠธ๋น„ํŠธ ํŽ˜์ด๋กœ๋“œ๋ฅผ ์ „์†กํ•œ๋‹ค๋ฉด: - 1 User = 86,400 writes/day. - 1,000 Use...