Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/floriansalvi/HEIG-VD_Ocha-api/llms.txt

Use this file to discover all available pages before exploring further.

The Ocha API stores its data in MongoDB through five Mongoose models: User, Product, Store, Order, and OrderItem. Each model defines the shape of its documents, enforces validation rules, and controls which fields are exposed in API responses. The sections below document every field for each model as defined in the source schemas.

User

A User represents a registered account. Passwords are hashed with bcrypt before storage and are excluded from all query results via select: false.
_id
ObjectId
required
MongoDB-generated unique identifier for the user document.
email
string
required
The user’s email address. Stored in lowercase. Must be unique across all accounts.
display_name
string
required
The user’s chosen display name. Must be unique across all accounts.
phone
string
Optional phone number. Not validated against a format at the schema level.
role
string
default:"user"
required
Access level for the account. Accepted values: user, admin. Determines which protected endpoints the account can reach.
password
string
required
Bcrypt-hashed password. This field is excluded from all query results (select: false) and is never returned by the API.
created_at
date
default:"Date.now"
required
Timestamp set automatically when the account is created.
Example User document
{
  "_id": "664a1f2e3c4b5a6d7e8f9012",
  "email": "[email protected]",
  "display_name": "matcha_lover",
  "phone": "+41791234567",
  "role": "user",
  "created_at": "2024-05-20T10:30:00.000Z"
}
The password field is never included in API responses. Do not attempt to read it from returned JSON.

Product

A Product represents a menu item available in Ocha stores. Products have size variants with per-size price surcharges. Mongoose timestamps adds createdAt and updatedAt automatically.
_id
ObjectId
required
MongoDB-generated unique identifier.
slug
string
required
URL-safe unique identifier derived from the product name. Generated automatically.
name
string
required
Human-readable product name. Must be unique.
category
string
required
Product category (e.g., "matcha latte", "cold brew").
description
string
required
Full text description of the product.
basePriceCHF
number
required
Base price in Swiss francs. Minimum value: 0. The final price for a given size is basePriceCHF + extra_chf[size].
isActive
boolean
default:"true"
Controls visibility. When false, the product is excluded from the active products listing (GET /products?active=true).
image
string
required
Cloudinary URL pointing to the product image.
size
string[]
default:"[\"S\", \"M\", \"L\"]"
Array of available sizes for this product. Each value must be one of S, M, or L.
extra_chf
object
default:"{\"S\": 0, \"M\": 2, \"L\": 3}"
Per-size price surcharge in CHF added on top of basePriceCHF.
createdAt
date
Automatically managed by Mongoose timestamps.
updatedAt
date
Automatically managed by Mongoose timestamps. Updated on every save.
Example Product document
{
  "_id": "664b2a3f4d5c6e7f8a9b0123",
  "slug": "ceremonial-matcha-latte",
  "name": "Ceremonial Matcha Latte",
  "category": "matcha latte",
  "description": "Premium ceremonial grade matcha with steamed oat milk.",
  "basePriceCHF": 6.5,
  "isActive": true,
  "image": "https://res.cloudinary.com/demo/image/upload/v1/matcha-latte.jpg",
  "size": ["S", "M", "L"],
  "extra_chf": { "S": 0, "M": 2, "L": 3 },
  "createdAt": "2024-05-20T08:00:00.000Z",
  "updatedAt": "2024-05-21T14:22:00.000Z"
}
Use GET /api/v1/products?active=true to retrieve only products where isActive is true.

Store

