TreeMap
무료 오픈소스 디스크 사용량 시각화 도구로, 사각형 트리맵·중복 파일 탐색·디스크 가득 예측·정리 시 파일을 휴지통으로만 이동한다
The hours you and your team log in GitLab, by day, month and project.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
The hours you log in GitLab — by day, by month, by project and by team, at a glance.README 전문 보기 ↗The hours you log in GitLab — by day, by month, by project and by team, at a glance.
At the company where I work, people log the hours they put into each project as time tracking on GitLab issues and merge requests. GitLab keeps every entry, but it is hard to see how many hours were logged in a day, in a month or on a project — and harder still for managers to follow the hours of the people on their teams. GitLab Dashboard was built for exactly that: you sign in with your own GitLab account and see those hours aggregated in a dashboard that is easy to read, for yourself and for the teams you follow.
🤖 The project was developed with
Claude Code. Each change was planned as an
OpenSpec proposal, following the rules
in AGENTS.md, with the quality gates below enforced in CI.
Dashboard — today, this week and this month, the week day by day, and your history, or all of it as of any day you pick
Insights — a month's heatmap, hours by project and what took the time, for this month or any month before it
Team month — people down the side, days across the top
/days/2026-08-21 can be linked and
reloaded, with every work item and its hours./?date=2026-08-21 and /insights?month=2026-08
survive a reload and can be sent to somebody; an address with no date always
means today.| Area | Choice |
|---|---|
| UI | React 19, TypeScript, Tailwind CSS v4, shadcn/ui on Base UI |
| Routing, data | TanStack Router (file-based SPA routes) and TanStack Query |
| Build | Vite, with a Content-Security-Policy written after the build |
| i18n | Paraglide JS — English and Brazilian Portuguese |
| Backend | Three Netlify Functions over Netlify Blobs, jose verifying GitLab tokens |
| Monitoring | Sentry, EU region, errors only, through a tunnel on this origin |
| Tooling | Bun as package manager, script runner and runtime |
| Architecture | Feature-Sliced Design outside, Clean Architecture inside each slice |
Browser (static files on a CDN)
├── PKCE authorize ──> gitlab.com/oauth/authorize
├── token / refresh ──> gitlab.com/oauth/token (no client secret)
├── hours ──> gitlab.com/api/graphql (Bearer, CORS allows it)
├── teams ──> /.netlify/functions/teams (id_token, same origin)
├── settings ──> /.netlify/functions/preferences (id_token, same origin)
└── faults ──> /.netlify/functions/monitor (same origin) ──> Sentry, EU
AGENTS.md documents the architecture and every decision behind it.
A one-time, self-service step in your own GitLab account — no administrator involved.
GitLab Dashboard.http://localhost:3000/auth/callback
https://<your-site>.netlify.app/auth/callback
read_api and openid, and nothing else. The app
never writes to GitLab; openid only lets GitLab state who you are, in a
short-lived signed token the two endpoints verify.[!IMPORTANT] Tick
openidbefore deploying a bundle that asks for it. GitLab checks an authorize request against the application's scopes, so the other order fails every sign-in withinvalid_scope. A session granted before the scope was added keeps working; it only shows a notice asking you to sign in again.
cp .env.example .env
Put the Application ID in VITE_GITLAB_CLIENT_ID. It is public by design — it
ships inside the bundle, which is how a PKCE public client works. There is no
secret in this repository.
bun install
bun run dev
Open http://localhost:3000 and sign in with GitLab. Both endpoints are served by the dev server itself, over an in-memory store.
| Command | What it does |
|---|---|
bun run dev | Dev server on http://localhost:3000 |
bun run verify | Every fast gate: format, lint, ARIA, contrast, i18n, types, architecture … |
bun run test | Unit, component, Gherkin domain and endpoint tests |
bun run test:coverage | The same, with the coverage thresholds enforced |
bun run test:e2e | The acceptance suite — Chromium locally, three browsers in CI |
bun run test:mutation | Mutation testing on the model layer |
bun run build | Production build into dist/, plus its CSP |
Everything below fails the build rather than warning. All of it runs on every pull request in GitHub Actions, except mutation testing, which runs weekly:
| Gate | Where |
|---|---|
90% coverage, 100% on model/ | bun run test:coverage |
Mutation score ≥ 85% on model/ | bun run test:mutation, weekly in CI |
| Zero vulnerabilities in production | bun run security:audit |
| No new vulnerable package, at all | dependency review, over bun.lock |
| 196 kB gzip initial bundle | size-limit |
| Zero axe violations, both themes | the acceptance suite |
| Layout shift under 0.1 | the acceptance suite |
| No sideways scrolling at 375 px | the acceptance suite |
| Every requirement cited by a test | bun run arch:trace |
docs/qa/ holds the test plan, the manual regression pass, the
browser matrix, the screen-reader procedure, the release checklist and the
measured value of every gate.
Found a vulnerability? Please report it privately, as SECURITY.md
describes, rather than in a public issue.
@lhci/cli pulls in vulnerable puppeteer → extract-zip, tmp and uuid
(performance is guarded by the bundle budget and the layout-shift assertion
instead), and qs is pinned through overrides because Stryker reaches an
older one.localStorage and rotates on
every use. The scope is read_api openid and nothing more.id_token offline against GitLab's published keys (RS256 named, audience
checked, nothing older than 150 seconds accepted). The storage key is derived
from that verified identity and from nothing the request carried, so reaching
somebody else's data is not expressible. A write must name the version it
was made against, or it is refused.default-src 'none', connect-src
limited to this origin and your GitLab — with the hash of the one inline
script, written by bun run csp into dist/_headers.[!NOTE] What the host can see. Netlify Blobs holds each document as it was written, unencrypted: your teams — the names, usernames and GitLab ids of the colleagues you put on them — and your daily targets and time zone. No hours are ever stored there, but whoever can reach the site's blob store can see which colleagues you grouped together.
What the error tracker can see. When reporting is configured, Sentry holds each fault report in its EU region for its plan's retention: the error's class, its stack, the path of the screen, the release, the deploy and the browser. No name, username, email, token, team, group, hour or address is in one.
The app deploys to Netlify as static files plus the
three functions in netlify/functions/. Production is built from main;
homologation from staging, at
staging--gitlabdashboard.netlify.app,
with teams and schedules of its own; and every pull request gets a deploy
preview.
VITE_GITLAB_CLIENT_ID in the site's environment variables, for every
deploy context — the functions read the same one. On a self-managed GitLab,
set VITE_GITLAB_BASE_URL beside it; it defaults to https://gitlab.com./auth/callback to the OAuth application's
redirect URIs.openid on the application before the first deploy that asks for it.VITE_SENTRY_DSN for every deploy context (the functions read the same one),
and SENTRY_AUTH_TOKEN, SENTRY_ORG and SENTRY_PROJECT for builds only,
so the source maps are uploaded and never served. Without the DSN nothing is
reported and the reporting code is not even built.The first three fail at sign-in rather than at build time.
docs/qa/release-checklist.md is the full pass.
Changes go into staging by pull request, and staging is promoted to main;
every merge into main is a tagged release whose notes come from its commits.
CONTRIBUTING.md has the environments, the branch names,
hotfixes, promotion and the commit convention.
Copyright © 2026 Rafael Daily Santos Martins. Released under the
GNU Affero General Public License v3.0 (AGPL-3.0-only).
You may use, study, change and share this code, commercially or not. What the licence asks in return is that anybody who gives others a changed version, whether as files or as a service they reach over a network, also gives them its source, under these same terms. A licence on other terms is available from the author; get in touch through GitHub.
Created and maintained by:
| Rafael Daily |
|---|