Skip to content

Commit 032c590

Browse files
authored
Merge branch 'main' into docs/849-indexer-operational-runbook
2 parents 2361885 + 4bd2cc2 commit 032c590

111 files changed

Lines changed: 4013 additions & 1048 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CODE_OF_CONDUCT.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
11
# Contributor Covenant Code of Conduct
22

3-
## Our Pledge
4-
5-
We as members, contributors, and leaders pledge to make participation in our
6-
community a harassment-free experience for everyone, regardless of age, body
7-
size, visible or invisible disability, ethnicity, sex characteristics, gender
8-
identity and expression, level of experience, education, socio-economic status,
9-
nationality, personal appearance, race, religion, or sexual identity
10-
and orientation.
113

12-
We pledge to act and interact in ways that contribute to an open, welcoming,
13-
diverse, inclusive, and healthy community.
144

155
## Our Standards
166

@@ -36,6 +26,19 @@ Examples of unacceptable behavior include:
3626
* Other conduct which could reasonably be considered inappropriate in a
3727
professional setting
3828

29+
30+
## Our Pledge
31+
32+
We as members, contributors, and leaders pledge to make participation in our
33+
community a harassment-free experience for everyone, regardless of age, body
34+
size, visible or invisible disability, ethnicity, sex characteristics, gender
35+
identity and expression, level of experience, education, socio-economic status,
36+
nationality, personal appearance, race, religion, or sexual identity
37+
and orientation.
38+
39+
We pledge to act and interact in ways that contribute to an open, welcoming,
40+
diverse, inclusive, and healthy community.
41+
3942
## Enforcement Responsibilities
4043

4144
Community leaders are responsible for clarifying and enforcing our standards of

ISSUE_134_SUMMARY.md

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,5 @@
11
# Issue #134: Backend SSE Stream Updates - COMPLETE ✅
22

3-
## What Was Built
4-
5-
A production-ready **Server-Sent Events (SSE)** system for real-time stream updates in FlowFi.
6-
7-
## Key Decisions
8-
9-
### SSE vs WebSockets
10-
**Chose SSE** for:
11-
- Unidirectional updates (server → client)
12-
- Simpler implementation & debugging
13-
- Automatic browser reconnection
14-
- Better HTTP/2 compatibility
15-
- Lower overhead for broadcasting
16-
17-
## Implementation Summary
18-
19-
### Core Files Created (7)
20-
```
21-
backend/src/
22-
├── services/sse.service.ts # SSE connection manager
23-
├── controllers/sse.controller.ts # Subscription endpoint
24-
└── routes/events.routes.ts # /events routes
25-
26-
backend/
27-
├── docs/
28-
│ ├── SSE_IMPLEMENTATION.md # Full guide
29-
│ └── SSE_ARCHITECTURE.md # Architecture diagrams
30-
├── examples/useStreamEvents.tsx # React hook
31-
└── test-sse-client.html # Test client
32-
```
33-
34-
### Files Modified (2)
35-
- `src/app.ts` - Added events routes
36-
- `src/controllers/stream.controller.ts` - Added broadcasting
373

384
## API Endpoints
395

@@ -205,3 +171,39 @@ Blockchain → Backend → SSE Service → Multiple Clients
205171
**Secure** with documented best practices
206172

207173
**Ready for integration with blockchain indexer and frontend.**
174+
175+
176+
## What Was Built
177+
178+
A production-ready **Server-Sent Events (SSE)** system for real-time stream updates in FlowFi.
179+
180+
## Key Decisions
181+
182+
### SSE vs WebSockets
183+
**Chose SSE** for:
184+
- Unidirectional updates (server → client)
185+
- Simpler implementation & debugging
186+
- Automatic browser reconnection
187+
- Better HTTP/2 compatibility
188+
- Lower overhead for broadcasting
189+
190+
## Implementation Summary
191+
192+
### Core Files Created (7)
193+
```
194+
backend/src/
195+
├── services/sse.service.ts # SSE connection manager
196+
├── controllers/sse.controller.ts # Subscription endpoint
197+
└── routes/events.routes.ts # /events routes
198+
199+
backend/
200+
├── docs/
201+
│ ├── SSE_IMPLEMENTATION.md # Full guide
202+
│ └── SSE_ARCHITECTURE.md # Architecture diagrams
203+
├── examples/useStreamEvents.tsx # React hook
204+
└── test-sse-client.html # Test client
205+
```
206+
207+
### Files Modified (2)
208+
- `src/app.ts` - Added events routes
209+
- `src/controllers/stream.controller.ts` - Added broadcasting

