|
2 | 2 |
|
3 | 3 | Last updated: March 15, 2026 |
4 | 4 |
|
5 | | -## Overview |
6 | | - |
7 | | -FairShare is a monorepo expense-sharing application with: |
8 | | - |
9 | | -- A NestJS backend in `apps/backend` |
10 | | -- An Expo React Native mobile app in `apps/mobile` |
11 | | -- A web app workspace in `apps/web` |
12 | | -- Shared TypeScript contracts in `@fairshare/shared-types` |
13 | | - |
14 | | -The project is beyond bootstrap stage. Core expense-sharing flows, settlements, notifications, receipts, realtime updates, and payment intent creation are implemented. Recent work has shifted toward reliability, idempotency, delivery safety, and production hardening. The repository is currently clean and aligned with `origin/main` as of March 15, 2026. |
15 | | - |
16 | | -## Infrastructure And Deployment |
17 | | - |
18 | | -- Monorepo managed with `pnpm` and Turbo |
19 | | -- PostgreSQL accessed through Prisma |
20 | | -- Redis used for cache invalidation and queue-related workflows |
21 | | -- Socket.IO used for realtime updates |
22 | | -- S3 integration present for receipt flows using AWS SDK v3 presigning |
23 | | -- Stripe integration present for payment intents and webhooks |
24 | | -- Sentry and OpenTelemetry hooks present in the backend |
25 | | - |
26 | | -Backend runtime characteristics: |
27 | | - |
28 | | -- Nest listens on `0.0.0.0` |
29 | | -- Global API prefix is `/api/v1` |
30 | | -- CORS is enabled from configured origins |
31 | | -- Throttling, compression, helmet, cookie parsing, CSRF protection, and request logging are enabled |
32 | | - |
33 | | -## Backend Implementation |
34 | | - |
35 | | -### Implemented modules |
36 | | - |
37 | | -The backend currently wires these major modules: |
38 | | - |
39 | | -- Auth |
40 | | -- Users |
41 | | -- Groups |
42 | | -- Expenses |
43 | | -- Balances |
44 | | -- Settlements |
45 | | -- Simplify |
46 | | -- Receipts |
47 | | -- Notifications |
48 | | -- Payments |
49 | | -- Jobs |
50 | | -- Activity |
51 | | -- Realtime |
52 | | -- Health |
53 | | -- Observability |
54 | | -- Redis |
55 | | -- S3 |
56 | | -- Prisma |
57 | | - |
58 | | -### Implemented backend capabilities |
59 | | - |
60 | | -- User authentication and token-based login flows |
61 | | -- Group creation and membership management |
62 | | -- Expense creation, listing, update, deletion, and detail retrieval |
63 | | -- Balance tracking and debt simplification support |
64 | | -- Settlement creation between group members |
65 | | -- Receipt upload URL generation |
66 | | -- Activity logging for domain actions |
67 | | -- Push token registration and notification delivery workflows |
68 | | -- Stripe payment intent creation |
69 | | -- Payment webhook handling that records successful payments as settlements |
70 | | -- Realtime emission for group activity |
71 | | -- Health and metrics endpoints |
72 | | - |
73 | | -### Recent backend fix |
74 | | - |
75 | | -A NestJS startup failure caused by a module cycle was resolved. |
76 | | - |
77 | | -Problem chain: |
78 | | - |
79 | | -- `SettlementsModule -> NotificationsModule -> JobsModule -> PaymentsModule -> SettlementsModule` |
80 | | - |
81 | | -Resolution: |
82 | | - |
83 | | -- `SettlementsModule` now uses `forwardRef(() => NotificationsModule)` so Nest can resolve the cycle during module initialization |
84 | | - |
85 | | -This restored a clean backend boot path. |
86 | | - |
87 | | -### Recent backend reliability work |
88 | | - |
89 | | -Additional backend hardening completed in the latest pass: |
90 | | - |
91 | | -- Migrated S3 presigned upload generation from AWS SDK v2 to AWS SDK v3 |
92 | | -- Added receipt upload URL coverage with service-level and HTTP-level tests |
93 | | -- Hardened payment webhook processing so settlement creation happens before payment status is marked `succeeded` |
94 | | -- Improved settlement idempotency handling for duplicate webhook delivery and unique-key races |
95 | | -- Enforced Stripe signature presence when a webhook secret is configured |
96 | | -- Added notification delivery retry backoff and automatic cleanup of invalid Expo push tokens |
97 | | - |
98 | | -## Frontend And UX |
99 | | - |
100 | | -### Mobile status |
101 | | - |
102 | | -The Expo mobile app already includes: |
103 | | - |
104 | | -- Login and registration |
105 | | -- Group list and group detail flows |
106 | | -- Group members view |
107 | | -- Add expense and expense detail flows |
108 | | -- Settlement flow |
109 | | -- Activity screen |
110 | | -- Profile and settings screens |
111 | | -- Shared UI components for cards, buttons, avatars, skeleton states, empty states, and toasts |
112 | | -- Zustand-based stores for auth, groups, expenses, and toast state |
113 | | -- Service clients for auth, groups, expenses, settlements, realtime, and users |
114 | | - |
115 | | -Implemented mobile platform features: |
116 | | - |
117 | | -- API client with request logging and latency tracking |
118 | | -- Bearer-token injection from secure storage |
119 | | -- Realtime connection after authentication |
120 | | -- Push token registration through `expo-notifications` |
121 | | -- Offline POST queueing for selected write actions |
122 | | - |
123 | | -### Recent mobile fixes |
124 | | - |
125 | | -Recent development fixes addressed local runtime issues: |
126 | | - |
127 | | -- Removed the stale `apps/mobile/.env` override for `EXPO_PUBLIC_API_URL` |
128 | | -- Stopped forcing the dead API host `http://10.111.154.142:3001/api/v1` |
129 | | -- Restored local API host auto-detection from the Expo runtime host |
130 | | -- Removed the `api.ts` <-> `offlineQueue.ts` require cycle |
131 | | -- Refactored the offline queue so it receives a request executor from `api.ts` instead of importing the API client directly |
132 | | - |
133 | | -This makes local mobile networking more reliable as long as the device and backend machine are on the same reachable network. |
134 | | - |
135 | | -### Web status |
136 | | - |
137 | | -The web workspace exists in the monorepo, but backend and mobile appear to be the most actively implemented parts of the product at this stage. Web should be treated as secondary until a dedicated milestone or readiness target is documented. |
138 | | - |
139 | | -## Testing And CI |
140 | | - |
141 | | -Repository-level scripts include: |
142 | | - |
143 | | -- `pnpm lint` |
144 | | -- `pnpm test` |
145 | | -- `pnpm e2e` |
146 | | - |
147 | | -Recent validation used during current fixes: |
148 | | - |
149 | | -- `pnpm --filter backend lint` |
150 | | -- `pnpm --filter backend build` |
151 | | -- `pnpm --filter backend test -- receipts` |
152 | | -- `pnpm --filter backend test -- payments settlements` |
153 | | -- `pnpm --filter backend test -- notifications` |
154 | | -- `pnpm --filter mobile exec tsc --noEmit` |
155 | | - |
156 | | -There are tests in both backend and mobile codebases. The latest backend pass added direct coverage for receipt URL generation, payment webhook idempotency, settlement idempotency behavior, and notification retry handling. |
157 | | - |
158 | | -## Logging And Observability |
159 | | - |
160 | | -Backend observability already includes: |
161 | | - |
162 | | -- Sentry initialization |
163 | | -- OpenTelemetry startup and shutdown hooks |
164 | | -- Request logging middleware |
165 | | -- Domain logging around notifications and payments |
166 | | -- Prometheus-style metrics infrastructure through `prom-client` |
167 | | - |
168 | | -Mobile development diagnostics currently include: |
169 | | - |
170 | | -- API base URL logging in development |
171 | | -- Request, response, and error logging in the API client |
172 | | -- API latency tracking |
173 | | - |
174 | | -## Environment And Secrets |
175 | | - |
176 | | -Backend environment configuration currently covers: |
177 | | - |
178 | | -- Port |
179 | | -- CORS origins |
180 | | -- Redis connection |
181 | | -- PostgreSQL and Prisma access |
182 | | -- Stripe secret and webhook configuration |
183 | | -- S3 configuration |
184 | | -- Sentry DSN |
185 | | - |
186 | | -Mobile environment configuration currently covers: |
187 | | - |
188 | | -- Optional `EXPO_PUBLIC_API_URL` override |
189 | | -- Optional `EXPO_PUBLIC_SENTRY_DSN` |
190 | | - |
191 | | -Important local mobile networking behavior: |
192 | | - |
193 | | -- If `EXPO_PUBLIC_API_URL` is set, it overrides host auto-detection |
194 | | -- If it is not set, the app derives the backend host from the Expo runtime host during local development |
195 | | -- The phone or emulator and the backend machine must still be on the same reachable network |
196 | | - |
197 | | -## Current Status |
198 | | - |
199 | | -### Working now |
200 | | - |
201 | | -- Backend boots successfully |
202 | | -- Core API surface for auth, groups, expenses, balances, settlements, receipts, notifications, payments, and activity is implemented |
203 | | -- Prisma, Redis, realtime, and payment flows are integrated in the backend |
204 | | -- Receipt upload URLs are generated through AWS SDK v3 presigning |
205 | | -- Payment webhook settlement handling is idempotent at the settlement layer and safer under retry |
206 | | -- Invalid Expo push tokens are removed automatically after permanent delivery failures |
207 | | -- Mobile app can authenticate, navigate the core flows, register push tokens, connect to realtime, and use the offline queue |
208 | | - |
209 | | -### Partially complete |
210 | | - |
211 | | -- Push notifications are implemented, but full remote notification testing should use a development build instead of Expo Go |
212 | | -- Payments are implemented at the intent and webhook level, with improved idempotency, but still need broader production validation |
213 | | -- Web progress is less clearly advanced than backend and mobile |
214 | | - |
215 | | -## Known Gaps |
216 | | - |
217 | | -- Expo package versions are slightly out of sync with the installed SDK and still produce compatibility warnings |
218 | | -- `expo-notifications` remote push support is limited in Expo Go |
219 | | -- Local mobile networking remains environment-sensitive when LAN addressing changes |
220 | | -- Receipt OCR and structured receipt parsing are not implemented yet |
221 | | -- Smart split suggestion APIs and UI are not implemented yet |
222 | | -- Mobile notification center and expanded offline retry UI are not implemented yet |
223 | | -- Broader observability counters and tracing for expense, settlement, and webhook flows still need expansion |
| 5 | +## Snapshot |
| 6 | +- Monorepo with NestJS API, Expo mobile client, and a Next.js marketing site managed via Turbo + pnpm. |
| 7 | +- Core expense, settlement, receipt, notification, realtime, and payment primitives are implemented server-side with Prisma/PostgreSQL (Supabase URL) and Redis/BullMQ. |
| 8 | +- Mobile app ships full flows (auth, groups, expenses, settle-up, activity, profile/settings) with offline queueing, push tokens, realtime sockets, and UPI deep-link helper; UI built with React Native Paper + Reanimated. |
| 9 | +- Web app is currently a single-page marketing/landing experience with Framer Motion; no dashboard/auth wiring yet. |
| 10 | +- Observability (Sentry, OpenTelemetry, Prometheus metrics) and security hardening (helmet, throttling, CSRF on refresh, JWT + refresh cookies) are wired in backend startup. |
| 11 | + |
| 12 | +## Project Structure |
| 13 | +- apps/backend — NestJS service exposing REST + WebSocket APIs; background jobs via BullMQ. |
| 14 | +- apps/mobile — Expo Router/React Native client with feature screens and state stores (Zustand). |
| 15 | +- apps/web — Next.js 15 site styled with Tailwind + Framer Motion animations. |
| 16 | +- packages/shared-types — DTOs and response contracts shared across apps. |
| 17 | +- infra/terraform — Terraform skeleton for AWS (ECS, RDS, S3) deployment. |
| 18 | + |
| 19 | +## Backend (apps/backend) |
| 20 | +### Major modules & responsibilities |
| 21 | +- Auth: register/login/google, refresh tokens (httpOnly cookie), CSRF token endpoint. |
| 22 | +- Users: `GET /users/me`, `POST /users/push-token` to register Expo tokens. |
| 23 | +- Groups: CRUD-ish flows (`POST /groups`, `GET /groups`, `GET /groups/:id`, members, invite, per-user/group summaries). |
| 24 | +- Expenses: create/list/update/delete per group; pagination via cursor+limit; detail fetch. |
| 25 | +- Balances: `GET /groups/:id/balances` to expose pairwise balances. |
| 26 | +- Simplify: `GET /groups/:id/simplify` returns settlement suggestions (used by mobile settle-up). |
| 27 | +- Settlements: `POST /groups/:id/settlements` with optional `x-idempotency-key`. |
| 28 | +- Receipts: `POST /expenses/:id/receipt-url` returns presigned S3 upload URL and records receipt key. |
| 29 | +- Activity: user and group feeds with cursor pagination. |
| 30 | +- Payments: `POST /payments/create-intent` (Stripe PaymentIntent) and `POST /payments/webhook` (queues handling); settlements are recorded from successful webhooks. |
| 31 | +- Realtime: Socket.IO gateway with `join_group`/`leave_group` rooms; emits expense/settlement/group-member events per group. |
| 32 | +- Notifications: Expo push delivery via Redis pub/sub + BullMQ retries; invalid tokens are cleaned up. |
| 33 | +- Health/Observability: `/health` checks PostgreSQL + Redis; `/metrics` exposes Prometheus text; OpenTelemetry auto-instrumentation on boot. |
| 34 | + |
| 35 | +### Data model (Prisma) |
| 36 | +- Users with JWT/refresh tokens, push tokens, activities. |
| 37 | +- Groups with members (roles), expenses (splits), balances, settlements, receipts, invites, payments, activities. |
| 38 | +- Expenses store cent-precision totals plus per-user splits; receipts are 1:1 with expenses. |
| 39 | +- Settlements & payments support idempotency keys; payments map to Stripe PaymentIntents. |
| 40 | + |
| 41 | +### Integrations & infrastructure |
| 42 | +- PostgreSQL via `SUPABASE_DATABASE_URL`. |
| 43 | +- Redis for queues + pub/sub + throttling state. |
| 44 | +- AWS S3 (AWS SDK v3) for receipt uploads (presigned PUT URLs). |
| 45 | +- Stripe (v18 SDK) for PaymentIntents; webhook signature enforced when `STRIPE_WEBHOOK_SECRET` set. |
| 46 | +- Google OAuth via `passport-google-oauth20` alongside email/password. |
| 47 | +- Expo push notifications via `expo-server-sdk`. |
| 48 | +- Security middleware: helmet, compression, cookie-parser, CSRF on refresh/csrf-token routes, Nest ValidationPipe (whitelist/forbid), global throttling, CORS allowlist. |
| 49 | + |
| 50 | +### Background jobs (BullMQ) |
| 51 | +- Notification delivery with exponential backoff and invalid-token cleanup. |
| 52 | +- Receipt processing placeholder queue hook (currently enqueues on presign, no downstream worker in repo). |
| 53 | +- Payment webhook handling queued with retries to shield Stripe endpoint. |
| 54 | + |
| 55 | +### Testing |
| 56 | +- Unit/integration Jest suites for activity, balances, expenses (service + integration), settlements (service + integration), receipts (service + integration), payments, simplify, users, notifications. |
| 57 | + |
| 58 | +## Mobile (apps/mobile) |
| 59 | +- Stack: Expo SDK 54, React Native 0.81, React Navigation, React Native Paper, Reanimated, Lottie, Zustand stores, Axios client, Socket.IO client, Expo Notifications, SecureStore, NetInfo. |
| 60 | +- UX flows: onboarding (login/register), group list/detail, members, add expense, expense detail, activity feed, settle-up suggestions, profile, settings, toasts, skeleton placeholders. |
| 61 | +- Offline: SecureStore-backed offline POST queue with automatic flush when connectivity returns; queues group expense creation, settlements, and invites. |
| 62 | +- Networking: Axios client auto-injects bearer token from SecureStore; base URL auto-derives from Expo host or `EXPO_PUBLIC_API_URL`; logs in dev; latency tracked; retry queue marks requests with `x-offline-retry` to avoid loops. |
| 63 | +- Realtime: connects to Socket.IO after auth for group events. |
| 64 | +- Push: registers device tokens and posts to `/users/push-token`. |
| 65 | +- Payments/settle-up UX: uses simplify suggestions; triggers UPI deep links for payers then marks settlement via API (does not yet surface Stripe PaymentIntent flow in-app). |
| 66 | +- Visuals: gradient/neo styling, animations on hero cards/actions, Avatar initials, haptic feedback hooks present. |
| 67 | +- Tests: basic Jest + testing-library specs for login, group list, add expense screens; TypeScript lint via `tsc --noEmit`. |
| 68 | + |
| 69 | +## Web (apps/web) |
| 70 | +- Next.js 15 single-page marketing site with Framer Motion animations, Lucide icons, Tailwind utility styles. |
| 71 | +- Sections: hero CTA, feature grid, comparison table, FAQ/dev log, newsletter form, footer links. |
| 72 | +- No auth or API wiring yet; currently a static experience suitable for marketing/landing only. |
| 73 | + |
| 74 | +## Shared Types (packages/shared-types) |
| 75 | +- Zod/TypeScript DTOs for auth payloads, expenses, balances, settlements, receipts, activity feeds, payments, notifications; consumed by backend controllers and mobile client. |
| 76 | + |
| 77 | +## DevOps & Tooling |
| 78 | +- Scripts: `pnpm dev|dev:backend|dev:mobile|dev:web`, `pnpm build`, `pnpm lint`, `pnpm test`, `pnpm e2e` (Playwright), `pnpm seed`. |
| 79 | +- Docker: backend Dockerfile; `docker-compose.yml` for local Postgres/Redis/S3? (check services before use). |
| 80 | +- Monitoring: Sentry DSN + OTEL hooks; Prometheus metrics endpoint. |
| 81 | +- Infra: Terraform stubs for AWS ECS/RDS/S3; CI assumed via GitHub Actions (see README claim) though pipeline files not present in repo root. |
| 82 | + |
| 83 | +## Known Gaps / Risks |
| 84 | +- Web app is marketing-only; product dashboard, auth, and API integration are not implemented. |
| 85 | +- Payments: mobile flow currently bypasses Stripe; settles via UPI link + manual settlement API. Stripe PaymentIntent UX is not exposed to clients yet. |
| 86 | +- Receipt processing queue lacks worker implementation; uploads are stored but no OCR/parsing pipeline exists. |
| 87 | +- Offline queue can replay POSTs without deduplication beyond backend idempotency keys; ensure idempotency keys are supplied for settlements/payments when adding clients. |
| 88 | +- Expo SDK 54 with React Native 0.81/React 19 stack may emit peer warnings; verify compatibility before release builds. |
| 89 | +- CI configuration for lint/test/e2e is referenced but not included in the repo snapshot. |
224 | 90 |
|
225 | 91 | ## Next Steps |
226 | | - |
227 | | -1. Align Expo package versions with the installed SDK. |
228 | | -2. Validate login, expense, settlement, payment, and notification flows end to end on a real device and a development build. |
229 | | -3. Add receipt OCR processing and structured receipt item storage. |
230 | | -4. Add smart split suggestion APIs and mobile UI. |
231 | | -5. Expand observability counters and tracing for expense creation, settlement creation, and webhook processing. |
232 | | -6. Clarify the target scope and milestone for the web workspace. |
| 92 | +1. Decide on in-app payment path: surface Stripe PaymentIntent client flow or keep UPI-only and disable PaymentIntent endpoint if unused. |
| 93 | +2. Implement receipt-processing worker (OCR or at least validation) for queued jobs; expose receipt retrieval in UI. |
| 94 | +3. Build authenticated web dashboard (groups/expenses/settlements) reusing shared-types + backend APIs. |
| 95 | +4. Add end-to-end tests (Playwright) for critical flows: auth, expense creation, settlement, receipt upload. |
| 96 | +5. Tighten mobile offline/idempotency by attaching idempotency keys and surfacing retry status to users. |
| 97 | +6. Add CI pipeline files (GitHub Actions) to run lint/test/build on PRs and publish metrics artifacts. |
0 commit comments