SkillShare Logo
STEP 3 OF 7 · DATA

Database & Models

Spin up your database in Docker, then describe the two things this app stores: users and products. Use the Postgres tab (TypeORM) or the MongoDB tab (Mongoose) — whichever you picked.

01 — CHOOSE

Postgres vs MongoDB

Relational tables (Postgres) or flexible documents (MongoDB). Either works fine for this app — pick one and follow its tab everywhere.

PostgreSQL + TypeORMPOSTGRESQL + TYPEORM

  • Structured tables with strict types
  • Great for clear relationships & reporting
  • TypeORM models tables as decorated classes
  • First-class NestJS integration

MongoDB + MongooseMONGODB + MONGOOSE

  • Flexible JSON-like documents
  • Fast to start, schema can evolve
  • Mongoose adds schemas & validation
  • Feels natural if you think in JSON
Unsure?
Pick PostgreSQL. Inventory data is naturally tabular, and TypeORM gives you type safety end-to-end.
02 — RUN IT

Set Up the Database

No messy local install — Postgres runs in a local Docker container, and MongoDB runs in the cloud via MongoDB Atlas.

run Postgres 16
$ docker run --name inv-pg -e POSTGRES_PASSWORD=secret \
    -e POSTGRES_DB=inventory -p 5432:5432 -d postgres:16

# .env →
DATABASE_URL="postgresql://postgres:secret@localhost:5432/inventory"
Daily commands
For Postgres, use docker start inv-pg / docker stop inv-pg to start & stop. MongoDB Atlas is hosted in the cloud, so it is always online and doesn't require daily commands. We'll replace Postgres startup with a tidy docker-compose.yml on the deploy page.
03 — THE SHAPE

The Data Model

Two tables/collections power everything. Keep them small — you can always add fields later.

U

User

id · email (unique) · passwordHash · isVerified (default false) · createdAt

P

Product

id · name · sku (unique) · quantity · minStock · createdAt · updatedAt

Why isVerified and minStock?
isVerified blocks login until the email link is clicked. minStock is the threshold that triggers a low-stock alert when quantity drops to or below it.
04 — DEFINE

Connect & Define the Models

Pick your database tab. Each shows the connection plus both Express and NestJS wiring.

tsconfig
TypeORM uses decorators. In server/tsconfig.json set "experimentalDecorators": true and "emitDecoratorMetadata": true, and add import "reflect-metadata"; at the very top of your entry file.

Entities

server/src/entities.ts
import {
  Entity, PrimaryGeneratedColumn, Column,
  CreateDateColumn, UpdateDateColumn,
} from "typeorm";

@Entity()
export class User {
  @PrimaryGeneratedColumn("uuid") id!: string;
  @Column({ unique: true }) email!: string;
  @Column() passwordHash!: string;
  @Column({ default: false }) isVerified!: boolean;
  @CreateDateColumn() createdAt!: Date;
}

@Entity()
export class Product {
  @PrimaryGeneratedColumn("uuid") id!: string;
  @Column() name!: string;
  @Column({ unique: true }) sku!: string;
  @Column({ type: "int", default: 0 }) quantity!: number;
  @Column({ type: "int", default: 0 }) minStock!: number;
  @CreateDateColumn() createdAt!: Date;
  @UpdateDateColumn() updatedAt!: Date;
}

For Express — a DataSource

server/src/data-source.ts
import "reflect-metadata";
import { DataSource } from "typeorm";
import { User, Product } from "./entities";

export const AppDataSource = new DataSource({
  type: "postgres",
  url: process.env.DATABASE_URL,
  entities: [User, Product],
  synchronize: true, // auto-creates tables in dev — turn OFF in prod
});

// in index.ts, before app.listen():
await AppDataSource.initialize();

For NestJS — TypeOrmModule

server/src/app.module.ts
import { TypeOrmModule } from "@nestjs/typeorm";
import { ConfigModule } from "@nestjs/config";
import { User, Product } from "./entities";

@Module({
  imports: [
    ConfigModule.forRoot({ isGlobal: true }),
    TypeOrmModule.forRoot({
      type: "postgres",
      url: process.env.DATABASE_URL,
      entities: [User, Product],
      synchronize: true,
    }),
    TypeOrmModule.forFeature([User, Product]),
  ],
})
export class AppModule {}
About synchronize / auto-schema
In development, letting the ORM (the library that maps code to database tables) create tables for you is convenient. For production, generate proper migrationsinstead so you never risk data loss. See the TypeORM & Mongoose docs linked above.
05 — CHECKPOINT

Confirm the Connection

Restart your backend. On boot you should see the connection log and (for Postgres) two tables created.

  • Database is running (Docker container for Postgres, cloud Atlas cluster for MongoDB)
  • Backend logs "connected" with no errors on start
  • User and Product models are defined and imported