Files
TimeTracker/docs/PROJECT_ARCHIVING_GUIDE.md
Dries Peeters 6de86fca2b feat: Implement comprehensive project archiving system
Add enhanced project archiving functionality for better organization of
completed projects with metadata tracking and validation.

Key Features:
- Archive metadata tracking (timestamp, user, reason)
- Archive form with quick-select reason templates
- Bulk archiving with optional shared reason
- Archive information display on project details
- Prevent time tracking on archived projects
- Activity logging for archive/unarchive actions

Database Changes:
- Add migration 026_add_project_archiving_metadata.py
- New fields: archived_at, archived_by (FK), archived_reason
- Index on archived_at for faster filtering
- Cascade on user deletion (SET NULL)

Model Enhancements (app/models/project.py):
- Enhanced archive() method with user_id and reason parameters
- Enhanced unarchive() method to clear all metadata
- New properties: is_archived, archived_by_user
- Updated to_dict() to include archive metadata

Route Updates (app/routes/projects.py):
- Convert archive route to GET/POST (form-based)
- Add archive reason handling
- Enhanced bulk operations with reason support
- Activity logging for all archive operations

UI Improvements:
- New archive form template (app/templates/projects/archive.html)
- Quick-select buttons for common archive reasons
- Archive metadata display on project view page
- Bulk archive modal with reason input
- Updated project list filtering

Validation (app/routes/timer.py):
- Prevent timer start on archived projects
- Block manual entry creation on archived projects
- Block bulk entry creation on archived projects
- Clear error messages for users

Testing:
- 90+ comprehensive test cases
- Unit tests (tests/test_project_archiving.py)
- Model tests (tests/test_project_archiving_models.py)
- Smoke tests for complete workflows
- Edge case coverage

Documentation:
- User guide (docs/PROJECT_ARCHIVING_GUIDE.md)
- Implementation summary (PROJECT_ARCHIVING_IMPLEMENTATION_SUMMARY.md)
- API reference and examples
- Best practices and troubleshooting

Migration Notes:
- Backward compatible with existing archived projects
- Existing archives will have NULL metadata (can be added later)
- No data migration required
- Run: migrations/manage_migrations.py upgrade head

Breaking Changes: None
- All changes are additive and backward compatible

Related: Feat-Project-Archiving branch
2025-10-24 09:06:51 +02:00

568 lines
15 KiB
Markdown

