# afloresc/time-control architecture

> Architecture diagram of the GitHub repository afloresc/time-control, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-08-03). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/afloresc/time-control
- Repository: https://github.com/afloresc/time-control

## Overview

#### Purpose and Deployable Entry Points
Time Control is a labor time-tracking system: a Go HTTP API records work sessions under Spanish labor-control requirements, and a separate React/Vite client provides clock and session views. The API starts at `cmd/api/main.go`; the browser client boots from `time-control-frontend/src/main.jsx` into `time-control-frontend/src/App.jsx`.

#### API Composition and Routing
The backend is modular by domain and exposes protected user (`/me`) and administrator (`/admin`) APIs. Router assembly, middleware placement, and endpoint binding are centralized in `internal/router/router.go`. Session operations flow handler → service → repository, separating HTTP concerns, business rules, and persistence:
- `internal/sessions/handler.go`
- `internal/sessions/service.go`
- `internal/sessions/repository.go`

#### Authentication and Authorization Boundary
Firebase is the identity authority. Request middleware validates Bearer JWTs, derives identity/claims, provisions a local user when needed, and places user ID, email, and role in request context. Admin routes add a role gate after authentication. This is the principal external trust boundary:
- `internal/auth/firebase.go`
- `internal/auth/firebase_middleware.go`
- `internal/admin/handler.go`

#### Work-Session Lifecycle
Authenticated users start and end an active work session or create manual dated intervals; they can retrieve their own session history. The session model represents persisted work-time records, while the service governs lifecycle transitions and repository writes/queries:
- `internal/sessions/model.go`
- `internal/sessions/service.go`
- `internal/sessions/repository.go`

An admin can inspect all sessions and filter them by Firebase/local user ID through the admin-facing routing/handler layer.

#### Interval and Time Presentation Domain
A distinct intervals module appears to support interval-oriented API behavior alongside the core sessions domain. It has its own HTTP, service, persistence, and model boundaries:
- `internal/intervals/handler.go`
- `internal/intervals/service.go`
- `internal/intervals/repository.go`

On the frontend, clock state and elapsed-time behavior are encapsulated separately from visual active/inactive states:
- `time-control-frontend/src/hooks/useClock.js`
- `time-control-frontend/src/components/clock/ClockActiveSession.jsx`
- `time-control-frontend/src/components/clock/ClockInactiveSession.jsx`

#### Persistence and Local User Projection
SQLite is the system of record, accessed through GORM, with the checked-in runtime database located at `data/timecontrol.db`. Firebase identities are projected into a local `users` table so application roles and session ownership can be queried locally. User persistence is isolated from auth and sessions:
- `internal/database/sqlite.go`
- `internal/users/model.go`
- `internal/users/repository.go`

#### Frontend Application Boundary
The React client uses Firebase client authentication, maintains auth state in context, protects routes, and calls the backend session API. Its main application flow is auth bootstrap → protected route → clock/sessions page → API request carrying Firebase credentials:
- `time-control-frontend/src/Firebase.js`
- `time-control-frontend/src/context/AuthContext.jsx`
- `time-control-frontend/src/api/sessionsApi.js`

Routing and application shell are separated from feature pages:
- `time-control-frontend/src/app/router.jsx`
- `time-control-frontend/src/components/RequireAuth.jsx`
- `time-control-frontend/src/pages/Clock.jsx`

