Synmet is an open-source, SaaS-managed, and self-hosted development activity tracking platform with a strong emphasis on privacy and self-owned data.
Provide developers with a private, flexible, and transparent way to monitor their productivity and coding metrics without compromising their coding data.
-
π Heartbeat Tracking: Detailed recording of coding activity
- File/entity being edited
- Git project and branch information
- Programming language used
- Coding duration and timestamps
- Activity type (coding, debugging, testing, etc.)
- AI-assisted development time tracking
-
π Analytics & Metrics: Intuitive visualization of productivity patterns
- Total coding time per day/week/month
- Most-used programming languages
- Streak of active days
- Metrics per project
- Export capabilities (GitHub, Images, PDF, JSON, CSV)
- API consumption tracking
-
π Privacy First: 100% self-hosted
- Your data stays in your infrastructure
- Complete control over your data
- No external telemetry or tracking
-
π Multi-language Support: Full support for multiple languages
- Spanish (es)
- English (en)
- PortuguΓͺs (pt)
- More coming soon...
-
π API Keys: Integration with code editors
- VS Code plugin (coming soon)
- JetBrains IDEs plugin (coming soon)
- Neovim plugin (coming soon)
This project is built with modern and robust technologies:
- Framework: Next.js 16 (App Router, RSC)
- Language: TypeScript 5+
- Database: PostgreSQL with Prisma Postgres
- ORM: Prisma 7 with Accelerate
- Authentication: NextAuth.js v4
- UI Framework: Tailwind CSS v4
- UI Components: Shadcn UI + Base UI
- Icons: Lucide React
- Charts: Recharts
- Validation: Zod
- i18n: next-intl
- Deployment: Cloudflare Workers + Docker
- Linting: ESLint with @antfu/eslint-config
- Node.js 20+
- pnpm 9+
- PostgreSQL 14+ (local or remote)
- Git
git clone https://github.com/yourusername/synmet.git
cd synmetpnpm installCopy and complete the environment file:
# For local development
cp .dev.vars.example .dev.vars
# Edit .dev.vars with your actual valuesRequired variables in .dev.vars:
# Database
DATABASE_URL="postgresql://user:password@localhost:5432/synmet_dev"
# NextAuth
NEXTAUTH_SECRET="openssl rand -hex 32" # Generate with: openssl rand -hex 32
NEXTAUTH_URL="http://localhost:3000"
# GitHub OAuth (create at https://github.com/settings/developers)
GITHUB_ID="your-github-oauth-app-id"
GITHUB_SECRET="your-github-oauth-app-secret"# Generate Prisma client
pnpm generate
# Run migrations
pnpm migrate
# (Optional) Load test data
pnpm prisma db seedpnpm devOpen http://localhost:3000 in your browser.
synmet/
βββ src/ # Source code
β βββ app/ # Next.js App Router
β β βββ [locale]/ # i18n routing layer
β β β βββ page.tsx
β β β βββ layout.tsx
β β β βββ dashboard/
β β β βββ auth/
β β β βββ settings/
β β β βββ .../
β β βββ api/ # API routes
β β βββ auth/ # Authentication
β β βββ heartbeat/ # Heartbeat tracking
β β βββ api-keys/ # API key management
β β βββ subscription/ # SaaS subscription
β β βββ .../
β βββ components/ # React components
β β βββ ui/ # Reusable UI components
β β βββ dashboard/ # Dashboard components
β β βββ .../
β βββ lib/ # Utilities & services
β β βββ auth.ts # Authentication logic
β β βββ subscription.ts # SaaS subscription service
β β βββ ai-usage.ts # AI usage tracking
β β βββ plan.ts # Plan definitions
β β βββ validations/ # Zod schemas
β β βββ .../
β βββ i18n/ # Internationalization config
β βββ styles/ # Global styles
β βββ middleware.ts # Next.js middleware
βββ messages/ # i18n translation files
β βββ es.json
β βββ en.json
β βββ pt.json
βββ prisma/ # Database
β βββ schema.prisma # Database schema
β βββ migrations/ # DB migrations
β βββ .../
βββ docs/ # Documentation
β βββ SAAS-REFORMA-PLAN.md
β βββ TEST-PLAN.md
β βββ .../
βββ public/ # Static assets
βββ .github/workflows/ # CI/CD pipelines
βββ Dockerfile # Container setup
βββ docker-compose.yml # Docker services
βββ next.config.ts # Next.js config
βββ wrangler.jsonc # Cloudflare Workers
βββ .../
- Go to GitHub Settings β Developer Settings β OAuth Apps
- Click "New OAuth App"
- Fill in the following:
- Application name: Synmet
- Homepage URL: http://localhost:3000 (local) or https://synmet.dev (production)
- Authorization callback URL: http://localhost:3000/api/auth/callback/github
- Copy
Client IDandClient Secretto.dev.vars
Routes under /dashboard and /[locale]/dashboard require user authentication. Unauthenticated requests are redirected to the sign-in page.
The project supports multiple languages using next-intl:
messages/
βββ es.json # Spanish
βββ en.json # English
βββ pt.json # Portuguese
Language is automatically detected from the URL: /es/, /en/, /pt/
Default language is English. Users can switch languages by changing the URL prefix.
- User: System users with roles and sessions
- Account: OAuth accounts (NextAuth integration)
- Session: Authentication sessions
- ApiKey: API keys for editor plugins
- Project: User projects for organizing heartbeats
- Heartbeat: Individual coding activity records
- DailyMetrics: Aggregated daily metrics per user/project
- User β has many ApiKeys, Projects, Heartbeats, DailyMetrics
- Project β belongs to User, has many Heartbeats
- Heartbeat β belongs to User and Project
- ApiKey β belongs to User
See prisma/schema.prisma for complete schema details.
# Build and deploy
pnpm deployRequirements:
- Cloudflare account with Workers enabled
- Environment variables configured in Wrangler
The project includes an automated CI/CD pipeline:
- β Lint and type-check on PRs
- β Build on each push to main
- β Automatic deploy to Cloudflare (main branch)
- β Docker image build and push
# Development
pnpm dev # Start development server
pnpm build # Build for production
pnpm start # Start production server
pnpm lint # Run ESLint
pnpm lint:fix # Fix ESLint issues
# Prisma
pnpm generate # Generate Prisma client
pnpm migrate # Run database migrations
pnpm studio # Open Prisma Studio
# Deployment
pnpm preview # Preview before deployment
pnpm deploy # Deploy to Cloudflare
pnpm upload # Upload to Cloudflare- Real-time heartbeat collection
- Interactive activity charts
- Enhanced project management
- User profile customization
- VS Code extension
- JetBrains IDE plugin
- Neovim plugin
- Stripe payment system
- Subscription plans
- Team management
- Share metrics publicly
- Slack and Discord integrations
- Custom webhooks
- Data export features
Issue: API keys do not automatically transition from active to expired status when their expiration date passes.
Impact: Expired API keys may still appear as "active" in the UI and can be used to authenticate heartbeats until manually revoked.
Workaround: Manually revoke expired keys from the API Keys settings page.
Solution (Iteration 2): Implement one of the following:
- Option A: Add a scheduled background job (cron) to mark expired keys as
expiredstatus - Option B: Validate API key expiration at auth time in the heartbeat validation middleware
- Option C: Combine both approaches for comprehensive coverage
Affected Endpoints:
POST /api/heartbeat- Accepts expired keysGET /api/api-keys- Shows expired keys as "active"
- Add expiration validation middleware for API key authentication
- Implement background job for periodic status updates
- Add visual warnings in UI for soon-to-expire keys
- Add audit logging for key usage and expiration events
This project is licensed under the Server Side Public License (SSPL).
The SSPL is designed to ensure that if you offer the functionality of this software as a service to third parties, you must make the service's source code available under this license. This protects against large cloud providers offering the software as a service without contributing back to the open source community.
For more details, see the SSPL FAQ.
- π§ Email: support@synmet.dev
- π¬ GitHub Issues for bug reports
Made with β€οΈ by @marprezd and the Synmet community