mirror of
https://github.com/farcasclaudiu/learn-build-apps-copilot-agent.git
synced 2026-06-29 03:01:40 +03:00
feat: implement backend API with models and seed data for OctoFit application
This commit is contained in:
+93
@@ -0,0 +1,93 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = __importDefault(require("express"));
|
||||
const mongoose_1 = __importDefault(require("mongoose"));
|
||||
const Activity_1 = require("./models/Activity");
|
||||
const Leaderboard_1 = require("./models/Leaderboard");
|
||||
const Team_1 = require("./models/Team");
|
||||
const User_1 = require("./models/User");
|
||||
const Workout_1 = require("./models/Workout");
|
||||
const app = (0, express_1.default)();
|
||||
const port = Number(process.env.PORT) || 8000;
|
||||
const mongoUri = process.env.MONGO_URI || "mongodb://127.0.0.1:27017/octofit_db";
|
||||
const codespaceName = process.env.CODESPACE_NAME;
|
||||
const baseUrl = codespaceName
|
||||
? `https://${codespaceName}-8000.app.github.dev`
|
||||
: `http://localhost:${port}`;
|
||||
app.use(express_1.default.json());
|
||||
app.get("/health", (_req, res) => {
|
||||
res.status(200).json({ status: "ok", baseUrl });
|
||||
});
|
||||
app.get("/api/users/", async (_req, res) => {
|
||||
try {
|
||||
const items = await User_1.UserModel.find().sort({ createdAt: -1 }).lean();
|
||||
res.status(200).json({ resource: "users", count: items.length, items });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ message: "Failed to fetch users", error });
|
||||
}
|
||||
});
|
||||
app.get("/api/teams/", async (_req, res) => {
|
||||
try {
|
||||
const items = await Team_1.TeamModel.find()
|
||||
.populate("captain", "username email")
|
||||
.populate("members", "username email")
|
||||
.sort({ createdAt: -1 })
|
||||
.lean();
|
||||
res.status(200).json({ resource: "teams", count: items.length, items });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ message: "Failed to fetch teams", error });
|
||||
}
|
||||
});
|
||||
app.get("/api/activities/", async (_req, res) => {
|
||||
try {
|
||||
const items = await Activity_1.ActivityModel.find()
|
||||
.populate("user", "username email")
|
||||
.populate("team", "name city")
|
||||
.sort({ completedAt: -1 })
|
||||
.lean();
|
||||
res.status(200).json({ resource: "activities", count: items.length, items });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ message: "Failed to fetch activities", error });
|
||||
}
|
||||
});
|
||||
app.get("/api/leaderboard/", async (_req, res) => {
|
||||
try {
|
||||
const items = await Leaderboard_1.LeaderboardModel.find()
|
||||
.populate("entries.user", "username email")
|
||||
.populate("entries.team", "name city")
|
||||
.sort({ generatedAt: -1 })
|
||||
.lean();
|
||||
res.status(200).json({ resource: "leaderboard", count: items.length, items });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ message: "Failed to fetch leaderboard", error });
|
||||
}
|
||||
});
|
||||
app.get("/api/workouts/", async (_req, res) => {
|
||||
try {
|
||||
const items = await Workout_1.WorkoutModel.find().sort({ createdAt: -1 }).lean();
|
||||
res.status(200).json({ resource: "workouts", count: items.length, items });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ message: "Failed to fetch workouts", error });
|
||||
}
|
||||
});
|
||||
const start = async () => {
|
||||
try {
|
||||
await mongoose_1.default.connect(mongoUri);
|
||||
app.listen(port, () => {
|
||||
console.log(`OctoFit backend listening on ${baseUrl}`);
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Failed to start backend:", error);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
void start();
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ActivityModel = void 0;
|
||||
const mongoose_1 = require("mongoose");
|
||||
const activitySchema = new mongoose_1.Schema({
|
||||
user: { type: mongoose_1.Types.ObjectId, ref: "User", required: true },
|
||||
team: { type: mongoose_1.Types.ObjectId, ref: "Team", required: true },
|
||||
type: { type: String, required: true, trim: true },
|
||||
durationMinutes: { type: Number, required: true, min: 1 },
|
||||
caloriesBurned: { type: Number, required: true, min: 1 },
|
||||
completedAt: { type: Date, required: true },
|
||||
}, {
|
||||
timestamps: true,
|
||||
});
|
||||
exports.ActivityModel = (0, mongoose_1.model)("Activity", activitySchema);
|
||||
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.LeaderboardModel = void 0;
|
||||
const mongoose_1 = require("mongoose");
|
||||
const leaderboardEntrySchema = new mongoose_1.Schema({
|
||||
user: { type: mongoose_1.Types.ObjectId, ref: "User", required: true },
|
||||
team: { type: mongoose_1.Types.ObjectId, ref: "Team", required: true },
|
||||
points: { type: Number, required: true, min: 0 },
|
||||
rank: { type: Number, required: true, min: 1 },
|
||||
}, { _id: false });
|
||||
const leaderboardSchema = new mongoose_1.Schema({
|
||||
period: { type: String, required: true, trim: true },
|
||||
generatedAt: { type: Date, required: true },
|
||||
entries: { type: [leaderboardEntrySchema], required: true },
|
||||
}, {
|
||||
timestamps: true,
|
||||
});
|
||||
exports.LeaderboardModel = (0, mongoose_1.model)("Leaderboard", leaderboardSchema);
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TeamModel = void 0;
|
||||
const mongoose_1 = require("mongoose");
|
||||
const teamSchema = new mongoose_1.Schema({
|
||||
name: { type: String, required: true, trim: true },
|
||||
city: { type: String, required: true, trim: true },
|
||||
captain: { type: mongoose_1.Types.ObjectId, ref: "User", required: true },
|
||||
members: [{ type: mongoose_1.Types.ObjectId, ref: "User", required: true }],
|
||||
}, {
|
||||
timestamps: true,
|
||||
});
|
||||
exports.TeamModel = (0, mongoose_1.model)("Team", teamSchema);
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UserModel = void 0;
|
||||
const mongoose_1 = require("mongoose");
|
||||
const userSchema = new mongoose_1.Schema({
|
||||
username: { type: String, required: true, trim: true },
|
||||
email: { type: String, required: true, unique: true, lowercase: true, trim: true },
|
||||
age: { type: Number, required: true, min: 13 },
|
||||
heightCm: { type: Number, required: true, min: 100 },
|
||||
weightKg: { type: Number, required: true, min: 30 },
|
||||
fitnessGoal: { type: String, required: true, trim: true },
|
||||
}, {
|
||||
timestamps: true,
|
||||
});
|
||||
exports.UserModel = (0, mongoose_1.model)("User", userSchema);
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WorkoutModel = void 0;
|
||||
const mongoose_1 = require("mongoose");
|
||||
const workoutSchema = new mongoose_1.Schema({
|
||||
title: { type: String, required: true, trim: true },
|
||||
category: { type: String, required: true, trim: true },
|
||||
difficulty: { type: String, required: true, trim: true },
|
||||
durationMinutes: { type: Number, required: true, min: 1 },
|
||||
equipment: { type: [String], required: true },
|
||||
targetMuscles: { type: [String], required: true },
|
||||
}, {
|
||||
timestamps: true,
|
||||
});
|
||||
exports.WorkoutModel = (0, mongoose_1.model)("Workout", workoutSchema);
|
||||
+161
@@ -0,0 +1,161 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const mongoose_1 = __importDefault(require("mongoose"));
|
||||
const Activity_1 = require("../models/Activity");
|
||||
const Leaderboard_1 = require("../models/Leaderboard");
|
||||
const Team_1 = require("../models/Team");
|
||||
const User_1 = require("../models/User");
|
||||
const Workout_1 = require("../models/Workout");
|
||||
const mongoUri = process.env.MONGO_URI || "mongodb://127.0.0.1:27017/octofit_db";
|
||||
const seed = async () => {
|
||||
try {
|
||||
await mongoose_1.default.connect(mongoUri);
|
||||
console.log("Seed the octofit_db database with test data");
|
||||
await Promise.all([
|
||||
Activity_1.ActivityModel.deleteMany({}),
|
||||
Leaderboard_1.LeaderboardModel.deleteMany({}),
|
||||
Team_1.TeamModel.deleteMany({}),
|
||||
User_1.UserModel.deleteMany({}),
|
||||
Workout_1.WorkoutModel.deleteMany({}),
|
||||
]);
|
||||
const users = await User_1.UserModel.insertMany([
|
||||
{
|
||||
username: "alex_runner",
|
||||
email: "alex.runner@example.com",
|
||||
age: 29,
|
||||
heightCm: 178,
|
||||
weightKg: 74,
|
||||
fitnessGoal: "Half marathon in under 1h40",
|
||||
},
|
||||
{
|
||||
username: "maya_lifter",
|
||||
email: "maya.lifter@example.com",
|
||||
age: 33,
|
||||
heightCm: 165,
|
||||
weightKg: 62,
|
||||
fitnessGoal: "Increase deadlift max to 140kg",
|
||||
},
|
||||
{
|
||||
username: "liam_hiker",
|
||||
email: "liam.hiker@example.com",
|
||||
age: 26,
|
||||
heightCm: 182,
|
||||
weightKg: 79,
|
||||
fitnessGoal: "Improve endurance for alpine trekking",
|
||||
},
|
||||
{
|
||||
username: "sofia_cycle",
|
||||
email: "sofia.cycle@example.com",
|
||||
age: 31,
|
||||
heightCm: 170,
|
||||
weightKg: 66,
|
||||
fitnessGoal: "Ride a 100km gran fondo",
|
||||
},
|
||||
]);
|
||||
const teams = await Team_1.TeamModel.insertMany([
|
||||
{
|
||||
name: "Pulse Pacers",
|
||||
city: "Cluj-Napoca",
|
||||
captain: users[0]._id,
|
||||
members: [users[0]._id, users[2]._id],
|
||||
},
|
||||
{
|
||||
name: "Iron Orbit",
|
||||
city: "Bucharest",
|
||||
captain: users[1]._id,
|
||||
members: [users[1]._id, users[3]._id],
|
||||
},
|
||||
]);
|
||||
await Workout_1.WorkoutModel.insertMany([
|
||||
{
|
||||
title: "Tempo Run 8K",
|
||||
category: "Cardio",
|
||||
difficulty: "Intermediate",
|
||||
durationMinutes: 50,
|
||||
equipment: ["Running shoes", "Sports watch"],
|
||||
targetMuscles: ["Quadriceps", "Hamstrings", "Calves", "Core"],
|
||||
},
|
||||
{
|
||||
title: "Barbell Strength Circuit",
|
||||
category: "Strength",
|
||||
difficulty: "Advanced",
|
||||
durationMinutes: 60,
|
||||
equipment: ["Barbell", "Weight plates", "Bench"],
|
||||
targetMuscles: ["Glutes", "Back", "Chest", "Shoulders"],
|
||||
},
|
||||
{
|
||||
title: "Mobility and Recovery Flow",
|
||||
category: "Mobility",
|
||||
difficulty: "Beginner",
|
||||
durationMinutes: 30,
|
||||
equipment: ["Yoga mat", "Resistance band"],
|
||||
targetMuscles: ["Hips", "Lower back", "Shoulders"],
|
||||
},
|
||||
]);
|
||||
await Activity_1.ActivityModel.insertMany([
|
||||
{
|
||||
user: users[0]._id,
|
||||
team: teams[0]._id,
|
||||
type: "Interval Run",
|
||||
durationMinutes: 42,
|
||||
caloriesBurned: 520,
|
||||
completedAt: new Date("2026-06-18T06:40:00.000Z"),
|
||||
},
|
||||
{
|
||||
user: users[1]._id,
|
||||
team: teams[1]._id,
|
||||
type: "Heavy Strength Session",
|
||||
durationMinutes: 64,
|
||||
caloriesBurned: 610,
|
||||
completedAt: new Date("2026-06-18T18:20:00.000Z"),
|
||||
},
|
||||
{
|
||||
user: users[2]._id,
|
||||
team: teams[0]._id,
|
||||
type: "Hill Hike",
|
||||
durationMinutes: 95,
|
||||
caloriesBurned: 780,
|
||||
completedAt: new Date("2026-06-19T07:10:00.000Z"),
|
||||
},
|
||||
{
|
||||
user: users[3]._id,
|
||||
team: teams[1]._id,
|
||||
type: "Road Cycling",
|
||||
durationMinutes: 88,
|
||||
caloriesBurned: 845,
|
||||
completedAt: new Date("2026-06-19T16:05:00.000Z"),
|
||||
},
|
||||
]);
|
||||
await Leaderboard_1.LeaderboardModel.insertMany([
|
||||
{
|
||||
period: "weekly-2026-W25",
|
||||
generatedAt: new Date("2026-06-20T00:00:00.000Z"),
|
||||
entries: [
|
||||
{ user: users[3]._id, team: teams[1]._id, points: 1280, rank: 1 },
|
||||
{ user: users[2]._id, team: teams[0]._id, points: 1225, rank: 2 },
|
||||
{ user: users[1]._id, team: teams[1]._id, points: 1160, rank: 3 },
|
||||
{ user: users[0]._id, team: teams[0]._id, points: 1095, rank: 4 },
|
||||
],
|
||||
},
|
||||
]);
|
||||
const counts = {
|
||||
users: await User_1.UserModel.countDocuments(),
|
||||
teams: await Team_1.TeamModel.countDocuments(),
|
||||
activities: await Activity_1.ActivityModel.countDocuments(),
|
||||
leaderboard: await Leaderboard_1.LeaderboardModel.countDocuments(),
|
||||
workouts: await Workout_1.WorkoutModel.countDocuments(),
|
||||
};
|
||||
console.log("Seed complete", counts);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Seed failed", error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
finally {
|
||||
await mongoose_1.default.disconnect();
|
||||
}
|
||||
};
|
||||
void seed();
|
||||
Reference in New Issue
Block a user