|
1 | | -# FairShare - Current Documentation (March 2026) |
2 | | - |
3 | | -## 1. Project Snapshot |
4 | | -FairShare is a pnpm + Turborepo monorepo for shared expense management. |
5 | | - |
6 | | -- Mobile: Expo React Native (TypeScript strict) |
7 | | -- Backend: NestJS (TypeScript strict) |
8 | | -- Web: Next.js |
9 | | -- Database: PostgreSQL (Supabase) via Prisma |
10 | | -- Cache: Redis |
11 | | -- Storage: AWS S3 |
12 | | - |
13 | | -Current baseline: |
14 | | -- Auth + Supabase flow is working. |
15 | | -- Group/member flows are implemented. |
16 | | -- Real split creation UI is implemented. |
17 | | -- Backend and mobile have expanded logging + tests. |
18 | | - |
19 | | -## 2. Monorepo Layout |
20 | | -- `apps/backend` |
21 | | -- `apps/mobile` |
22 | | -- `apps/web` |
23 | | -- `packages/shared-types` |
24 | | -- `infra/terraform` |
25 | | -- `scripts` |
26 | | -- `.github/workflows` |
27 | | - |
28 | | -Key root files: |
29 | | -- `pnpm-workspace.yaml` |
30 | | -- `turbo.json` |
31 | | -- `package.json` |
32 | | -- `Makefile` |
33 | | -- `.prettierrc` |
34 | | -- `doc.md` |
35 | | - |
36 | | -## 3. Shared Types |
37 | | -`packages/shared-types` is the contract source for backend + mobile. |
38 | | - |
39 | | -Notable DTOs: |
40 | | -- Auth tokens + auth request DTOs |
41 | | -- Groups, expenses, balances, settlements |
42 | | -- Activity DTOs |
43 | | -- Receipt URL DTO |
44 | | -- Push token DTO |
45 | | -- Group member summary DTO (`GroupMemberSummaryDto`) |
46 | | - |
47 | | -## 4. Backend Status |
48 | | - |
49 | | -### 4.1 Core Runtime |
50 | | -- API prefix: `/api/v1` |
51 | | -- ValidationPipe: enabled globally |
52 | | -- Helmet + compression + cookie parser |
53 | | -- CORS from env config |
54 | | -- Throttler enabled (`100/min/IP`) |
55 | | -- Request logging middleware: |
56 | | - - logs method, path, status, duration |
57 | | - |
58 | | -### 4.2 Auth |
59 | | -Endpoints: |
60 | | -- `POST /api/v1/auth/register` |
61 | | -- `POST /api/v1/auth/login` |
62 | | -- `POST /api/v1/auth/google` |
63 | | -- `POST /api/v1/auth/refresh` |
64 | | - |
65 | | -Behavior: |
66 | | -- JWT access + refresh |
67 | | -- Refresh rotation persisted in DB |
68 | | -- duplicate email handling in register |
69 | | - |
70 | | -### 4.3 Group/Member Management |
71 | | -Endpoints: |
72 | | -- `POST /api/v1/groups` |
73 | | -- `GET /api/v1/groups` |
74 | | -- `GET /api/v1/groups/:id` |
75 | | -- `GET /api/v1/groups/:id/members` |
76 | | -- `POST /api/v1/groups/:id/invite` |
77 | | - |
78 | | -Membership validation: |
79 | | -- group-read and group-member routes validate actor membership |
80 | | - |
81 | | -### 4.4 Expenses / Balances / Settlements / Simplify / Receipts |
82 | | -Expenses: |
83 | | -- `POST /api/v1/groups/:id/expenses` |
84 | | -- `GET /api/v1/groups/:id/expenses`d |
85 | | -- `GET /api/v1/expenses/:id` |
86 | | -- `PATCH /api/v1/expenses/:id` |
87 | | -- `DELETE /api/v1/expenses/:id` |
88 | | - |
89 | | -Balances: |
90 | | -- `GET /api/v1/groups/:id/balances` |
91 | | - |
92 | | -Settlements: |
93 | | -- `POST /api/v1/groups/:id/settlements` |
94 | | - |
95 | | -Simplify: |
96 | | -- `GET /api/v1/groups/:id/simplify` |
97 | | - |
98 | | -Receipts: |
99 | | -- `POST /api/v1/expenses/:id/receipt-url` |
100 | | - |
101 | | -### 4.5 Activity + Notifications |
102 | | -Activity: |
103 | | -- `GET /api/v1/groups/:id/activity` |
104 | | - |
105 | | -Notifications: |
106 | | -- Notification event types: |
107 | | - - `expense_created` |
108 | | - - `expense_deleted` |
109 | | - - `settlement_created` |
110 | | - - `group_invite` |
111 | | -- Redis pub/sub channel used for internal notification queue/broadcast |
112 | | -- Push provider is still a stub logger (infra-ready, not external provider yet) |
113 | | - |
114 | | -### 4.6 Database and Prisma |
115 | | -- Prisma datasource points to `SUPABASE_DATABASE_URL` |
116 | | -- Schema synced with Supabase |
117 | | -- Key models in use: |
118 | | - - users, groups, group_members, expenses, splits, balances, settlements, |
119 | | - receipts, refresh_tokens, activities, push_tokens |
120 | | - |
121 | | -## 5. Mobile Status |
122 | | - |
123 | | -### 5.1 Navigation |
124 | | -Auth stack: |
125 | | -- `LoginScreen` |
126 | | -- `RegisterScreen` |
127 | | - |
128 | | -Root stack (post-auth): |
129 | | -- `Dashboard` (HomeScreen) |
130 | | -- `Tabs` |
131 | | -- `GroupDetail` |
132 | | -- `GroupMembers` |
133 | | -- `AddExpense` |
134 | | -- `ExpenseDetail` |
135 | | -- `SettleUp` |
136 | | -- `Settings` |
137 | | - |
138 | | -Tabs: |
139 | | -- `Groups` |
140 | | -- `Activity` |
141 | | -- `Profile` |
142 | | - |
143 | | -### 5.2 Dashboard |
144 | | -`HomeScreen` now acts as dashboard: |
145 | | -- recent activity preview |
146 | | -- quick add expense action |
147 | | -- quick settle suggestion action |
148 | | -- floating add-expense button |
149 | | - |
150 | | -### 5.3 Group Flows |
151 | | -`GroupDetailScreen`: |
152 | | -- member avatars row at top |
153 | | -- member tap -> member balance summary toast |
154 | | -- sections: |
155 | | - - Today |
156 | | - - This week |
157 | | - - Older |
158 | | -- expense row shows payer/avatar/participants/date/amount |
159 | | -- swipe left -> delete |
160 | | -- confirm delete modal |
161 | | - |
162 | | -`GroupMembersScreen`: |
163 | | -- list members |
164 | | -- invite by email |
165 | | -- invite action button |
166 | | - |
167 | | -### 5.4 Expense Creation (Real Split UI) |
168 | | -`AddExpenseScreen` now supports: |
169 | | -- load real group members |
170 | | -- payer selection |
171 | | -- participant selection |
172 | | -- split types: |
173 | | - - equal |
174 | | - - exact amount |
175 | | - - percentage |
176 | | -- inline split validation mismatch error |
177 | | - |
178 | | -`SplitSelector` component: |
179 | | -- path: `app/components/ui/SplitSelector.tsx` |
180 | | - |
181 | | -Split math utilities: |
182 | | -- path: `app/utils/split.ts` |
183 | | - |
184 | | -### 5.5 API Layer and Error Handling |
185 | | -`app/services/api.ts`: |
186 | | -- auth header interceptor |
187 | | -- base URL resolution for real-device dev |
188 | | -- structured API errors (`code`, `message`, `context`) |
189 | | -- critical server errors reported to Sentry |
190 | | - |
191 | | -### 5.6 Notifications on Mobile |
192 | | -- push token registration on authenticated state |
193 | | -- notification tap routing: |
194 | | - - expense event -> `ExpenseDetail` |
195 | | - - settlement/invite event -> `GroupDetail` |
196 | | - |
197 | | -### 5.7 UI/Polish |
198 | | -- MaterialCommunityIcons standardized in navigation/empty-state usage |
199 | | -- custom button variants + press-scale animation in `ui/Button` |
200 | | -- empty-state visual improvements |
201 | | -- illustration placeholders added: |
202 | | - - `app/assets/illustrations/no-groups.txt` |
203 | | - - `app/assets/illustrations/no-expenses.txt` |
204 | | - - `app/assets/illustrations/no-activity.txt` |
205 | | - |
206 | | -## 6. Logging Guide |
207 | | - |
208 | | -### Mobile logs |
209 | | -- `[auth-ui]`: button click, validation, submit start/success/failure |
210 | | -- `[auth]`: auth service payload tracing |
211 | | -- `[api]`: base URL, request, response, structured error |
212 | | - |
213 | | -### Backend logs |
214 | | -- `AuthController`: route entry |
215 | | -- `AuthService`: auth attempt/success/failure |
216 | | -- `PrismaService`: DB host + connection state |
217 | | -- `RequestLoggerMiddleware`: method/path/status/duration |
218 | | - |
219 | | -## 7. Testing Status |
220 | | - |
221 | | -Backend tests expanded for: |
222 | | -- group invite edge cases |
223 | | -- member listing |
224 | | -- split sum validation |
225 | | -- notification assertions in expense flow |
226 | | - |
227 | | -Mobile tests added for: |
228 | | -- `GroupListScreen` render path |
229 | | -- `AddExpenseScreen` validation path |
230 | | -- `SplitSelector` interaction |
231 | | -- split utility math |
232 | | - |
233 | | -## 8. CI Status (`.github/workflows/ci.yml`) |
234 | | -Pipeline now has separate jobs: |
235 | | -- `typecheck` |
236 | | -- `lint` |
237 | | -- `test` |
238 | | -- `build` (depends on above) |
239 | | - |
240 | | -Includes: |
241 | | -- pnpm cache |
242 | | -- turbo cache |
243 | | -- Prisma generate step |
244 | | -- coverage artifact upload |
245 | | - |
246 | | -## 9. Env Variables |
247 | | - |
248 | | -Root `.env.example` includes: |
249 | | -- `SUPABASE_DATABASE_URL` |
250 | | -- `JWT_SECRET` |
251 | | -- `JWT_REFRESH_SECRET` |
252 | | -- `GOOGLE_CLIENT_ID` |
253 | | -- `GOOGLE_CLIENT_SECRET` |
254 | | -- `REDIS_URL` |
255 | | -- `CORS_ORIGINS` |
256 | | -- `AWS_ACCESS_KEY_ID` |
257 | | -- `AWS_SECRET_ACCESS_KEY` |
258 | | -- `AWS_REGION` |
259 | | -- `S3_BUCKET` |
260 | | -- `SENTRY_DSN` |
261 | | -- `EXPO_PUBLIC_SENTRY_DSN` |
262 | | - |
263 | | -Mobile `apps/mobile/.env.example`: |
264 | | -- `EXPO_PUBLIC_API_URL` |
265 | | -- `EXPO_PUBLIC_SENTRY_DSN` |
266 | | -- `EXPO_PUBLIC_S3_BASE_URL` |
267 | | - |
268 | | -## 10. Scripts and Tooling |
269 | | - |
270 | | -Root scripts: |
271 | | -- `pnpm install` |
272 | | -- `pnpm dev` |
273 | | -- `pnpm dev:backend` |
274 | | -- `pnpm dev:mobile` |
275 | | -- `pnpm dev:web` |
276 | | -- `pnpm build` |
277 | | -- `pnpm test` |
278 | | -- `pnpm format` |
279 | | -- `pnpm seed` |
280 | | - |
281 | | -Makefile: |
282 | | -- `make dev` |
283 | | -- `make test` |
284 | | -- `make build` |
285 | | -- `make dev-backend` |
286 | | -- `make dev-mobile` |
287 | | -- `make dev-web` |
288 | | - |
289 | | -## 11. Known Notes |
290 | | -- Expo Go shows `expo-notifications` limitation warnings (expected in Expo Go). |
291 | | -- AWS SDK v2 deprecation warning appears in backend logs; migration to v3 is pending. |
292 | | -- Push notification sending is queue + logging infrastructure ready, external push provider integration pending. |
| 1 | +# FairShare — Production Launch Notes (March 2026) |
| 2 | + |
| 3 | +## 1. Overview |
| 4 | +FairShare is a pnpm/Turborepo monorepo built for collaborative expense sharing across Expo mobile, NestJS backend, and a Next.js marketing/dashboard experience. The stack is hard‑typed (TypeScript strict), backed by Prisma + Supabase PostgreSQL, Redis caching, and AWS S3 storage. JWT auth, refresh rotation, Google OAuth, and production observability are already wired together. |
| 5 | + |
| 6 | +## 2. Infrastructure & Deployment |
| 7 | +- **Terraform**: reusable modules (`vpc`, `ecs_cluster`, `ecs_service_backend`, `redis`, `s3_storage`, `cloudwatch_logs`) plus per‑env stacks (dev/staging/prod) deploy ECS Fargate backend, ElastiCache Redis, S3 buckets, and CloudWatch log groups. ECS service uses ALB health checks against `/health` and auto scaling (min/max caps). |
| 8 | +- **Docker**: multi‑stage backend image with `HEALTHCHECK` hitting `/health`, Prisma migrations bundled, and runtime environment variables wired from `AppConfigService`. |
| 9 | +- **CI/CD**: |
| 10 | + - `ci.yml`: pnpm + Turbo cache; jobs for typecheck, lint, tests, frontend builds, security audit, dependency review, coverage uploads, and Playwright e2e (guarded by `RUN_E2E`). |
| 11 | + - `deploy.yml`: on `main` builds/test -> docker image -> pushes to AWS ECR -> forces ECS service redeploy; image tagged with SHA + `latest`. |
| 12 | +- **Scripts**: `pnpm dev`, `pnpm build`, `pnpm test`, `pnpm mobile:build` (EAS production AAB), `pnpm seed`, `pnpm --filter backend prisma:generate`. |
| 13 | + |
| 14 | +## 3. Backend Implementation |
| 15 | +- **Core runtime**: `/api/v1` prefix, global `ValidationPipe`, helmet, compression, CSRF on refresh + `/auth/csrf-token`, and structured request logging (method/path/status/duration plus Prometheus metrics via `observeApiRequest`). AppConfig enforces environment variables for Supabase, Redis, AWS, S3, Stripe, etc. |
| 16 | +- **Health, metrics, observability**: `GET /health` reports DB + Redis status, `/metrics` exports Prometheus metrics, and OpenTelemetry NodeSDK auto-instrumentation starts on bootstrap with graceful shutdown. |
| 17 | +- **Auth + security**: |
| 18 | + - Email/password + Google OAuth, refresh rotation stored hashed, secure `refresh_token` cookie (`httpOnly`, `secure`, `sameSite=strict`). |
| 19 | + - `csurf` middleware across refresh endpoints; `AuthController` provides `/csrf-token`. |
| 20 | + - Throttler limits auth/login/register to 10 req/min in addition to global 100/min. |
| 21 | +- **Payments & settlements**: |
| 22 | + - Stripe-based `payments` module creates payment intents, stores idempotency keys, handles webhooks queued via BullMQ, and records settlements (duplicate guard + idempotency). |
| 23 | + - Payment webhook job ensures settlement is created once per intent. |
| 24 | +- **Jobs + notifications**: |
| 25 | + - BullMQ queues for notification delivery, receipt processing, payment webhooks; workers publish Expo push notifications asynchronously (job retry/backoff configured). |
| 26 | + - `NotificationsService` now enqueues jobs, reads push tokens from Prisma, and retries chunked Expo requests. |
| 27 | +- **Data integrity**: |
| 28 | + - Prisma schema now includes `Payment`, `Activity`, `PushToken`, `Balance`, `Settlement`, etc., with indexes and soft delete awareness via `createdAt`. |
| 29 | + - Utilities `money.util.ts` and `sanitize.util.ts` ensure BigInt sums and protected text. |
| 30 | + - Validation ensures splits add to total, payer/members exist, expenses capped at 1,000,000 cents, settlements prevent duplicates, invites sanitize email, and idempotency key support in payments/settlements. |
| 31 | + |
| 32 | +## 4. Frontend & UX (priority on polish + flow) |
| 33 | +### Mobile Experience |
| 34 | +- **Navigation**: auth stack (`Login`, `Register`), main stack with `Dashboard`, tab navigator (`Groups`, `Activity`, `Profile`), and deep links to `GroupDetail`, `GroupMembers`, `AddExpense`, `ExpenseDetail`, `SettleUp`, `Settings`. |
| 35 | +- **Dashboard (HomeScreen)**: quick insights, activity preview, quick add expense, quick settle suggestion, and floating action button linking to `AddExpenseScreen`. |
| 36 | +- **Group detail**: |
| 37 | + - Sections framed by time (`Today`, `This Week`, `Older`) with payer avatars, participant chips, swipe-to-delete (modal confirm), and member avatars that show balance summaries on tap. |
| 38 | + - Member roster view with invite-by-email action and inline loading states/empty states backed by themed illustrations (`no-groups`, `no-expenses`, `no-activity`). |
| 39 | +- **Add Expense workflow**: |
| 40 | + - Real group members loaded, payer + participant selection, split selector supporting equal, exact, and percentage splits with inline validation. |
| 41 | + - `SplitSelector` component and shared `split.ts` utility manage calculations; `money` utilities ensure BigInt-friendly arithmetic. |
| 42 | +- **Settle Up flow**: |
| 43 | + - Greedy simplify data drives buttons; UPI deeplink (`upi://pay?...`) plus “Mark as paid” button after payment ensures manual checkoff; success animation via Lottie. |
| 44 | + - Offline + queue backed by `offlineQueue` using NetInfo; API wrappers mark retried POSTs accordingly. |
| 45 | +- **Theming & UI polish**: |
| 46 | + - Design system with responsive spacing/typography/colors (`#4F46E5`, `#F8FAFC`, Inter), button variants (primary/secondary/danger) with press-scale animation via Reanimated. |
| 47 | + - Custom UI primitives (`Avatar`, `Button`, `Card`, `MoneyText`, `LoadingSpinner`, `EmptyState`) built on react-native-paper plus MaterialCommunityIcons. |
| 48 | + - Animations for settlements (Lottie), skeleton loaders, haptic feedback, toast system, and offline-safe retry notices. |
| 49 | +- **Networking**: |
| 50 | + - Axios layer logs requests/responses, attaches JWT, measures latency (`trackApiLatency`), reports high latency to Sentry, and queues POSTs when offline. |
| 51 | + - SecureStore persists tokens; Expo Notifications + Sentry SDK initialized in App.tsx; realtime socket handled via `socket.io-client` with rooms by group. |
| 52 | + |
| 53 | +### Web Experience |
| 54 | +- Authenticated dashboard under `/dashboard` showing group list, balances, and recent activity (reuses API contracts). |
| 55 | +- Marketing + documentation pages (`/features`, `/pricing`, `/about`, `/login`) include TailwindCSS + Framer Motion cards, hero with CTA, FAQ, newsletter form, and metadata for SEO. |
| 56 | + |
| 57 | +## 5. Testing & CI |
| 58 | +- Backend: Jest suites cover groups, balances, settlements (integration + unit), expenses, simplify, activity, notifications; newly updated mocks support duplicate-guard logic. |
| 59 | +- Mobile: jest-expo tests for `SplitSelector`, `AddExpenseScreen`, `GroupListScreen`, `LoginScreen`. |
| 60 | +- Playwright e2e: registration → login → group → invite → expense → settlement → activity assertions. |
| 61 | +- CI pipeline (see `.github/workflows/ci.yml`) ensures typecheck, lint, tests, builds, security audit, dependency review, coverage artifacts, and Playwright run (conditioned). |
| 62 | + |
| 63 | +## 6. Logging & Observability |
| 64 | +- Backend structured logging (RequestLogger + Sentry + Prometheus). Observability controller exposes metrics for API latency, error count, expense creation, active users. |
| 65 | +- Mobile logs prefixed `[api]`, `[auth-ui]`, `[auth]`; Sentry receives high-latency warnings and slow-screen traces. |
| 66 | + |
| 67 | +## 7. Environment & Secrets |
| 68 | +- `.env.example` contains Supabase, JWT secrets, Google OAuth, Redis, CORS, AWS, S3, Stripe, Sentry keys. |
| 69 | +- Mobile `.env.example` covers `EXPO_PUBLIC_API_URL`, Sentry, and S3 base URL. |
| 70 | +- `AppConfigService` enforces `mustGet` for mandatory vars, while mobile/respective services resolve host addresses for Expo Go vs LAN dev. |
| 71 | + |
| 72 | +## 8. Next Steps |
| 73 | +1. Wire Expo notification tokens to backend + real push service (currently logged through Expo queue). |
| 74 | +2. Migrate AWS SDK usage to v3 and align Terraform CDK if needed. |
| 75 | +3. Document E2E setup (`RUN_E2E=true`) and release Playwright builds in CI. |
0 commit comments