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
13 changes: 12 additions & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
}
},
"customizations": {
"codespaces": {
"openFiles": [
"codespaces.md"
]
},
"vscode": {
"extensions": [
"mongodb.mongodb-vscode"
Expand All @@ -22,7 +27,8 @@
],
"portsAttributes": {
"4200": {
"label": "Angular Client"
"label": "Angular Client",
"onAutoForward": "openPreview"
},
"5300": {
"label": "Express API"
Expand All @@ -35,5 +41,10 @@
"postStartCommand": "bash -lc 'for i in {1..60}; do mongosh --quiet \"$DATABASE_URI\" --eval \"db.hello().isWritablePrimary\" | grep -q true && break; sleep 2; done; npm run seed'",
"remoteEnv": {
"DATABASE_URI": "mongodb://localhost:27017/meanStackExample?appName=mean-stack-example-devcontainer"
},
"postAttachCommand": {
"server": "cd server && npm start",
"client": "export NG_CLI_ANALYTICS=\"false\"; cd client && npm start",
"portSetup": "sleep 5 && .devcontainer/portSetup.sh"
}
}
22 changes: 22 additions & 0 deletions .devcontainer/portSetup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e

if [ -z "$CODESPACE_NAME" ]; then
echo "Not running in a codespace, exiting."
exit
fi

echo "Installing GH"

(type -p wget >/dev/null || (sudo apt update && sudo apt install wget -y)) \
&& sudo mkdir -p -m 755 /etc/apt/keyrings \
&& out=$(mktemp) && wget -nv -O$out https://cli.github.com/packages/githubcli-archive-keyring.gpg \
&& cat $out | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null \
&& sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg \
&& sudo mkdir -p -m 755 /etc/apt/sources.list.d \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& sudo apt update \
&& sudo apt install gh -y

echo "Exposing ports"
gh codespace ports visibility 4200:public 27017:public 5300:public -c $CODESPACE_NAME
5 changes: 4 additions & 1 deletion client/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ export function app(): express.Express {
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');

const angularApp = new AngularNodeAppEngine();
// Codespaces (and other hosted dev/proxy setups) terminate TLS at a trusted
// reverse proxy that forwards the original request via X-Forwarded-* headers.
// Trust them so Angular reconstructs the correct request URL.
const angularApp = new AngularNodeAppEngine({ trustProxyHeaders: true });

// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
Expand Down
78 changes: 78 additions & 0 deletions codespaces.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# 👋 Welcome to the MEAN Stack Example

This Codespace is **already up and running** — dependencies are installed, the database is seeded, and both the API and the Angular client have started for you. There's nothing to `npm install` or `npm start`; just wait a few seconds for the servers to finish booting.

## 🚀 What's running

| Service | Port | Description |
|---------|------|-------------|
| **Angular Client** | `4200` | The web app (opens automatically in a Simple Browser preview) |
| **Express API** | `5300` | REST API for employee CRUD operations |
| **MongoDB** | `27017` | Local database, pre-seeded with sample employees |

The **Angular Client** preview opens on its own when the client finishes compiling. If you don't see it (or you closed it), open the **Ports** tab, find port **4200** ("Angular Client"), and click the 🌐 globe icon to open the preview.

> ⏳ First launch takes a moment while the client compiles. If the preview shows an error at first, give it a few seconds and refresh.

## 🧭 Try it out

In the client preview you can:

- **View** the seeded list of employees.
- **Add a New Employee** with the button below the list.
- **Edit** or **Delete** any row with the action buttons.

Changes are saved through the Express API to MongoDB and reflected in the list immediately.

You can also hit the API directly from the terminal:

```bash
curl http://localhost:5300/healthcheck # → {"status":"ok"}
curl http://localhost:5300/employees # → the seeded employees
```

## 🗂️ Project structure

```
server/ Express + MongoDB REST API (TypeScript)
src/
server.ts App entry, CORS, /healthcheck, mounts the router
employee.routes.ts CRUD routes for /employees
database.ts MongoDB connection + schema validation
client/ Angular 22 app (standalone, zoneless, SSR)
src/app/
employees-list/ List view (Material table)
employee-form/ Shared reactive form
add-employee/ Create page
edit-employee/ Edit page (loaded via a route resolver)
employee.service.ts httpResource + CRUD calls to the API
```

## ✏️ Making changes

Both servers run in **watch mode** — just edit and save:

- Edit files under **`client/src/`** → the client rebuilds and the preview reloads.
- Edit files under **`server/src/`** → restart the API from the terminal if needed:
```bash
cd server && npm start
```

## 🌱 Reseeding the database

The database is seeded on startup. To reset it to the sample data at any time:

```bash
npm run seed
```

## 🧪 Running tests

```bash
npm test # client + server unit tests
npm run test:integration # API integration tests (in-memory MongoDB)
```

## 📚 Learn more

This project is the companion code for the [MEAN Stack Tutorial](https://www.mongodb.com/resources/languages/mean-stack-tutorial). Happy hacking! 🎉
Loading