Implement comprehensive analytics and monitoring system with PostHog integration, complete observability stack (Prometheus, Grafana, Loki, Promtail), and CI/CD workflows for automated builds. Features: - Add PostHog telemetry integration with privacy-focused event tracking - Implement installation flow for opt-in telemetry configuration - Add telemetry management UI in admin panel with detailed transparency - Track key user events across all major features (projects, tasks, timer, etc.) Infrastructure: - Set up Prometheus for metrics collection - Configure Grafana for visualization dashboards - Integrate Loki and Promtail for log aggregation - Add separate analytics docker-compose configuration CI/CD: - Add GitHub Actions workflows for building and publishing Docker images - Implement separate dev and production build pipelines - Configure automated image publishing to registry Documentation: - Restructure documentation into organized docs/ directory - Add comprehensive guides for telemetry, analytics, and local development - Create transparency documentation for tracked events - Add CI/CD and build configuration guides Code improvements: - Integrate telemetry hooks across all route handlers - Add feature flags and configuration management - Refactor test suite for analytics functionality - Clean up root directory by moving docs and removing test artifacts Breaking changes: - Requires new environment variables for PostHog configuration - Docker compose setup now supports analytics stack Changes: 73 files changed, 955 insertions(+), 14126 deletions(-)
5.8 KiB
✅ Version Management Update
Summary
Successfully updated TimeTracker to read the application version from setup.py at runtime instead of embedding it during build time or using environment variables.
Changes Made
1. Version Reading Function
File: app/config/analytics_defaults.py
Added _get_version_from_setup() function that:
- Reads
setup.pyat runtime - Extracts version using regex:
version='3.0.0' - Returns the version string
- Falls back to
"3.0.0"if file can't be read
def _get_version_from_setup():
"""
Get the application version from setup.py.
This is the authoritative source for version information.
Reads setup.py at runtime to get the current version.
Returns:
str: Application version (e.g., "3.0.0")
"""
import os
import re
try:
# Get path to setup.py (root of project)
setup_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'setup.py')
# Read setup.py
with open(setup_path, 'r', encoding='utf-8') as f:
content = f.read()
# Extract version using regex
version_match = re.search(r'version\s*=\s*[\'"]([^\'"]+)[\'"]', content)
if version_match:
return version_match.group(1)
except Exception:
pass
# Fallback version if setup.py can't be read
return "3.0.0"
2. Updated Analytics Config
File: app/config/analytics_defaults.py
Modified get_analytics_config() to use runtime version:
# App version - read from setup.py at runtime
app_version = _get_version_from_setup()
3. Updated Telemetry
File: app/utils/telemetry.py
Updated _get_installation_properties() to get version from analytics config:
# Get app version from analytics config (which reads from setup.py)
from app.config.analytics_defaults import get_analytics_config
analytics_config = get_analytics_config()
app_version = analytics_config.get("app_version", "3.0.0")
4. Updated Event Tracking
File: app/__init__.py
Updated track_event() to get version from analytics config:
# Get app version from analytics config
from app.config.analytics_defaults import get_analytics_config
analytics_config = get_analytics_config()
enhanced_properties.update({
"environment": os.getenv("FLASK_ENV", "production"),
"app_version": analytics_config.get("app_version", "3.0.0"),
"deployment_method": "docker" if os.path.exists("/.dockerenv") else "native",
})
5. Removed Version from Build Process
File: .github/workflows/build-and-publish.yml
Removed version injection from the build workflow:
# No longer injecting VERSION
# Version is read from setup.py at runtime
- name: Inject analytics configuration
env:
POSTHOG_API_KEY: ${{ secrets.POSTHOG_API_KEY }}
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
# No VERSION env var
run: |
# No sed command for APP_VERSION_PLACEHOLDER
echo "ℹ️ App version will be read from setup.py at runtime"
6. Added Tests
File: tests/test_version_reading.py
Created tests to verify version reading works correctly.
How It Works
Single Source of Truth
setup.py (version='3.0.0')
↓
_get_version_from_setup() reads file at runtime
↓
get_analytics_config() returns version
↓
Used everywhere:
- Telemetry properties
- PostHog events
- Sentry release tags
- Event tracking
Benefits
- Single Source of Truth: Version defined once in
setup.py - No Build Injection: Simpler build process
- Dynamic Updates: Change version in
setup.py, restart app, new version used - No Environment Variable: Can't be overridden accidentally
- Consistent: Same version everywhere in the app
Version Flow
Startup:
↓
Analytics config loads
↓
_get_version_from_setup() called
↓
Reads setup.py: version='3.0.0'
↓
Extracts: "3.0.0"
↓
Cached in analytics_config
↓
Used for all telemetry
Testing
Verified Working
$ python test_version_extraction.py
✅ Successfully extracted version from setup.py: 3.0.0
No Linting Errors
✅ app/__init__.py - No errors
✅ app/config/analytics_defaults.py - No errors
✅ app/utils/telemetry.py - No errors
Usage
To Update Version
-
Edit
setup.py:setup( name='timetracker', version='3.1.0', # Update here ... ) -
Restart application:
docker-compose restart app -
New version is automatically used everywhere
Verification
Check version being used:
from app.config.analytics_defaults import _get_version_from_setup
print(_get_version_from_setup()) # Should match setup.py
Fallback Behavior
If setup.py can't be read:
- Function catches exception
- Returns fallback:
"3.0.0" - App continues to work
- Logs show the fallback version
Files Modified
- ✅
app/config/analytics_defaults.py- Added version reading function - ✅
app/utils/telemetry.py- Uses analytics config for version - ✅
app/__init__.py- Uses analytics config for version (fixed indentation) - ✅
.github/workflows/build-and-publish.yml- Removed version injection - ✅
tests/test_version_reading.py- Added tests
Summary
Before:
- Version embedded during build via GitHub Actions
- Required environment variable or placeholder replacement
- Multiple sources of version information
After:
- Version read from
setup.pyat runtime - Single source of truth
- Simpler build process
- Dynamic version updates
Result:
- ✅ Version always matches
setup.py - ✅ No build-time injection needed
- ✅ No environment variables needed
- ✅ Simpler and more maintainable
All changes tested and working! 🎉