The ordering management platform for The Whale Café. Built with Next.js.
Overview · Development · Production · Environment Variables · Settings · Contribution · License
Project Whale is a customized ordering system for The Whale Café, a student-run coffee shop at BAID.
Project Whale is maintained by WebArtistry @BAID. Authentication uses LinkBAID, and Weixin Pay is integrated through YunGouOS. It was originally developed by Lin Donglai.
- Menu management. Organize items into categories and add tags to them. Configure prices and discounts for each item. Add options such as size or temperature that may modify the price of each item. Reorder these items as you will. Add images to each item. Exempt any item you want from the quotas.
- Ordering. Customers build a cart and can choose pick-up or delivery. When choosing pick-up, the customer can specify a pick-up time: morning, afternoon, or evening. Customers do not need to log in to order.
- Automated payments. Customers could pay with Weixin Pay, or sign up for an account to recharge and pay with their balance. All three forms of Weixin Pay (QR code, in-WeChat payment, redirect-to-WeChat payment) are supported. If enabled, customers can "Pay Later." They cannot order another cup with Pay Later before settling existing bills.
- Coupon codes. Generate as many coupon codes as you like, which can reduce the amount of money customers pay for a drink. Coupon codes are automatically consumed when customers use them.
- Customer accounts. Customers can sign in with Seiue LMS or Feishu via LinkBAID. Signed-in customers can review their order history and balance. Customers also accrue points when they pay for an order.
- On-site ordering. Turn on "on-site ordering mode" on staff devices. They can then help customers visiting in-person order, either with cash or Weixin Pay.
- Staff dashboard. A simple UI to view waiting orders and mark them complete. Easily refund orders and view their payment status.
- Opening hours. Manually open the store only. Or set a fixed time period everyday where live-ordering is available. Or allow ordering only during weekdays. Easily override opening hours for one specific day on the staff interface—they revert on the next day.
- Quota management. Set a fixed number of cups that the store can make in a day, and stop accepting further orders when it is reached.
- Pre-orders. Set a "pre-order" period where the store does not make drinks but customers can still place orders. Set a pre-order quota, separate from the live-ordering quota, that carries into the live-ordering quota if not completely consumed.
- Inventory management. Each item can either have a tracked stock count, which is automatically reserved upon payment. The stock count is restored if the order is cancelled or refunded. Or you can use a manual sold-out option without automatic trackking.
- Advertisements. Add promotion images, links, and text to the menu.
- Administration. Audit logs for all website operations. Statistics reporting include analysis per gender, user, categories, items, and more. Configurable reporting periods and predefined statistic breakdown.
- Bilingual interface. English and Chinese are supported throughout the user interface.
To run in development:
-
Install Node.js and npm.
-
Copy
.env.exampleto.env. -
Run
npm install. -
Set up a PostgreSQL database and set
DATABASE_URIin.env. -
Set
HOST=http://localhost:3000,UPLOAD_PATH=public/uploads, andUPLOAD_SERVE_PATH=uploads. -
Apply Prisma migrations and generate the client:
prisma migrate deploy prisma generate
-
Run a development server of LinkBAID to support authentication or use the official LinkBAID server by informing your school point of contact. When you create a LinkBAID application, you must enable the scopes
basic,phone, andsms, and register${HOST}/login/authorizeas an OAuth2 redirect URI. -
Fill the remaining environment variables.
-
Run
npm run devto start the development server.
In development mode, Weixin Pay will not work, because you will not be able to set up a valid merchant ID. Use "Pay Later" for debugging instead.
- After pulling someone else's migrations, run
prisma migrate deploy, thenprisma generate. - To create your own migration, edit
prisma/schema.prismaand runprisma migrate dev --name describe_change. Commit the schema and the entireprisma/migrations/directory together. - On production, run
prisma migrate deploy, thenprisma generatebefore building and restarting Project Whale. Monitor the messages carefully, do NOT reset the database!
To run in production:
- Install Node.js and npm.
- Copy
.env.exampleto.env. - Run
npm install. - Set up a PostgreSQL database and set
DATABASE_URIin.env. - For a fresh database, run
prisma migrate deploy. - Run
prisma generate. - Gain access to the production LinkBAID server.
- LinkBAID server: You must create a LinkBAID application with the following scopes:
basic,phone, andsms. This app must be approved before continuing.
- LinkBAID server: You must create a LinkBAID application with the following scopes:
- Gain access to the YunGouOS Weixin Pay merchant account.
- You must have a domain name registered with a Chinese ISP and with ICP registration completed. You must also have a server in mainland China that is tied to this domain name.
- You must run the website first by following the remaining steps before you can create a YunGouOS merchant account.
- Creating this account requires a Chinese citizen with a national ID and a Chinese bank account. You must choose "渠道商户" for the account type.
- After creating the account, you must contact YunGouOS staff to complete a video verification before you can use the account.
- After verification, you must contact YunGouOS staff again to enable H5 payments for the account.
- You must add the domain name you are running on to the H5 payment callback authorized domain list.
- Congratulations, after taking around 1-2 weeks on this you will finally be able to access Weixin Pay without having a company registered.
- Set up a cron task that triggers the scheduled jobs below. The cron task must send GET requests with
key=${CRON_KEY}. - Fill the remaining environmental variables.
- Run
npm run buildto build the production server. - Using
pm2, runpm2 start npm --name whale -- run startto start the production server. You can also usepm2 saveto save the process list andpm2 startupto configure it to start on boot. - Whale runs on port 52323 by default.
- Create a reverse proxy with Nginx as appropriate such that Nginx handles HTTPS and serves static files. An example Nginx configuration is shown below. HTTPS can usually be configured with Let's Encrypt.
server {
listen 443 ssl;
server_name cafe.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
client_max_body_size 11M;
location ^~ /uploads/ {
alias /home/web/whale/uploads/; # By setting up Nginx to serve files from /uploads/, we must set `UPLOAD_SERVE_PATH` to `/uploads` (users access uploaded files on `https://.../uploads/...`) and `UPLOAD_PATH` to `uploads` (uploaded files are saved to `/home/web/whale/uploads/`)
autoindex off;
add_header X-Content-Type-Options nosniff always;
try_files $uri =404;
}
location / {
proxy_pass http://localhost:52323;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}- Log in with LinkBAID.
- Configure your account in the database directly: add permission
admin.manage. - Completed! You can now add the products and configure store opening times.
| Endpoint | Schedule | Action |
|---|---|---|
/order/prune |
Every 30 minutes | Remove ordinary unpaid orders older than one hour and restore tracked inventory. |
/balance/prune |
Every 30 minutes | Remove unfinished balance recharge records older than one hour. |
/order/pay-later |
Daily at 20:00 | Send reminders for outstanding Pay Later orders. |
| Name | Description |
|---|---|
DATABASE_URI |
The database URI to use. PostgreSQL is required. |
HOST |
The absolute URI where Whale is hosted. No trailing slashes. For example, http://localhost:3000 in development. |
UPLOAD_PATH |
The directory where uploaded files are stored. In development, use public/uploads to have the Next.js development server serve uploaded files. |
UPLOAD_SERVE_PATH |
The relative URI where uploaded files are served. In development, this is uploads. |
ONELOGIN_HOST |
The URI where LinkBAID is hosted. No trailing slashes. |
ONELOGIN_CLIENT_ID |
LinkBAID client ID. |
ONELOGIN_CLIENT_SECRET |
LinkBAID client secret. |
JWT_SECRET |
The JWT secret key to use. You can generate one with openssl rand -hex 32. |
WX_PAY_MCH_ID |
YunGouOS Weixin Pay merchant ID. |
WX_PAY_MCH_KEY |
YunGouOS Weixin Pay signing key. |
CRON_KEY |
Secret key required by cron-only API endpoints. Generate one with openssl rand -hex 32. |
BOTTOM_TEXT |
ICP registration number, if it is necessary to display. |
Contributions are welcome through pull requests!
Copyright © 2026 Team WebArtistry. Project Whale is licensed under the GNU General Public License, version 3 or later.