Cashory Demo is a full-stack personal finance and lightweight invoicing application built as a Bun monorepo. It combines an Expo-powered React Native client, a Hono API, Better Auth authentication, Drizzle ORM, and PostgreSQL to deliver a mobile-first experience for onboarding users, managing wallets, recording transactions, reviewing reports, generating invoices, and exporting invoice PDFs.
Repository audit note
This codebase currently implements a finance management product, not a YouTube long-form video creation and publishing workflow. There is no YouTube API, Google OAuth for YouTube upload, video rendering pipeline, or publishing automation in the repository at this time. This README documents the current implementation on disk so other developers can set it up and contribute accurately.
- Project Overview
- Feature Highlights
- Workflow Guide
- Technical Architecture
- Requirements and Dependencies
- Setup and Installation
- Configuration
- Usage Guide
- API Surface
- Project Structure
- Contribution Guidelines
- License
- Troubleshooting
Cashory Demo helps a user move through a simple money-management lifecycle:
- Authenticate with email and password.
- Complete onboarding by filling in profile data and selecting preferences.
- Create wallets to represent cash, bank, credit, or mobile balances.
- Organize categories for income and expenses.
- Add transactions and review historical activity with filtering and summaries.
- Track invoices for client work, update invoice status, and generate PDF exports.
- Review notifications and profile settings from the in-app settings area.
For developers, the project demonstrates a strongly typed monorepo where schemas, environment validation, authentication, and database logic are shared across client and server packages.
- Mobile-first UX with Expo Router navigation, onboarding screens, drawer and tab layouts, theming, and HeroUI Native components.
- Typed API layer using Hono on the server and Hono client bindings in the mobile app.
- Authentication with Better Auth, secure Expo storage, and session-aware API requests.
- Finance data model for wallets, categories, transactions, budgets, notifications, and invoices.
- Invoice lifecycle support including status changes, notification generation, server-side HTML creation, and client-side PDF export and sharing.
- Shared schemas and validation with Zod and workspace packages to reduce duplication across the stack.
flowchart TD
A[User opens app] --> B[Sign up or sign in]
B --> C[Onboarding profile setup]
C --> D[Dashboard]
D --> E[Create wallets and categories]
E --> F[Record income and expense transactions]
F --> G[Review summaries and reports]
D --> H[Create invoice]
H --> I[Update invoice status]
I --> J[Generate and share PDF]
I --> K[Notification created by API]
apps/nativecontains the React Native application built with Expo and Expo Router.apps/servercontains the Hono API, route registration, middleware, and business services.packages/authcentralizes Better Auth configuration and database-backed auth setup.packages/dbcontains Drizzle configuration, PostgreSQL schema definitions, and migrations.packages/envvalidates native and server environment variables with@t3-oss/env-core.packages/schemaprovides shared Zod schemas and input contracts for API operations.packages/configstores shared TypeScript configuration.
- The mobile app authenticates with Better Auth through the server.
- Session state is stored using the Expo Better Auth client and secure storage.
- The mobile app calls the Hono API through a typed client and injects the auth cookie.
- Hono middleware validates the session and exposes
userIdto route handlers. - Service functions interact with PostgreSQL through Drizzle ORM.
- Shared Zod schemas validate request payloads and query parameters.
| Layer | Technology | Responsibility |
|---|---|---|
| Client | Expo, React Native, Expo Router, HeroUI Native, TanStack Query | UI, navigation, mutation/query orchestration, secure auth session handling |
| API | Bun, Hono, Better Auth | REST endpoints, auth handling, request validation, business logic |
| Data | PostgreSQL, Drizzle ORM, Drizzle Kit | Persistence, typed schema access, migrations |
| Shared | Zod, workspace packages, TypeScript | Shared contracts, environment validation, reusable domain types |
- Bun
1.2.19or newer - Node-compatible mobile toolchain for Expo development
- PostgreSQL database for application data
- Expo Go or an iOS/Android simulator/device for running the native app
turbotypescriptdotenvzod
exporeact-nativeexpo-routerheroui-native@tanstack/react-queryreact-hook-formexpo-image-pickerexpo-printexpo-sharing
honobetter-auth@hono/zod-validator
drizzle-ormdrizzle-kitpg@t3-oss/env-core
git clone <your-fork-or-repo-url>
cd cashory-demo
bun installCreate the server environment file at apps/server/.env:
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/cashory
BETTER_AUTH_SECRET=replace-with-a-random-secret-at-least-32-characters-long
BETTER_AUTH_URL=http://localhost:3000
CORS_ORIGIN=http://localhost:8081
NODE_ENV=developmentCreate the native environment file at apps/native/.env:
EXPO_PUBLIC_SERVER_URL=http://localhost:3000Push the current schema to PostgreSQL:
bun run db:pushOptional database commands:
bun run db:generate
bun run db:migrate
bun run db:studioRun both the API and mobile app:
bun run devRun the server only:
bun run dev:serverRun the mobile app only:
bun run dev:nativebun run check-types| Variable | Scope | Required | Description |
|---|---|---|---|
DATABASE_URL |
Server | Yes | PostgreSQL connection string used by Drizzle and runtime DB access |
BETTER_AUTH_SECRET |
Server | Yes | Secret used by Better Auth for signing and session security |
BETTER_AUTH_URL |
Server | Yes | Base URL for Better Auth endpoints |
CORS_ORIGIN |
Server | Yes | Allowed origin for client requests |
NODE_ENV |
Server | Yes | Runtime environment, defaults to development |
EXPO_PUBLIC_SERVER_URL |
Native | Yes | Base URL used by the Expo app for API requests |
- The server uses Better Auth with a Drizzle adapter backed by PostgreSQL.
- The native app uses the Expo Better Auth client with secure storage.
- Trusted origins include the configured CORS origin and native schemes used by the Expo app.
- Drizzle reads schema files from
packages/db/src/schema. - Drizzle Kit reads
DATABASE_URLfromapps/server/.env. - A local Supabase configuration exists under
packages/db/supabasefor local database tooling.
The repository does not currently include any of the following:
- YouTube Data API credentials
- Google OAuth client setup for YouTube publishing
- Video upload or scheduling endpoints
- Rendering, transcoding, thumbnail generation, or script-to-video automation
If the product is intended to evolve into a YouTube publishing system, you will need to add new environment variables, API routes, background processing, and storage workflows before a YouTube configuration section would be actionable.
- Launch the native app from Expo.
- Register with email and password from the sign-up screen.
- Existing users can sign in from the sign-in screen.
- Fill in profile information such as name, email, country, phone, and currency.
- Optionally choose a profile image through the native image picker.
- Finish onboarding to unlock the main application routes.
- Create at least one wallet for bank, cash, credit, or mobile money.
- Mark one wallet as the default if needed.
- Create income and expense categories to structure later transaction entry.
- Add income or expense entries from the transaction flow.
- Provide amount, category, wallet, date, description, and note.
- Review grouped transaction history and filter by type, wallet, category, or date range.
- Open the home dashboard to view balance cards, monthly income and expenses, and invoice previews.
- Open the reports section to review overview, income, and expense visualizations.
- Open the invoice section and create a new invoice with:
- invoice number
- client name and optional email
- issue and due dates
- tax rate
- one or more line items
- optional note
- Update invoice status to draft, sent, paid, overdue, or cancelled.
- Download and share the generated PDF from the invoice detail screen.
- Visit the notifications screen to review status updates and alerts.
- Use the settings area to view profile information, notification preferences, and sign out.
The current API is mounted under the following route groups:
| Route Group | Purpose |
|---|---|
/api/auth/* |
Better Auth handlers for session and credential flows |
/api/category |
CRUD operations for income and expense categories |
/api/wallet |
CRUD operations for user wallets and default wallet lookup |
/api/budget |
Budget listing and management |
/api/transaction |
Transaction CRUD operations and summary reporting |
/api/invoice |
Invoice CRUD, status updates, and HTML generation for PDF export |
/api/notification |
Notification listing and read-state updates |
Example commands:
bun run dev
bun run dev:server
bun run check-typescashory-demo/
├── apps/
│ ├── native/
│ │ ├── app/ # Expo Router screens
│ │ ├── components/ # UI building blocks, containers, templates
│ │ ├── contexts/ # Theme and app-level React context
│ │ ├── hooks/ # Query and mutation hooks
│ │ ├── lib/ # API client, auth client, shared helpers
│ │ └── types/ # Native app types
│ └── server/
│ └── src/
│ ├── middleware/ # Auth middleware
│ ├── routes/ # Hono route modules
│ └── services/ # Business logic and DB access
├── packages/
│ ├── auth/ # Better Auth server configuration
│ ├── config/ # Shared TypeScript config
│ ├── db/ # Drizzle schema, migrations, Supabase config
│ ├── env/ # Typed env validation
│ └── schema/ # Shared Zod contracts
├── turbo.json
└── package.json
- Keep shared contracts in
packages/schemawhenever client and server both depend on them. - Update
packages/envwhen adding new environment variables. - Prefer typed API access through the existing Hono client instead of creating ad hoc fetch wrappers.
- Follow existing naming and folder conventions for screens, hooks, services, and schema files.
- Create a feature branch.
- Install dependencies with
bun install. - Run the database locally and configure environment variables.
- Implement the change in the appropriate app or shared package.
- Run
bun run check-types. - Open a pull request with a clear summary of user-facing and technical changes.
bun run check-typesis available at the workspace level.- No workspace
lintor automated test script is currently defined in the repository root. - When adding new functionality, include verification steps in your pull request description.
There is currently no LICENSE file in this repository. Until a license is added by the maintainers, the project should be treated as all rights reserved.
If you plan to distribute or open-source the project, add a license file and update this section accordingly.
- Recheck
apps/server/.envandapps/native/.env. - Make sure required values are present and valid URLs where applicable.
- Ensure
BETTER_AUTH_SECRETis at least 32 characters long.
- Confirm the server is running.
- Confirm
EXPO_PUBLIC_SERVER_URLpoints to the reachable API host. - If testing on a physical device, replace
localhostwith your machine's LAN IP.
- Verify
BETTER_AUTH_URLmatches the actual API origin. - Verify
CORS_ORIGINmatches the client origin used during development. - Restart both the server and Expo after changing auth-related environment variables.
- Confirm PostgreSQL is running and accepting connections.
- Verify
DATABASE_URLinapps/server/.env. - Re-run
bun run db:pushafter fixing connectivity or credential issues.
- PDF export depends on
expo-printandexpo-sharing. - Some simulators and environments have limited share-sheet support.
- Test on a physical device if share functionality appears unavailable.
- Restart Expo with a cleared cache:
bun run dev:native- If needed, start Expo directly with:
cd apps/native
bun run dev