README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ flowfi/
2929
│ └── DEVELOPMENT.md # Local development guide
3030
```
3131

32+
33+
34+
For full step-by-step instructions, see our [Development Guide](docs/DEVELOPMENT.md).
35+
36+
### Prerequisites
37+
38+
- Node.js & npm
39+
- Rust & Cargo
40+
- Stellar CLI (optional but recommended)
41+
- Docker & Docker Compose (for containerized setup)
42+
43+
3244
## Architecture
3345

3446
FlowFi consists of three main components that work together:
@@ -43,14 +55,6 @@ For full local setup and contributor onboarding, see the [Development Guide](doc
4355

4456
## Getting Started
4557

46-
For full step-by-step instructions, see our [Development Guide](docs/DEVELOPMENT.md).
47-
48-
### Prerequisites
49-
50-
- Node.js & npm
51-
- Rust & Cargo
52-
- Stellar CLI (optional but recommended)
53-
- Docker & Docker Compose (for containerized setup)
5458

5559
### Docker (Recommended)
5660

@@ -83,18 +87,19 @@ To reset the database:
8387
docker compose down -v
8488
```
8589

86-
### Backend (Manual)
90+
91+
92+
### Frontend
8793

8894
```bash
89-
cd backend
95+
cd frontend
9096
npm install
9197
npm run dev
9298
```
93-
94-
### Frontend
99+
### Backend (Manual)
95100

96101
```bash
97-
cd frontend
102+
cd backend
98103
npm install
99104
npm run dev
100105
```

