diff --git a/src/app/project/model.go b/src/app/project/model.go
new file mode 100644
index 0000000000000000000000000000000000000000..858689c14a6849b76340919bea2bed9176832551
--- /dev/null
+++ b/src/app/project/model.go
@@ -0,0 +1,168 @@
+package project
+
+import (
+	"time"
+
+	"github.com/google/uuid"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+// Project represents the main project entity stored in MongoDB
+// This struct defines the complete data structure for a project including
+// metadata fields for tracking creation and modification times
+type Project struct {
+	// ID is the unique MongoDB ObjectID that serves as the primary key
+	// The omitempty tag excludes this field if it's empty during insertion
+	ID primitive.ObjectID bson:"_id,omitempty" json:"id"
+
+	// ProjectID is a human-readable unique identifier (e.g., "PRJ-2025-001")
+	// This allows users to reference projects with meaningful IDs
+	ProjectID string bson:"project_id" json:"projectId"
+
+	// Name is the display name of the project (e.g., "HARMONY Mobile")
+	// This is what users see in the interface as the project title
+	Name string bson:"name" json:"name"
+
+	// Description provides detailed information about the project's purpose
+	// This field is optional and can be empty for simple projects
+	Description string bson:"description" json:"description"
+
+	// StartDate defines when the project begins
+	// Used for project timeline calculations and reporting
+	StartDate time.Time bson:"start_date" json:"startDate"
+
+	// EndDate defines when the project is scheduled to complete
+	// Must be after StartDate as enforced by business logic
+	EndDate time.Time bson:"end_date" json:"endDate"
+
+	// CreatedBy stores the UUID of the user who created this project
+	// This establishes ownership and is used for access control
+	CreatedBy uuid.UUID bson:"created_by" json:"createdBy"
+
+	// CreatedAt records when this project was first created
+	// Automatically set during project creation for audit trails
+	CreatedAt time.Time bson:"created_at" json:"createdAt"
+
+	// UpdatedAt tracks the last modification time
+	// Uses pointer to allow nil values when no updates have occurred
+	// The omitempty tag excludes this field if it's nil
+	UpdatedAt *time.Time bson:"updated_at,omitempty" json:"updatedAt,omitempty"
+}
+
+// ProjectToCreate represents the data structure used when creating new projects
+// This struct contains only the fields that users can specify during creation
+// System-generated fields like ID and timestamps are handled separately
+type ProjectToCreate struct {
+	// ProjectID must be provided by the user and must be unique
+	// Validation ensures this field is not empty
+	ProjectID string json:"projectId" hvalidate:"required"
+
+	// Name is required and serves as the display title
+	// Validation ensures this field is not empty
+	Name string json:"name" hvalidate:"required"
+
+	// Description is optional and can be left empty
+	// No validation constraints are applied to this field
+	Description string json:"description"
+
+	// StartDate is required and must be a valid date
+	// Validation ensures this field is provided
+	StartDate time.Time json:"startDate" hvalidate:"required"
+
+	// EndDate is required and must be after StartDate
+	// Basic validation ensures this field is provided
+	// Business logic validation ensures it's after StartDate
+	EndDate time.Time json:"endDate" hvalidate:"required"
+
+	// CreatedBy is set by the system based on the current user
+	// The - tag excludes this from JSON serialization as it's not user input
+	CreatedBy uuid.UUID json:"-"
+}
+
+// ProjectToUpdate represents the data structure used when updating existing projects
+// This struct includes the project ID to identify which project to update
+// Note: ProjectID is not included as it cannot be changed after creation
+type ProjectToUpdate struct {
+	// ID identifies which project to update using the MongoDB ObjectID
+	// This field is populated from the URL parameter
+	ID primitive.ObjectID bson:"_id" json:"id"
+
+	// Name can be updated and is required to be non-empty
+	// Users can change the display name of their projects
+	Name string json:"name" hvalidate:"required"
+
+	// Description can be updated and can be empty
+	// Users can modify or clear the project description
+	Description string json:"description"
+
+	// StartDate can be updated but must remain valid
+	// Users can adjust project timelines as needed
+	StartDate time.Time json:"startDate" hvalidate:"required"
+
+	// EndDate can be updated but must remain after StartDate
+	// Business logic validation ensures timeline consistency
+	EndDate time.Time json:"endDate" hvalidate:"required"
+}
+
+// ToUpdate converts a Project instance to a ProjectToUpdate structure
+// This method is useful when pre-filling edit forms with existing project data
+// It extracts only the fields that can be modified during updates
+func (p *Project) ToUpdate() *ProjectToUpdate {
+	return &ProjectToUpdate{
+		ID:          p.ID,          // Preserve the project identifier
+		Name:        p.Name,        // Current name as default
+		Description: p.Description, // Current description as default
+		StartDate:   p.StartDate,   // Current start date as default
+		EndDate:     p.EndDate,     // Current end date as default
+	}
+}
+
+// ProjectWithRequirements represents a project along with its associated requirements
+// This structure is used for project detail views where both project information
+// and requirement summaries need to be displayed together
+type ProjectWithRequirements struct {
+	// Embed the base Project struct to inherit all project fields
+	// This allows access to all project properties directly
+	*Project
+
+	// Requirements contains summary information for all requirements in this project
+	// This is optimized for display purposes rather than full requirement details
+	Requirements []*RequirementSummary json:"requirements"
+
+	// RequirementCount provides a quick count of total requirements
+	// This avoids the need to calculate len(Requirements) in templates
+	RequirementCount int json:"requirementCount"
+}
+
+// RequirementSummary provides essential requirement information for project views
+// This structure contains only the fields needed for requirement lists and summaries
+// Full requirement details would be loaded separately when viewing individual requirements
+type RequirementSummary struct {
+	// ID is the unique MongoDB ObjectID for this requirement
+	// Used for linking to detailed requirement views
+	ID primitive.ObjectID bson:"_id" json:"id"
+
+	// RequirementID is a human-readable identifier for this requirement
+	// Generated automatically if not provided (e.g., "REQ-abc123")
+	RequirementID string bson:"requirement_id" json:"requirementId"
+
+	// Condition describes the circumstances under which this requirement applies
+	// This field comes from the requirement parsing and validation process
+	Condition string bson:"condition" json:"condition"
+
+	// System identifies which system or component this requirement affects
+	// This helps organize requirements by their target systems
+	System string bson:"system" json:"system"
+
+	// Requirement contains the actual requirement text
+	// This is the main content that describes what must be implemented
+	Requirement string bson:"requirement" json:"requirement"
+
+	// Status tracks the current state of this requirement
+	// Possible values include "Entwurf", "In Prüfung", "Genehmigt", "Abgelehnt"
+	Status string bson:"status" json:"status"
+
+	// CreatedAt records when this requirement was first created
+	// Used for sorting and audit purposes
+	CreatedAt time.Time bson:"created_at" json:"createdAt"
+}
\ No newline at end of file
diff --git a/src/app/project/mongodb.go b/src/app/project/mongodb.go
new file mode 100644
index 0000000000000000000000000000000000000000..33bd24ab8b3b06df8fd9788b87f9cfa8e3af69e3
--- /dev/null
+++ b/src/app/project/mongodb.go
@@ -0,0 +1,97 @@
+package project
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"time"
+
+	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/options"
+)
+
+// MongoManager handles MongoDB connection management and database operations
+// This struct encapsulates the MongoDB client and database references
+// It provides a centralized way to manage database connections throughout the application
+type MongoManager struct {
+	client *mongo.Client   // The MongoDB client for connection management
+	db     *mongo.Database // The specific database instance for this application
+}
+
+// NewMongoManager creates and initializes a new MongoDB connection manager
+// This function establishes a connection to MongoDB with optimized settings
+// and returns a manager instance that can be used throughout the application
+func NewMongoManager(uri, dbName string) (*MongoManager, error) {
+	log.Printf("INFO: Connecting to MongoDB at %s, database: %s", uri, dbName)
+
+	// Configure MongoDB client options for optimal performance
+	clientOptions := options.Client().ApplyURI(uri)
+
+	// Set connection pool parameters for handling concurrent requests efficiently
+	// MaxPoolSize: Maximum number of connections in the pool (100 connections)
+	// This allows the application to handle many concurrent database operations
+	clientOptions.SetMaxPoolSize(100)
+
+	// MinPoolSize: Minimum number of connections to maintain (10 connections)
+	// This ensures quick response times by keeping connections ready
+	clientOptions.SetMinPoolSize(10)
+
+	// MaxConnIdleTime: How long idle connections stay open (30 seconds)
+	// This balances resource usage with connection availability
+	clientOptions.SetMaxConnIdleTime(30 * time.Second)
+
+	log.Printf("DEBUG: MongoDB connection pool configured - max: 100, min: 10, idle timeout: 30s")
+
+	// Attempt to create a connection to MongoDB using the configured options
+	client, err := mongo.Connect(context.TODO(), clientOptions)
+	if err != nil {
+		log.Printf("ERROR: Failed to connect to MongoDB: %v", err)
+		return nil, fmt.Errorf("failed to connect to MongoDB: %w", err)
+	}
+
+	log.Println("DEBUG: MongoDB client created, testing connection...")
+
+	// Test the connection by pinging the MongoDB server
+	// This ensures that the connection is actually working before proceeding
+	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
+	defer cancel() // Ensure the context is cleaned up after the ping
+
+	if err := client.Ping(ctx, nil); err != nil {
+		log.Printf("ERROR: MongoDB ping failed: %v", err)
+		return nil, fmt.Errorf("failed to ping MongoDB: %w", err)
+	}
+
+	log.Printf("INFO: Successfully connected to MongoDB database '%s'", dbName)
+
+	// Return a configured MongoManager instance
+	return &MongoManager{
+		client: client,                  // Store the client for connection management
+		db:     client.Database(dbName), // Store the database reference for operations
+	}, nil
+}
+
+// GetDatabase returns the MongoDB database instance for performing operations
+// This method provides access to the database for repositories and other components
+// that need to interact with MongoDB collections
+func (m *MongoManager) GetDatabase() *mongo.Database {
+	log.Printf("DEBUG: Returning database instance: %s", m.db.Name())
+	return m.db
+}
+
+// Close gracefully shuts down the MongoDB connection
+// This method should be called when the application is shutting down
+// to ensure all connections are properly closed and resources are released
+func (m *MongoManager) Close() error {
+	log.Println("INFO: Closing MongoDB connection...")
+
+	// Disconnect the MongoDB client using a background context
+	// This ensures that ongoing operations can complete before disconnection
+	err := m.client.Disconnect(context.Background())
+	if err != nil {
+		log.Printf("ERROR: Failed to close MongoDB connection: %v", err)
+		return err
+	}
+
+	log.Println("INFO: MongoDB connection closed successfully")
+	return nil
+}
diff --git a/src/app/project/repository.go b/src/app/project/repository.go
new file mode 100644
index 0000000000000000000000000000000000000000..164ff09bcff81560690b25aac0b4fad14d1f55a8
--- /dev/null
+++ b/src/app/project/repository.go
@@ -0,0 +1,393 @@
+package project
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"time"
+
+	"github.com/google/uuid"
+	"go.mongodb.org/mongo-driver/bson"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+	"go.mongodb.org/mongo-driver/mongo"
+	"go.mongodb.org/mongo-driver/mongo/options"
+)
+
+// MongoDB collection names used throughout the application
+// These constants ensure consistent collection naming and make changes easier
+const (
+	ProjectCollectionName     = "projects"     // Main projects collection
+	RequirementCollectionName = "requirements" // Requirements associated with projects
+)
+
+// ProjectRepository defines the interface for project data access operations
+// This interface abstracts the underlying database technology and allows for
+// easy testing with mock implementations or switching database providers
+type ProjectRepository interface {
+	// Create inserts a new project into the database
+	Create(ctx context.Context, project *ProjectToCreate) (*Project, error)
+
+	// FindByID retrieves a project using its MongoDB ObjectID
+	FindByID(ctx context.Context, id primitive.ObjectID) (*Project, error)
+
+	// FindByProjectID retrieves a project using its human-readable project ID
+	FindByProjectID(ctx context.Context, projectID string) (*Project, error)
+
+	// FindByCreatedBy retrieves all projects created by a specific user
+	FindByCreatedBy(ctx context.Context, userID uuid.UUID) ([]*Project, error)
+
+	// FindWithRequirements retrieves a project along with all its requirements
+	FindWithRequirements(ctx context.Context, id primitive.ObjectID) (*ProjectWithRequirements, error)
+
+	// Update modifies an existing project with new data
+	Update(ctx context.Context, update *ProjectToUpdate) (*Project, error)
+
+	// Delete removes a project and all associated requirements
+	Delete(ctx context.Context, id primitive.ObjectID) error
+
+	// Search finds projects matching a text query for a specific user
+	Search(ctx context.Context, query string, userID uuid.UUID) ([]*Project, error)
+}
+
+// MongoProjectRepository implements ProjectRepository using MongoDB
+// This struct contains MongoDB-specific implementation details and connection handling
+type MongoProjectRepository struct {
+	projectCollection     *mongo.Collection // MongoDB collection for projects
+	requirementCollection *mongo.Collection // MongoDB collection for requirements
+	timeout               time.Duration     // Default timeout for database operations
+}
+
+// NewMongoProjectRepository creates a new MongoDB-based repository instance
+// This constructor initializes the repository with references to the required collections
+func NewMongoProjectRepository(db *mongo.Database) ProjectRepository {
+	log.Printf("INFO: Creating MongoProjectRepository with database %s", db.Name())
+	return &MongoProjectRepository{
+		projectCollection:     db.Collection(ProjectCollectionName),
+		requirementCollection: db.Collection(RequirementCollectionName),
+		timeout:               10 * time.Second, // Standard timeout for all operations
+	}
+}
+
+// Create inserts a new project document into the MongoDB projects collection
+// This method handles the conversion from ProjectToCreate to Project and sets system fields
+func (r *MongoProjectRepository) Create(ctx context.Context, toCreate *ProjectToCreate) (*Project, error) {
+	// Set a timeout for this operation to prevent hanging connections
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Creating project document for '%s'", toCreate.ProjectID)
+
+	// Convert the creation request to a full project document
+	// Set system-generated fields like ID and creation timestamp
+	project := &Project{
+		ID:          primitive.NewObjectID(), // Generate new MongoDB ObjectID
+		ProjectID:   toCreate.ProjectID,      // User-provided project identifier
+		Name:        toCreate.Name,           // Project display name
+		Description: toCreate.Description,    // Optional project description
+		StartDate:   toCreate.StartDate,      // Project start date
+		EndDate:     toCreate.EndDate,        // Project end date
+		CreatedBy:   toCreate.CreatedBy,      // User who created this project
+		CreatedAt:   time.Now(),              // Current timestamp
+	}
+
+	log.Printf("DEBUG: Inserting project into MongoDB collection %s", ProjectCollectionName)
+
+	// Insert the project document into MongoDB
+	result, err := r.projectCollection.InsertOne(ctx, project)
+	if err != nil {
+		log.Printf("ERROR: MongoDB insert failed for project '%s': %v", toCreate.ProjectID, err)
+		return nil, fmt.Errorf("failed to create project: %w", err)
+	}
+
+	// Update the project with the actual ObjectID assigned by MongoDB
+	if oid, ok := result.InsertedID.(primitive.ObjectID); ok {
+		project.ID = oid
+		log.Printf("INFO: Project '%s' inserted with MongoDB ID %s", project.ProjectID, oid.Hex())
+	}
+
+	return project, nil
+}
+
+// FindByID retrieves a project using its MongoDB ObjectID
+// This is the primary method for finding projects when you have the database ID
+func (r *MongoProjectRepository) FindByID(ctx context.Context, id primitive.ObjectID) (*Project, error) {
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Finding project by MongoDB ID %s", id.Hex())
+
+	var project Project
+	// Query MongoDB using the _id field (primary key)
+	err := r.projectCollection.FindOne(ctx, bson.M{"_id": id}).Decode(&project)
+	if err != nil {
+		if err == mongo.ErrNoDocuments {
+			log.Printf("WARN: Project with ID %s not found", id.Hex())
+			return nil, fmt.Errorf("project not found")
+		}
+		log.Printf("ERROR: MongoDB query failed for project ID %s: %v", id.Hex(), err)
+		return nil, fmt.Errorf("failed to find project: %w", err)
+	}
+
+	log.Printf("INFO: Found project '%s' (ProjectID: %s)", project.Name, project.ProjectID)
+	return &project, nil
+}
+
+// FindByProjectID retrieves a project using its human-readable project identifier
+// This method is used when checking for duplicate project IDs during creation
+func (r *MongoProjectRepository) FindByProjectID(ctx context.Context, projectID string) (*Project, error) {
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Finding project by ProjectID '%s'", projectID)
+
+	var project Project
+	// Query using the project_id field (user-defined identifier)
+	err := r.projectCollection.FindOne(ctx, bson.M{"project_id": projectID}).Decode(&project)
+	if err != nil {
+		if err == mongo.ErrNoDocuments {
+			log.Printf("DEBUG: Project with ProjectID '%s' not found (this may be expected)", projectID)
+			return nil, fmt.Errorf("project not found")
+		}
+		log.Printf("ERROR: MongoDB query failed for ProjectID '%s': %v", projectID, err)
+		return nil, fmt.Errorf("failed to find project: %w", err)
+	}
+
+	log.Printf("INFO: Found project '%s' by ProjectID '%s'", project.Name, projectID)
+	return &project, nil
+}
+
+// FindByCreatedBy retrieves all projects created by a specific user
+// Results are sorted by creation date (newest first) for better user experience
+func (r *MongoProjectRepository) FindByCreatedBy(ctx context.Context, userID uuid.UUID) ([]*Project, error) {
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Finding projects for user %s", userID)
+
+	// Query for all projects where created_by matches the user ID
+	// Sort by created_at in descending order (newest first)
+	cursor, err := r.projectCollection.Find(
+		ctx,
+		bson.M{"created_by": userID}, // Filter condition
+		options.Find().SetSort(bson.D{{"created_at", -1}}), // Sort options
+	)
+	if err != nil {
+		log.Printf("ERROR: MongoDB query failed for user %s: %v", userID, err)
+		return nil, fmt.Errorf("failed to find projects: %w", err)
+	}
+	defer cursor.Close(ctx) // Ensure cursor is closed to free resources
+
+	// Iterate through the cursor and decode each document
+	var projects []*Project
+	for cursor.Next(ctx) {
+		var project Project
+		if err := cursor.Decode(&project); err != nil {
+			log.Printf("ERROR: Failed to decode project document: %v", err)
+			return nil, fmt.Errorf("failed to decode project: %w", err)
+		}
+		projects = append(projects, &project)
+	}
+
+	log.Printf("INFO: Found %d projects for user %s", len(projects), userID)
+	return projects, cursor.Err() // Return any cursor iteration errors
+}
+
+// FindWithRequirements retrieves a project along with all its associated requirements
+// This method is optimized for project detail pages where both sets of data are needed
+func (r *MongoProjectRepository) FindWithRequirements(ctx context.Context, id primitive.ObjectID) (*ProjectWithRequirements, error) {
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Finding project with requirements for ID %s", id.Hex())
+
+	// First, load the base project information
+	project, err := r.FindByID(ctx, id)
+	if err != nil {
+		log.Printf("ERROR: Failed to find base project for ID %s: %v", id.Hex(), err)
+		return nil, err
+	}
+
+	log.Printf("DEBUG: Loading requirements for project '%s' (ProjectID: %s)", project.Name, project.ProjectID)
+
+	// Load all requirements associated with this project
+	// Requirements are linked by the project_id field (not MongoDB ObjectID)
+	cursor, err := r.requirementCollection.Find(
+		ctx,
+		bson.M{"project_id": project.ProjectID}, // Link by project_id
+		options.Find().SetSort(bson.D{{"created_at", -1}}), // Newest first
+	)
+	if err != nil {
+		log.Printf("ERROR: Failed to query requirements for project '%s': %v", project.ProjectID, err)
+		return nil, fmt.Errorf("failed to find requirements: %w", err)
+	}
+	defer cursor.Close(ctx)
+
+	// Process each requirement document
+	var requirements []*RequirementSummary
+	for cursor.Next(ctx) {
+		var req RequirementSummary
+		if err := cursor.Decode(&req); err != nil {
+			log.Printf("WARN: Skipping invalid requirement document: %v", err)
+			continue // Skip documents that can't be decoded rather than failing entirely
+		}
+
+		// Extract additional fields from nested parsing_result if available
+		// This handles requirements that have been processed by the EIFFEL system
+		var doc bson.M
+		cursor.Decode(&doc)
+		if parsingResult, ok := doc["parsing_result"].(bson.M); ok {
+			if requirement, ok := parsingResult["requirement"].(string); ok {
+				req.Requirement = requirement
+			}
+		}
+
+		// Set default values for missing fields to ensure consistency
+		if req.Status == "" {
+			req.Status = "Entwurf" // Default status for new requirements
+		}
+		if req.RequirementID == "" {
+			// Generate a default requirement ID from the MongoDB ObjectID
+			req.RequirementID = fmt.Sprintf("REQ-%s", req.ID.Hex()[:6])
+		}
+
+		requirements = append(requirements, &req)
+	}
+
+	log.Printf("INFO: Loaded project '%s' with %d requirements", project.Name, len(requirements))
+
+	// Return the combined structure with project and requirements
+	return &ProjectWithRequirements{
+		Project:          project,
+		Requirements:     requirements,
+		RequirementCount: len(requirements),
+	}, nil
+}
+
+// Update modifies an existing project with new data and sets the updated timestamp
+// This method only updates the fields that can be modified, preserving system fields
+func (r *MongoProjectRepository) Update(ctx context.Context, update *ProjectToUpdate) (*Project, error) {
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Updating project %s with name '%s'", update.ID.Hex(), update.Name)
+
+	// Prepare the update document with new values and current timestamp
+	now := time.Now()
+	updateDoc := bson.M{
+		"$set": bson.M{
+			"name":        update.Name,        // Updated project name
+			"description": update.Description, // Updated description
+			"start_date":  update.StartDate,   // Updated start date
+			"end_date":    update.EndDate,     // Updated end date
+			"updated_at":  now,                // Set current time as update timestamp
+		},
+	}
+
+	// Execute the update operation
+	result, err := r.projectCollection.UpdateOne(
+		ctx,
+		bson.M{"_id": update.ID}, // Find the project by ObjectID
+		updateDoc,                // Apply the updates
+	)
+	if err != nil {
+		log.Printf("ERROR: MongoDB update failed for project %s: %v", update.ID.Hex(), err)
+		return nil, fmt.Errorf("failed to update project: %w", err)
+	}
+
+	log.Printf("INFO: Project %s updated - matched: %d, modified: %d",
+		update.ID.Hex(), result.MatchedCount, result.ModifiedCount)
+
+	// Return the updated project by fetching it again
+	// This ensures we return the most current data including the updated timestamp
+	return r.FindByID(ctx, update.ID)
+}
+
+// Delete removes a project and all its associated requirements from the database
+// This method ensures referential integrity by cleaning up related data
+func (r *MongoProjectRepository) Delete(ctx context.Context, id primitive.ObjectID) error {
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Starting deletion process for project %s", id.Hex())
+
+	// First, find the project to get its ProjectID for requirement cleanup
+	project, err := r.FindByID(ctx, id)
+	if err != nil {
+		log.Printf("ERROR: Cannot find project %s for deletion: %v", id.Hex(), err)
+		return err
+	}
+
+	log.Printf("INFO: Deleting project '%s' and all its requirements", project.Name)
+
+	// Delete all requirements associated with this project
+	// Requirements are linked by project_id (string) not MongoDB ObjectID
+	reqDeleteResult, err := r.requirementCollection.DeleteMany(ctx, bson.M{"project_id": project.ProjectID})
+	if err != nil {
+		log.Printf("ERROR: Failed to delete requirements for project '%s': %v", project.ProjectID, err)
+		return fmt.Errorf("failed to delete project requirements: %w", err)
+	}
+
+	log.Printf("INFO: Deleted %d requirements for project '%s'", reqDeleteResult.DeletedCount, project.ProjectID)
+
+	// Delete the project itself
+	projDeleteResult, err := r.projectCollection.DeleteOne(ctx, bson.M{"_id": id})
+	if err != nil {
+		log.Printf("ERROR: Failed to delete project %s: %v", id.Hex(), err)
+		return fmt.Errorf("failed to delete project: %w", err)
+	}
+
+	// Verify that the project was actually deleted
+	if projDeleteResult.DeletedCount == 0 {
+		log.Printf("WARN: No project was deleted for ID %s", id.Hex())
+	} else {
+		log.Printf("INFO: Project '%s' deleted successfully", project.Name)
+	}
+
+	return nil
+}
+
+// Search finds projects matching a text query across multiple fields
+// This method provides flexible search functionality for the project list interface
+func (r *MongoProjectRepository) Search(ctx context.Context, query string, userID uuid.UUID) ([]*Project, error) {
+	ctx, cancel := context.WithTimeout(ctx, r.timeout)
+	defer cancel()
+
+	log.Printf("DEBUG: Searching projects for user %s with query '%s'", userID, query)
+
+	// Build a MongoDB query that searches across multiple fields
+	// Uses case-insensitive regular expressions for flexible matching
+	filter := bson.M{
+		"created_by": userID, // Only search projects owned by this user
+		"$or": []bson.M{ // Search across multiple fields
+			{"name": bson.M{"$regex": query, "$options": "i"}},        // Project name
+			{"description": bson.M{"$regex": query, "$options": "i"}}, // Project description
+			{"project_id": bson.M{"$regex": query, "$options": "i"}},  // Project ID
+		},
+	}
+
+	// Execute the search query with sorting
+	cursor, err := r.projectCollection.Find(
+		ctx,
+		filter,
+		options.Find().SetSort(bson.D{{"created_at", -1}}), // Newest first
+	)
+	if err != nil {
+		log.Printf("ERROR: MongoDB search query failed for '%s': %v", query, err)
+		return nil, fmt.Errorf("failed to search projects: %w", err)
+	}
+	defer cursor.Close(ctx)
+
+	// Decode the search results
+	var projects []*Project
+	for cursor.Next(ctx) {
+		var project Project
+		if err := cursor.Decode(&project); err != nil {
+			log.Printf("ERROR: Failed to decode project in search results: %v", err)
+			return nil, fmt.Errorf("failed to decode project: %w", err)
+		}
+		projects = append(projects, &project)
+	}
+
+	log.Printf("INFO: Search completed - found %d projects for query '%s'", len(projects), query)
+	return projects, cursor.Err()
+}
diff --git a/src/app/project/service.go b/src/app/project/service.go
new file mode 100644
index 0000000000000000000000000000000000000000..03691430ffd83bab2f88810799d2e545ad34cac4
--- /dev/null
+++ b/src/app/project/service.go
@@ -0,0 +1,176 @@
+package project
+
+import (
+	"context"
+	"fmt"
+	"log"
+
+	"github.com/google/uuid"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+// ProjectService contains the business logic for project management operations
+// This service layer sits between the web controllers and the data repository
+// It enforces business rules, handles validation, and coordinates data operations
+type ProjectService struct {
+	repo ProjectRepository // Repository interface for data access operations
+}
+
+// NewProjectService creates and initializes a new ProjectService instance
+// The service requires a repository implementation to handle data persistence
+func NewProjectService(repo ProjectRepository) *ProjectService {
+	log.Println("INFO: ProjectService initialized")
+	return &ProjectService{repo: repo}
+}
+
+// CreateProject handles the creation of new projects with business logic validation
+// This method ensures project uniqueness, validates business rules, and creates the project
+func (s *ProjectService) CreateProject(ctx context.Context, toCreate *ProjectToCreate) (*Project, error) {
+	log.Printf("INFO: Creating project with ID '%s' and name '%s'", toCreate.ProjectID, toCreate.Name)
+
+	// Business Rule 1: Project IDs must be unique across the entire system
+	// Check if a project with this ID already exists before creating a new one
+	log.Printf("DEBUG: Checking if project ID '%s' already exists", toCreate.ProjectID)
+	existing, err := s.repo.FindByProjectID(ctx, toCreate.ProjectID)
+	if err == nil && existing != nil {
+		// If we found an existing project, the creation should fail
+		log.Printf("WARN: Project creation failed - ID '%s' already exists", toCreate.ProjectID)
+		return nil, fmt.Errorf("project with ID '%s' already exists", toCreate.ProjectID)
+	}
+
+	// Business Rule 2: Project end date must be after the start date
+	// This prevents creating projects with invalid date ranges
+	if toCreate.EndDate.Before(toCreate.StartDate) {
+		log.Printf("WARN: Project creation failed - end date (%s) before start date (%s)",
+			toCreate.EndDate.Format("2006-01-02"), toCreate.StartDate.Format("2006-01-02"))
+		return nil, fmt.Errorf("end date must be after start date")
+	}
+
+	log.Printf("DEBUG: Project validation passed, creating in repository")
+
+	// All business rules passed, delegate to repository for actual creation
+	project, err := s.repo.Create(ctx, toCreate)
+	if err != nil {
+		log.Printf("ERROR: Failed to create project '%s' in repository: %v", toCreate.ProjectID, err)
+		return nil, err
+	}
+
+	log.Printf("INFO: Project '%s' created successfully with MongoDB ID %s",
+		project.ProjectID, project.ID.Hex())
+	return project, nil
+}
+
+// GetProjectsByUser retrieves all projects belonging to a specific user
+// This method provides a simple interface for fetching user-specific projects
+func (s *ProjectService) GetProjectsByUser(ctx context.Context, userID uuid.UUID) ([]*Project, error) {
+	log.Printf("INFO: Getting projects for user %s", userID)
+
+	// Delegate to repository for data retrieval
+	projects, err := s.repo.FindByCreatedBy(ctx, userID)
+	if err != nil {
+		log.Printf("ERROR: Failed to get projects for user %s: %v", userID, err)
+		return nil, err
+	}
+
+	log.Printf("INFO: Found %d projects for user %s", len(projects), userID)
+
+	// Debug logging: Show project names for troubleshooting
+	if len(projects) > 0 {
+		log.Printf("DEBUG: Projects found: %v", func() []string {
+			names := make([]string, len(projects))
+			for i, p := range projects {
+				names[i] = p.Name
+			}
+			return names
+		}())
+	}
+
+	return projects, nil
+}
+
+// GetProjectWithRequirements retrieves a project along with all its associated requirements
+// This method is optimized for displaying project detail pages where both
+// project information and requirements are needed simultaneously
+func (s *ProjectService) GetProjectWithRequirements(ctx context.Context, id primitive.ObjectID) (*ProjectWithRequirements, error) {
+	log.Printf("INFO: Getting project with requirements for ID %s", id.Hex())
+
+	// Use the repository method that efficiently loads project and requirements together
+	// This is more efficient than making separate calls for project and requirements
+	projectWithReqs, err := s.repo.FindWithRequirements(ctx, id)
+	if err != nil {
+		log.Printf("ERROR: Failed to get project with requirements for ID %s: %v", id.Hex(), err)
+		return nil, err
+	}
+
+	log.Printf("INFO: Loaded project '%s' with %d requirements",
+		projectWithReqs.Project.Name, projectWithReqs.RequirementCount)
+
+	return projectWithReqs, nil
+}
+
+// UpdateProject handles project updates with business rule validation
+// This method ensures that updates maintain data integrity and business rules
+func (s *ProjectService) UpdateProject(ctx context.Context, update *ProjectToUpdate) (*Project, error) {
+	log.Printf("INFO: Updating project %s with name '%s'", update.ID.Hex(), update.Name)
+
+	// Business Rule: End date must still be after start date after the update
+	// This validation is applied to updates just like it is for creation
+	if update.EndDate.Before(update.StartDate) {
+		log.Printf("WARN: Project update failed - end date (%s) before start date (%s)",
+			update.EndDate.Format("2006-01-02"), update.StartDate.Format("2006-01-02"))
+		return nil, fmt.Errorf("end date must be after start date")
+	}
+
+	log.Printf("DEBUG: Project update validation passed, updating in repository")
+
+	// Delegate to repository for the actual update operation
+	project, err := s.repo.Update(ctx, update)
+	if err != nil {
+		log.Printf("ERROR: Failed to update project %s: %v", update.ID.Hex(), err)
+		return nil, err
+	}
+
+	log.Printf("INFO: Project '%s' updated successfully", project.Name)
+	return project, nil
+}
+
+// DeleteProject handles the complete removal of a project and all associated data
+// This method ensures that all related requirements are also deleted to maintain data consistency
+func (s *ProjectService) DeleteProject(ctx context.Context, id primitive.ObjectID) error {
+	log.Printf("INFO: Deleting project with ID %s", id.Hex())
+
+	// The repository handles the cascading deletion of requirements
+	// This ensures that no orphaned requirements remain in the database
+	err := s.repo.Delete(ctx, id)
+	if err != nil {
+		log.Printf("ERROR: Failed to delete project %s: %v", id.Hex(), err)
+		return err
+	}
+
+	log.Printf("INFO: Project %s and all its requirements deleted successfully", id.Hex())
+	return nil
+}
+
+// SearchProjects provides flexible project search functionality
+// This method handles both empty queries (return all projects) and text-based searches
+func (s *ProjectService) SearchProjects(ctx context.Context, query string, userID uuid.UUID) ([]*Project, error) {
+	// Handle empty search queries by returning all projects for the user
+	// This provides a consistent interface regardless of whether a search term is provided
+	if query == "" {
+		log.Printf("INFO: Empty search query, returning all projects for user %s", userID)
+		return s.repo.FindByCreatedBy(ctx, userID)
+	}
+
+	log.Printf("INFO: Searching projects for user %s with query '%s'", userID, query)
+
+	// Delegate to repository for the actual search implementation
+	// The repository handles the specifics of text searching across project fields
+	projects, err := s.repo.Search(ctx, query, userID)
+	if err != nil {
+		log.Printf("ERROR: Search failed for query '%s' and user %s: %v", query, userID, err)
+		return nil, err
+	}
+
+	log.Printf("INFO: Search completed - found %d projects for query '%s'", len(projects), query)
+	return projects, nil
+}
diff --git a/src/app/project/web/web.go b/src/app/project/web/web.go
new file mode 100644
index 0000000000000000000000000000000000000000..198aff1e64ff14e07a472e95cdc3ba65d93d5a49
--- /dev/null
+++ b/src/app/project/web/web.go
@@ -0,0 +1,492 @@
+package web
+
+import (
+	"errors"
+	"fmt"
+	"log"
+	"net/http"
+	"time"
+
+	"github.com/org-harmony/harmony/src/app/user"
+	"github.com/org-harmony/harmony/src/core/hctx"
+	"github.com/org-harmony/harmony/src/core/validation"
+	"github.com/org-harmony/harmony/src/core/web"
+	"go.mongodb.org/mongo-driver/bson/primitive"
+)
+
+// ProjectFormData represents the data structure needed for rendering project forms
+// This struct is used for both creating new projects and editing existing ones
+type ProjectFormData struct {
+	Project    any  // Can hold either *project.ProjectToCreate or *project.ProjectToUpdate
+	IsEditForm bool // Flag to determine if this is an edit form (true) or create form (false)
+}
+
+// ProjectListData contains the list of projects for template rendering
+// This structure is passed to the project list template
+type ProjectListData struct {
+	Projects []*project.Project // Array of all projects belonging to a user
+}
+
+// ProjectDetailData holds all necessary data for displaying detailed project information
+// including tab navigation and requirement management
+type ProjectDetailData struct {
+	Project             *project.ProjectWithRequirements // The project with all its requirements loaded
+	ActiveTab           string                           // Currently active tab: "general" or "requirements"
+	RequirementStatuses []string                         // Available status options for requirements
+}
+
+// RegisterController sets up all HTTP routes and handlers for project management
+// This function is called during application startup to configure the web routing
+func RegisterController(appCtx *hctx.AppCtx, webCtx *web.Ctx, mongoManager *project.MongoManager) {
+	log.Println("INFO: Registering project controllers...")
+
+	// Initialize the data access layer (repository) and business logic layer (service)
+	// Repository handles MongoDB operations, Service handles business rules
+	projectRepo := project.NewMongoProjectRepository(mongoManager.GetDatabase())
+	projectService := project.NewProjectService(projectRepo)
+	log.Println("INFO: Project repository and service initialized")
+
+	// Create a router group that requires user authentication
+	// All routes defined here will require a logged-in user
+	router := webCtx.Router.With(user.LoggedInMiddleware(appCtx))
+
+	// Define all HTTP routes for project management:
+
+	// GET /project/list - Display all projects for the current user
+	router.Get("/project/list", projectListController(appCtx, webCtx, projectService).ServeHTTP)
+
+	// GET /project/new - Show form for creating a new project
+	router.Get("/project/new", projectNewController(appCtx, webCtx).ServeHTTP)
+
+	// POST /project/new - Process new project creation form submission
+	router.Post("/project/new", projectCreateController(appCtx, webCtx, projectService).ServeHTTP)
+
+	// GET /project/{id} - Display detailed view of a specific project
+	router.Get("/project/{id}", projectDetailController(appCtx, webCtx, projectService).ServeHTTP)
+
+	// GET /project/{id}/edit - Show form for editing an existing project
+	router.Get("/project/{id}/edit", projectEditFormController(appCtx, webCtx, projectService).ServeHTTP)
+
+	// PUT /project/{id} - Process project update form submission
+	router.Put("/project/{id}", projectUpdateController(appCtx, webCtx, projectService).ServeHTTP)
+
+	// DELETE /project/{id} - Delete a project and all its requirements
+	router.Delete("/project/{id}", projectDeleteController(appCtx, webCtx, projectService).ServeHTTP)
+
+	// POST /project/search - Handle project search functionality
+	router.Post("/project/search", projectSearchController(appCtx, webCtx, projectService).ServeHTTP)
+
+	log.Println("INFO: Project routes registered successfully")
+}
+
+// projectListController handles requests to display all projects belonging to the current user
+// This controller fetches projects from the database and renders them in a list view
+func projectListController(appCtx *hctx.AppCtx, webCtx *web.Ctx, service *project.ProjectService) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		ctx := io.Context()
+		// Extract the currently logged-in user from the request context
+		// This user information was added by the authentication middleware
+		usr := user.MustCtxUser(ctx)
+
+		log.Printf("INFO: Loading project list for user %s", usr.ID)
+
+		// Fetch all projects created by this user from the database
+		// This calls through the service layer to maintain separation of concerns
+		projects, err := service.GetProjectsByUser(ctx, usr.ID)
+		if err != nil {
+			log.Printf("ERROR: Failed to get projects for user %s: %v", usr.ID, err)
+			return io.Error(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Found %d projects for user %s", len(projects), usr.ID)
+
+		// Prepare data structure for template rendering
+		data := ProjectListData{Projects: projects}
+		log.Printf("DEBUG: Rendering project list with %d projects", len(data.Projects))
+
+		// Render the template with the project data
+		// The template system will wrap this data in BaseTemplateData automatically
+		err = io.Render(
+			data,
+			"project.list.page",         // Template name to execute
+			"project/list-page.go.html", // Main page template file
+			"project/_list.go.html",     // Partial template for the project list
+		)
+
+		if err != nil {
+			log.Printf("ERROR: Failed to render project list: %v", err)
+			return err
+		}
+
+		log.Println("INFO: Project list rendered successfully")
+		return nil
+	})
+}
+
+// projectNewController displays an empty form for creating a new project
+// This controller prepares default values and renders the project creation form
+func projectNewController(appCtx *hctx.AppCtx, webCtx *web.Ctx) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		log.Println("INFO: Showing new project form")
+
+		// Create a new project structure with sensible default values
+		// Start date is today, end date is 6 months in the future
+		toCreate := &project.ProjectToCreate{
+			StartDate: time.Now(),
+			EndDate:   time.Now().AddDate(0, 6, 0), // Add 6 months to current date
+		}
+
+		// Render the project form with empty/default values
+		return renderProjectForm(io, &ProjectFormData{
+			Project:    toCreate,
+			IsEditForm: false, // This is a creation form, not an edit form
+		}, nil, nil)
+	})
+}
+
+// projectCreateController processes the form submission for creating a new project
+// This controller validates the input, creates the project, and handles success/error cases
+func projectCreateController(appCtx *hctx.AppCtx, webCtx *web.Ctx, service *project.ProjectService) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		ctx := io.Context()
+		// Get the current user to associate the new project with them
+		usr := user.MustCtxUser(ctx)
+
+		log.Printf("INFO: Creating new project for user %s", usr.ID)
+
+		// Initialize a new project creation object with the user ID
+		toCreate := &project.ProjectToCreate{CreatedBy: usr.ID}
+
+		// Parse and validate the form data from the HTTP request
+		// This extracts form fields and validates them against defined rules
+		err, validationErrs := web.ReadForm(io.Request(), toCreate, appCtx.Validator)
+		if err != nil {
+			log.Printf("ERROR: Failed to read project form: %v", err)
+			return io.Error(web.ErrInternal, err)
+		}
+
+		// If there are validation errors, redisplay the form with error messages
+		if validationErrs != nil {
+			log.Printf("WARN: Project creation validation failed: %d errors", len(validationErrs))
+			return renderProjectForm(io, &ProjectFormData{
+				Project:    toCreate,
+				IsEditForm: false,
+			}, nil, validationErrs)
+		}
+
+		log.Printf("INFO: Creating project with ID '%s' and name '%s'", toCreate.ProjectID, toCreate.Name)
+
+		// Attempt to create the project using the business logic service
+		// The service will handle additional validation and database operations
+		newProject, err := service.CreateProject(ctx, toCreate)
+		if err != nil {
+			log.Printf("ERROR: Failed to create project '%s': %v", toCreate.ProjectID, err)
+			// If creation fails, redisplay the form with the error message
+			return renderProjectForm(io, &ProjectFormData{
+				Project:    toCreate,
+				IsEditForm: false,
+			}, nil, []error{validation.Error{Msg: err.Error()}})
+		}
+
+		log.Printf("INFO: Project '%s' created successfully with MongoDB ID %s", newProject.ProjectID, newProject.ID.Hex())
+
+		// On successful creation, redirect to the project detail page
+		return io.Redirect(fmt.Sprintf("/project/%s", newProject.ID.Hex()), http.StatusFound)
+	})
+}
+
+// projectDetailController displays detailed information about a specific project
+// This includes general project info and requirements, organized in tabs
+func projectDetailController(appCtx *hctx.AppCtx, webCtx *web.Ctx, service *project.ProjectService) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		ctx := io.Context()
+
+		// Extract the project ID from the URL parameters
+		id, err := parseObjectID(io.Request(), "id")
+		if err != nil {
+			log.Printf("ERROR: Invalid project ID in URL: %v", err)
+			return io.Error(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Loading project details for ID %s", id.Hex())
+
+		// Fetch the project along with all its requirements from the database
+		// This is more efficient than making separate calls for project and requirements
+		projectWithReqs, err := service.GetProjectWithRequirements(ctx, id)
+		if err != nil {
+			log.Printf("ERROR: Failed to get project with requirements for ID %s: %v", id.Hex(), err)
+			return io.Error(web.ErrInternal, err)
+		}
+
+		// Determine which tab should be active (from URL query parameter)
+		// Default to "general" tab if no tab is specified
+		activeTab := io.Request().URL.Query().Get("tab")
+		if activeTab == "" {
+			activeTab = "general"
+		}
+
+		log.Printf("INFO: Loaded project '%s' with %d requirements, showing tab '%s'",
+			projectWithReqs.Project.Name, projectWithReqs.RequirementCount, activeTab)
+
+		// Prepare all data needed for the project detail template
+		data := ProjectDetailData{
+			Project:             projectWithReqs,
+			ActiveTab:           activeTab,
+			RequirementStatuses: []string{"Entwurf", "In Prüfung", "Genehmigt", "Abgelehnt"}, // Available status options
+		}
+
+		// Render the project detail page with multiple template files
+		err = io.Render(
+			data,
+			"project.detail.page",                          // Main template name
+			"templates/project/detail-page.go.html",        // Page wrapper template
+			"templates/project/_detail.go.html",            // Project detail content
+			"templates/project/_requirements-list.go.html", // Requirements list partial
+		)
+
+		if err != nil {
+			log.Printf("ERROR: Failed to render project detail page: %v", err)
+			return err
+		}
+
+		log.Println("INFO: Project detail page rendered successfully")
+		return nil
+	})
+}
+
+// projectEditFormController displays a form pre-filled with existing project data for editing
+// This controller loads the current project data and renders it in an editable form
+func projectEditFormController(appCtx *hctx.AppCtx, webCtx *web.Ctx, service *project.ProjectService) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		ctx := io.Context()
+
+		// Parse the project ID from the URL
+		id, err := parseObjectID(io.Request(), "id")
+		if err != nil {
+			log.Printf("ERROR: Invalid project ID for edit: %v", err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Loading project edit form for ID %s", id.Hex())
+
+		// Get all projects for the current user to find the requested project
+		// This ensures the user can only edit their own projects
+		proj, err := service.GetProjectsByUser(ctx, user.MustCtxUser(ctx).ID)
+		if err != nil {
+			log.Printf("ERROR: Failed to get projects for edit: %v", err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		// Search through the user's projects to find the one being edited
+		var targetProject *project.Project
+		for _, p := range proj {
+			if p.ID == id {
+				targetProject = p
+				break
+			}
+		}
+
+		// If the project is not found, it either doesn't exist or doesn't belong to this user
+		if targetProject == nil {
+			log.Printf("ERROR: Project with ID %s not found for edit", id.Hex())
+			return io.InlineError(web.ErrInternal, errors.New("project not found"))
+		}
+
+		log.Printf("INFO: Showing edit form for project '%s'", targetProject.Name)
+
+		// Convert the project to an update structure and render the edit form
+		return renderProjectEditForm(io, targetProject.ToUpdate(), nil, nil)
+	})
+}
+
+// projectUpdateController processes form submissions for updating existing projects
+// This controller validates changes and applies them to the database
+func projectUpdateController(appCtx *hctx.AppCtx, webCtx *web.Ctx, service *project.ProjectService) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		ctx := io.Context()
+
+		// Extract project ID from URL parameters
+		id, err := parseObjectID(io.Request(), "id")
+		if err != nil {
+			log.Printf("ERROR: Invalid project ID for update: %v", err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Updating project with ID %s", id.Hex())
+
+		// Create an update structure with the project ID
+		toUpdate := &project.ProjectToUpdate{ID: id}
+
+		// Parse and validate the form data from the request
+		err, validationErrs := web.ReadForm(io.Request(), toUpdate, appCtx.Validator)
+		if err != nil {
+			log.Printf("ERROR: Failed to read update form: %v", err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		// If validation fails, redisplay the form with error messages
+		if validationErrs != nil {
+			log.Printf("WARN: Project update validation failed: %d errors", len(validationErrs))
+			return renderProjectEditForm(io, toUpdate, nil, validationErrs)
+		}
+
+		log.Printf("INFO: Updating project '%s' with new name '%s'", id.Hex(), toUpdate.Name)
+
+		// Apply the updates through the service layer
+		updatedProject, err := service.UpdateProject(ctx, toUpdate)
+		if err != nil {
+			log.Printf("ERROR: Failed to update project %s: %v", id.Hex(), err)
+			return renderProjectEditForm(io, toUpdate, nil, []error{validation.Error{Msg: err.Error()}})
+		}
+
+		log.Printf("INFO: Project '%s' updated successfully", updatedProject.Name)
+
+		// Redisplay the form with a success message
+		return renderProjectEditForm(io, updatedProject.ToUpdate(), []string{"Projekt erfolgreich aktualisiert"}, nil)
+	})
+}
+
+// projectDeleteController handles project deletion requests
+// This controller removes the project and all associated requirements from the database
+func projectDeleteController(appCtx *hctx.AppCtx, webCtx *web.Ctx, service *project.ProjectService) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		ctx := io.Context()
+		usr := user.MustCtxUser(ctx)
+
+		// Parse the project ID from the URL
+		id, err := parseObjectID(io.Request(), "id")
+		if err != nil {
+			log.Printf("ERROR: Invalid project ID for deletion: %v", err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Deleting project with ID %s for user %s", id.Hex(), usr.ID)
+
+		// Delete the project and all its requirements through the service
+		err = service.DeleteProject(ctx, id)
+		if err != nil {
+			log.Printf("ERROR: Failed to delete project %s: %v", id.Hex(), err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Project %s deleted successfully", id.Hex())
+
+		// After deletion, fetch and return the updated project list
+		// This provides immediate feedback to the user about the deletion
+		projects, err := service.GetProjectsByUser(ctx, usr.ID)
+		if err != nil {
+			log.Printf("ERROR: Failed to get updated project list after deletion: %v", err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Returning updated project list with %d projects", len(projects))
+
+		// Return the updated project list as HTML to replace the current list
+		data := ProjectListData{Projects: projects}
+		return io.Render(
+			data,
+			"project.list",          // Template name for just the list part
+			"project/_list.go.html", // Partial template for project list
+		)
+	})
+}
+
+// projectSearchController handles search requests for projects
+// This controller filters projects based on user input and returns matching results
+func projectSearchController(appCtx *hctx.AppCtx, webCtx *web.Ctx, service *project.ProjectService) http.Handler {
+	return web.NewController(appCtx, webCtx, func(io web.IO) error {
+		ctx := io.Context()
+		usr := user.MustCtxUser(ctx)
+
+		request := io.Request()
+
+		// Parse the form data to extract search parameters
+		err := request.ParseForm()
+		if err != nil {
+			log.Printf("ERROR: Failed to parse search form: %v", err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		// Extract the search query from the form
+		query := request.FormValue("search")
+		log.Printf("INFO: Searching projects for user %s with query '%s'", usr.ID, query)
+
+		// Perform the search using the service layer
+		// The service handles both empty queries (return all) and actual searches
+		projects, err := service.SearchProjects(ctx, query, usr.ID)
+		if err != nil {
+			log.Printf("ERROR: Project search failed for query '%s': %v", query, err)
+			return io.InlineError(web.ErrInternal, err)
+		}
+
+		log.Printf("INFO: Search found %d projects for query '%s'", len(projects), query)
+
+		// Return the search results as a partial HTML update
+		data := ProjectListData{Projects: projects}
+		return io.Render(
+			data,
+			"project.list",                    // Template name for the list
+			"templates/project/_list.go.html", // Partial template file
+		)
+	})
+}
+
+// Helper Functions
+
+// parseObjectID extracts and validates a MongoDB ObjectID from HTTP request parameters
+// This function ensures that URL parameters containing IDs are valid MongoDB ObjectIDs
+func parseObjectID(r *http.Request, param string) (primitive.ObjectID, error) {
+	// Extract the parameter value from the URL
+	idStr := web.URLParam(r, param)
+	if idStr == "" {
+		return primitive.NilObjectID, errors.New("missing id parameter")
+	}
+
+	// Convert the string to a valid MongoDB ObjectID
+	return primitive.ObjectIDFromHex(idStr)
+}
+
+// renderProjectForm is a helper function to render project creation/edit forms
+// This function handles both success messages and validation errors
+func renderProjectForm(io web.IO, data *ProjectFormData, success []string, errs []error) error {
+	log.Printf("DEBUG: Rendering project form (edit=%t, errors=%d)", data.IsEditForm, len(errs))
+
+	// Wrap the form data with success messages and errors for template rendering
+	err := io.Render(
+		web.NewFormData(data, success, errs...),
+		"project.form.page",         // Main template name
+		"project/form-page.go.html", // Page wrapper template
+		"project/_form.go.html",     // Form partial template
+	)
+
+	if err != nil {
+		log.Printf("ERROR: Failed to render project form: %v", err)
+	}
+
+	return err
+}
+
+// renderProjectEditForm is a specialized helper for rendering edit forms
+// This function prepares edit-specific form data and renders the appropriate templates
+func renderProjectEditForm(io web.IO, toUpdate *project.ProjectToUpdate, success []string, errs []error) error {
+	// Create form data structure specifically for editing
+	formData := &ProjectFormData{
+		Project:    toUpdate,
+		IsEditForm: true, // This flag helps the template render edit-specific elements
+	}
+
+	log.Printf("DEBUG: Rendering project edit form for project %s (errors=%d)", toUpdate.ID.Hex(), len(errs))
+
+	// Render the edit form with the current project data
+	err := io.Render(
+		web.NewFormData(formData, success, errs...),
+		"project.edit.form",     // Template name for edit forms
+		"project/_form.go.html", // Shared form partial template
+	)
+
+	if err != nil {
+		log.Printf("ERROR: Failed to render project edit form: %v", err)
+	}
+
+	return err
+}