# Synapse-Time

Enterprise-grade, **standalone** workforce management portal (rostering, time & attendance,
HR contract management) with an **API-first** integration layer.

- **Deployment:** Dockerised microservices, self-hosted (on-prem) or cloud. Data sovereignty first.
- **Surface:** Web portal + REST/webhook API only. **No mobile app, MDM, or offline mobile sync.**
- **Security:** Granular RBAC (System Admin / HR-Payroll / Manager / Employee), optional TOTP MFA,
  scoped & hashed API keys, immutable audit logging on all state changes.

---

## Brand

| Token                | Value       | Usage                                   |
|----------------------|-------------|-----------------------------------------|
| `--st-green-forest`  | `#0B3D2E`   | Primary nav, headers, sidebar           |
| `--st-green-emerald` | `#10B981`   | Primary action buttons, logo gradient   |
| `--st-green-mint`    | `#D1FAE5`   | Success states, subtle highlights       |
| `--st-white`         | `#FFFFFF`   | App background                           |
| `--st-ink`           | `#0F172A`   | Body text                               |

**Logo (`Synapse`):** minimalist geometric neural node / network junction whose central
connecting lines resolve into the abstract silhouette of a sandglass (clock hands), rendered as a
dark-green → emerald gradient on pure white. Shipped as `frontend/src/assets/logo.svg` and reused
in PDF/document exports.

---

## 1. System Directory Structure (Dockerised monorepo)

```
Synapse-Time/
├── docker-compose.yml            # Orchestrates all services
├── docker-compose.prod.yml       # Prod overrides (TLS, replicas, secrets)
├── .env.example
├── README.md
│
├── db/
│   ├── schema.sql                # Canonical PostgreSQL schema (deliverable #2)
│   └── migrations/               # Alembic / versioned migrations
│
├── services/
│   ├── api-gateway/              # Identity, Auth, RBAC, MFA, API-Key mgmt  (FastAPI)
│   │   ├── Dockerfile
│   │   ├── requirements.txt
│   │   └── app/
│   │       ├── main.py
│   │       ├── config.py
│   │       ├── db.py
│   │       ├── models/           # SQLAlchemy models
│   │       ├── schemas/          # Pydantic DTOs
│   │       ├── security/
│   │       │   ├── api_key.py    # Scoped API-key auth middleware (deliverable #4)
│   │       │   ├── rbac.py       # Role/permission dependency guards
│   │       │   ├── mfa.py        # TOTP enrol/verify
│   │       │   └── jwt.py        # Session tokens
│   │       ├── routers/
│   │       │   ├── auth.py
│   │       │   ├── api_keys.py
│   │       │   ├── contracts.py  # Maker-Checker workflow (deliverable #4)
│   │       │   └── audit.py
│   │       └── services/audit.py # Immutable audit-log writer
│   │
│   ├── rostering-engine/         # Shift building, conflict/fatigue detection (FastAPI)
│   │   └── app/rules/            # Overlap, rest-period, max-hours rule engine
│   │
│   ├── time-attendance/          # Clock in/out, timesheet & OT calc, leave (FastAPI)
│   │
│   └── webhooks/                 # Outbound push (event fan-out) + inbound receiver
│       └── app/dispatcher.py     # Signed webhook delivery w/ retry + DLQ
│
├── frontend/                     # React + Vite + TypeScript SPA (deliverable #3)
│   ├── Dockerfile
│   ├── package.json
│   └── src/
│       ├── app/                  # Router, providers, RBAC guards
│       ├── components/           # Shared UI (design system)
│       ├── features/             # dashboard / roster / timesheets / hr / developer
│       ├── lib/                  # api client, auth, rbac hooks
│       └── assets/logo.svg
│
├── gateway/                      # Nginx / Traefik reverse proxy + TLS termination
│   └── nginx.conf
│
└── infra/
    ├── grafana/                  # Dashboards
    └── prometheus/               # Metrics scrape config
```

### Service responsibilities

| Service            | Port | Responsibility                                                        |
|--------------------|------|----------------------------------------------------------------------|
| `frontend`         | 5173 | React SPA (nginx-served in prod)                                      |
| `api-gateway`      | 8000 | AuthN/AuthZ, RBAC, MFA, API-key issuance, contract maker-checker      |
| `rostering-engine` | 8010 | Shift CRUD, conflict + fatigue rule evaluation, swap approvals        |
| `time-attendance`  | 8020 | Clock events, timesheet/overtime calculation, leave & absence        |
| `webhooks`         | 8030 | Outbound signed event delivery + inbound integration receiver        |
| `postgres`         | 5432 | System of record                                                     |
| `redis`            | 6379 | Session cache, rate limiting, rule-engine memoisation, webhook queue |

Inter-service calls are authenticated with short-lived service JWTs minted by the gateway; the
gateway is the only public ingress (through the Nginx/Traefik proxy).

