This guide provides all the steps you need to set up, initialize, and run BDate. The app uses React for the frontend, Go for the backend, and SQLite for the database.
Before you start, ensure you meet the Prerequisites listed below. You'll also need to create a Supabase account to obtain the required API keys and secrets.
Team Info: Group #33 Tiffany Best Friends
Alexis Kim - @alexisjkim; Meryl Mathew - @hypatiav2; Aarush Agte - @apaphy; Tiffany Chen - @t1ffanyc; Daniel Chen - @dmychen;
-
Install Required Software
- Node.js and npm (latest stable version)
- Go (latest stable version)
- SQLite
- Git (optional, for cloning the repository)
-
Set Up Supabase
- Create a Supabase account at supabase.com.
- Create a new project and note down your:
REACT_APP_SUPABASE_URL
REACT_APP_SUPABASE_ANON_KEY
- Obtain a
SUPABASE_JWT_SECRET
from your Supabase project settings.
-
Environment Setup
- Ensure your system has a terminal or shell configured to run Node.js, Go, and SQLite commands.
git clone https://github.com/hypatiav2/35L-project
cd 35L-project
For the frontend (React):
npm install
This will use the provided package-lock.json to ensure consistent dependency versions.
Create a .env file in the root directory with the following content:
Frontend .env:
REACT_APP_SUPABASE_URL=<your-supabase-url>
REACT_APP_SUPABASE_ANON_KEY=<your-supabase-anon-key>
SUPABASE_JWT_SECRET=<your-supabase-jwt-secret>
Replace <your-supabase-url>, <your-supabase-anon-key>, and <your-supabase-jwt-secret> with the values from your Supabase account.
Navigate to the backend directory:
cd backend
Ensure the Go module dependencies are set up:
go mod tidy
Run the database initialization script:
go run init_db.go
Run the main Go application:
go run main.go
Navigate to the root directory:
npm start
Once both the backend and frontend are running:
Open your browser and navigate to http://localhost:3000
Run
npm i
and
npm start
to get frontend running. Page mockups to implement can be found on Figma.
See backend/documentation.md
for more detailed documentation on the available API routes, responses, and parameters.
To test routes, we can use postman or curl. We need a valid JWT token to pass along with all our requests, since our backend verifies authentication. Tokens expire after some time.
We can call supabase directly to get a valid token, simulating logging into our frontend.
Call the endpoint
https://<OUR_SUPABASE_URL_THING>/auth/v1/token?grant_type=password
In the request header include..."Content-Type": application/json
"apikey": <OUR_API_KEY>In the body include raw JSON with a valid login...
{
"email": "[email protected]", "password": "123456"
}
The response should include the JWT token we need. When we call routes to our backend, supply that as the JWT token. ( "Authorization": <THE_TOKEN> in the headers field).
users GET /api/v1/users: Retrieve JSON list of users. GET /api/v1/users/me: Retrieve current user. POST /api/v1/profiles: add a new user. PATCH /api/v1/profiles: update the CURRENT user. DELETE /api/v1/profiles: delete any user.
availability
GET /api/v1/availability: get all timeslots for the current user.
POST /api/v1/availability: add one new timeslot to availability
for the current user.
PUT /api/v1/availability: update a timeslot in availability
for the current user.
DELETE /api/v1/availability: delete a timeslot by ID from availability
, if it belongs to the current user.
vector GET /api/v1/vector: get similarity vector for current user. PUT /api/v1/vector: create new similarity vector or update existing vactor for current user. DELETE /api/v1/vector: set similarity vector to null for current user.
matches GET /api/v1/matches: Get "count" number of top matches with current user, with "offset" offset from closest match.
webhooks POST/api/v1/webhooks/users: insert new user. Automatically called by supabase. PATCH/api/v1/webhooks/users: Same as above. DELETE/api/v1/webhooks/users: Same as above.
- Still need to implement webhook on Supabase. Also will not work when running server locally.
Entry point to our go backend.
- Create a multiplexer using the
gorilla/mux
package. mux allows grouping and stuff for HTTP request routing. - Import .env variables globally.
- Create connection pool. Connects to our db and allows reusable connections for multiple requests.
- Call
RegisterRoutes
defined ingo-react-backend/routes
. Registers our backend routes. - Wrap our router in a CORS handler. (Handles preflight request handling and specifies what origins can access resources).
- Wrap routes in
middleware.AuthMiddleware()
. Authenticates and adds userID to request context. - Wrap routes in
middleware.DbMiddleware()
. Adds sql.DB to request context. - Define the handler function for each route by passing our
handler
functions, which implement the logic of the route.
Deal with business logic for our route endpoints. Each file corresponds with a particular resource.
profile.go
Logic for accessing the profile table in our Supabase PostgreSQL database. Create handler functions that will be registered to our routes in routes/routers.go
.
Deal with actual data transfer to and from our Supabase SQL db. Use pgx to interact with the db.
profile.go
- Define a
Profile
struct that corresponds to the form of our profiles table in SQL. GetProfileByID
NOT IMPLEMENTED. Query our db for the profile corresponding touserID
, and return aProfile
struct or error if unsuccessful.
availability.go
GetAvailabilityForUserID
retrieves the availability time slots for a given user. Queries the availability table for a user by their userID and returns a list of time slots in the form of a Availability struct.PostAvailability
adds a new availability time slot for a given user. Inserts a new record into the availability table using the provided Availability struct. Returns an error if the operation fails.
We use Supabase for authentication and Sqlite our postgres database.
User information. Each entry is tied to particular user. We use an user id that references auth.users
, which contains IDs for all users, dealt with by supabases' authentication stuff.
id
: uuid references auth.users(id) (PRIMARY KEY)
updated_at
timestamp with time zone
username
text (must be unique)
full_name
text
bio
text
avatar_url
text (link to a user's images in ouravatar
bucket)
- SELECT: Profiles are viewable by everyone.
- INSERT: Users can insert their own profile.
- UPDATE: Users can update own profile.
Availability for users in the system. Each entry is a timeslot for which a particular user is available. A user's availability schedule is made up of all the entries corresponding to that user.
id
Unique ID for the timeslot (PRIMARY KEY)
user_id
link to auth.users (id)
duration
tstzrange that captures the duration of a timeslotcreated_at
Timestamp of entry creation now()
updated_at
Timestamp of last update now()
All entries corresponding to a single user_id must have unique timeslots. Overlapping time slots are not allowed for a single user.
- SELECT: Enable read access for all users.
- INSERT: Enable insert for users based on user_id.
Examples of manipulating the table...
INSERT INTO availability (user_id, duration)
VALUES (auth.uid(), tstzrange('2024-01-01 10:00:00+00', '2024-01-01 12:00:00+00'));
UPDATE availability
SET duration = tstzrange('2024-01-01 11:00', '2024-01-01 13:00')
WHERE user_id = auth.uid()
AND id = 'specific-availability-id';