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.example
to.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 dev
The server will start on http://localhost:3000
by default.
Build and start the production server:
pnpm run build
# Start the server
pnpm run start
pnpm 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_KEY
in your environment variables - Include the secret key in your requests using the
x-api-secret
header:
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_ack
to 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_game
to 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_ack
to the client with the move. - if the move is invalid, the server sends a
error
to 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_ended
to 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_ended
to the other participant with the game id and status. - if the other participant rejects the draw request, the server sends a
resume_game
to 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.