A Node.js TypeScript service implementing Express API and websocket server.
- Node.js (v16 or higher)
- PostgreSQL (for database)
- npm or yarn
- Clone the repository:
git clone <repository-url> rollup-on-tba-backend
cd rollup-on-tba-backend- Install dependencies:
pnpm install-
Set up environment variables:
- Copy
.env.exampleto.env - Update the following variables in
.env:DATABASE_URL: Your PostgreSQL connection stringDIRECT_URL: Direct PostgreSQL connection string (same as DATABASE_URL)NEYNAR_API_KEY: Your Neynar API keyAPP_URL: Your application's public URL- Other variables can be left as default for local development
- Copy
Run the development server with hot reload:
pnpm run devThe server will start on http://localhost:3000 by default.
Build and start the production server:
pnpm run build
# Start the server
pnpm run startpnpm run dev: Start development server with hot reloadpnpm run build: Build the TypeScript codepnpm run start: Start the production serverpnpm run lint: Run ESLint
src/
├── index.ts # Application entry point
├── routes/ # API routes
├── controllers/ # Route controllers
├── services/ # Business logic
└── types/ # TypeScript type definitions
Key environment variables that need to be configured:
PORT: Server port (default: 3000)NODE_ENV: Environment (development/production)API_SECRET_KEY: Secret key for API authentication (min 32 characters)DATABASE_URL: PostgreSQL connection stringDIRECT_URL: Direct PostgreSQL connection stringNEYNAR_API_KEY: Your Neynar API keyAPP_URL: Your application's public URL
All API endpoints (except /health) require authentication using an API secret key. To make authenticated requests:
- Set the
API_SECRET_KEYin your environment variables - Include the secret key in your requests using the
x-api-secretheader:
curl -X POST http://localhost:3000/api/notifications \
-H "x-api-secret: your-secret-key-here" \
-H "Content-Type: application/json" \
-d '{"title": "Test", "text": "Message"}'- Create a new branch for your feature
- Make your changes
- Run tests and linting
- Submit a pull request
See LICENSE.md
Explanation of the websocket events based on the flow of the game.
create_game_request: Client sends a request to create a game with an opponentcreate_game_response: Server sends a response to the client with the game id and status.- The client now can share the game id with the opponent through the app, either via a DC or a public cast.
- if the opponent has the miniapp saved, he will receive a notification to join the game.
- TBD
Once an opponent joins the game, it sends a JoinGameRequest to the server.
join_game_request: Client sends a request to join a game.join_game_response: Server sends a response to the client with the game id and status.payment_confirmed: The opponent send this once he has paid the requested amount to join the game.payment_confirmed_ack: Once the payment is confirmed, the server sends apayment_confirmed_ackto the client.- The client now can start the game.
participant_ready: Client sends a request to indicate that the participant is ready to start the game.participant_ready_ack: Server sends a response to the client with the game id and status.
start_game: Once all the participants are ready, the server sends astart_gameto the client with the game id and status.
move_piece: Client sends a request to move a piece.move_piece_error: Server sends a response to the client with the error message and a request to undo the move on the client side.move_piece_ack: Server sends a response to the client with the move.- The server now can update the game board and check if the move is valid.
- if the move is valid, the server sends a
move_piece_ackto the client with the move. - if the move is invalid, the server sends a
errorto the client with the error message and a request to undo the move on the client side. - if the game is at an end state, the server sends a
game_endedto the client with the game id and end game reason.
Any participant can end the game, either by resigning or by requesting a draw.
end_game_request: Client sends a request to end the game.game_ended: Server sends a response to all participants with the game id and status.- The server now can update the game board and check if the game is ended.
end_game_request: Client sends a request to end the game with COLOR_REQUESTED_DRAW as reason.accept_game_end: The server sends this message to the other participant with the game id and status.accept_game_end_response: The other participant answer back, either accepting or rejecting the draw request.- if the other participant accepts the draw request, the server sends a
game_endedto the other participant with the game id and status. - if the other participant rejects the draw request, the server sends a
resume_gameto the client with the game id and status telling all the players to resume the game.
If a user disconnects (close app, drop connection, etc.), the game continues up to the participant remaining time.
participant_left: The server notifies the client that some participant left the game.participant_joined: The server notifies the client that the opponent joined the game.
Any user watching or playing a game can send messages to the game chat. A message can be a text, an image or a tip.
message_sent: Client sends a request to send a message to the game chat.message_sent_ack: Server sends a response to the client with the message.
Spectators can join a game to watch the game.
spectator_join: Client sends a request to join a game as a spectator.spectator_join_ack: Server sends a response to the client with the game id and status.- The client now can watch the game.
There can be errors in the game moves, or in the update to db state or in the backend logic:
error: The server sends a response to the client with the error message.- The client now can undo the move on the client side.
If a client tries to impersonate another user, the server will send a Banned event to the client with the cheating message.
banned: The server sends a response to the client with the cheating message.- The client now can undo the move on the client side.