# Project Archiving Guide
## Overview
The Project Archiving feature provides a comprehensive solution for organizing completed, cancelled, or inactive projects in TimeTracker. This guide explains how to use the archiving system effectively.
## Table of Contents
1. [What is Project Archiving?](#what-is-project-archiving)
2. [When to Archive Projects](#when-to-archive-projects)
3. [Archiving a Single Project](#archiving-a-single-project)
4. [Bulk Archiving](#bulk-archiving)
5. [Viewing Archived Projects](#viewing-archived-projects)
6. [Unarchiving Projects](#unarchiving-projects)
7. [Archive Metadata](#archive-metadata)
8. [Restrictions on Archived Projects](#restrictions-on-archived-projects)
9. [API Reference](#api-reference)
10. [Best Practices](#best-practices)
---
## What is Project Archiving?
Project archiving allows you to hide completed or inactive projects from your active project lists while preserving all historical data. Archived projects:
- Are removed from active project dropdowns
- Cannot have new time entries added
- Retain all existing time entries and data
- Can be filtered and viewed separately
- Can be unarchived if needed
- Store metadata about when, why, and by whom they were archived
---
## When to Archive Projects
Consider archiving a project when:
- ✅ The project is completed
- ✅ The client contract has ended
- ✅ The project has been cancelled
- ✅ Work is on indefinite hold
- ✅ The maintenance period has ended
- ✅ You want to declutter your active project list
**Do NOT archive projects that:**
- ❌ Are temporarily paused (use "Inactive" status instead)
- ❌ May need time tracking in the near future
- ❌ Are awaiting client feedback
- ❌ Have ongoing maintenance work
---
## Archiving a Single Project
### Step-by-Step Process
1. **Navigate to the Project**
- Go to **Projects** in the main navigation
- Find the project you want to archive
- Click **View** to open the project details
2. **Click Archive Button**
- On the project details page, click the **Archive** button (visible to administrators only)
- You'll be taken to the archive confirmation page
3. **Provide Archive Reason (Optional but Recommended)**
- Enter a reason for archiving in the text field
- This helps with future reference and organization
- Use the **Quick Select** buttons for common reasons:
- Project Completed
- Contract Ended
- Cancelled
- On Hold
- Maintenance Ended
- Or type a custom reason
4. **Confirm Archive**
- Click **Archive Project** to confirm
- The project will be archived immediately
- You'll be redirected to the archived projects list
### Example Archive Reasons
```
✓ "Project delivered on 2025-01-15. Client satisfied with results."
✓ "Annual contract ended. Client chose not to renew."
✓ "Project cancelled by client due to budget constraints."
✓ "Website maintenance complete. No further updates planned."
✓ "Internal tool - replaced with new system."
```
---
## Bulk Archiving
When you need to archive multiple projects at once:
### Using Bulk Archive
1. **Navigate to Projects List**
- Go to **Projects****List All Projects**
2. **Select Projects**
- Check the boxes next to projects you want to archive
- Or click **Select All** to select all visible projects
3. **Open Bulk Actions Menu**
- Click **Bulk Actions (N)** button (where N is the number selected)
- Select **Archive** from the dropdown
4. **Enter Bulk Archive Reason**
- A modal will appear
- Enter a reason that applies to all selected projects
- Or use one of the quick select buttons
- Click **Archive** to confirm
5. **Confirmation**
- All selected projects will be archived with the same reason
- You'll see a success message with the count
### Bulk Archive Tips
- You can archive up to 100 projects at once
- All selected projects will receive the same archive reason
- The current user will be recorded as the archiver for all projects
- Projects with active timers cannot be archived (stop timers first)
---
## Viewing Archived Projects
### Filter Archived Projects
1. **Navigate to Projects List**
- Go to **Projects** in the main navigation
2. **Apply Archive Filter**
- In the filter section, select **Status**: **Archived**
- Click **Filter**
3. **View Archived Project List**
- All archived projects will be displayed
- The list shows:
- Project name and client
- Archive status badge
- Budget and billing information
- Quick actions
### Viewing Individual Archived Project
When viewing an archived project's details page, you'll see:
**Archive Information Section:**
- **Archived on**: Date and time of archiving
- **Archived by**: User who archived the project
- **Reason**: Why the project was archived
All historical data remains accessible:
- Time entries
- Tasks
- Project costs
- Extra goods
- Comments
- Budget information
---
## Unarchiving Projects
If you need to reactivate an archived project:
### Unarchive Process
1. **Navigate to Archived Projects**
- Go to **Projects** with **Status**: **Archived** filter
2. **Open Project Details**
- Click **View** on the project you want to unarchive
3. **Click Unarchive Button**
- Click the **Unarchive** button (administrators only)
- Confirm the action in the dialog
4. **Project Reactivated**
- The project status changes to **Active**
- Archive metadata is cleared
- The project appears in active lists again
- Time tracking can resume
**Note**: Unarchiving a project:
- Removes all archive metadata (reason, date, user)
- Sets the project status to "active"
- Makes the project available for time tracking
- Preserves all historical data
---
## Archive Metadata
Each archived project stores three pieces of metadata:
### 1. Archived At (Timestamp)
- **Type**: Date and time
- **Timezone**: UTC
- **Purpose**: Track when the project was archived
- **Displayed**: Yes (in project details)
- **Example**: "2025-10-24 14:30:00"
### 2. Archived By (User)
- **Type**: User reference
- **Purpose**: Track who archived the project
- **Displayed**: Yes (shows username or full name)
- **Note**: If user is deleted, this field may show "Unknown"
### 3. Archived Reason (Text)
- **Type**: Free text (optional)
- **Max Length**: Unlimited
- **Purpose**: Document why the project was archived
- **Displayed**: Yes (in dedicated section)
- **Can include**: Multi-line text, special characters, emojis
### Viewing Metadata
Archive metadata is displayed on:
- Project details page (Archive Information section)
- API responses (`to_dict()` method)
- Activity logs
- Export reports
---
## Restrictions on Archived Projects
### What You CANNOT Do with Archived Projects
**Time Tracking**
- Cannot start new timers
- Cannot create manual time entries
- Cannot create bulk time entries
- Error message: "Cannot start timer for an archived project. Please unarchive the project first."
**Project Dropdown**
- Archived projects don't appear in:
- Timer start modal
- Manual entry forms
- Bulk entry forms
- Quick timer buttons
### What You CAN Do with Archived Projects
**View Data**
- View project details
- Access time entry history
- See tasks and their status
- Review project costs
- Read comments
**Generate Reports**
- Include in time reports
- Generate invoices from historical data
- Export time entries
- View analytics
**Admin Actions**
- Unarchive the project
- Edit project details (after unarchiving)
- Delete the project (if no time entries)
- Change client assignment
---
## API Reference
### Archive a Project
```python
# Python/Flask
project = Project.query.get(project_id)
project.archive(user_id=current_user.id, reason="Project completed")
db.session.commit()
```
```javascript
// JavaScript/API
fetch('/projects/123/archive', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-CSRFToken': csrfToken
},
body: new URLSearchParams({
'reason': 'Project completed successfully'
})
});
```
### Unarchive a Project
```python
# Python/Flask
project = Project.query.get(project_id)
project.unarchive()
db.session.commit()
```
```javascript
// JavaScript/API
fetch('/projects/123/unarchive', {
method: 'POST',
headers: {
'X-CSRFToken': csrfToken
}
});
```
### Get Archive Status
```python
# Check if project is archived
if project.is_archived:
print(f"Archived on: {project.archived_at}")
print(f"Archived by: {project.archived_by_user.username}")
print(f"Reason: {project.archived_reason}")
```
### Project to Dictionary
```python
# Get project data including archive metadata
project_dict = project.to_dict()
# Access archive fields
is_archived = project_dict['is_archived']
archived_at = project_dict['archived_at'] # ISO format string or None
archived_by = project_dict['archived_by'] # User ID or None
archived_reason = project_dict['archived_reason'] # Text or None
```
### Filter Archived Projects
```python
# Get all archived projects
archived_projects = Project.query.filter_by(status='archived').all()
# Get projects archived by specific user
user_archived = Project.query.filter_by(
status='archived',
archived_by=user_id
).all()
# Get projects archived in date range
from datetime import datetime, timedelta
week_ago = datetime.utcnow() - timedelta(days=7)
recently_archived = Project.query.filter(
Project.status == 'archived',
Project.archived_at >= week_ago
).all()
```
### Bulk Archive
```http
POST /projects/bulk-status-change
Content-Type: application/x-www-form-urlencoded
project_ids[]=1&project_ids[]=2&project_ids[]=3&new_status=archived&archive_reason=Bulk+archive+reason
```
---
## Best Practices
### 1. Always Provide Archive Reasons
**Good Practice:**
```
✓ Document WHY the project was archived
✓ Include relevant dates (completion, cancellation)
✓ Mention key outcomes or decisions
✓ Reference client communications if applicable
```
**Example Good Reasons:**
- "Project completed on schedule. Final invoice sent and paid."
- "Client contract ended Q4 2024. No renewal planned."
- "Cancelled due to client budget cuts. 75% of work completed."
### 2. Review Before Archiving
Before archiving, verify:
- [ ] All time entries are logged
- [ ] Final invoice generated (if applicable)
- [ ] All outstanding tasks are resolved or noted
- [ ] Client deliverables are complete
- [ ] No active timers are running
- [ ] Team members are notified
### 3. Use Bulk Archive Strategically
Bulk archive is ideal for:
- End-of-year cleanup
- Multiple projects from same client (contract ended)
- Maintenance projects after completion
- Internal projects that are no longer needed
### 4. Regular Archive Audits
Periodically review archived projects:
- **Monthly**: Review recently archived projects
- **Quarterly**: Audit archive reasons for completeness
- **Yearly**: Consider permanent deletion of very old projects (backup first!)
### 5. Archive vs. Inactive
Use the right status:
**Archive when:**
- Project is completely finished
- No future work expected
- Want to hide from all lists
**Inactive when:**
- Temporarily paused
- Waiting for client
- May resume in near future
- Want to keep in lists but marked as not active
### 6. Unarchive Sparingly
Only unarchive if:
- New work is required on the project
- Contract is renewed
- Client requests additional features
- You need to add historical entries
Consider creating a new project instead if:
- It's a new phase/version
- Significant time has passed
- Scope has changed dramatically
---
## Troubleshooting
### Cannot Start Timer on Archived Project
**Problem**: Error message when starting timer
**Solution**:
1. Check if project is archived (Projects → Filter: Archived)
2. Unarchive the project if work needs to continue
3. Or create a new project for new work
### Cannot Find Archived Project in Dropdown
**Problem**: Archived project doesn't appear in timer dropdown
**Solution**: This is expected behavior. Archived projects are hidden from active lists. To work on an archived project, unarchive it first.
### Lost Archive Reason After Unarchive
**Problem**: Archive reason is gone after unarchiving
**Solution**: This is by design. Archive metadata is cleared when unarchiving. If you need to preserve the reason:
1. Copy the archive reason before unarchiving
2. Add it to project description or comments
3. Or take a screenshot of the archive information
### Bulk Archive Not Working
**Problem**: Some projects not archived in bulk operation
**Solution**:
1. Check if you have admin permissions
2. Ensure no projects have active timers
3. Verify projects are selected (checkboxes checked)
4. Check for error messages in the flash notifications
---
## Migration from Old System
If you're upgrading from a version without archive metadata:
### What Happens to Existing Archived Projects?
- Existing archived projects retain their "archived" status
- Archive metadata fields will be NULL:
- `archived_at`: NULL
- `archived_by`: NULL
- `archived_reason`: NULL
- Projects still function normally
- You can add archive reasons by:
1. Unarchiving the project
2. Re-archiving with a reason
### Manual Migration (Optional)
To add metadata to existing archived projects:
```python
# Example migration script
from app import db
from app.models import Project
from datetime import datetime
# Get all archived projects without metadata
archived_projects = Project.query.filter(
Project.status == 'archived',
Project.archived_at.is_(None)
).all()
# Set archive timestamp to created_at or updated_at
for project in archived_projects:
project.archived_at = project.updated_at or project.created_at
project.archived_reason = "Migrated from old system"
# Leave archived_by as NULL if you don't know who archived it
db.session.commit()
```
---
## Database Schema
For developers and database administrators:
### New Fields in `projects` Table
```sql
ALTER TABLE projects
ADD COLUMN archived_at DATETIME NULL,
ADD COLUMN archived_by INTEGER NULL,
ADD COLUMN archived_reason TEXT NULL,
ADD FOREIGN KEY (archived_by) REFERENCES users(id) ON DELETE SET NULL,
ADD INDEX ix_projects_archived_at (archived_at);
```
### Field Specifications
| Field | Type | Nullable | Index | Default | Foreign Key |
|-------|------|----------|-------|---------|-------------|
| `archived_at` | DATETIME | Yes | Yes | NULL | - |
| `archived_by` | INTEGER | Yes | No | NULL | users(id) ON DELETE SET NULL |
| `archived_reason` | TEXT | Yes | No | NULL | - |
---
## Support and Feedback
If you encounter issues with project archiving:
1. Check this documentation
2. Review the [Troubleshooting](#troubleshooting) section
3. Contact your system administrator
4. Report bugs via GitHub Issues
---
**Document Version**: 1.0
**Last Updated**: October 24, 2025
**TimeTracker Version**: 2.0+