A Store represents a physical Ocha matcha shop location. Coordinates are stored as a GeoJSON Point to enable geospatial queries via the $near operator. The slug is generated automatically from name using slugify.
_id
ObjectId
required
MongoDB-generated unique identifier.
name
string
required
Store display name. Must be unique and between 3 and 50 characters long.
slug
string
required
URL-safe unique identifier generated from name. Lowercased and auto-updated when name changes.
email
string
required
Contact email for the store. Must be unique and pass email format validation.
phone
string
Optional contact phone number. Validated as a valid mobile phone number if provided.
address
object
required
Physical mailing address of the store.
location
object
required
GeoJSON Point used for geospatial proximity queries.
is_active
boolean
default:"true"
Whether the store is currently active. Inactive stores are excluded from nearby-store queries.
opening_hours
array
Array of exactly 7 entries, one per day of the week starting from Sunday (index 0). Each entry is either an empty array [] (store closed that day) or a two-element array ["HH:MM", "HH:MM"] representing opening and closing times in 24-hour format.Default: Sunday closed, Monday–Saturday ["09:00", "17:00"].
created_at
date
default:"Date.now"
Timestamp set when the store document is first created.
updated_at
date
default:"Date.now"
Timestamp updated automatically on every save via a pre('save') hook.
Example Store document
{
  "_id": "664c3b4e5f6d7a8b9c0d1234",
  "name": "Ocha Lausanne",
  "slug": "ocha-lausanne",
  "email": "[email protected]",
  "phone": "+41213456789",
  "address": {
    "line1": "Rue de Lausanne 12",
    "city": "Lausanne",
    "zipcode": "1003",
    "country": "Switzerland"
  },
  "location": {
    "type": "Point",
    "coordinates": [6.6323, 46.5197]
  },
  "is_active": true,
  "opening_hours": [
    [],
    ["09:00", "17:00"],
    ["09:00", "17:00"],
    ["09:00", "17:00"],
    ["09:00", "17:00"],
    ["09:00", "17:00"],
    ["09:00", "17:00"]
  ],
  "created_at": "2024-05-20T08:00:00.000Z",
  "updated_at": "2024-05-21T10:00:00.000Z"
}
coordinates follows the GeoJSON convention of [longitude, latitude] — longitude first, latitude second.

Order

An Order groups items purchased by a user at a specific store for a scheduled pickup. Mongoose timestamps adds createdAt and updatedAt automatically.
_id
ObjectId
required
MongoDB-generated unique identifier.
user_id
ObjectId
required
Reference to the User who placed the order.
store_id
ObjectId
required
Reference to the Store where the order will be picked up.
status
string
default:"\"en préparation\""
Current lifecycle state of the order. Accepted values:
  • "en préparation" — order received, being prepared
  • "prête" — order ready for pickup
  • "récupérée" — order collected by the customer
pickup
date
required
Scheduled date and time for the customer to collect the order.
total_price_chf
number
required
Total cost of the order in Swiss francs. Minimum value: 0.
createdAt
date
Automatically managed by Mongoose timestamps.
updatedAt
date
Automatically managed by Mongoose timestamps.
Example Order document
{
  "_id": "664d4c5f6a7b8c9d0e1e2345",
  "user_id": "664a1f2e3c4b5a6d7e8f9012",
  "store_id": "664c3b4e5f6d7a8b9c0d1234",
  "status": "en préparation",
  "pickup": "2024-05-22T12:00:00.000Z",
  "total_price_chf": 17,
  "createdAt": "2024-05-22T09:00:00.000Z",
  "updatedAt": "2024-05-22T09:00:00.000Z"
}

OrderItem

An OrderItem represents a single product line within an Order. Prices are snapshotted from the Product at creation time via a pre('validate') hook, so they remain accurate even if the product price changes later.
_id
ObjectId
required
MongoDB-generated unique identifier.
order_id
ObjectId
required
Reference to the parent Order.
product_id
ObjectId
required
Reference to the Product being ordered.
product_name
string
required
Snapshot of the product’s name at the time the item was created. Preserved even if the product is later renamed.
size
string
required
Selected size for this line item. Must be one of S, M, or L.
quantity
number
default:"1"
Number of units ordered. Minimum: 1, maximum: 100.
base_price_chf
number
required
Snapshot of the product’s basePriceCHF at order creation time.
extra_chf
number
default:"0"
Snapshot of the size surcharge (extra_chf[size]) from the product at order creation time.
final_price_chf
number
required
Total unit price: base_price_chf + extra_chf. Computed automatically before validation.
createdAt
date
Automatically managed by Mongoose timestamps.
updatedAt
date
Automatically managed by Mongoose timestamps.
Example OrderItem document
{
  "_id": "664e5d6a7b8c9d0e1f2f3456",
  "order_id": "664d4c5f6a7b8c9d0e1e2345",
  "product_id": "664b2a3f4d5c6e7f8a9b0123",
  "product_name": "Ceremonial Matcha Latte",
  "size": "M",
  "quantity": 2,
  "base_price_chf": 6.5,
  "extra_chf": 2,
  "final_price_chf": 8.5,
  "createdAt": "2024-05-22T09:00:00.000Z",
  "updatedAt": "2024-05-22T09:00:00.000Z"
}
base_price_chf, extra_chf, and final_price_chf are computed and stored at creation time. They are not recalculated if the underlying product changes after the order is placed.

Build docs developers (and LLMs) love