Skip to content

Commit fe90770

Browse files
authored
Merge branch 'dev' into collab/basic-realtime
2 parents b0af18f + 3c3a0aa commit fe90770

40 files changed

+1906
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
**/node_modules/
88
.env
99

10+
.vscode/

frontend/peerprep/app/assets/images/logo.svg

Lines changed: 9 additions & 0 deletions
Loading
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { Grid, TextInput, Button, PasswordInput, Divider, Text, Image } from "@mantine/core";
2+
import { useForm } from "@mantine/form";
3+
import { Link } from "react-router";
4+
import logo from "../assets/images/logo.svg";
5+
6+
export function meta() {
7+
return [
8+
{ title: "PeerPrep - Login" },
9+
{ name: "description", content: "Welcome to PeerPrep!" },
10+
];
11+
}
12+
13+
export default function Login() {
14+
const form = useForm({
15+
initialValues: {
16+
email: "",
17+
password: "",
18+
},
19+
20+
validate: {
21+
email: (value) => (/^\S+@\S+$/.test(value) ? null : "Invalid email"),
22+
password: (value) =>
23+
value.length < 6 ? "Password must be at least 6 characters" : null,
24+
},
25+
});
26+
27+
return (
28+
<Grid>
29+
<Grid.Col span={12}>
30+
<Grid justify="center" gutter={"xs"} mt={{ base: 20, md: 200 }}>
31+
<Grid.Col span={{ base: 12, md: 4 }}>
32+
<Image src={logo} alt="PeerPrep Logo" />
33+
<form onSubmit={form.onSubmit((values) => console.log(values))}>
34+
<Grid.Col span={12}>
35+
<TextInput
36+
label="Email"
37+
placeholder="Enter your email"
38+
type="email"
39+
key={form.key("email")}
40+
{...form.getInputProps('email')}
41+
error={undefined}
42+
/>
43+
</Grid.Col>
44+
<Grid.Col span={12}>
45+
<PasswordInput
46+
label="Password"
47+
placeholder="Enter your password"
48+
type="password"
49+
key={form.key("password")}
50+
{...form.getInputProps('password')}
51+
/>
52+
</Grid.Col>
53+
<Grid.Col span={12} mt="md">
54+
<Button type="submit" fullWidth autoContrast>
55+
Login
56+
</Button>
57+
</Grid.Col>
58+
</form>
59+
<Grid.Col span={12} mt="md">
60+
<Divider my="xs" />
61+
</Grid.Col>
62+
<Grid.Col span={12} mt="md" className="text-center">
63+
<Text span>Don't have an account? </Text><Link to="/signup"><Text span td="underline" c="blue" className="cursor-pointer">Sign up!</Text></Link>
64+
</Grid.Col>
65+
</Grid.Col>
66+
</Grid>
67+
</Grid.Col>
68+
</Grid>
69+
);
70+
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { Grid, TextInput, Button, PasswordInput, Divider, Text, Image } from "@mantine/core";
2+
import { useForm } from "@mantine/form";
3+
import { Link } from "react-router";
4+
import logo from "../assets/images/logo.svg";
5+
6+
export function meta() {
7+
return [
8+
{ title: "PeerPrep - Signup" },
9+
{ name: "description", content: "Welcome to PeerPrep!" },
10+
];
11+
}
12+
13+
export default function Signup() {
14+
const form = useForm({
15+
initialValues: {
16+
email: "",
17+
username: "",
18+
password: "",
19+
},
20+
21+
validate: {
22+
email: (value) => (/^\S+@\S+$/.test(value) ? null : "Invalid email"),
23+
password: (value) =>
24+
value.length < 6 ? "Password must be at least 6 characters" : null,
25+
},
26+
});
27+
28+
return (
29+
<Grid>
30+
<Grid.Col span={12}>
31+
<Grid justify="center" gutter={"xs"} mt={{ base: 20, md: 200 }}>
32+
<Grid.Col span={{ base: 12, md: 4 }}>
33+
<Image src={logo} alt="PeerPrep Logo" />
34+
<form onSubmit={form.onSubmit((values) => console.log(values))}>
35+
<Grid.Col span={12}>
36+
<TextInput
37+
label="Email"
38+
placeholder="Enter your email"
39+
type="email"
40+
key={form.key("email")}
41+
{...form.getInputProps('email')}
42+
error={undefined}
43+
/>
44+
</Grid.Col>
45+
<Grid.Col span={12}>
46+
<TextInput
47+
label="Username"
48+
placeholder="Enter your Username"
49+
type="text"
50+
key={form.key("username")}
51+
{...form.getInputProps('username')}
52+
error={undefined}
53+
/>
54+
</Grid.Col>
55+
<Grid.Col span={12}>
56+
<PasswordInput
57+
label="Password"
58+
placeholder="Enter your password"
59+
type="password"
60+
key={form.key("password")}
61+
{...form.getInputProps('password')}
62+
/>
63+
</Grid.Col>
64+
<Grid.Col span={12} mt="md">
65+
<Button type="submit" fullWidth autoContrast>
66+
Login
67+
</Button>
68+
</Grid.Col>
69+
</form>
70+
<Grid.Col span={12} mt="md">
71+
<Divider my="xs" />
72+
</Grid.Col>
73+
<Grid.Col span={12} mt="md" className="text-center">
74+
<Text span>Already have an account? </Text><Link to="/login"><Text span td="underline" c="blue" className="cursor-pointer">Log in!</Text></Link>
75+
</Grid.Col>
76+
</Grid.Col>
77+
</Grid>
78+
</Grid.Col>
79+
</Grid>
80+
);
81+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
__pycache__/
2+
*.pyc
3+
*.pyo
4+
*.pyd
5+
.venv/
6+
venv/
7+
.git
8+
.gitignore
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
__pycache__/
2+
*.pyc
3+
*.pyo
4+
*.pyd
5+
.venv/
6+
venv/
7+
.env
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
FROM python:3.11-slim
2+
3+
WORKDIR /app
4+
5+
COPY requirements.txt .
6+
RUN pip install --no-cache-dir -r requirements.txt
7+
8+
COPY ./app ./app
9+
10+
EXPOSE 8000
11+
12+
# Dev mode (reload)
13+
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]

services/matching-service/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
run:
2+
uvicorn app.main:app --reload --port 8000
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Matching Service
2+
3+
## Overview
4+
5+
The **Matching Service** is responsible for pairing users in PeerPrep based on selected topic, difficulty, and programming language. It manages user queues, handles match creation, and communicates with other services such as:
6+
7+
- **User Service**
8+
- **Question Service**
9+
- **Collaboration Service**
10+
11+
This service is built using **FastAPI** and is designed to be **containerised using Docker**.
12+
13+
---
14+
15+
## Features
16+
17+
- Join a match queue for a specific topic, difficulty, and programming language
18+
- Automatic peer matching from the queue
19+
- Cancel a queue request
20+
- Integration points for collaboration sessions
21+
- Health check endpoint for service monitoring
22+
23+
---
24+
25+
## API Testing with Postman
26+
27+
A **Postman collection** is provided to test the Matching Service:
28+
29+
1. Open Postman -> Import -> File -> `postman/PeerPrep.postman_collection.json`
30+
2. The collection includes:
31+
- Join queue (`/match/request`)
32+
- Cancel queue (`/match/cancel`)
33+
3. Update environment variables if needed (e.g., `url`)
34+
35+
---
36+
37+
## WebSocket Testing
38+
39+
To test real-time events such as match found or timeout:
40+
41+
1. Open Postman -> New -> WebSocket Request
42+
2. URL: `ws://localhost:8000/match/ws/{{user_id}}`
43+
3. Replace `{{user_id}}` with your test user
44+
4. Click **Connect**
45+
5. To simulate events:
46+
- POST `/match/request` from **user 1** and **user 2** to trigger `match.found`
47+
- POST `/match/request` to trigger `match.timeout` if no peer is found within 60 seconds
48+
49+
---
50+
51+
## Running the service
52+
53+
### Using Make
54+
55+
From the `matching-service` folder, run:
56+
57+
```bash
58+
make run
59+
```
File renamed without changes.

0 commit comments

Comments
 (0)