Time-Tracking Platform
Multi-tenant time-tracking and scheduling backend.
Enterprise backend for the kind of time-tracking and scheduling that labour inspectors actually look at. Every domain is a module, every module is a layer cake — api → domain → infrastructure — and the HTTP surface is just routing.
Clean architecture
The codebase is organised by domain, not by technical role. Each top-level module (auth, companies, schedules, calendars, users, integrations) ships with its own services, schemas and repositories.
app/
├── api/v1/ # HTTP routers and endpoints
├── domain/ # business logic
│ ├── auth/ # RBAC service, permissions, sessions
│ ├── companies/ # multi-tenant scope
│ ├── schedules/ # work calendars, shifts
│ ├── calendars/ # Google Calendar bridge
│ └── users/ # user lifecycle
├── infrastructure/ # SQLAlchemy sessions, external APIs
│ ├── database/
│ └── integrations/
└── shared/ # exceptions, utils, RBAC primitives
Boundaries are enforced: infrastructure never imports from api, api never writes SQL directly. Testing is straightforward because domain services take repositories as dependencies.
RBAC with dynamic permissions
Permissions aren’t hardcoded decorators — they’re a table. The API layer resolves them at request time through a shared dependency.
# app/api/deps.py
def require_permission(code: str):
def _dep(
user: User = Depends(get_current_user),
rbac: RBACService = Depends(get_rbac_service),
):
if not rbac.user_has(user, code):
raise HTTPException(403, "forbidden")
return user
return _dep
# usage
@router.post("/schedules")
def create_schedule(
payload: ScheduleCreate,
user = Depends(require_permission("schedules.create")),
):
...
What makes it interesting
- Google Calendar integration — two-way sync of schedules with employee calendars via the Google API. OAuth tokens encrypted at rest with Fernet.
- Offline-friendly data model — timestamps normalised to UTC, conflict resolution when a shift is edited while a sync was in flight.
- DOCX report generation —
docxtpltemplates render signed attendance reports from the same domain objects — no secondary export pipeline. - Audit, always — every mutation writes to a dedicated log table; a labour inspector walking in can be given a PDF of the month in seconds.
- Real-time — WebSocket channel for presence (clock-ins/clock-outs) streamed to the admin dashboard.