---

## 3. Frontend Architecture — React component tree

```
<AppRoot>                                       # QueryClient, Theme, Toaster providers
└── <AuthProvider>                              # session + MFA challenge state
    └── <RBACProvider>                          # exposes usePermission() / <Can>
        └── <Router>
            ├── <PublicRoutes>
            │   ├── <LoginPage>
            │   └── <MfaChallengePage>          # TOTP 6-digit entry
            │
            └── <AppShell>                      # Forest-green sidebar + top bar + logo
                ├── <SidebarNav>                # items filtered by <Can permission=…>
                ├── <TopBar>                    # org switcher, user menu, notifications
                │
                └── <Outlet>
                    ├── <DashboardPage>
                    │   ├── <KpiRow>            # headcount, hours today, OT, open swaps
                    │   ├── <CoverageHeatmap>   # staffing vs demand
                    │   ├── <ConflictFeed>      # live fatigue / overlap flags
                    │   └── <PendingApprovals>  # HR: contract changes awaiting sign-off
                    │
                    ├── <RosterPage>                       # Manager
                    │   ├── <RosterToolbar>                # week picker, location, publish
                    │   ├── <RosterGrid>                   # DnD schedule (react-dnd / dnd-kit)
                    │   │   ├── <EmployeeLane>  (rows)
                    │   │   │   └── <ShiftBlock> draggable # resize = change hours
                    │   │   └── <TimeAxisHeader>
                    │   ├── <ConflictBadge>                # inline overlap/rest violation
                    │   ├── <ShiftEditorDrawer>            # create/edit shift
                    │   └── <ShiftSwapModal>               # request + approve swaps
                    │
                    ├── <TimesheetsPage>
                    │   ├── <TimeClockWidget>              # web clock in/out
                    │   ├── <TimesheetTable>               # std vs OT breakdown
                    │   └── <LeaveRequestPanel>            # absence / leave mgmt
                    │
                    ├── <HrPage>                           # HR / Payroll
                    │   ├── <EmployeeDirectory>
                    │   ├── <EmployeeContractCard>
                    │   │   ├── <ContractSummary>
                    │   │   └── <ContractChangeTimeline>   # audit trail of adjustments
                    │   └── <ContractChangeReview>         # CHECKER: approve + Effective From
                    │       └── <ProposeContractChange>    # MAKER: manager proposal form
                    │
                    └── <DeveloperPage>                    # API / integrations module
                        ├── <ApiKeyList>                   # active keys, last-used, scopes
                        ├── <GenerateApiKeyModal>          # scope picker → one-time secret
                        │   └── <ScopeSelector>            # read/write per resource
                        ├── <RevokeKeyDialog>
                        ├── <WebhookEndpointManager>       # register push URLs + secret
                        └── <ApiUsagePanel>                # request counts, rate-limit status
```

**Cross-cutting primitives:** `<Can permission="roster:write">`, `usePermission()`,
`useAuth()`, a typed `apiClient` (adds bearer/session + CSRF), and a `<DesignSystem>` set
(`Button`, `Badge`, `DataTable`, `Drawer`, `Modal`) themed with the green tokens above.

---

## Quick start

```bash
cp .env.example .env
docker compose up --build -d
docker compose exec api-gateway python -m app.seed     # demo users + employee
# Frontend  → https://localhost         (via Nginx proxy)
# API docs  → http://localhost:8000/docs
```

## Services & ports

| Service            | Port | Health       |
|--------------------|------|--------------|
| api-gateway        | 8000 | `/healthz`   |
| rostering-engine   | 8010 | `/healthz`   |
| time-attendance    | 8020 | `/healthz`   |
| webhooks           | 8030 | `/healthz`   |

## End-to-end demo (Maker-Checker)

```bash
docker compose exec api-gateway python -m app.seed
EMP_ID=<seeded employment id> API=http://localhost:8000 ./scripts/e2e_demo.sh
```

Drives: manager login → **propose** 40h→32h → HR login → **approve** with
`Effective From` → and asserts a manager approving their *own* proposal is `403`
(segregation of duties). See [scripts/e2e_demo.sh](scripts/e2e_demo.sh).

## Verification

The three rule-heavy cores are pure Python and unit-tested with the stdlib — no
DB or containers required:

```bash
python -m unittest discover -s tests -v      # 17 tests: fatigue rules, OT calc, HMAC
```

- **Fatigue/conflict engine** — `services/rostering-engine/app/rules/engine.py`
  (overlap, 11h rest period, weekly hours vs. effective `contract_versions`, 48h legal max).
- **Overtime calc** — `services/time-attendance/app/timesheet.py`
  (break-aware worked hours + std/OT split; malformed clock sequences rejected).
- **Webhook signing** — `services/webhooks/app/signing.py`
  (HMAC-SHA256 `t=…,v1=…`, constant-time verify, replay window, backoff).