backend/README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,37 @@ DATABASE_URL=postgresql://user:password@localhost:5433/flowfi?schema=public
1919
PORT=3001
2020
STELLAR_RPC_URL=https://soroban-testnet.stellar.org
2121
NETWORK_PASSPHRASE="Test SDF Network ; September 2015"
22+
API_BASE_URL=https://api.staging.flowfi.io
2223
```
2324

25+
- `API_BASE_URL`: Overrides the Swagger UI server URL for the deployed environment (e.g., staging or production). When set, Swagger UI targets `<API_BASE_URL>/v1` instead of the hardcoded defaults.
26+
2427
## Prisma Database
2528

2629
We use Prisma as our ORM to interact with PostgreSQL.
2730

2831
- Schema is located at `prisma/schema.prisma`.
32+
- Configuration (schema path, migrations path, datasource URL) is defined in `prisma.config.ts`.
2933
- Run `npx prisma studio` to view the database through a web UI.
3034

35+
### Seeding the database
36+
37+
`prisma/seed.ts` populates the database with demo fixtures for local development. Run it with:
38+
39+
```bash
40+
npm run prisma:seed
41+
```
42+
43+
(this runs `prisma db seed`, which in turn runs `tsx prisma/seed.ts` as configured under the `prisma.seed` key in `package.json`.)
44+
45+
The script is idempotent (it uses `upsert`/fixed IDs), so it's safe to run multiple times. It creates:
46+
47+
- Two demo users, keyed by fixed Stellar testnet public keys — a sender (`GCM5WPR4DDR24FSAX5LIEM4J7AI3KOWJYANSXEPKYXCSZOTAYXE75AFN`) and a recipient (`GBJCHUKZMTFSLOMNC7P4TS4VJJBTCYL3XKSOLXAUJSD56C4LHND5TWUC`).
48+
- One demo `Stream` (`streamId: 101`) between those two users, using a fixed demo token address, with a sample rate/deposit amount and `isActive: true`.
49+
- One demo `StreamEvent` (`eventType: 'CREATED'`) attached to that stream, with sample transaction hash, ledger sequence, and metadata.
50+
51+
These fixtures are intended purely for local development/demo purposes so the frontend has data to render out of the box; they are not used in automated tests.
52+
3153
## /v1 API
3254

3355
All REST API endpoints are prefixed with `/v1`. Refer to the API Documentation in the root `README.md` and the `docs/` folder for versioning and authentication details.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- Replace the unused (streamId, createdAt) composite with (streamId, timestamp),
2+
-- which matches streamId-scoped event listings that ORDER BY timestamp.
3+
4+
-- CreateIndex
5+
CREATE INDEX IF NOT EXISTS "StreamEvent_streamId_timestamp_idx" ON "StreamEvent"("streamId", "timestamp");
6+
7+
-- DropIndex
8+
DROP INDEX IF EXISTS "StreamEvent_streamId_createdAt_idx";
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-- Convert on-chain stream identifiers from int4 to bigint (Soroban u64).
2+
-- Drop the FK first so both columns can be widened, then recreate it.
3+
4+
ALTER TABLE "StreamEvent" DROP CONSTRAINT IF EXISTS "StreamEvent_streamId_fkey";
5+
6+
ALTER TABLE "Stream" ALTER COLUMN "streamId" TYPE BIGINT USING ("streamId"::bigint);
7+
ALTER TABLE "StreamEvent" ALTER COLUMN "streamId" TYPE BIGINT USING ("streamId"::bigint);
8+
9+
ALTER TABLE "StreamEvent"
10+
ADD CONSTRAINT "StreamEvent_streamId_fkey"
11+
FOREIGN KEY ("streamId") REFERENCES "Stream"("streamId")
12+
ON DELETE RESTRICT ON UPDATE CASCADE;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- AlterTable
2+
ALTER TABLE "Stream" ALTER COLUMN "startTime" SET DATA TYPE BIGINT,
3+
ALTER COLUMN "lastUpdateTime" SET DATA TYPE BIGINT,
4+
ALTER COLUMN "endTime" SET DATA TYPE BIGINT,
5+
ALTER COLUMN "pausedAt" SET DATA TYPE BIGINT;
6+
7+
-- AlterTable
8+
ALTER TABLE "StreamEvent" ALTER COLUMN "timestamp" SET DATA TYPE BIGINT;

backend/prisma/schema.prisma

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,19 @@ model User {
2727
// Stream model - mirrors on-chain stream state for fast querying
2828
model Stream {
2929
id String @id @default(uuid())
30-
streamId Int @unique // On-chain stream ID
30+
streamId BigInt @unique // On-chain stream ID (Soroban u64)
3131
sender String // Sender's Stellar public key
3232
recipient String // Recipient's Stellar public key
3333
tokenAddress String // Token contract address
3434
ratePerSecond String // Rate as string to preserve precision (i128)
3535
depositedAmount String // Total deposited amount (i128)
3636
withdrawnAmount String // Total withdrawn amount (i128)
37-
startTime Int // Unix timestamp when stream started
38-
lastUpdateTime Int // Unix timestamp of last update
39-
endTime Int? // Unix timestamp when stream ends
37+
startTime BigInt // Unix timestamp when stream started
38+
lastUpdateTime BigInt // Unix timestamp of last update
39+
endTime BigInt? // Unix timestamp when stream ends
4040
isActive Boolean @default(true)
4141
isPaused Boolean @default(false)
42-
pausedAt Int? // Unix timestamp when paused
42+
pausedAt BigInt? // Unix timestamp when paused
4343
totalPausedDuration Int @default(0) // Accumulated paused duration in seconds
4444
createdAt DateTime @default(now())
4545
updatedAt DateTime @updatedAt
@@ -68,12 +68,12 @@ model IndexerState {
6868
// StreamEvent model - indexer events for tracking all on-chain stream activities
6969
model StreamEvent {
7070
id String @id @default(uuid())
71-
streamId Int // Reference to on-chain stream ID
71+
streamId BigInt // Reference to on-chain stream ID (Soroban u64)
7272
eventType String // EventType: "CREATED", "TOPPED_UP", "WITHDRAWN", "CANCELLED", "COMPLETED", "PAUSED", "RESUMED"
7373
amount String? // Amount involved in the event (for top-ups, withdrawals)
7474
transactionHash String // Stellar transaction hash
7575
ledgerSequence Int // Ledger sequence number
76-
timestamp Int // Unix timestamp
76+
timestamp BigInt // Unix timestamp
7777
metadata String? // JSON string for additional event data
7878
createdAt DateTime @default(now())
7979
@@ -86,5 +86,6 @@ model StreamEvent {
8686
@@index([timestamp])
8787
@@index([transactionHash])
8888
@@index([createdAt])
89-
@@index([streamId, createdAt])
89+
@@index([streamId, timestamp])
90+
@@unique([transactionHash, eventType])
9091
}

backend/src/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { requestIdMiddleware } from "./middleware/requestId.js";
1616
import v1Routes from "./routes/v1/index.js";
1717

1818
import healthRoutes from "./routes/health.routes.js";
19+
import "./lib/stream-id.js";
1920

2021
const app = express();
2122
const isProduction = process.env.NODE_ENV === "production";

backend/src/config/swagger.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,16 @@ See [Sandbox Mode Documentation](../docs/SANDBOX_MODE.md) for details.`,
3737
url: 'https://opensource.org/licenses/MIT',
3838
},
3939
},
40-
servers: [
41-
{
42-
url: 'http://localhost:3001/v1',
43-
description: 'Development server (v1)',
44-
},
45-
{
46-
url: 'https://api.flowfi.io/v1',
47-
description: 'Production server (v1)',
48-
},
49-
],
40+
servers: (() => {
41+
const baseUrl = process.env.API_BASE_URL;
42+
if (baseUrl) {
43+
return [{ url: `${baseUrl}/v1`, description: 'API server' }];
44+
}
45+
return [
46+
{ url: 'http://localhost:3001/v1', description: 'Development server (v1)' },
47+
{ url: 'https://api.flowfi.io/v1', description: 'Production server (v1)' },
48+
];
49+
})(),
5050
tags: [
5151
{
5252
name: 'Health',

0 commit comments

Comments
 (0)