Implement comprehensive project time logging feature

Add complete project management system with role-based access control:

**Core Features:**
- Project creation and management for Admins/Supervisors
- Time tracking with optional project selection and notes
- Project-based filtering and reporting in history
- Enhanced export functionality with project data
- Team-specific project assignments

**Database Changes:**
- New Project model with full relationships
- Enhanced TimeEntry model with project_id and notes
- Updated migration scripts with rollback support
- Sample project creation for testing

**User Interface:**
- Project management templates (create, edit, list)
- Enhanced time tracking with project dropdown
- Project filtering in history page
- Updated navigation for role-based access
- Modern styling with hover effects and responsive design

**API Enhancements:**
- Project validation and access control
- Updated arrive endpoint with project support
- Enhanced export functions with project data
- Role-based route protection

**Migration Support:**
- Comprehensive migration scripts (migrate_projects.py)
- Updated main migration script (migrate_db.py)
- Detailed migration documentation
- Rollback functionality for safe deployment

**Role-Based Access:**
- Admins: Full project CRUD operations
- Supervisors: Project creation and management
- Team Leaders: View team hours with projects
- Team Members: Select projects when tracking time

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Jens Luedicke
2025-06-29 17:18:10 +02:00
parent 77d26a6063
commit be111a4bed
12 changed files with 1393 additions and 14 deletions

View File

@@ -0,0 +1,127 @@
{% extends "layout.html" %}
{% block content %}
<div class="timetrack-container">
<div class="admin-header">
<h2>Project Management</h2>
<a href="{{ url_for('create_project') }}" class="btn">Create New Project</a>
</div>
{% if projects %}
<div class="projects-table">
<table class="time-history">
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Team</th>
<th>Status</th>
<th>Start Date</th>
<th>End Date</th>
<th>Created By</th>
<th>Time Entries</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for project in projects %}
<tr class="{% if not project.is_active %}inactive-project{% endif %}">
<td><strong>{{ project.code }}</strong></td>
<td>{{ project.name }}</td>
<td>
{% if project.team %}
{{ project.team.name }}
{% else %}
<em>All Teams</em>
{% endif %}
</td>
<td>
<span class="status-badge {% if project.is_active %}active{% else %}inactive{% endif %}">
{{ 'Active' if project.is_active else 'Inactive' }}
</span>
</td>
<td>{{ project.start_date.strftime('%Y-%m-%d') if project.start_date else '-' }}</td>
<td>{{ project.end_date.strftime('%Y-%m-%d') if project.end_date else '-' }}</td>
<td>{{ project.created_by.username }}</td>
<td>{{ project.time_entries|length }}</td>
<td class="actions">
<a href="{{ url_for('edit_project', project_id=project.id) }}" class="btn btn-small">Edit</a>
{% if g.user.role.name == 'ADMIN' and project.time_entries|length == 0 %}
<form method="POST" action="{{ url_for('delete_project', project_id=project.id) }}" style="display: inline;"
onsubmit="return confirm('Are you sure you want to delete this project?')">
<button type="submit" class="btn btn-small btn-danger">Delete</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="no-data">
<p>No projects found. <a href="{{ url_for('create_project') }}">Create your first project</a>.</p>
</div>
{% endif %}
</div>
<style>
.admin-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
.projects-table {
overflow-x: auto;
}
.inactive-project {
opacity: 0.6;
}
.status-badge {
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.875rem;
font-weight: 500;
}
.status-badge.active {
background-color: #d4edda;
color: #155724;
}
.status-badge.inactive {
background-color: #f8d7da;
color: #721c24;
}
.actions {
white-space: nowrap;
}
.btn-small {
padding: 0.375rem 0.75rem;
font-size: 0.875rem;
margin-right: 0.5rem;
}
.btn-danger {
background-color: #dc3545;
border-color: #dc3545;
}
.btn-danger:hover {
background-color: #c82333;
border-color: #bd2130;
}
.no-data {
text-align: center;
padding: 3rem;
color: #666;
}
</style>
{% endblock %}