Index: backend/src/main/java/com/trekr/backend/controller/WeightController.java
===================================================================
--- backend/src/main/java/com/trekr/backend/controller/WeightController.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/controller/WeightController.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,97 @@
+package com.trekr.backend.controller;
+
+import com.trekr.backend.dto.weight.CreateDailyIntakeRequest;
+import com.trekr.backend.dto.weight.TrackingStatusResponse;
+import com.trekr.backend.dto.weight.WeightDailyIntakeDto;
+import com.trekr.backend.dto.weight.WeightDailyIntakesResponse;
+import com.trekr.backend.dto.weight.WeightProfileResponse;
+import com.trekr.backend.dto.weight.WeightStartRequest;
+import com.trekr.backend.dto.weight.TodayTrainingInfoDto;
+import com.trekr.backend.security.UserPrincipal;
+import com.trekr.backend.service.WeightService;
+import jakarta.validation.Valid;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/weight")
+public class WeightController {
+
+    private final WeightService weightService;
+
+    public WeightController(WeightService weightService) {
+        this.weightService = weightService;
+    }
+
+    @GetMapping("/status")
+    public TrackingStatusResponse status(Authentication authentication) {
+        UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
+        return new TrackingStatusResponse(weightService.isTracking(principal.getUserId()));
+    }
+
+    @PostMapping("/start")
+    @ResponseStatus(HttpStatus.CREATED)
+    public TrackingStatusResponse start(
+            @Valid @RequestBody WeightStartRequest request,
+            Authentication authentication) {
+        UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
+        weightService.startTracking(principal.getUserId(), request);
+        return new TrackingStatusResponse(true);
+    }
+
+    @GetMapping("/profile")
+    public WeightProfileResponse profile(Authentication authentication) {
+        UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
+        return weightService.getProfile(principal.getUserId());
+    }
+
+    @GetMapping("/intakes")
+    public WeightDailyIntakesResponse intakes(
+            @RequestParam(defaultValue = "0") int page,
+            @RequestParam(defaultValue = "5") int size,
+            Authentication authentication) {
+        if (size < 1) {
+            size = 5;
+        }
+        if (size > 50) {
+            size = 50;
+        }
+        if (page < 0) {
+            page = 0;
+        }
+
+        UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
+        return weightService.getDailyIntakes(principal.getUserId(), page, size);
+    }
+
+    @PostMapping("/intakes")
+    @ResponseStatus(HttpStatus.CREATED)
+    public WeightDailyIntakeDto createDailyIntake(
+            @Valid @RequestBody CreateDailyIntakeRequest request,
+            Authentication authentication) {
+        UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
+        return weightService.createDailyIntake(principal.getUserId(), request);
+    }
+
+    @PutMapping("/profile")
+    public WeightProfileResponse updateProfile(
+            @Valid @RequestBody WeightStartRequest request,
+            Authentication authentication) {
+        UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
+        return weightService.updateProfile(principal.getUserId(), request);
+    }
+
+    @GetMapping("/today-training")
+    public TodayTrainingInfoDto getTodayTrainingInfo(Authentication authentication) {
+        UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
+        return weightService.getTodayTrainingInfo(principal.getUserId());
+    }
+}
Index: backend/src/main/java/com/trekr/backend/dto/weight/CreateDailyIntakeRequest.java
===================================================================
--- backend/src/main/java/com/trekr/backend/dto/weight/CreateDailyIntakeRequest.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/dto/weight/CreateDailyIntakeRequest.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,22 @@
+package com.trekr.backend.dto.weight;
+
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.PositiveOrZero;
+
+import java.math.BigDecimal;
+
+public class CreateDailyIntakeRequest {
+
+    @NotNull(message = "Calories are required")
+    @PositiveOrZero(message = "Calories must be 0 or greater")
+    private BigDecimal calories;
+
+    public BigDecimal getCalories() {
+        return calories;
+    }
+
+    public void setCalories(BigDecimal calories) {
+        this.calories = calories;
+    }
+}
+
Index: backend/src/main/java/com/trekr/backend/dto/weight/TodayTrainingInfoDto.java
===================================================================
--- backend/src/main/java/com/trekr/backend/dto/weight/TodayTrainingInfoDto.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/dto/weight/TodayTrainingInfoDto.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,34 @@
+package com.trekr.backend.dto.weight;
+
+import java.math.BigDecimal;
+
+public class TodayTrainingInfoDto {
+
+    private boolean trainedToday;
+    private BigDecimal totalBurnedCalories;
+
+    public TodayTrainingInfoDto() {
+    }
+
+    public TodayTrainingInfoDto(boolean trainedToday, BigDecimal totalBurnedCalories) {
+        this.trainedToday = trainedToday;
+        this.totalBurnedCalories = totalBurnedCalories;
+    }
+
+    public boolean isTrainedToday() {
+        return trainedToday;
+    }
+
+    public void setTrainedToday(boolean trainedToday) {
+        this.trainedToday = trainedToday;
+    }
+
+    public BigDecimal getTotalBurnedCalories() {
+        return totalBurnedCalories;
+    }
+
+    public void setTotalBurnedCalories(BigDecimal totalBurnedCalories) {
+        this.totalBurnedCalories = totalBurnedCalories;
+    }
+}
+
Index: backend/src/main/java/com/trekr/backend/dto/weight/TrackingStatusResponse.java
===================================================================
--- backend/src/main/java/com/trekr/backend/dto/weight/TrackingStatusResponse.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/dto/weight/TrackingStatusResponse.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,22 @@
+package com.trekr.backend.dto.weight;
+
+public class TrackingStatusResponse {
+
+    private boolean tracking;
+
+    public TrackingStatusResponse() {
+    }
+
+    public TrackingStatusResponse(boolean tracking) {
+        this.tracking = tracking;
+    }
+
+    public boolean isTracking() {
+        return tracking;
+    }
+
+    public void setTracking(boolean tracking) {
+        this.tracking = tracking;
+    }
+}
+
Index: backend/src/main/java/com/trekr/backend/dto/weight/WeightDailyIntakeDto.java
===================================================================
--- backend/src/main/java/com/trekr/backend/dto/weight/WeightDailyIntakeDto.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/dto/weight/WeightDailyIntakeDto.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,73 @@
+package com.trekr.backend.dto.weight;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+
+public class WeightDailyIntakeDto {
+
+    private Long dailyIntakeId;
+    private LocalDate date;
+    private BigDecimal calories;
+    private boolean trainedThatDay;
+    private BigDecimal burnedCalories;
+
+    public WeightDailyIntakeDto() {
+    }
+
+    public WeightDailyIntakeDto(Long dailyIntakeId, LocalDate date, BigDecimal calories) {
+        this.dailyIntakeId = dailyIntakeId;
+        this.date = date;
+        this.calories = calories;
+        this.trainedThatDay = false;
+        this.burnedCalories = BigDecimal.ZERO;
+    }
+
+    public WeightDailyIntakeDto(Long dailyIntakeId, LocalDate date, BigDecimal calories, boolean trainedThatDay, BigDecimal burnedCalories) {
+        this.dailyIntakeId = dailyIntakeId;
+        this.date = date;
+        this.calories = calories;
+        this.trainedThatDay = trainedThatDay;
+        this.burnedCalories = burnedCalories;
+    }
+
+    public Long getDailyIntakeId() {
+        return dailyIntakeId;
+    }
+
+    public void setDailyIntakeId(Long dailyIntakeId) {
+        this.dailyIntakeId = dailyIntakeId;
+    }
+
+    public LocalDate getDate() {
+        return date;
+    }
+
+    public void setDate(LocalDate date) {
+        this.date = date;
+    }
+
+    public BigDecimal getCalories() {
+        return calories;
+    }
+
+    public void setCalories(BigDecimal calories) {
+        this.calories = calories;
+    }
+
+    public boolean isTrainedThatDay() {
+        return trainedThatDay;
+    }
+
+    public void setTrainedThatDay(boolean trainedThatDay) {
+        this.trainedThatDay = trainedThatDay;
+    }
+
+    public BigDecimal getBurnedCalories() {
+        return burnedCalories;
+    }
+
+    public void setBurnedCalories(BigDecimal burnedCalories) {
+        this.burnedCalories = burnedCalories;
+    }
+}
+
Index: backend/src/main/java/com/trekr/backend/dto/weight/WeightDailyIntakesResponse.java
===================================================================
--- backend/src/main/java/com/trekr/backend/dto/weight/WeightDailyIntakesResponse.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/dto/weight/WeightDailyIntakesResponse.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,44 @@
+package com.trekr.backend.dto.weight;
+
+import java.util.List;
+
+public class WeightDailyIntakesResponse {
+
+    private List<WeightDailyIntakeDto> intakes;
+    private boolean hasMore;
+    private boolean hasTodayIntake;
+
+    public WeightDailyIntakesResponse() {
+    }
+
+    public WeightDailyIntakesResponse(List<WeightDailyIntakeDto> intakes, boolean hasMore, boolean hasTodayIntake) {
+        this.intakes = intakes;
+        this.hasMore = hasMore;
+        this.hasTodayIntake = hasTodayIntake;
+    }
+
+    public List<WeightDailyIntakeDto> getIntakes() {
+        return intakes;
+    }
+
+    public void setIntakes(List<WeightDailyIntakeDto> intakes) {
+        this.intakes = intakes;
+    }
+
+    public boolean isHasMore() {
+        return hasMore;
+    }
+
+    public void setHasMore(boolean hasMore) {
+        this.hasMore = hasMore;
+    }
+
+    public boolean isHasTodayIntake() {
+        return hasTodayIntake;
+    }
+
+    public void setHasTodayIntake(boolean hasTodayIntake) {
+        this.hasTodayIntake = hasTodayIntake;
+    }
+}
+
Index: backend/src/main/java/com/trekr/backend/dto/weight/WeightProfileResponse.java
===================================================================
--- backend/src/main/java/com/trekr/backend/dto/weight/WeightProfileResponse.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/dto/weight/WeightProfileResponse.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,56 @@
+package com.trekr.backend.dto.weight;
+
+import java.math.BigDecimal;
+
+public class WeightProfileResponse {
+
+    private BigDecimal weight;
+    private BigDecimal height;
+    private BigDecimal goalWeight;
+    private BigDecimal goalCalories;
+
+    public WeightProfileResponse() {
+    }
+
+    public WeightProfileResponse(BigDecimal weight, BigDecimal height, BigDecimal goalWeight,
+            BigDecimal goalCalories) {
+        this.weight = weight;
+        this.height = height;
+        this.goalWeight = goalWeight;
+        this.goalCalories = goalCalories;
+    }
+
+    public BigDecimal getWeight() {
+        return weight;
+    }
+
+    public void setWeight(BigDecimal weight) {
+        this.weight = weight;
+    }
+
+    public BigDecimal getHeight() {
+        return height;
+    }
+
+    public void setHeight(BigDecimal height) {
+        this.height = height;
+    }
+
+    public BigDecimal getGoalWeight() {
+        return goalWeight;
+    }
+
+    public void setGoalWeight(BigDecimal goalWeight) {
+        this.goalWeight = goalWeight;
+    }
+
+
+    public BigDecimal getGoalCalories() {
+        return goalCalories;
+    }
+
+    public void setGoalCalories(BigDecimal goalCalories) {
+        this.goalCalories = goalCalories;
+    }
+}
+
Index: backend/src/main/java/com/trekr/backend/dto/weight/WeightStartRequest.java
===================================================================
--- backend/src/main/java/com/trekr/backend/dto/weight/WeightStartRequest.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/dto/weight/WeightStartRequest.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,69 @@
+package com.trekr.backend.dto.weight;
+
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Positive;
+import jakarta.validation.constraints.PositiveOrZero;
+
+import java.math.BigDecimal;
+
+public class WeightStartRequest {
+
+    @NotNull(message = "Current weight is required")
+    @Positive(message = "Current weight must be greater than 0")
+    private BigDecimal weight;
+
+    @NotNull(message = "Height is required")
+    @Positive(message = "Height must be greater than 0")
+    private BigDecimal height;
+
+    @NotNull(message = "Goal weight is required")
+    @Positive(message = "Goal weight must be greater than 0")
+    private BigDecimal goalWeight;
+
+    @PositiveOrZero(message = "Goal calories must be 0 or greater")
+    private BigDecimal goalCalories;
+
+    private Boolean autoCalculateTargets = Boolean.TRUE;
+
+    public BigDecimal getWeight() {
+        return weight;
+    }
+
+    public void setWeight(BigDecimal weight) {
+        this.weight = weight;
+    }
+
+    public BigDecimal getHeight() {
+        return height;
+    }
+
+    public void setHeight(BigDecimal height) {
+        this.height = height;
+    }
+
+    public BigDecimal getGoalWeight() {
+        return goalWeight;
+    }
+
+    public void setGoalWeight(BigDecimal goalWeight) {
+        this.goalWeight = goalWeight;
+    }
+
+
+    public BigDecimal getGoalCalories() {
+        return goalCalories;
+    }
+
+    public void setGoalCalories(BigDecimal goalCalories) {
+        this.goalCalories = goalCalories;
+    }
+
+    public Boolean getAutoCalculateTargets() {
+        return autoCalculateTargets;
+    }
+
+    public void setAutoCalculateTargets(Boolean autoCalculateTargets) {
+        this.autoCalculateTargets = autoCalculateTargets;
+    }
+}
+
Index: backend/src/main/java/com/trekr/backend/entity/weight/WeightUser.java
===================================================================
--- backend/src/main/java/com/trekr/backend/entity/weight/WeightUser.java	(revision 89156c1feb4b06a2d4ecb2bbac89f7c39f0df7e2)
+++ backend/src/main/java/com/trekr/backend/entity/weight/WeightUser.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -81,4 +81,5 @@
     }
 
