Skip to content

dogukan10/angular-test

Repository files navigation

MEAN Stack Starter Project

A minimal MEAN stack (MongoDB, Express, Angular, Node.js) project for interns — a login form backed by a real Express API and a MongoDB database, with a default admin user created automatically.


Architecture

Angular dev server (:4200)  --/api/*-->  Express (:3000)  --Mongoose-->  MongoDB (:27017)
  • Angular (src/) — the frontend. In development, its dev server proxies any request to /api/* straight through to the Express server, so the browser never needs to know about port 3000 directly and there's no CORS to think about.
  • Express (server/) — the backend API. It exposes POST /api/auth/login, which checks the submitted username/password against MongoDB.
  • MongoDB — the database. It stores user documents. Note: passwords are currently stored in plaintext on purpose — see Suggested Exercises for Interns. You can run MongoDB via Docker (no local install needed) or install it directly on your machine — see Prerequisites.

The frontend and backend are two independent Node projects (separate package.json, separate node_modules) living in one repository. This keeps the two stacks easy to reason about separately — you can work on the Angular app without touching the backend, and vice versa.

Why the proxy? (CORS)

The Angular dev server runs on http://localhost:4200, and Express runs on a different port, http://localhost:3000. From a browser's point of view, those are two different origins (same host, different port still counts as a different origin), and browsers block a page from one origin from calling an API on another origin unless that API explicitly allows it — this is called CORS (Cross-Origin Resource Sharing). Without anything in place, AuthService's call to /api/auth/login would fail in the browser console with a CORS error, even though the request works fine from something like curl or Postman (those tools don't enforce CORS — only browsers do).

This project avoids the problem entirely in development: proxy.conf.json (wired up in angular.json) tells the Angular dev server "any request to /api/* isn't actually for me — silently forward it to http://localhost:3000 and hand back the response." The browser only ever talks to localhost:4200, so as far as it's concerned there's no cross-origin request happening at all, and no CORS error to hit.

The cors() middleware in server/src/app.ts is a second, independent layer of protection — it's what would matter if you called the API directly from a different origin (e.g. a production build served from a different domain, or a tool that bypasses the proxy). You don't need it for the standard npm run dev flow, but it's there so the API still works if the proxy isn't in the picture.


Prerequisites

Make sure the following are installed before you begin:

Tool Required version Check Download
Node.js 22.22.3 or newer node --version nodejs.org/en/download
npm 10 or newer npm --version Included with Node.js
Angular CLI 22.x ng version npm install -g @angular/cli (see below)

Install Angular CLI globally if you don't have it:

npm install -g @angular/cli

MongoDB: pick one option

You need a MongoDB instance running on localhost:27017. Pick whichever is easier for you — the app doesn't care which one you use, since both are reachable at the same address.

Option Best for Download
A. Docker (recommended) No local install, easiest to reset/wipe docker.com/get-started
B. MongoDB Community Server If you'd rather not use Docker at all mongodb.com/try/download/community
  • If you choose Docker: on Windows, make sure Docker Desktop is running and using the WSL2 backend (Docker Desktop → Settings → General → "Use the WSL 2 based engine"). Docker Desktop must be running before you start MongoDB with npm run mongo:up (see Getting Started).
  • If you choose MongoDB Community Server: install it and make sure the MongoDB service is running locally (it listens on localhost:27017 by default, same as the Docker option). You can then skip npm run mongo:up/npm run mongo:down/npm run mongo:logs entirely — those are Docker-only scripts.

Optional but recommended either way: MongoDB Compass is a free GUI for browsing your database. Once MongoDB is running, connect it to mongodb://localhost:27017 to inspect the angular_test database and its users collection visually instead of using the mongosh CLI.


Getting Started

1. Clone the repository

git clone https://github.com/dogukan10/angular-test.git
cd angular-test

2. Install dependencies (frontend and backend)

npm install
npm run server:install

3. Start MongoDB

Pick the option that matches what you installed in Prerequisites:

Option A — Docker:

npm run mongo:up

This starts a MongoDB container in the background (docker compose up -d). It stays running until you stop it with npm run mongo:down, so you typically only need to run this once per work session.

Option B — MongoDB Community Server: make sure the MongoDB service is running locally (it starts automatically as a background service on most installs — check your OS's services list if you're not sure). Nothing else to do here; skip npm run mongo:up.

4. Start the frontend and backend together

npm run dev

This runs the Angular dev server and the Express server side by side (via concurrently), both with live reload. Watch the terminal output for:

  • Server listening on http://localhost:3000 and Created default admin user "admin". (Express)
  • Local: http://localhost:4200/ (Angular)

5. Open the UI

Navigate to http://localhost:4200 in your browser. The login form appears immediately.


Demo Credentials & Scenarios

Credentials are validated against a real MongoDB document.

Scenario 1 — Successful login

Field Value
Username admin
Password password123

Expected result: A green success banner appears with the message "Welcome, admin!"

Scenario 2 — Failed login

Enter any other username/password combination (e.g. user / wrong) and click Login.

Expected result: A red error banner appears with the message "Invalid credentials. Please try again."

Scenario 3 — Empty fields

Leave either field blank and try to submit.

Expected result: The Login button is disabled and inline validation hints appear beneath the empty fields.


Folder Structure

angular-test/
├── src/
│   ├── app/
│   │   ├── components/
│   │   │   └── login/
│   │   │       ├── login.ts        # Login component — form logic, calls AuthService
│   │   │       ├── login.html      # Form template with reactive bindings
│   │   │       └── login.css       # Component-scoped styles
│   │   ├── services/
│   │   │   └── auth.service.ts     # AuthService — calls the backend login API
│   │   ├── app.ts                  # Root component — hosts <app-login>
│   │   └── app.config.ts           # Application-level providers (incl. HttpClient)
│   ├── styles.css                  # Global stylesheet
│   ├── index.html                  # HTML shell — Angular mounts inside <app-root>
│   └── main.ts                     # Entry point — bootstraps the application
├── server/                         # Express + TypeScript backend (independent Node project)
│   ├── src/
│   │   ├── index.ts                # Entry point — connects DB, creates the admin user, starts the server
│   │   ├── app.ts                  # Builds the Express app (middleware + routes)
│   │   ├── config/env.ts           # Reads environment variables with sane defaults
│   │   ├── db/connection.ts        # Connects to MongoDB via Mongoose
│   │   ├── models/user.model.ts    # Mongoose User schema (username, password, role)
│   │   ├── controllers/auth.controller.ts  # Login request handler
│   │   ├── routes/auth.routes.ts   # POST /login route
│   │   └── admin/createAdminUser.ts  # Creates the default admin user if it doesn't exist
│   └── package.json                # Backend dependencies and scripts
├── docker-compose.yml               # Spins up MongoDB for local development (only needed if using Docker)
├── proxy.conf.json                  # Angular dev-server proxy: /api/* → localhost:3000
├── package.json                     # npm dependencies and scripts (start, build, test, dev, ...)
└── angular.json                     # Angular CLI workspace configuration

Key files explained

Frontend

  • src/main.ts — The first file that runs. It calls bootstrapApplication(App, appConfig) to mount the Angular app into the browser.
  • src/app/app.config.ts — Registers app-wide providers, including provideHttpClient() so services can make HTTP calls.
  • src/app/app.ts — The root component (<app-root>). Currently it just renders <app-login> to keep the top level clean.
  • src/app/components/login/login.ts — The Login component class. It creates a reactive form and, on submit, subscribe()s to AuthService.login() to update the result message. message/isSuccess are signals, so the template updates automatically whenever they change.
  • src/app/components/login/login.html — The form template. Uses Angular's [formGroup] binding, @if control flow, and [class] binding to render validation messages and the result banner. Signals are read as functions (message(), isSuccess()).
  • src/app/services/auth.service.ts — Calls POST /api/auth/login via HttpClient and returns an Observable<{ success, message }>. Non-2xx responses (400/401/500) are caught with catchError and turned into a normal { success: false, message } emission, so components only need to handle the success path.

Backend

  • server/src/index.ts — Boots the server: connects to MongoDB, creates the default admin user, then starts listening.
  • server/src/app.ts — Builds the Express app: CORS, JSON body parsing, and the /api/auth routes.
  • server/src/config/env.ts — Centralizes all environment variables (port, Mongo URI, admin credentials, CORS origin) with defaults so the app runs even without a .env file.
  • server/src/db/connection.ts — Connects to MongoDB using Mongoose.
  • server/src/models/user.model.ts — The Mongoose schema for users: username, password, role. TODO (intern exercise): the password is stored as plaintext — see Suggested Exercises for Interns.
  • server/src/controllers/auth.controller.ts — Handles POST /api/auth/login: looks up the user, compares the password directly, and responds with a success or error message. TODO (intern exercise): swap the plaintext comparison for a hashed one.
  • server/src/admin/createAdminUser.ts — Creates the default admin user if it doesn't already exist. Runs automatically on server startup, and can also be run standalone via npm run server:create-admin.

API Reference

POST /api/auth/login (http://localhost:3000, proxied to /api/auth/login from the Angular app)

Request body:

{ "username": "admin", "password": "password123" }

Response is always { "success": boolean, "message": string }:

Case Status Message
Valid credentials 200 Welcome, <username>!
Missing username/password 400 Username and password are required.
Unknown user or wrong password 401 Invalid credentials. Please try again.
Server/database error 500 Something went wrong. Please try again later.

Resetting the Database

  • Recreate the admin user without losing other data: npm run server:create-admin — safe to run any time; it does nothing if the admin user already exists. Works the same regardless of which MongoDB option you chose.
  • Wipe everything and start fresh:
    • Docker:
      npm run mongo:down
      docker compose down -v   # -v also removes the Mongo data volume
      npm run mongo:up
      npm run dev              # server automatically recreates the admin user on boot
    • MongoDB Community Server: drop the database directly, then restart the backend:
      mongosh --eval "use angular_test" --eval "db.dropDatabase()"
      npm run dev              # server automatically recreates the admin user on boot

Available Scripts

Run from the repository root:

Command Description
npm run dev Start the Angular dev server and the Express server together, with live reload
npm start Start only the Angular dev server at http://localhost:4200
npm run build Build the Angular app for production into dist/
npm test Run Angular unit tests with Vitest
npm run mongo:up (Docker only) Start the MongoDB container (detached)
npm run mongo:down (Docker only) Stop the MongoDB container
npm run mongo:logs (Docker only) Tail the MongoDB container logs
npm run server:install Install backend dependencies (server/node_modules)
npm run server:dev Start only the Express server with live reload
npm run server:create-admin Manually (re)create the default admin user

Inside server/, the same backend scripts are also available directly: npm run dev, npm run build, npm start, npm run create-admin.


Troubleshooting

  • Express fails to start with ECONNREFUSED — MongoDB isn't running.
    • Docker: check docker ps for angular-test-mongo, make sure Docker Desktop is open, then run npm run mongo:up.
    • MongoDB Community Server: check that the MongoDB service is actually running (check your OS's services list, or try starting it manually).
  • First docker compose up takes a while — Docker is downloading the mongo:7 image the first time. This is normal and only happens once. (Not applicable if you're using MongoDB Community Server.)
  • "Port already in use" — something else is using 3000, 4200, or 27017. Find and stop it:
    netstat -ano | findstr :3000
    taskkill /PID <pid> /F
    If you change PORT in server/.env, also update the target in proxy.conf.json to match.
  • CORS error in the browser console — this shouldn't happen with the normal npm run dev flow, since the Angular dev server proxies /api/* requests to Express. It usually means the app was opened outside the dev server (e.g. a production build served directly) or an absolute URL was hardcoded somewhere instead of the relative /api/... path.
  • Login always fails right after cloning — check the Express startup logs for Created default admin user "admin".. If it's missing, MongoDB probably wasn't reachable when the server started; confirm MongoDB is actually running (docker ps for Docker, or your OS's services list for MongoDB Community Server), then restart the server.

Suggested Exercises for Interns

This project is intentionally left with a few rough edges to fix as learning exercises. They're marked with TODO (intern exercise) comments in the code:

  • Hash passwords instead of storing them in plaintext. server/src/models/user.model.ts stores password as-is, and server/src/controllers/auth.controller.ts compares it with ===. Try using a library like bcrypt or bcryptjs to hash the password before saving it (in server/src/admin/createAdminUser.ts) and to compare it safely on login (in auth.controller.ts). After changing this, you'll need to reset the database (see Resetting the Database) since existing plaintext passwords won't match a hashed comparison.

About

Angular Test Project

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors