---
title: "Install and get started"
url: https://phatdev.net/en/docs/moneyflow/cai-dat
lang: en
updated: 2026-10-23
alternate:
  vi: https://phatdev.net/docs/moneyflow/cai-dat
markdown: https://phatdev.net/en/docs/moneyflow/cai-dat.md
---

# Install and get started

Part of the doc set: [MoneyFlow](https://phatdev.net/en/docs/moneyflow.md)

> Requirements, building from source, first sign-in, demo mode, setting up the sync server and troubleshooting.

**MoneyFlow** is currently an internal development build (0.x): it is not on the App Store, not on TestFlight, and the source code lives in a private repository. This page explains how to build the app from source, how to try it with demo mode, and, in general terms, how to set up the sync server.

## Requirements

- A Mac with Xcode 27 or later.
- An iPhone or iPad running iOS/iPadOS 26.1 or later (or a matching simulator).
- Sync server: Node.js 20 or later and PostgreSQL.

## Build the app from source

```sh
open MoneyFlow.xcodeproj                     # scheme MoneyFlow
xcodebuild test -project MoneyFlow.xcodeproj -scheme MoneyFlow \
  -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \
  -only-testing:MoneyFlowTests
```

Open `MoneyFlow.xcodeproj` in Xcode, choose the `MoneyFlow` scheme and run. The sync server address is declared in `MoneyFlow/Config.swift`; change it to your own server's address before building. The test suite has 63 tests running on an in-memory SwiftData store.

## First sign-in

The app authenticates entirely on the sync server, so the first launch needs a username and password issued by whoever runs the server. After signing in, the app syncs right away and keeps its session token in the Keychain. The session lasts 30 days by default; when it expires, the app lets you sign in again from the Account screen without losing the changes waiting to be pushed.

The app contains no passwords or API keys. See [Security and privacy](https://phatdev.net/en/docs/moneyflow/bao-mat).

## Demo mode

Debug builds include a demo mode for trying the app, or taking screenshots, without a server. Launch the app with the `-seedDemoData` argument:

- The app loads about two and a half months of sample data for two made-up members and signs in locally.
- Demo data lives in its own store, fully separate from the real one.
- Sync and server-side erase are disabled, so sample data never reaches the production server. Demo bill notifications also leave the real ones untouched.

Demo mode is not part of Release builds.

## Set up the sync server

The server is a Node.js + Express application backed by PostgreSQL. In general terms:

```sh
cd Backend
cp .env.example .env        # database settings, JWT_SECRET, BTMC_API_KEY
npm install
npm run db:init             # create the schema and default accounts (random passwords, printed once)
npm test                    # sync payload validation tests
npm start
```

- Create a PostgreSQL database and a dedicated account for the app, then put the settings in `.env`.
- `JWT_SECRET` must be a long random string. The server refuses to start if it is missing or still the example value.
- `BTMC_API_KEY` is the key of the gold price source and lives only on the server.
- `npm run db:init` generates a random password for each new account and prints it exactly once (or uses `DEFAULT_USER_PASSWORD` if you set it). Existing accounts are never overwritten. Change a password later with `npm run user:passwd -- <name>`.
- `JWT_EXPIRES_IN` sets the session lifetime, `30d` by default.
- By default the server listens only on the loopback interface. Put it behind a tunnel or an HTTPS reverse proxy so the app can reach it from outside; there is no need to open a port directly.
- To upgrade an existing server: stop the process, update the code, run `npm install` and `npm run db:init` again (safe to repeat), then restart.

Step-by-step instructions, including the safe upgrade procedure, are in `Backend/DEPLOY.md` in the repository.

## Common problems

- **The server will not start.** Check that `JWT_SECRET` is set and is not the example value, and that Node.js is version 20 or later.
- **Sign-in says the session expired.** Open Account and choose "Đăng nhập lại để đồng bộ" (sign in again to sync). Changes on the device are kept and pushed after you sign in.
- **Sync says the server rejected the data.** The message names the invalid record. Other records are still downloaded normally.
- **Gold price shows "Chưa có giá" (no price yet).** The app has not been able to get a real price from the server; the gold value is only an estimate. See [Savings and gold](https://phatdev.net/en/docs/moneyflow/tiet-kiem-vang).
- **A device that ran an older build's demo data is blocked from syncing.** In Account choose "Xoá toàn bộ dữ liệu" (erase all data) to clear the sample data, then sync again.
- **Tests hang.** Use the release Xcode instead of a beta; a beta can leave the test runner unresponsive.