+
     public BigDecimal getGoalCalories() {
         return goalCalories;
Index: backend/src/main/java/com/trekr/backend/repository/DailyIntakeRepository.java
===================================================================
--- backend/src/main/java/com/trekr/backend/repository/DailyIntakeRepository.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/repository/DailyIntakeRepository.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,17 @@
+package com.trekr.backend.repository;
+
+import com.trekr.backend.entity.weight.DailyIntake;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.time.LocalDate;
+
+@Repository
+public interface DailyIntakeRepository extends JpaRepository<DailyIntake, Long> {
+    Page<DailyIntake> findByWeightUser_UserIdOrderByDateDesc(Long userId, Pageable pageable);
+
+    boolean existsByWeightUser_UserIdAndDate(Long userId, LocalDate date);
+}
+
Index: backend/src/main/java/com/trekr/backend/repository/TrainingSessionRepository.java
===================================================================
--- backend/src/main/java/com/trekr/backend/repository/TrainingSessionRepository.java	(revision 89156c1feb4b06a2d4ecb2bbac89f7c39f0df7e2)
+++ backend/src/main/java/com/trekr/backend/repository/TrainingSessionRepository.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -10,3 +10,4 @@
 public interface TrainingSessionRepository extends JpaRepository<TrainingSession, Long> {
     Page<TrainingSession> findByTrainingUser_UserIdOrderByDateDesc(Long userId, Pageable pageable);
+    java.util.List<TrainingSession> findByTrainingUser_UserIdAndDate(Long userId, java.time.LocalDate date);
 }
Index: backend/src/main/java/com/trekr/backend/repository/WeightUserRepository.java
===================================================================
--- backend/src/main/java/com/trekr/backend/repository/WeightUserRepository.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/repository/WeightUserRepository.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,10 @@
+package com.trekr.backend.repository;
+
+import com.trekr.backend.entity.weight.WeightUser;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface WeightUserRepository extends JpaRepository<WeightUser, Long> {
+}
+
Index: backend/src/main/java/com/trekr/backend/service/WeightService.java
===================================================================
--- backend/src/main/java/com/trekr/backend/service/WeightService.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ backend/src/main/java/com/trekr/backend/service/WeightService.java	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,212 @@
+package com.trekr.backend.service;
+
+import com.trekr.backend.dto.weight.CreateDailyIntakeRequest;
+import com.trekr.backend.dto.weight.TodayTrainingInfoDto;
+import com.trekr.backend.dto.weight.WeightDailyIntakeDto;
+import com.trekr.backend.dto.weight.WeightDailyIntakesResponse;
+import com.trekr.backend.dto.weight.WeightProfileResponse;
+import com.trekr.backend.dto.weight.WeightStartRequest;
+import com.trekr.backend.entity.User;
+import com.trekr.backend.entity.weight.DailyIntake;
+import com.trekr.backend.entity.weight.WeightUser;
+import com.trekr.backend.repository.DailyIntakeRepository;
+import com.trekr.backend.repository.TrainingSessionRepository;
+import com.trekr.backend.repository.UserRepository;
+import com.trekr.backend.repository.WeightUserRepository;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+
+@Service
+public class WeightService {
+
+    private static final BigDecimal CALORIE_WEIGHT_FACTOR = new BigDecimal("10");
+    private static final BigDecimal CALORIE_HEIGHT_FACTOR = new BigDecimal("6.25");
+    private static final BigDecimal CALORIE_BASE = new BigDecimal("50");
+    private static final BigDecimal LOSS_CALORIE_DELTA = new BigDecimal("500");
+    private static final BigDecimal GAIN_CALORIE_DELTA = new BigDecimal("300");
+
+    private final WeightUserRepository weightUserRepository;
+    private final DailyIntakeRepository dailyIntakeRepository;
+    private final UserRepository userRepository;
+    private final TrainingSessionRepository trainingSessionRepository;
+
+    public WeightService(
+            WeightUserRepository weightUserRepository,
+            DailyIntakeRepository dailyIntakeRepository,
+            UserRepository userRepository,
+            TrainingSessionRepository trainingSessionRepository) {
+        this.weightUserRepository = weightUserRepository;
+        this.dailyIntakeRepository = dailyIntakeRepository;
+        this.userRepository = userRepository;
+        this.trainingSessionRepository = trainingSessionRepository;
+    }
+
+    public boolean isTracking(Long userId) {
+        return weightUserRepository.existsById(userId);
+    }
+
+    @Transactional
+    public void startTracking(Long userId, WeightStartRequest request) {
+        if (weightUserRepository.existsById(userId)) {
+            return;
+        }
+
+        User user = userRepository.findById(userId)
+                .orElseThrow(() -> new RuntimeException("User not found"));
+
+        BigDecimal goalCalories = resolveGoalCalories(request, request.getWeight(), request.getHeight(), request.getGoalWeight());
+
+        WeightUser weightUser = new WeightUser();
+        weightUser.setUser(user);
+        weightUser.setWeight(request.getWeight());
+        weightUser.setHeight(request.getHeight());
+        weightUser.setGoalWeight(request.getGoalWeight());
+        weightUser.setGoalCalories(goalCalories);
+
+        weightUserRepository.save(weightUser);
+    }
+
+    public WeightProfileResponse getProfile(Long userId) {
+        WeightUser weightUser = weightUserRepository.findById(userId)
+                .orElseThrow(() -> new RuntimeException("Weight tracking is not enabled for this user"));
+
+        return new WeightProfileResponse(
+                weightUser.getWeight(),
+                weightUser.getHeight(),
+                weightUser.getGoalWeight(),
+                weightUser.getGoalCalories());
+    }
+
+    public WeightDailyIntakesResponse getDailyIntakes(Long userId, int page, int size) {
+        if (!weightUserRepository.existsById(userId)) {
+            return new WeightDailyIntakesResponse(List.of(), false, false);
+        }
+
+        Page<DailyIntake> result = dailyIntakeRepository
+                .findByWeightUser_UserIdOrderByDateDesc(userId, PageRequest.of(page, size));
+
+        List<WeightDailyIntakeDto> intakes = result.getContent().stream()
+                .map(d -> {
+                    // Fetch training data for this date
+                    var trainingSessions = trainingSessionRepository.findByTrainingUser_UserIdAndDate(userId, d.getDate());
+                    boolean trainedThatDay = !trainingSessions.isEmpty();
+                    BigDecimal burnedCalories = trainingSessions.stream()
+                            .map(ts -> ts.getCalories() != null ? ts.getCalories() : BigDecimal.ZERO)
+                            .reduce(BigDecimal.ZERO, BigDecimal::add)
+                            .setScale(2, java.math.RoundingMode.HALF_UP);
+                    
+                    return new WeightDailyIntakeDto(
+                            d.getDailyIntakeId(),
+                            d.getDate(),
+                            d.getCalories(),
+                            trainedThatDay,
+                            burnedCalories);
+                })
+                .toList();
+
+        boolean hasTodayIntake = dailyIntakeRepository.existsByWeightUser_UserIdAndDate(userId, LocalDate.now());
+        return new WeightDailyIntakesResponse(intakes, result.hasNext(), hasTodayIntake);
+    }
+
+    @Transactional
+    public WeightDailyIntakeDto createDailyIntake(Long userId, CreateDailyIntakeRequest request) {
+        WeightUser weightUser = weightUserRepository.findById(userId)
+                .orElseThrow(() -> new RuntimeException("Weight tracking is not enabled for this user"));
+
+        LocalDate today = LocalDate.now();
+        if (dailyIntakeRepository.existsByWeightUser_UserIdAndDate(userId, today)) {
+            throw new RuntimeException("Today's intake has already been recorded");
+        }
+
+        DailyIntake intake = new DailyIntake();
+        intake.setWeightUser(weightUser);
+        intake.setCalories(request.getCalories());
+        intake.setDate(today);
+
+        DailyIntake saved = dailyIntakeRepository.save(intake);
+        
+        // Fetch today's training data
+        var trainingSessions = trainingSessionRepository.findByTrainingUser_UserIdAndDate(userId, today);
+        boolean trainedToday = !trainingSessions.isEmpty();
+        BigDecimal burnedCalories = trainingSessions.stream()
+                .map(ts -> ts.getCalories() != null ? ts.getCalories() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add)
+                .setScale(2, java.math.RoundingMode.HALF_UP);
+        
+        return new WeightDailyIntakeDto(saved.getDailyIntakeId(), saved.getDate(), saved.getCalories(), trainedToday, burnedCalories);
+    }
+
+    @Transactional
+    public WeightProfileResponse updateProfile(Long userId, WeightStartRequest request) {
+        WeightUser weightUser = weightUserRepository.findById(userId)
+                .orElseThrow(() -> new RuntimeException("Weight tracking is not enabled for this user"));
+
+        BigDecimal goalCalories = resolveGoalCalories(request, request.getWeight(), request.getHeight(), request.getGoalWeight());
+
+        weightUser.setWeight(request.getWeight());
+        weightUser.setHeight(request.getHeight());
+        weightUser.setGoalWeight(request.getGoalWeight());
+        weightUser.setGoalCalories(goalCalories);
+
+        WeightUser updated = weightUserRepository.save(weightUser);
+        return new WeightProfileResponse(
+                updated.getWeight(),
+                updated.getHeight(),
+                updated.getGoalWeight(),
+                updated.getGoalCalories());
+    }
+
+    public TodayTrainingInfoDto getTodayTrainingInfo(Long userId) {
+        // Try to get training user, if doesn't exist just return zeros
+        var trainingUser = trainingSessionRepository.findByTrainingUser_UserIdAndDate(userId, LocalDate.now());
+
+        boolean trainedToday = !trainingUser.isEmpty();
+        BigDecimal totalBurnedCalories = trainingUser.stream()
+                .map(ts -> ts.getCalories() != null ? ts.getCalories() : BigDecimal.ZERO)
+                .reduce(BigDecimal.ZERO, BigDecimal::add)
+                .setScale(2, java.math.RoundingMode.HALF_UP);
+
+        return new TodayTrainingInfoDto(trainedToday, totalBurnedCalories);
+    }
+
+    private static BigDecimal resolveGoalCalories(
+            WeightStartRequest request,
+            BigDecimal currentWeight,
+            BigDecimal height,
+            BigDecimal goalWeight) {
+        if (!Boolean.FALSE.equals(request.getAutoCalculateTargets())) {
+            return calculateGoalCalories(currentWeight, height, goalWeight);
+        }
+
+        BigDecimal goalCalories = request.getGoalCalories();
+        if (goalCalories == null) {
+            throw new RuntimeException("Goal calories are required when auto-calculation is disabled");
+        }
+        if (goalCalories.compareTo(BigDecimal.ZERO) < 0) {
+            throw new RuntimeException("Goal calories must be 0 or greater");
+        }
+        return goalCalories.setScale(2, java.math.RoundingMode.HALF_UP);
+    }
+
+    private static BigDecimal calculateGoalCalories(BigDecimal currentWeight, BigDecimal height, BigDecimal goalWeight) {
+        BigDecimal maintenanceCalories = currentWeight.multiply(CALORIE_WEIGHT_FACTOR)
+                .add(height.multiply(CALORIE_HEIGHT_FACTOR))
+                .add(CALORIE_BASE)
+                .setScale(2, java.math.RoundingMode.HALF_UP);
+
+        int direction = goalWeight.compareTo(currentWeight);
+        if (direction < 0) {
+            return maintenanceCalories.subtract(LOSS_CALORIE_DELTA).max(BigDecimal.ZERO).setScale(2, java.math.RoundingMode.HALF_UP);
+        }
+        if (direction > 0) {
+            return maintenanceCalories.add(GAIN_CALORIE_DELTA).setScale(2, java.math.RoundingMode.HALF_UP);
+        }
+        return maintenanceCalories;
+    }
+}
Index: db-scripts/ddl.sql
===================================================================
--- db-scripts/ddl.sql	(revision 89156c1feb4b06a2d4ecb2bbac89f7c39f0df7e2)
+++ db-scripts/ddl.sql	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -55,8 +55,8 @@
     user_id BIGINT PRIMARY KEY
         REFERENCES USERS(user_id) ON DELETE CASCADE,
-    weight NUMERIC,
-    height NUMERIC,
-    goal_weight NUMERIC,
-    goal_calories NUMERIC
+    weight NUMERIC NOT NULL,
+    height NUMERIC NOT NULL,
+    goal_weight NUMERIC NOT NULL,
+    goal_calories NUMERIC NOT NULL
 );
 
