danwel
What Is It?
danwel is a multi-tenant SaaS application that helps organizations manage their weekly time planning with seamless integration to external calendar and invoicing systems.
**Core idea**: Plan your week visually, sync to your calendar, track time for invoicing—all in one place.
---
The Problem
Freelancers and teams juggle multiple tools:
• Google Calendar / Outlook for scheduling
• Moneybird / Harvest for time tracking & invoicing
• Manual copy-paste between systems
• No unified view of "what am I working on this week?"
**Pain points:**
• Double entry (calendar + time tracker)
• Forgetting to log billable hours
• No visual weekly planning tool that connects everything
• Teams can't see each other's availability---
The Solution
A weekly planner that:
1. **Shows your week** in a clean, visual grid (Mon-Sun, 8am-6pm)
2. **Syncs bidirectionally** with Google Calendar / Office 365
3. **Logs time automatically** to Moneybird / Harvest
4. **Works for teams** with shared visibility and organization management
┌─────────────────────────────────────────────────────────────┐
│ danwel │
│ │
│ Plan Block ──► Syncs to Google Calendar │
│ │ │
│ └───────► Logs to Moneybird (billable time) │
│ │
│ Team members see shared calendar, plan together │
└─────────────────────────────────────────────────────────────┘
---
Who Is It For?
Primary Users
• **Freelancers** managing multiple clients
• **Small agencies** (2-20 people) needing team visibility
• **Consultants** billing hourly to different projects
User Roles
| Role | Can Do |
|------|--------|
| **Owner** | Everything + billing + delete org |
| **Admin** | Manage team, integrations, see all time blocks |
| **Member** | Create/edit own time blocks, view clients/projects |
| **Viewer** | Read-only access to calendar |
---
Key Features
Implemented Features
• [x] Weekly calendar grid with drag-drop time blocks
• [x] Horizontal scroll for calendar (smooth day navigation)
• [x] Google Calendar integration (read/write with two-way sync)
• [x] Moneybird integration (time entries, clients, projects, invoices)
• [x] Multi-tenant organizations
• [x] Multiple calendars per integration
• [x] User preferences (timezone, work hours, work days, locale)
• [x] Statistics & analytics dashboard
• [x] Income tracking with hourly rates
• [x] Invoice sync from Moneybird
• [x] Favorites for clients and projects
• [x] External event import with client/project assignment
• [x] Billable vs non-billable tracking
• [x] Privacy controls (show/hide external event details)
• [x] Multi-language support (EN/NL)
Additional Implemented Features
• [x] Team invitations and roles
• [x] Advanced authentication (OAuth, WebAuthn, 2FA)
• [x] Task/Entry management system with comments and labels
• [x] GitHub integration for project management
• [x] Platform administration with impersonation
• [x] Multi-language support (EN/NL)
• [x] Demo mode with restrictions
• [x] Mobile app support with token generation
• [x] Billing integration with VAT validation
• [x] Favorites system for clients/projects
• [x] Advanced user preferences and privacy controls
• [x] Audit logging and system monitoring
Future Enhancements
• [ ] Office 365 calendar integration
• [ ] Harvest integration
• [ ] Mobile/tablet PWA
• [ ] Recurring time blocks
• [ ] Subdomain per organization---
How It Works
1. Sign Up & Create Organization
User registers → Creates "Acme Agency" org → Becomes owner
2. Connect Integrations
Settings → Connect Google Calendar → Select calendars to sync
Settings → Connect Moneybird → Clients & projects imported
3. Plan Your Week
Drag to create block → Saved to DB instantly → Background sync to Calendar/Moneybird
4. Invite Team
Settings → Team → Invite colleague → They join with "member" role
---
Data Strategy
Source of Truth: danwel Database
┌─────────────────────────────────────────────────────────────────┐
│ danwel Database │
│ (Source of Truth) │
└─────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Google │ │ Moneybird │
│ Calendar │ │ │
│ (Mirror) │ │ (Mirror) │
└─────────────┘ └─────────────┘
**Why local DB, not Google Calendar as source of truth?**
• **Offline resilience** - Works even if Google/Moneybird is down
• **Fast UI** - Load instantly from DB, sync in background
• **Data ownership** - You control your data
• **Reporting** - Query hours per client, trends, etc.
• **Provider flexibility** - Switch calendar providers without losing data
**Sync approach:**
1. Save to database immediately (instant UI response)
2. Queue background job to sync to external services
3. Show sync status: ✓ synced, ⟳ pending, ⚠ error
4. Periodic inbound sync pulls external changes
---
Data Model (Simplified)
Organization (tenant)
├── Users (with roles: owner/admin/member/viewer)
│ └── Preferences
│ ├── timezone (e.g., 'Europe/Amsterdam')
│ ├── work_days (e.g., ['mon','tue','wed','thu','fri'])
│ ├── work_hours_start (e.g., '08:00')
│ └── work_hours_end (e.g., '18:00')
├── Integrations
│ ├── Google Calendar → Calendars (multiple)
│ └── Moneybird → Clients, Projects
└── Time Blocks
├── Synced to calendar
└── Synced to invoicing
---
Technical Approach
| Aspect | Choice |
|--------|--------|
| **Framework** | Laravel 11 |
| **Multi-tenancy** | Single DB with
organization_id scoping |
| **Frontend** | Blade + Alpine.js + Tailwind |
| **Integrations** | Strategy pattern (pluggable providers) |
| **Security** | Encrypted OAuth tokens, 5-layer access control |
| **Deployment** | SpinupWP (MySQL, Redis, PHP 8.2+) |
---
Integration Architecture
**Extensible by design**—adding a new provider (e.g., Office 365) requires:
1. Implement
CalendarProviderInterface
2. Add config entry
3. Register in service provider
No changes to core application logic.
CalendarProviderInterface
├── GoogleCalendarProvider ✓
├── Office365CalendarProvider (future)
└── [Your Provider Here]
InvoicingProviderInterface
├── MoneybirdProvider ✓
├── HarvestProvider (future)
└── [Your Provider Here]
---
Security Highlights
• **Tenant isolation**: Global scopes prevent cross-organization data access
• **Token encryption**: OAuth tokens stored with AES-256 encryption
• **Role-based access**: Policies enforce permissions at every level
• **Audit logging**: Sensitive operations tracked
• **No secrets in code**: All credentials via environment variables---
What Already Exists (Prototype)
The original prototype is preserved in initial_prototype/ (~2,500 lines):
Files
| File | Purpose | Lines |
|------|---------|-------|
|
initial_prototype/config.php | OAuth credentials, constants | 44 |
|
initial_prototype/index.php | Settings page (connection status) | 182 |
|
initial_prototype/callback.php | Google OAuth callback | ~90 |
|
initial_prototype/moneybird-callback.php | Moneybird OAuth callback | ~87 |
|
initial_prototype/disconnect.php | Google disconnect | 15 |
|
initial_prototype/moneybird-disconnect.php | Moneybird disconnect | 11 |
|
initial_prototype/oauth-relay.php | Localhost OAuth relay (Google) | 18 |
|
initial_prototype/moneybird-relay.php | Localhost OAuth relay (Moneybird) | 18 |
|
initial_prototype/api.php | JSON API backend | 758 |
|
initial_prototype/calendar.php | Calendar UI + JavaScript | 1,434 |
Working Features
• **Google Calendar OAuth** - Full flow with token refresh
• **Moneybird OAuth** - Full flow with token refresh
• **Weekly Calendar UI** - Mon-Sun, 8am-6pm grid
• **Drag-and-drop** - Move and resize time blocks (using interact.js)
• **Week navigation** - Previous/next week, week picker
• **Time block CRUD** - Create, update, delete via API
• **Bidirectional sync** - Events sync to Google Calendar
• **Moneybird time entries** - Auto-create time entries when blocks created
• **Clients/Projects** - Load from Moneybird, create new inline
• **External events** - Display non-danwel Google Calendar events (read-only)
• **Metadata on external events** - Assign project/client to any event
• **Color coding** - danwel events (teal), external events (Google colors)
• **Summary row** - Total hours per day and week
Token Storage (Prototype - File-based)
• initial_prototype/token.json - Google OAuth tokens
• initial_prototype/moneybird_token.json - Moneybird OAuth tokens + administration ID
Known Limitations (Why Rebuild)
• Single-user only (no multi-tenancy)
• File-based token storage (not secure for production)
• No authentication/authorization
• No database (relies on Google Calendar as source of truth)
• Hardcoded config values
• No team features
• Fixed 8am-6pm, Mon-Sun (no customization)**This will be rebuilt** using proper Laravel architecture with multi-tenancy.
---
Success Metrics
1. **User activation**: User connects at least one integration within 24h
2. **Weekly active**: User creates 5+ time blocks per week
3. **Team adoption**: 50% of org members active weekly
4. **Sync reliability**: 99.9% successful syncs to external services
---
Open Questions
1. **Billing model**: Per-seat? Per-org? Free tier limits?
2. **Conflict resolution**: What if calendar event edited externally?
3. **Offline support**: How important for MVP?
4. **White-label**: Should orgs customize branding?
---
Documentation
For detailed technical documentation, see:
• [ARCHITECTURE.md](./ARCHITECTURE.md) - Core architecture decisions, multi-tenancy, security
• [DATABASE.md](./DATABASE.md) - Database schema and migrations
• [INTEGRATIONS.md](./INTEGRATIONS.md) - Provider interfaces, OAuth flows, data sync
• [API.md](./API.md) - RESTful API endpoints and formats
• [FRONTEND.md](./FRONTEND.md) - UI requirements and components
• [IMPLEMENTATION.md](./IMPLEMENTATION.md) - Phased implementation plan
**Phase 1 starts with:**
1. Fresh Laravel 11 installation
2. Multi-tenancy foundation (organizations, users, roles)
3. Integration framework
4. Google Calendar provider
5. Moneybird provider
6. Calendar UI