Main entry points: [`internal/router/router.go`](https://github.com/afloresc/time-control/blob/main/internal/router/router.go) (HTTP router), [`internal/database/sqlite.go`](https://github.com/afloresc/time-control/blob/main/internal/database/sqlite.go) (SQLite via GORM), [`time-control-frontend/src/pages/Clock.jsx`](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/pages/Clock.jsx) (Clock and sessions page), [`internal/auth/firebase_middleware.go`](https://github.com/afloresc/time-control/blob/main/internal/auth/firebase_middleware.go) (JWT authentication)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_frontend["React Client"]
  node_frontend_boot["Client bootstrap<br/>React/Vite entry<br/>[main.jsx]"]
  node_frontend_app["Application shell<br/>React app<br/>[App.jsx]"]
  node_frontend_router["Client routes<br/>React router<br/>[router.jsx]"]
  node_frontend_auth["Auth state<br/>React context<br/>[AuthContext.jsx]"]
  node_frontend_guard["Protected routes<br/>route guard<br/>[RequireAuth.jsx]"]
  node_frontend_clock["Clock and sessions page<br/>feature page<br/>[Clock.jsx]"]
  node_frontend_clock_hook["Elapsed clock state<br/>React hook<br/>[useClock.js]"]
  node_frontend_clock_views["Active/inactive clock<br/>clock components"]
  node_frontend_api["Session API client<br/>HTTP client<br/>[sessionsApi.js]"]
  node_firebase_client["Firebase client SDK<br/>authentication SDK<br/>[Firebase.js]"]
end

subgraph group_api["Go API"]
  node_api_entry["API server<br/>Go entry point<br/>[main.go]"]
  node_api_router["HTTP router<br/>route assembly<br/>[router.go]"]
  node_auth_middleware{{"JWT authentication<br/>request middleware"}}
  node_firebase_admin["Firebase verifier<br/>identity adapter<br/>[firebase.go]"]
  node_sessions["Session lifecycle<br/>[service.go]"]
  node_intervals["Intervals domain<br/>[service.go]"]
  node_admin["Admin session access<br/>admin handler<br/>[handler.go]"]
end

subgraph group_data["Persistence"]
  node_users["Local user projection<br/>user repository<br/>[repository.go]"]
  node_sqlite["SQLite via GORM<br/>database adapter<br/>[sqlite.go]"]
  node_database[("Time-control database<br/>SQLite database<br/>[timecontrol.db]")]
end

subgraph group_external["Identity Provider"]
  node_firebase{{"Firebase Auth<br/>external identity authority"}}
end

node_frontend_boot -->|"mounts"| node_frontend_app
node_frontend_app -->|"renders"| node_frontend_router
node_frontend_router -->|"protects routes"| node_frontend_guard
node_frontend_guard -->|"reads auth state"| node_frontend_auth
node_frontend_auth -->|"uses"| node_firebase_client
node_firebase_client -->|"authenticates with"| node_firebase
node_frontend_guard -->|"allows authenticated access"| node_frontend_clock
node_frontend_clock -->|"uses"| node_frontend_clock_hook
node_frontend_clock -->|"renders"| node_frontend_clock_views
node_frontend_clock -->|"loads and updates sessions"| node_frontend_api
node_frontend_api -->|"authenticated HTTP requests"| node_api_entry
node_api_entry -->|"starts"| node_api_router
node_api_router -->|"applies to protected APIs"| node_auth_middleware
node_auth_middleware -->|"verifies JWT"| node_firebase_admin
node_firebase_admin -->|"validates claims with"| node_firebase
node_auth_middleware -->|"provisions local user"| node_users
node_api_router -->|"/me session routes"| node_sessions
node_api_router -->|"interval routes"| node_intervals
node_api_router -->|"/admin routes"| node_admin
node_auth_middleware -->|"authenticated role context"| node_admin
node_sessions -->|"writes and queries sessions"| node_sqlite
node_intervals -->|"persists intervals"| node_sqlite
node_admin -->|"queries all sessions"| node_sqlite
node_users -->|"persists users and roles"| node_sqlite
node_sqlite -->|"opens"| node_database

click node_frontend_boot "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/main.jsx"
click node_frontend_app "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/App.jsx"
click node_frontend_router "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/app/router.jsx"
click node_frontend_auth "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/context/AuthContext.jsx"
click node_frontend_guard "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/components/RequireAuth.jsx"
click node_frontend_clock "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/pages/Clock.jsx"
click node_frontend_clock_hook "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/hooks/useClock.js"
click node_frontend_clock_views "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/components/clock/ClockActiveSession.jsx"
click node_frontend_api "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/api/sessionsApi.js"
click node_firebase_client "https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/Firebase.js"
click node_api_entry "https://github.com/afloresc/time-control/blob/main/cmd/api/main.go"
click node_api_router "https://github.com/afloresc/time-control/blob/main/internal/router/router.go"
click node_auth_middleware "https://github.com/afloresc/time-control/blob/main/internal/auth/firebase_middleware.go"
click node_firebase_admin "https://github.com/afloresc/time-control/blob/main/internal/auth/firebase.go"
click node_sessions "https://github.com/afloresc/time-control/blob/main/internal/sessions/service.go"
click node_intervals "https://github.com/afloresc/time-control/blob/main/internal/intervals/service.go"
click node_admin "https://github.com/afloresc/time-control/blob/main/internal/admin/handler.go"
click node_users "https://github.com/afloresc/time-control/blob/main/internal/users/repository.go"
click node_sqlite "https://github.com/afloresc/time-control/blob/main/internal/database/sqlite.go"
click node_database "https://github.com/afloresc/time-control/blob/main/data/timecontrol.db"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_frontend_boot,node_frontend_app,node_frontend_router,node_frontend_auth,node_frontend_guard,node_frontend_clock,node_frontend_clock_hook,node_frontend_clock_views,node_frontend_api,node_firebase_client toneBlue
class node_api_entry,node_api_router,node_auth_middleware,node_firebase_admin,node_sessions,node_intervals,node_admin toneAmber
class node_users,node_sqlite,node_database toneMint
class node_firebase toneRose
```

## Components

### React Client

- [Client bootstrap](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/main.jsx): React/Vite entry · `time-control-frontend/src/main.jsx`
- [Application shell](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/App.jsx): React app · `time-control-frontend/src/App.jsx`
- [Client routes](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/app/router.jsx): React router · `time-control-frontend/src/app/router.jsx`
- [Auth state](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/context/AuthContext.jsx): React context · Maintains Firebase client authentication state. · `time-control-frontend/src/context/AuthContext.jsx`
- [Protected routes](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/components/RequireAuth.jsx): route guard · `time-control-frontend/src/components/RequireAuth.jsx`
- [Clock and sessions page](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/pages/Clock.jsx): feature page · `time-control-frontend/src/pages/Clock.jsx`
- [Elapsed clock state](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/hooks/useClock.js): React hook · `time-control-frontend/src/hooks/useClock.js`
- [Active/inactive clock](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/components/clock/ClockActiveSession.jsx): clock components · `time-control-frontend/src/components/clock/ClockActiveSession.jsx`
- [Session API client](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/api/sessionsApi.js): HTTP client · Sends Firebase credentials with session requests. · `time-control-frontend/src/api/sessionsApi.js`
- [Firebase client SDK](https://github.com/afloresc/time-control/blob/main/time-control-frontend/src/Firebase.js): authentication SDK · `time-control-frontend/src/Firebase.js`

### Go API

- [API server](https://github.com/afloresc/time-control/blob/main/cmd/api/main.go): Go entry point · `cmd/api/main.go`
- [HTTP router](https://github.com/afloresc/time-control/blob/main/internal/router/router.go): route assembly · Binds /me and /admin endpoints and middleware. · `internal/router/router.go`
- [JWT authentication](https://github.com/afloresc/time-control/blob/main/internal/auth/firebase_middleware.go): request middleware · Validates Bearer tokens, projects users, and adds claims to context. · `internal/auth/firebase_middleware.go`
- [Firebase verifier](https://github.com/afloresc/time-control/blob/main/internal/auth/firebase.go): identity adapter · `internal/auth/firebase.go`
- [Session lifecycle](https://github.com/afloresc/time-control/blob/main/internal/sessions/service.go): handler → service → repository · Handles active sessions, manual intervals, and personal history. · `internal/sessions/service.go`
- [Intervals domain](https://github.com/afloresc/time-control/blob/main/internal/intervals/service.go): handler → service → repository · Provides interval-oriented API behavior. · `internal/intervals/service.go`
- [Admin session access](https://github.com/afloresc/time-control/blob/main/internal/admin/handler.go): admin handler · Role-gated inspection and user-filtered session queries. · `internal/admin/handler.go`

### Persistence

- [Local user projection](https://github.com/afloresc/time-control/blob/main/internal/users/repository.go): user repository · Stores Firebase identities and local application roles. · `internal/users/repository.go`
- [SQLite via GORM](https://github.com/afloresc/time-control/blob/main/internal/database/sqlite.go): database adapter · `internal/database/sqlite.go`
- [Time-control database](https://github.com/afloresc/time-control/blob/main/data/timecontrol.db): SQLite database · System of record for users and work-time records. · `data/timecontrol.db`

### Identity Provider

- **Firebase Auth**: external identity authority · Issues client credentials and validates identity claims.

## Connections

- Client bootstrap → Application shell: mounts
- Application shell → Client routes: renders
- Client routes → Protected routes: protects routes
- Protected routes → Auth state: reads auth state
- Auth state → Firebase client SDK: uses
- Firebase client SDK → Firebase Auth: authenticates with
- Protected routes → Clock and sessions page: allows authenticated access
- Clock and sessions page → Elapsed clock state: uses
- Clock and sessions page → Active/inactive clock: renders
- Clock and sessions page → Session API client: loads and updates sessions
- Session API client → API server: authenticated HTTP requests
- API server → HTTP router: starts
- HTTP router → JWT authentication: applies to protected APIs
- JWT authentication → Firebase verifier: verifies JWT
- Firebase verifier → Firebase Auth: validates claims with
- JWT authentication → Local user projection: provisions local user
- HTTP router → Session lifecycle: /me session routes
- HTTP router → Intervals domain: interval routes
- HTTP router → Admin session access: /admin routes
- JWT authentication → Admin session access: authenticated role context
- Session lifecycle → SQLite via GORM: writes and queries sessions
- Intervals domain → SQLite via GORM: persists intervals
- Admin session access → SQLite via GORM: queries all sessions
- Local user projection → SQLite via GORM: persists users and roles
- SQLite via GORM → Time-control database: opens