@@ -65,6 +65,8 @@
     user_id BIGINT
         REFERENCES WEIGHT_USERS(user_id) ON DELETE CASCADE,
-    calories NUMERIC,
-    date DATE
+    calories NUMERIC NOT NULL,
+    date DATE NOT NULL,
+
+    CONSTRAINT daily_intakes_unique_user_date UNIQUE (user_id, date)
 );
 
Index: frontend/src/App.jsx
===================================================================
--- frontend/src/App.jsx	(revision 89156c1feb4b06a2d4ecb2bbac89f7c39f0df7e2)
+++ frontend/src/App.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -10,4 +10,6 @@
 import NewTrainingSession from "./pages/Dashboard/pages/Training/NewTrainingSession.jsx";
 import Weight from "./pages/Dashboard/pages/Weight/Weight.jsx";
+import WeightTracking from "./pages/Dashboard/pages/Weight/WeightTracking.jsx";
+import NewWeightIntake from "./pages/Dashboard/pages/Weight/NewWeightIntake.jsx";
 import Finance from "./pages/Dashboard/pages/Finance/Finance.jsx";
 import Investing from "./pages/Dashboard/pages/Investing/Investing.jsx";
@@ -46,4 +48,6 @@
           />
           <Route path="weight" element={<Weight />} />
+          <Route path="weight/tracking" element={<WeightTracking />} />
+          <Route path="weight/intakes/new" element={<NewWeightIntake />} />
           <Route path="finance" element={<Finance />} />
           <Route path="investing" element={<Investing />} />
Index: frontend/src/pages/Dashboard/pages/Weight/NewWeightIntake.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/NewWeightIntake.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/NewWeightIntake.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,166 @@
+import React, { useEffect, useMemo, useState } from "react";
+import { useNavigate } from "react-router-dom";
+
+import api from "../../../../api/axios";
+
+export default function NewWeightIntake() {
+  const navigate = useNavigate();
+  const [goalCalories, setGoalCalories] = useState(null);
+  const [todayTrainingInfo, setTodayTrainingInfo] = useState(null);
+  const [isLoading, setIsLoading] = useState(true);
+  const [calories, setCalories] = useState("");
+  const [error, setError] = useState("");
+  const [isSubmitting, setIsSubmitting] = useState(false);
+
+  const todayLabel = useMemo(
+    () =>
+      new Date().toLocaleDateString(undefined, {
+        year: "numeric",
+        month: "short",
+        day: "2-digit",
+      }),
+    [],
+  );
+
+  const adjustedGoalCalories = useMemo(() => {
+    if (!goalCalories || !todayTrainingInfo) return null;
+    const goal = Number(goalCalories);
+    const burned = Number(todayTrainingInfo.totalBurnedCalories) || 0;
+    if (!Number.isFinite(goal)) return null;
+    return goal + burned;
+  }, [goalCalories, todayTrainingInfo]);
+
+  useEffect(() => {
+    let cancelled = false;
+    (async () => {
+      try {
+        setIsLoading(true);
+        setError("");
+        const [statusRes, profileRes, trainingRes] = await Promise.all([
+          api.get("/weight/status"),
+          api.get("/weight/profile"),
+          api.get("/weight/today-training"),
+        ]);
+        if (cancelled) return;
+        if (!statusRes?.data?.tracking) {
+          navigate("/dashboard/weight", { replace: true });
+          return;
+        }
+        setGoalCalories(profileRes?.data?.goalCalories ?? null);
+        setTodayTrainingInfo(trainingRes?.data ?? null);
+      } catch (err) {
+        if (cancelled) return;
+        const message = err?.response?.data?.message || "Failed to load weight profile.";
+        if (String(message).toLowerCase().includes("not enabled")) {
+          navigate("/dashboard/weight", { replace: true });
+          return;
+        }
+        setError(message);
+      } finally {
+        if (!cancelled) setIsLoading(false);
+      }
+    })();
+    return () => {
+      cancelled = true;
+    };
+  }, [navigate]);
+
+  const onSubmit = async (e) => {
+    e.preventDefault();
+    setError("");
+
+    const caloriesNum = calories === "" ? NaN : Number(calories);
+    if (!Number.isFinite(caloriesNum) || caloriesNum < 0) {
+      setError("Calories must be 0 or greater.");
+      return;
+    }
+
+    try {
+      setIsSubmitting(true);
+      await api.post("/weight/intakes", {
+        calories: caloriesNum,
+      });
+      navigate("/dashboard/weight/tracking", { replace: true });
+    } catch (err) {
+      setError(err?.response?.data?.message || "Failed to add today's intake.");
+    } finally {
+      setIsSubmitting(false);
+    }
+  };
+
+  return (
+    <div className="min-h-[70vh] w-full flex items-center justify-center">
+      <div className="w-full max-w-2xl">
+        <div className="card bg-base-200 border border-base-300">
+          <div className="card-body">
+            <h1 className="text-2xl font-bold">Add today's intake</h1>
+            <p className="opacity-80">
+              Log the calories you consumed today. Only one intake can be stored per day.
+            </p>
+
+            <div className="mt-2 text-sm opacity-70">Today: {todayLabel}</div>
+            <div className="mt-1 text-sm opacity-70">
+              Goal calories: {goalCalories === null ? "—" : `${goalCalories} kcal`}
+            </div>
+            {todayTrainingInfo?.trainedToday && (
+              <>
+                <div className="mt-2 text-sm opacity-70">
+                  Burned during training: {todayTrainingInfo.totalBurnedCalories} kcal
+                </div>
+                <div className="mt-1 text-sm font-semibold text-green-400">
+                  Adjusted goal for today: {adjustedGoalCalories === null ? "—" : `${adjustedGoalCalories} kcal`}
+                </div>
+              </>
+            )}
+
+            {error ? (
+              <div className="alert alert-error mt-4">
+                <span>{error}</span>
+              </div>
+            ) : null}
+
+            {isLoading ? <p className="opacity-80 mt-4">Loading…</p> : null}
+
+            <form onSubmit={onSubmit} className="mt-6 space-y-4">
+              <div>
+                <label className="label">
+                  <span className="label-text">Calories consumed</span>
+                </label>
+                <input
+                  type="number"
+                  step="0.1"
+                  min="0"
+                  className="input input-bordered w-full"
+                  placeholder="2200"
+                  value={calories}
+                  onChange={(e) => setCalories(e.target.value)}
+                  required
+                  disabled={isLoading}
+                />
+              </div>
+
+              <div className="flex flex-col gap-3 sm:flex-row sm:justify-end">
+                <button
+                  type="button"
+                  className="btn btn-ghost"
+                  onClick={() => navigate("/dashboard/weight/tracking")}
+                  disabled={isSubmitting}
+                >
+                  Cancel
+                </button>
+                <button
+                  type="submit"
+                  className="btn bg-green-400! text-black! hover:bg-green-500! border-0"
+                  disabled={isSubmitting || isLoading}
+                >
+                  {isSubmitting ? "Saving…" : "Save intake"}
+                </button>
+              </div>
+            </form>
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
+
Index: frontend/src/pages/Dashboard/pages/Weight/Weight.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/Weight.jsx	(revision 89156c1feb4b06a2d4ecb2bbac89f7c39f0df7e2)
+++ frontend/src/pages/Dashboard/pages/Weight/Weight.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -1,12 +1,164 @@
-import React from "react";
+import React, { useEffect, useMemo, useState } from "react";
+import { useNavigate } from "react-router-dom";
+
+import api from "../../../../api/axios";
+
+import WeightCenteredCard from "./components/WeightCenteredCard.jsx";
+import WeightStartCtaCard from "./components/WeightStartCtaCard.jsx";
+import WeightStartForm from "./components/WeightStartForm.jsx";
+
+function estimateGoalTimeWeeks(currentWeight, goalWeight) {
+  const current = Number(currentWeight);
+  const goal = Number(goalWeight);
+  if (!Number.isFinite(current) || !Number.isFinite(goal) || current <= 0 || goal <= 0) {
+    return null;
+  }
+  const difference = Math.abs(goal - current);
+  return Math.round((difference / 0.5) * 100) / 100;
+}
+
+function estimateGoalCalories(currentWeight, height, goalWeight) {
+  const current = Number(currentWeight);
+  const h = Number(height);
+  const goal = Number(goalWeight);
+  if (!Number.isFinite(current) || !Number.isFinite(h) || !Number.isFinite(goal)) {
+    return null;
+  }
+
+  const maintenance = current * 10 + h * 6.25 + 50;
+  if (goal < current) return Math.max(0, Math.round((maintenance - 500) * 100) / 100);
+  if (goal > current) return Math.round((maintenance + 300) * 100) / 100;
+  return Math.round(maintenance * 100) / 100;
+}
 
 const Weight = () => {
+  const navigate = useNavigate();
+
+  const [isLoading, setIsLoading] = useState(true);
+  const [isTracking, setIsTracking] = useState(false);
+  const [step, setStep] = useState("cta");
+  const [error, setError] = useState("");
+  const [isSubmitting, setIsSubmitting] = useState(false);
+  const [autoCalculateTargets, setAutoCalculateTargets] = useState(true);
+
+  const initialForm = useMemo(
+    () => ({
+      weight: "",
+      height: "",
+      goalWeight: "",
+      goalTimeWeeks: "",
+      goalCalories: "",
+    }),
+    [],
+  );
+  const [form, setForm] = useState(initialForm);
+
+  const estimatedGoalTimeWeeks = useMemo(
+    () => estimateGoalTimeWeeks(form.weight, form.goalWeight),
+    [form.weight, form.goalWeight],
+  );
+  const estimatedGoalCalories = useMemo(
+    () => estimateGoalCalories(form.weight, form.height, form.goalWeight),
+    [form.weight, form.height, form.goalWeight],
+  );
+
+  useEffect(() => {
+    let isMounted = true;
+    const run = async () => {
+      setIsLoading(true);
+      setError("");
+      try {
+        const res = await api.get("/weight/status");
+        const tracking = Boolean(res?.data?.tracking);
+        if (!isMounted) return;
+        setIsTracking(tracking);
+        if (tracking) {
+          navigate("/dashboard/weight/tracking", { replace: true });
+        }
+      } catch (err) {
+        if (!isMounted) return;
+        const message = err?.response?.data?.message || "Failed to load weight status";
+        setError(message);
+      } finally {
+        if (isMounted) setIsLoading(false);
+      }
+    };
+
+    run();
+    return () => {
+      isMounted = false;
+    };
+  }, [navigate]);
+
+  const onStart = () => {
+    setError("");
+    setStep("form");
+  };
+
+  const onCancel = () => {
+    setStep("cta");
+    setForm(initialForm);
+    setAutoCalculateTargets(true);
+    setError("");
+  };
+
+  const onSubmit = async (e) => {
+    e.preventDefault();
+    setError("");
+    setIsSubmitting(true);
+
+    try {
+      await api.post("/weight/start", {
+        weight: form.weight === "" ? null : Number(form.weight),
+        height: form.height === "" ? null : Number(form.height),
+        goalWeight: form.goalWeight === "" ? null : Number(form.goalWeight),
+        goalCalories: autoCalculateTargets
+          ? null
+          : form.goalCalories === ""
+            ? null
+            : Number(form.goalCalories),
+        autoCalculateTargets,
+      });
+
+      setIsTracking(true);
+      navigate("/dashboard/weight/tracking", { replace: true });
+    } catch (err) {
+      const message =
+        err?.response?.data?.message ||
+        Object.values(err?.response?.data?.errors ?? {})[0] ||
+        "Failed to start weight tracking";
+      setError(message);
+    } finally {
+      setIsSubmitting(false);
+    }
+  };
+
+  if (isLoading) {
+    return <WeightCenteredCard title="Weight" message="Loading…" />;
+  }
+
+  if (isTracking) {
+    return <WeightCenteredCard title="Weight" message="Redirecting…" />;
+  }
+
   return (
-    <div className="space-y-4">
-      <h1 className="text-2xl font-bold">Weight</h1>
-      <div className="card bg-base-200 border border-base-300">
-        <div className="card-body">
-          <p className="opacity-80">Weight dashboard content goes here.</p>
-        </div>
+    <div className="min-h-[70vh] w-full flex items-center justify-center">
+      <div className="w-full max-w-4xl">
+        {step === "cta" ? (
+          <WeightStartCtaCard error={error} onStart={onStart} isSubmitting={isSubmitting} />
+        ) : (
+          <WeightStartForm
+            form={form}
+            setForm={setForm}
+            onSubmit={onSubmit}
+            onCancel={onCancel}
+            error={error}
+            isSubmitting={isSubmitting}
+            autoCalculateTargets={autoCalculateTargets}
+            setAutoCalculateTargets={setAutoCalculateTargets}
+            estimatedGoalTimeWeeks={estimatedGoalTimeWeeks}
+            estimatedGoalCalories={estimatedGoalCalories}
+          />
+        )}
       </div>
     </div>
Index: frontend/src/pages/Dashboard/pages/Weight/WeightTracking.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/WeightTracking.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/WeightTracking.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,232 @@
+import React, { useCallback, useEffect, useMemo, useState } from "react";
+import { useNavigate } from "react-router-dom";
+
+import api from "../../../../api/axios";
+import graphPlaceholder from "../../../../assets/graph-placeholder.svg";
+
+import WeightProgressCard from "./components/WeightProgressCard.jsx";
+import WeightTrackingHeader from "./components/WeightTrackingHeader.jsx";
+import WeightSummaryCard from "./components/WeightSummaryCard.jsx";
+import WeightIntakesTable from "./components/WeightIntakesTable.jsx";
+import WeightStartForm from "./components/WeightStartForm.jsx";
+
+function estimateGoalTimeWeeks(currentWeight, goalWeight) {
+  const current = Number(currentWeight);
+  const goal = Number(goalWeight);
+  if (!Number.isFinite(current) || !Number.isFinite(goal) || current <= 0 || goal <= 0) {
+    return null;
+  }
+  const difference = Math.abs(goal - current);
+  return Math.round((difference / 0.5) * 100) / 100;
+}
+
+function estimateGoalCalories(currentWeight, height, goalWeight) {
+  const current = Number(currentWeight);
+  const h = Number(height);
+  const goal = Number(goalWeight);
+  if (!Number.isFinite(current) || !Number.isFinite(h) || !Number.isFinite(goal)) {
+    return null;
+  }
+  const maintenance = current * 10 + h * 6.25 + 50;
+  if (goal < current) return Math.max(0, Math.round((maintenance - 500) * 100) / 100);
+  if (goal > current) return Math.round((maintenance + 300) * 100) / 100;
+  return Math.round(maintenance * 100) / 100;
+}
+
+export default function WeightTracking() {
+  const navigate = useNavigate();
+  const pageSize = 5;
+
+  const [profile, setProfile] = useState(null);
+  const [intakes, setIntakes] = useState([]);
+  const [page, setPage] = useState(0);
+  const [hasMore, setHasMore] = useState(false);
+  const [hasTodayIntake, setHasTodayIntake] = useState(false);
+  const [todayTrainingInfo, setTodayTrainingInfo] = useState(null);
+  const [isLoading, setIsLoading] = useState(true);
+  const [isLoadingMore, setIsLoadingMore] = useState(false);
+  const [error, setError] = useState("");
+  const [isEditingProfile, setIsEditingProfile] = useState(false);
+  const [editForm, setEditForm] = useState({ weight: "", height: "", goalWeight: "", goalCalories: "" });
+  const [editAutoCalculate, setEditAutoCalculate] = useState(true);
+  const [editError, setEditError] = useState("");
+  const [isSubmittingEdit, setIsSubmittingEdit] = useState(false);
+
+  const fetchPage = useCallback(async (nextPage) => {
+    const [profileRes, intakesRes, trainingRes] = await Promise.all([
+      api.get("/weight/profile"),
+      api.get("/weight/intakes", {
+        params: { page: nextPage, size: pageSize },
+      }),
+      api.get("/weight/today-training"),
+    ]);
+
+    return {
+      profileData: profileRes?.data ?? null,
+      intakesData: intakesRes?.data ?? {},
+      trainingData: trainingRes?.data ?? null,
+    };
+  }, []);
+
+  useEffect(() => {
+    let cancelled = false;
+    (async () => {
+      try {
+        setIsLoading(true);
+        setError("");
+        const { profileData, intakesData, trainingData } = await fetchPage(0);
+        if (cancelled) return;
+        setProfile(profileData);
+        setIntakes(Array.isArray(intakesData.intakes) ? intakesData.intakes : []);
+        setHasMore(Boolean(intakesData.hasMore));
+        setHasTodayIntake(Boolean(intakesData.hasTodayIntake));
+        setTodayTrainingInfo(trainingData);
+        setPage(0);
+      } catch (e) {
+        if (cancelled) return;
+        const message =
+          e?.response?.data?.message || "Failed to load weight tracking data.";
+        if (String(message).toLowerCase().includes("not enabled")) {
+          navigate("/dashboard/weight", { replace: true });
+          return;
+        }
+        setError(message);
+      } finally {
+        if (!cancelled) setIsLoading(false);
+      }
+    })();
+
+    return () => {
+      cancelled = true;
+    };
+  }, [fetchPage, navigate]);
+
+  const onLoadMore = async () => {
+    if (isLoadingMore || !hasMore) return;
+    const nextPage = page + 1;
+    try {
+      setIsLoadingMore(true);
+      setError("");
+      const { intakesData } = await fetchPage(nextPage);
+      setIntakes((prev) => [...prev, ...(Array.isArray(intakesData.intakes) ? intakesData.intakes : [])]);
+      setHasMore(Boolean(intakesData.hasMore));
+      setHasTodayIntake(Boolean(intakesData.hasTodayIntake));
+      setPage(nextPage);
+    } catch (e) {
+      setError(e?.response?.data?.message || "Failed to load more intakes.");
+    } finally {
+      setIsLoadingMore(false);
+    }
+  };
+
+  const goalCalories = useMemo(() => profile?.goalCalories ?? null, [profile]);
+
+  const editEstimatedGoalCalories = useMemo(
+    () => estimateGoalCalories(editForm.weight, editForm.height, editForm.goalWeight),
+    [editForm.weight, editForm.height, editForm.goalWeight],
+  );
+
+  if (isLoading && !profile) {
+    return <div className="opacity-80">Loading…</div>;
+  }
+
+  const onOpenEditProfile = () => {
+    setEditForm({
+      weight: String(profile?.weight ?? ""),
+      height: String(profile?.height ?? ""),
+      goalWeight: String(profile?.goalWeight ?? ""),
+      goalCalories: String(profile?.goalCalories ?? ""),
+    });
+    setEditAutoCalculate(false);
+    setEditError("");
+    setIsEditingProfile(true);
+  };
+
+  const onCancelEdit = () => {
+    setIsEditingProfile(false);
+    setEditForm({ weight: "", height: "", goalWeight: "", goalCalories: "" });
+    setEditError("");
+  };
+
+  const onSubmitEdit = async (e) => {
+    e.preventDefault();
+    setEditError("");
+    setIsSubmittingEdit(true);
+    try {
+      const res = await api.put("/weight/profile", {
+        weight: editForm.weight === "" ? null : Number(editForm.weight),
+        height: editForm.height === "" ? null : Number(editForm.height),
+        goalWeight: editForm.goalWeight === "" ? null : Number(editForm.goalWeight),
+        goalCalories: editForm.goalCalories === "" ? null : Number(editForm.goalCalories),
+        autoCalculateTargets: editAutoCalculate,
+      });
+      setProfile(res.data);
+      setIsEditingProfile(false);
+    } catch (err) {
+      setEditError(
+        err?.response?.data?.message ||
+        Object.values(err?.response?.data?.errors ?? {})[0] ||
+        "Failed to update profile"
+      );
+    } finally {
+      setIsSubmittingEdit(false);
+    }
+  };
+
+  return (
+    <div className="space-y-6">
+      <WeightSummaryCard 
+        profile={profile} 
+        onEdit={onOpenEditProfile}
+        todayTrainingInfo={todayTrainingInfo}
+      />
+
+      {isEditingProfile ? (
+        <div className="modal modal-open" role="dialog" aria-modal="true">
+          <div className="modal-box max-w-2xl">
+            <WeightStartForm
+              form={editForm}
+              setForm={setEditForm}
+              onSubmit={onSubmitEdit}
+              onCancel={onCancelEdit}
+              error={editError}
+              isSubmitting={isSubmittingEdit}
+              autoCalculateTargets={editAutoCalculate}
+              setAutoCalculateTargets={setEditAutoCalculate}
+              estimatedGoalTimeWeeks={estimateGoalTimeWeeks(editForm.weight, editForm.goalWeight)}
+              estimatedGoalCalories={editEstimatedGoalCalories}
+            />
+            <button
+              type="button"
+              className="modal-backdrop"
+              aria-label="Close"
+              onClick={onCancelEdit}
+              disabled={isSubmittingEdit}
+            />
+          </div>
+        </div>
+      ) : null}
+
+      <WeightTrackingHeader
+        onAddIntake={() => navigate("/dashboard/weight/intakes/new")}
+        isTodayLogged={hasTodayIntake}
+      />
+
+      <WeightProgressCard graphSrc={graphPlaceholder} />
+
+      <WeightIntakesTable
+        intakes={intakes}
+        isLoading={isLoading}
+        error={error}
+        isLoadingMore={isLoadingMore}
+        hasMore={hasMore}
+        onLoadMore={onLoadMore}
+        pageSize={pageSize}
+        goalCalories={goalCalories}
+        onAddIntake={() => navigate("/dashboard/weight/intakes/new")}
+        currentWeight={profile?.weight}
+        goalWeight={profile?.goalWeight}
+      />
+    </div>
+  );
+}
Index: frontend/src/pages/Dashboard/pages/Weight/components/WeightCenteredCard.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/components/WeightCenteredCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/components/WeightCenteredCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,15 @@
+import React from "react";
+
+export default function WeightCenteredCard({ title, message }) {
+  return (
+    <div className="min-h-[70vh] w-full flex items-center justify-center">
+      <div className="card bg-base-200 border border-base-300 w-full max-w-2xl">
+        <div className="card-body items-center text-center">
+          <h1 className="text-3xl font-bold">{title}</h1>
+          <p className="opacity-80">{message}</p>
+        </div>
+      </div>
+    </div>
+  );
+}
+
Index: frontend/src/pages/Dashboard/pages/Weight/components/WeightIntakesTable.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/components/WeightIntakesTable.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/components/WeightIntakesTable.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,160 @@
+import React, { useMemo } from "react";
+
+function formatDate(value) {
+  if (!value) return "—";
+  const d = new Date(value);
+  if (Number.isNaN(d.getTime())) return String(value);
+  return d.toLocaleDateString(undefined, {
+    year: "numeric",
+    month: "short",
+    day: "2-digit",
+  });
+}
+
+function formatNumber(value) {
+  if (value === null || value === undefined || value === "") return "—";
+  const num = Number(value);
+  if (Number.isNaN(num)) return String(value);
+  return Number.isInteger(num) ? String(num) : num.toFixed(2);
+}
+
+export default function WeightIntakesTable({
+  intakes,
+  isLoading,
+  error,
+  isLoadingMore,
+  hasMore,
+  onLoadMore,
+  pageSize,
+  goalCalories,
+  onAddIntake,
+  currentWeight,
+  goalWeight,
+}) {
+  const columns = useMemo(
+    () => [
+      { key: "date", label: "Date" },
+      { key: "calories", label: "Calories" },
+      { key: "delta", label: "Vs goal" },
+    ],
+    [],
+  );
+
+  // Determine if user is bulking (goal > current) or cutting (goal < current)
+  const isBulking = useMemo(() => {
+    const current = Number(currentWeight);
+    const goal = Number(goalWeight);
+    if (!Number.isFinite(current) || !Number.isFinite(goal)) {
+      return null; // Can't determine
+    }
+    return goal > current;
+  }, [currentWeight, goalWeight]);
+
+  return (
+    <div className="card bg-base-200 border border-base-300">
+      <div className="card-body">
+        <div className="flex items-center justify-between gap-4">
+          <h2 className="text-lg font-semibold">Daily intakes</h2>
+          <span className="text-sm opacity-70">Showing {pageSize} per page</span>
+        </div>
+
+        {error ? (
+          <div className="alert alert-error mt-4">
+            <span>{error}</span>
+          </div>
+        ) : null}
+
+        <div className="mt-4 overflow-x-auto">
+          <table className="table">
+            <thead>
+              <tr>
+                {columns.map((c) => (
+                  <th key={c.key}>{c.label}</th>
+                ))}
+              </tr>
+            </thead>
+            <tbody>
+              {isLoading ? (
+                <tr>
+                  <td colSpan={columns.length} className="opacity-70">
+                    Loading…
+                  </td>
+                </tr>
+              ) : intakes.length === 0 ? (
+                <tr>
+                  <td colSpan={columns.length} className="py-10">
+                    <div className="flex flex-col items-center text-center gap-3">
+                      <p className="opacity-80">No daily intakes yet.</p>
+                      <button
+                        type="button"
+                        className="btn bg-green-400! text-black! hover:bg-green-500! border-0"
+                        onClick={onAddIntake}
+                      >
+                        Add your first daily intake
+                      </button>
+                    </div>
+                  </td>
+                </tr>
+              ) : (
+                intakes.map((intake) => {
+                  const calories = Number(intake?.calories);
+                  const goal = Number(goalCalories);
+                  const burned = Number(intake?.burnedCalories) || 0;
+                  // If user trained that day, add burned calories to goal
+                  const adjustedGoal = intake?.trainedThatDay ? goal + burned : goal;
+                  const hasGoal = Number.isFinite(adjustedGoal);
+                  const delta = hasGoal && Number.isFinite(calories) ? calories - adjustedGoal : null;
+                  const deltaLabel =
+                    delta === null
+                      ? "—"
+                      : `${delta > 0 ? "+" : ""}${formatNumber(delta)} kcal`;
+                  
+                  // Determine color based on bulking vs cutting
+                  let deltaClass = "opacity-80";
+                  if (delta !== null) {
+                    if (isBulking === true) {
+                      // Bulking: eating MORE is good (green), eating LESS is bad (red)
+                      deltaClass = delta > 0 ? "text-green-400 font-semibold" : delta < 0 ? "text-red-400 font-semibold" : "opacity-80";
+                    } else if (isBulking === false) {
+                      // Cutting: eating LESS is good (green), eating MORE is bad (red)
+                      deltaClass = delta > 0 ? "text-red-400 font-semibold" : delta < 0 ? "text-green-400 font-semibold" : "opacity-80";
+                    }
+                  }
+
+                  return (
+                    <tr key={intake.dailyIntakeId ?? `${intake.date}-${intake.calories}`}>
+                      <td>{formatDate(intake.date)}</td>
+                      <td>{formatNumber(intake.calories)} kcal</td>
+                      <td className={deltaClass}>{deltaLabel}</td>
+                    </tr>
+                  );
+                })
+              )}
+            </tbody>
+          </table>
+        </div>
+
+        <div className="mt-4 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
+          <button
+            type="button"
+            className="btn bg-green-400! text-black! hover:bg-green-500! border-0"
+            onClick={onAddIntake}
+            disabled={isLoading}
+          >
+            + Add today's intake
+          </button>
+
+          <button
+            type="button"
+            className="btn btn-outline"
+            onClick={onLoadMore}
+            disabled={isLoading || isLoadingMore || !hasMore}
+          >
+            {isLoadingMore ? "Loading…" : hasMore ? "Load more" : "No more"}
+          </button>
+        </div>
+      </div>
+    </div>
+  );
+}
+
Index: frontend/src/pages/Dashboard/pages/Weight/components/WeightProgressCard.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/components/WeightProgressCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/components/WeightProgressCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,29 @@
+import React from "react";
+
+export default function WeightProgressCard({ graphSrc }) {
+  return (
+    <div className="card bg-base-200 border border-base-300">
+      <div className="card-body">
+        <div className="flex items-center justify-between gap-4">
+          <div>
+            <h2 className="text-lg font-semibold">Progress</h2>
+            <p className="opacity-80">
+              Graph placeholder — calorie intake over time will appear here.
+            </p>
+          </div>
+          <span className="badge badge-ghost">Graph placeholder</span>
+        </div>
+        <div className="mt-4 overflow-hidden rounded-xl bg-base-300/30 border border-base-300">
+          <div className="p-4">
+            <img
+              src={graphSrc}
+              alt="Weight progress graph placeholder"
+              className="w-full max-h-64 object-contain opacity-90"
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+}
+
Index: frontend/src/pages/Dashboard/pages/Weight/components/WeightStartCtaCard.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/components/WeightStartCtaCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/components/WeightStartCtaCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,27 @@
+import React from "react";
+
+export default function WeightStartCtaCard({ error, onStart, isSubmitting }) {
+  return (
+    <div className="card bg-base-200 border border-base-300">
+      <div className="card-body items-center text-center">
+        <h1 className="text-4xl font-bold">You are not tracking weight</h1>
+        <p className="opacity-80 max-w-xl">
+          Start tracking to save your weight profile, calculate your target pace,
+          and keep daily calorie intake history.
+        </p>
+
+        {error ? <p className="text-error text-sm mt-2">{error}</p> : null}
+
+        <button
+          type="button"
+          className="btn btn-lg mt-6 w-full max-w-md bg-green-400! text-black! hover:bg-green-500!"
+          onClick={onStart}
+          disabled={isSubmitting}
+        >
+          {isSubmitting ? "Starting…" : "Start Tracking Weight"}
+        </button>
+      </div>
+    </div>
+  );
+}
+
Index: frontend/src/pages/Dashboard/pages/Weight/components/WeightStartForm.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/components/WeightStartForm.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/components/WeightStartForm.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,181 @@
+import React from "react";
+
+function formatNumber(value) {
+  if (value === null || value === undefined || value === "") return "—";
+  const num = Number(value);
+  if (Number.isNaN(num)) return String(value);
+  return Number.isInteger(num) ? String(num) : num.toFixed(2);
+}
+
+export default function WeightStartForm({
+  form,
+  setForm,
+  onSubmit,
+  onCancel,
+  error,
+  isSubmitting,
+  autoCalculateTargets,
+  setAutoCalculateTargets,
+  estimatedGoalTimeWeeks,
+  estimatedGoalCalories,
+}) {
+  return (
+    <form onSubmit={onSubmit} className="card bg-base-200 border border-base-300">
+      <div className="card-body items-center text-center">
+        <h1 className="text-3xl font-bold">Start tracking weight</h1>
+        <p className="opacity-80 max-w-2xl">
+          Fill in your current body metrics and the target you want to reach.
+          Trekr will estimate the time and goal calories in the form, and you can
+          override the calculation manually if you want to plan your own target.
+        </p>
+
+        {error ? <p className="text-error text-sm mt-2">{error}</p> : null}
+
+        <div className="mt-4 grid w-full grid-cols-1 gap-4 md:grid-cols-3">
+          <div>
+            <label className="label">Current weight (kg)</label>
+            <input
+              type="number"
+              className="input input-bordered w-full"
+              value={form.weight}
+              onChange={(e) => setForm((p) => ({ ...p, weight: e.target.value }))}
+              min={1}
+              step="0.1"
+              required
+            />
+          </div>
+
+          <div>
+            <label className="label">Height (cm)</label>
+            <input
+              type="number"
+              className="input input-bordered w-full"
+              value={form.height}
+              onChange={(e) => setForm((p) => ({ ...p, height: e.target.value }))}
+              min={1}
+              step="0.1"
+              required
+            />
+          </div>
+
+          <div>
+            <label className="label">Goal weight (kg)</label>
+            <input
+              type="number"
+              className="input input-bordered w-full"
+              value={form.goalWeight}
+              onChange={(e) =>
+                setForm((p) => ({ ...p, goalWeight: e.target.value }))
+              }
+              min={1}
+              step="0.1"
+              required
+            />
+          </div>
+        </div>
+
+        <div className="mt-4 w-full rounded-2xl border border-base-300 bg-base-100 p-4 text-left">
+          <label className="label cursor-pointer justify-start gap-3">
+            <input
+              type="checkbox"
+              className="checkbox"
+              checked={autoCalculateTargets}
+              onChange={(e) => {
+                const next = e.target.checked;
+                setAutoCalculateTargets(next);
+                if (!next) {
+                  if (form.goalTimeWeeks === "" && estimatedGoalTimeWeeks !== null) {
+                    setForm((p) => ({
+                      ...p,
+                      goalTimeWeeks: String(estimatedGoalTimeWeeks),
+                    }));
+                  }
+                  if (form.goalCalories === "" && estimatedGoalCalories !== null) {
+                    setForm((p) => ({
+                      ...p,
+                      goalCalories: String(estimatedGoalCalories),
+                    }));
+                  }
+                }
+              }}
+            />
+            <span className="label-text">Auto-calculate goal time and calories</span>
+          </label>
+          <p className="text-xs opacity-70 mt-1">
+            Trekr calculates the recommended time locally and only saves your
+            weight profile plus the calorie target.
+          </p>
+
+          <div className="mt-3 grid grid-cols-1 gap-3 sm:grid-cols-2">
+            <div className="rounded-xl border border-base-300 p-3">
+              <div className="text-xs uppercase opacity-60">Suggested time</div>
+              <div className="text-xl font-semibold">
+                {formatNumber(estimatedGoalTimeWeeks)} weeks
+              </div>
+            </div>
+            <div className="rounded-xl border border-base-300 p-3">
+              <div className="text-xs uppercase opacity-60">Suggested calories</div>
+              <div className="text-xl font-semibold">
+                {formatNumber(estimatedGoalCalories)} kcal
+              </div>
+            </div>
+          </div>
+        </div>
+
+        <div className="mt-4 grid w-full grid-cols-1 gap-4 md:grid-cols-2">
+          <div>
+            <label className="label">Goal time (weeks)</label>
+            <input
+              type="number"
+              className="input input-bordered w-full"
+              value={form.goalTimeWeeks}
+              onChange={(e) =>
+                setForm((p) => ({ ...p, goalTimeWeeks: e.target.value }))
+              }
+              min={0}
+              step="0.1"
+              disabled={autoCalculateTargets}
+              placeholder={autoCalculateTargets ? "Calculated automatically" : "12.5"}
+              required={!autoCalculateTargets}
+            />
+          </div>
+
+          <div>
+            <label className="label">Goal calories (kcal)</label>
+            <input
+              type="number"
+              className="input input-bordered w-full"
+              value={form.goalCalories}
+              onChange={(e) =>
+                setForm((p) => ({ ...p, goalCalories: e.target.value }))
+              }
+              min={0}
+              step="0.1"
+              disabled={autoCalculateTargets}
+              placeholder={autoCalculateTargets ? "Calculated automatically" : "2200"}
+              required={!autoCalculateTargets}
+            />
+          </div>
+        </div>
+
+        <div className="mt-6 flex w-full flex-col items-center gap-3 sm:flex-row sm:justify-center">
+          <button
+            className="btn btn-lg w-full sm:w-auto bg-green-400! text-black! hover:bg-green-500!"
+            type="submit"
+            disabled={isSubmitting}
+          >
+            {isSubmitting ? "Starting…" : "Start Tracking"}
+          </button>
+          <button
+            type="button"
+            className="btn btn-ghost btn-lg w-full sm:w-auto"
+            onClick={onCancel}
+          >
+            Cancel
+          </button>
+        </div>
+      </div>
+    </form>
+  );
+}
+
Index: frontend/src/pages/Dashboard/pages/Weight/components/WeightSummaryCard.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/components/WeightSummaryCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/components/WeightSummaryCard.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,63 @@
+import React, { useMemo } from "react";
+import { MdEdit } from "react-icons/md";
+
+function statValue(value, suffix = "") {
+  if (value === null || value === undefined || value === "") return "—";
+  const num = Number(value);
+  if (Number.isNaN(num)) return String(value);
+  const formatted = Number.isInteger(num) ? String(num) : num.toFixed(2);
+  return `${formatted}${suffix}`;
+}
+
+export default function WeightSummaryCard({ profile, onEdit, todayTrainingInfo }) {
+  const todayCalories = useMemo(() => {
+    if (!profile?.goalCalories || !todayTrainingInfo) return null;
+    const goal = Number(profile.goalCalories);
+    const burned = Number(todayTrainingInfo.totalBurnedCalories) || 0;
+    if (!Number.isFinite(goal)) return null;
+    return goal + burned;
+  }, [profile?.goalCalories, todayTrainingInfo]);
+
+  const stats = [
+    { label: "Current weight", value: profile?.weight, suffix: " kg" },
+    { label: "Goal weight", value: profile?.goalWeight, suffix: " kg" },
+    { label: "Goal calories", value: profile?.goalCalories, suffix: " kcal" },
+    todayTrainingInfo?.trainedToday ? 
+      { label: "Today's calories", value: todayCalories, suffix: " kcal", subtitle: `(+${statValue(todayTrainingInfo.totalBurnedCalories)} burned)` } 
+      : null,
+  ].filter(Boolean);
+
+  return (
+    <div className="card bg-base-200 border border-base-300">
+      <div className="card-body">
+        <div className="flex items-center justify-between gap-4">
+          <div>
+            <h2 className="text-lg font-semibold">Profile summary</h2>
+            <p className="opacity-80">
+              Your current target and calorie plan at a glance.
+            </p>
+          </div>
+          <button
+            type="button"
+            className="btn btn-sm btn-ghost text-blue-400 hover:text-blue-300"
+            title="Edit profile"
+            onClick={onEdit}
+          >
+            <MdEdit className="size-5" />
+          </button>
+        </div>
+
+        <div className="mt-4 grid grid-cols-1 gap-3 sm:grid-cols-3 lg:grid-cols-4">
+          {stats.map((stat) => (
+            <div key={stat.label} className="stat bg-base-100 rounded-box border border-base-300">
+              <div className="stat-title text-xs">{stat.label}</div>
+              <div className="stat-value text-lg">{statValue(stat.value, stat.suffix)}</div>
+              {stat.subtitle && <div className="stat-desc text-xs">{stat.subtitle}</div>}
+            </div>
+          ))}
+        </div>
+      </div>
+    </div>
+  );
+}
+
Index: frontend/src/pages/Dashboard/pages/Weight/components/WeightTrackingHeader.jsx
===================================================================
--- frontend/src/pages/Dashboard/pages/Weight/components/WeightTrackingHeader.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
+++ frontend/src/pages/Dashboard/pages/Weight/components/WeightTrackingHeader.jsx	(revision 708af9efba48db0445f07728b5d091a3d8898876)
@@ -0,0 +1,23 @@
+import React from "react";
+
+export default function WeightTrackingHeader({ onAddIntake, isTodayLogged }) {
+  return (
+    <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
+      <div>
+        <h1 className="text-2xl font-bold">Weight</h1>
+        <p className="opacity-80">
+          Track your daily calorie intakes and keep an eye on your target.
+        </p>
+      </div>
+      <button
+        type="button"
+        className="btn bg-green-400! text-black! hover:bg-green-500! border-0"
+        onClick={onAddIntake}
+        disabled={isTodayLogged}
+      >
+        {isTodayLogged ? "Today's intake already logged" : "+ Add today's intake"}
+      </button>
+    </div>
+  );
+}
+
