What's Changed
- Phase 0: Projektstruktur & Governance by @bigpuritz in #2
- chore: project governance & tooling (CLA, Renovate, copyright headers, branch-protection ADR) by @bigpuritz in #4
- docs: correct ADR-0016 — CLA_TOKEN optional, document cla-signatures bootstrap by @bigpuritz in #6
- feat: bootable Spring Boot server (qnop-app) with PostgreSQL, Liquibase and JPA by @bigpuritz in #24
- feat: OpenAPI-first REST contract tooling in qnop-api (#9) by @devtank42 in #26
- feat: security & crypto foundation (SecurityConfig, crypto, QnopProperties) by @devtank42 in #25
- feat: identity schema (qnop_user, oidc_provider, oidc_identity) by @devtank42 in #27
- feat: settings schema (application_setting + user_setting + seed) by @devtank42 in #28
- feat: mail template schema (mail_template + en seed) by @devtank42 in #29
- feat: application asset schema (application_asset) by @devtank42 in #31
- feat: token schema (refresh/revoked/email-verification/password-reset) (#12) by @devtank42 in #30
- feat: application settings service + admin endpoints by @devtank42 in #32
- feat: JWT & session core (access/refresh tokens, revocation, AuthController) by @devtank42 in #33
- feat: auth endpoint rate limiting (Bucket4j) by @devtank42 in #34
- feat: mail subsystem — runtime SMTP, jmustache templates, admin endpoints (#19) by @devtank42 in #35
- feat: per-user settings service + /users/me/settings by @devtank42 in #37
- feat: local-user lifecycle core — registration, verification, password reset (Part of #20) by @devtank42 in #38
- feat: OIDC provider admin + SSRF guard (Part of #21) by @devtank42 in #40
- feat: OIDC/OAuth2 browser login flow (#21) by @devtank42 in #42
- feat: branding asset upload, SVG sanitization, public serving by @devtank42 in #41
- fix: schedule cleanup of expired refresh and revoked tokens by @devtank42 in #51
- test: cover TokenRevocationService, JwtTokenService and refresh rotation (#44) by @devtank42 in #54
- fix: harden branding upload — SVG depth limit + I/O outside transaction by @devtank42 in #57
- perf: index application_setting.updated_by FK (issue #46) by @devtank42 in #58
- feat: distributed scheduler locks via ShedLock (Postgres-backed) by @devtank42 in #60
- fix: rate-limit hardening — trusted-proxy warning + bounded bucket cache by @devtank42 in #59
- fix: uniform ErrorResponse envelope for 401/403/429 + global @ControllerAdvice by @devtank42 in #55
- feat: optimistic locking for ApplicationSetting by @devtank42 in #56
- feat: atomic single-use guard for verification/reset tokens (part 2 of #61) by @devtank42 in #63
- feat: concurrency control for User writes (part 1 of #61) by @devtank42 in #62
- ci: override Renovate schedule so PRs are actually opened (#64) by @devtank42 in #65
- chore: phase-1 review code-quality follow-ups (issue #50) by @devtank42 in #66
- ci: pass App secrets to Renovate via secrets: inherit (#67) by @devtank42 in #68
- fix: drop invalid comment:schedule key from renovate.json by @devtank42 in #70
- ci: raise Renovate prHourlyLimit to 10 by @devtank42 in #74
- chore(deps): pin dependencies by @qnop-renovate[bot] in #72
- chore(deps): pin dependencies by @qnop-renovate[bot] in #73
- fix: ignore generated files in Prettier (unblock Renovate npm PRs) (#80) by @devtank42 in #81
- chore(deps): pin dependencies by @qnop-renovate[bot] in #75
- fix(deps): pin dependencies by @qnop-renovate[bot] in #79
- chore(deps): pin dependencies by @qnop-renovate[bot] in #76
- fix(deps): pin dependencies by @qnop-renovate[bot] in #77
- fix(deps): update swaggerannotations to v2.2.51 by @qnop-renovate[bot] in #83
- fix(deps): pin dependencies by @qnop-renovate[bot] in #78
- chore(deps): update gradle wrapper to v9.6.0 by @qnop-renovate[bot] in #85
- chore(deps): update npm dependencies to v11.8.0 by @qnop-renovate[bot] in #86
- fix(deps): update test dependencies by @qnop-renovate[bot] in #84
- chore(deps): update frontend lint/types tooling by @qnop-renovate[bot] in #82
- chore(deps): update openapigenerator by @qnop-renovate[bot] in #87
- fix(deps): update bucket4j by @qnop-renovate[bot] in #88
- fix(deps): update build tooling to v8.7.0 by @qnop-renovate[bot] in #89
- fix(deps): update jackson monorepo by @qnop-renovate[bot] in #90
- fix(deps): update shedlock monorepo to v7.7.0 by @qnop-renovate[bot] in #91
- chore(deps): update docker base images (major) by @qnop-renovate[bot] in #92
- chore(deps): update github actions major updates (major) by @qnop-renovate[bot] in #93
- fix(deps): update test dependencies (major) by @qnop-renovate[bot] in #94
- chore: guard qnop-ui against non-pnpm installs (#95) by @devtank42 in #96
- feat: global role model (ADMIN/MEMBER/AUDITOR) + fix admin authority in JWT by @bigpuritz in #107
- feat: GET /users/me profile endpoint + wire /config self-registration by @bigpuritz in #108
- chore: auto-load .env in bootRun for local dev by @bigpuritz in #111
- feat(ui): frontend foundation — routing, react-query, generated API client, auth by @bigpuritz in #109
- feat(ui): devtank42 design system as MUI theme (Outfit, navy/blue, light+dark) by @bigpuritz in #112
- feat(ui): app shell — sidebar, top bar, breadcrumbs, role-aware nav by @bigpuritz in #113
- feat(ui): auth screens — login, register, password reset, email verify, OIDC by @bigpuritz in #114
- feat: admin user management — /admin/users CRUD + UI (#104) by @bigpuritz in #115
- feat(ui): auth screen redesign + switch all UI texts to English (#118) by @bigpuritz in #119
- feat: teams subsystem — entity, /admin/teams CRUD, memberships + UI (#105) by @bigpuritz in #120
- test: cross-cutting authorization coverage for the Administration surface (#122) by @bigpuritz in #123
- feat: user-management feature parity — delete, filters/sort, provider name, reset (#124) by @bigpuritz in #125
- feat(ui): application settings screen + admin menu items (#106) by @devtank42 in #121
- fix: forced first-login password change — min-length + clear forced-change flag (#128, #130) by @bigpuritz in #129
- fix(deps): update npm dependencies by @qnop-renovate[bot] in #127
- chore(deps): update postgres:18 docker digest to 4efc78b by @qnop-renovate[bot] in #134
- fix(deps): update dependency io.swagger.core.v3:swagger-annotations to v2.2.52 by @qnop-renovate[bot] in #132
- feat: OIDC end-to-end — provider mgmt, login flow, account lifecycle, Keycloak test setup (#106) by @devtank42 in #126
- fix(deps): update dependency @mui/material to v9.1.2 by @qnop-renovate[bot] in #137
- chore(deps): update postgres:18 docker digest to 1a5b3e7 by @qnop-renovate[bot] in #136
- feat: reset / regenerate a user's password from the UI (#116) by @bigpuritz in #138
- feat(ui): mail template editor screen (#106) by @devtank42 in #147
- feat: profile-picture upload (admin + self-service) (#117) by @bigpuritz in #148
- fix(deps): update npm dependencies by @qnop-renovate[bot] in #131
- chore(deps): update vite by @qnop-renovate[bot] in #135
- chore(deps): update actions/setup-java digest to 1bcf9fb by @qnop-renovate[bot] in #151
- chore(deps): pin quay.io/keycloak/keycloak docker tag to 9b03307 by @qnop-renovate[bot] in #150
- feat(ui): branding upload screen (#106) by @devtank42 in #149
- fix(mail): align seeded templates with flow variables; brand HTML via EmailLayoutBuilder (#140) by @devtank42 in #152
- feat(api): mail-template metadata (placeholders, friendly name, defaults) + validate placeholders (#141) by @devtank42 in #155
- feat(mail): SMTP config parity — enabled switch, from-name, encryption mode (#142) by @bigpuritz in #156
- feat(ui): mail templates admin screen — list + editor (#144) by @bigpuritz in #157
- feat: mail template live preview (sandboxed iframe) + sample variables (#145) by @bigpuritz in #158
- feat(ui): complete send-test-email affordance in Email/SMTP settings (#146) by @bigpuritz in #159
- chore: Mailpit SMTP sink in docker-compose for local mail testing (#160) by @bigpuritz in #161
- feat(ui): render uploaded branding across the app, live on upload (#154) by @bigpuritz in #162
- test: integration-test suite foundation — testdata SQL seed + first ITs (#163) by @devtank42 in #164
- test: integration tests for the auth flows (#163) by @devtank42 in #203
- test: integration tests for admin users and teams (#163) by @devtank42 in #204
- test: integration tests for settings, OIDC providers and mail templates (#163) by @devtank42 in #205
- test: integration tests for scheduled cleanup and the error envelope (#163) by @devtank42 in #206
- ci: smoke-test deployment via docker-compose against testdata (#207) by @devtank42 in #208
- test(ci): OIDC login smoke test against Keycloak (#225) by @devtank42 in #226
- fix: validate login response before storing the access token by @devtank42 in #209
- fix: emit uniform ErrorResponse envelope from PasswordChangeRequiredFilter by @devtank42 in #210
- fix: revoke AvatarUploader crop-preview object URL on unmount (#171) by @devtank42 in #211
- fix: give AvatarService.store read-back a diagnosable failure by @devtank42 in #212
- fix: close encoded open-redirect bypass in safeRedirectPath by @devtank42 in #213
- chore: enforce a11y linting with eslint-plugin-jsx-a11y (#172) by @devtank42 in #214
- fix: decouple OIDC post-login redirect from CORS allowed-origins by @devtank42 in #216
- fix: accessible name for the UsersPage search field (#173) by @devtank42 in #217
- perf: skip the guaranteed-empty avatar lookup on user creation by @devtank42 in #218
- fix: re-apply the SSRF policy when (re)building OIDC registrations by @devtank42 in #219
- fix: enable "strict": true in tsconfig.app.json (#174) by @devtank42 in #220
- fix: application_asset.uploaded_by FK uses ON DELETE SET NULL by @devtank42 in #221
- fix: don't leak the constraint property path in the validation 400 by @devtank42 in #222
- fix: surface OIDC discovery failures instead of swallowing them (#175) by @devtank42 in #223
- perf: memoize the MUI theme in Root with useMemo by @devtank42 in #224
- fix(ci): set QNOP_AUTH_OIDC_FRONTEND_BASE_URL in the smoke compose by @devtank42 in #231
- perf: gate password-change from a JWT claim instead of a per-request DB read by @devtank42 in #215
- refactor: LAZY fetch for verification/reset token user association (#181) by @devtank42 in #227
- perf: partial index on refresh_token.family_id (#182) by @devtank42 in #228
- docs: declare the four missing OpenAPI tags (#183) by @devtank42 in #229
- fix: OIDC provider duplicate-name returns 409 not 400 (#184) by @devtank42 in #232
- fix: 409 EXTERNAL_ACCOUNT for change-password on OIDC accounts (#185) by @devtank42 in #233
- chore(deps): update frontend lint/types tooling by @qnop-renovate[bot] in #133
- docs: document the io.qnop.security layer in ARCHITECTURE.md by @devtank42 in #234
- docs: README status badge — Phase 0 → Phase 1 (#197) by @devtank42 in #235
- docs: note QNOP_AUTH_* secret setup before bootRun in the README by @devtank42 in #236
- docs: correct the frontend commands in CLAUDE.md by @devtank42 in #237
- docs(adr): document-review core architecture (#239) by @bigpuritz in #240
- docs(adr): e-signature approval as a post-finalization enterprise feature (#253) by @bigpuritz in #255
- docs: refresh CLAUDE.md current-state + module diagram (#198) by @devtank42 in #238
- fix(deps): pin dependencies by @qnop-renovate[bot] in #256
- fix(deps): update npm dependencies by @qnop-renovate[bot] in #258
- chore(deps): update docker base images by @qnop-renovate[bot] in #259
- chore(deps): update dependency vite to v8.1.2 by @qnop-renovate[bot] in #257
- fix(deps): pin dependencies by @qnop-renovate[bot] in #260
- chore(deps): update quay.io/keycloak/keycloak:26.6 docker digest to 0aae0de by @qnop-renovate[bot] in #261
- chore(deps): update gradle to v9.6.1 by @qnop-renovate[bot] in #262
- build: align Renovate minimumReleaseAge with pnpm 11 supply-chain karenz (#264) by @bigpuritz in #265
- build: align openapi-generator versions and group them in Renovate by @devtank42 in #266
- test: cover PasswordChangeRequiredFilter enforcement (#189) by @devtank42 in #268
- fix: align displayName maxLength to VARCHAR(255) across schemas by @devtank42 in #269
- build: pin the Gradle distribution checksum (distributionSha256Sum) by @devtank42 in #270
- test: PasswordResetTokenServiceTest for consume() guard branches (#190) by @devtank42 in #271
- test: OidcLoginService provider-resolution branches (#191) by @devtank42 in #272
- fix: add format:uri and maxLength to OIDC URI fields in the contract by @devtank42 in #273
- test: cover UserService self-registration, existence and password-reset paths by @devtank42 in #274
- ci: per-PR dependency vulnerability audit gates (frontend pnpm audit + backend OWASP) by @devtank42 in #275
- test: add controller-level IT for the public auth flows by @devtank42 in #276
- build: enforce SPDX headers on Kotlin DSL files via Spotless by @devtank42 in #277
- fix: replace invalid Renovate
//comment key withdescription(#267) by @devtank42 in #279 - chore: run integration tests on postgres:18 to match local/prod infra by @devtank42 in #278
- feat(core): durable async job queue on Postgres (#242) by @bigpuritz in #280
- feat(core): document-review domain model + schema (#244) by @bigpuritz in #281
- feat(core): StorageProvider SPI + S3/MinIO adapter (ADR-0005, #243) by @devtank42 in #282
- feat(core): review workflow state machine (ADR-0011) by @devtank42 in #283
- feat(core): document ingest, PDF extraction & serving (ADR-0032/0010) by @devtank42 in #284
- feat(core): annotations, comments & placements API (ADR-0009/0011, #247) by @devtank42 in #285
- feat(core): inter-version diff (ADR-0034, #249) by @devtank42 in #286
- feat(core): async re-anchoring engine (ADR-0009) by @devtank42 in #288
- feat(ui): document viewer + annotation layer (ADR-0032/0009) by @bigpuritz in #287
- feat(core): document listing, participants & principal directory API (#292) by @bigpuritz in #293
- feat(ui): reviews surface — overview, wizard, hub head & decisions (#251) by @bigpuritz in #294
- fix(core): stop interleaving characters of overlapping text runs (#296) by @bigpuritz in #297
- feat(core): glyph-true per-character span geometry & pointer selection (#290) by @bigpuritz in #299
- feat: make the annotation's first comment mandatory (#301) — re-land on main by @bigpuritz in #303
- feat: optional review due date (Community) (#295) by @devtank42 in #304
- feat(ui): version diff view with located change highlights (#252) by @bigpuritz in #305
- fix(ui): keep the review viewer polling after a new-version upload (#300) by @devtank42 in #350
- fix(core): dedup only COMMITTED storage rows; re-upload poisoned PENDING keys by @devtank42 in #310
- test: extend smoke test to cover object storage + review pipeline (#308) by @devtank42 in #309
- test: prove OIDC state is validated end-to-end (issue #321) by @devtank42 in #353
- fix(core): cap PDF page count to bound extraction DoS (issue #322) by @devtank42 in #356
- fix: authorize workflow status reads and drop entity leak from web (#311, #315) by @devtank42 in #355
- perf: resolve document access in a single query (#312) by @devtank42 in #358
- test(ui): cover the login flow (#317) by @devtank42 in #354
- perf: run extraction I/O outside the DB transaction and stream large PDFs (#314) by @devtank42 in #362
- perf: batch placements and comment counts in annotation list (#313) by @devtank42 in #360
- fix(core): require a READY version to finalize a review (issue #323) by @devtank42 in #357
- docs(api): reference the 429 response on rate-limited endpoints (#347) by @devtank42 in #364
- perf: stream document uploads instead of materializing them in the heap (#361) by @devtank42 in #365
- test(app): guard @Valid on every generated request body (#346) by @devtank42 in #367
- feat(ui): focus view mode — spotlight overlay for annotations (#291) by @bigpuritz in #363
- fix(ui): replace unsafe viewer casts and non-null assertions (#335) by @devtank42 in #366
- fix: explicit servlet + HTTP client timeouts (#342) by @devtank42 in #368
- test: exercise the multi-version document fixtures in IT and smoke (#370) by @bigpuritz in #371
- docs(api): document 401 on authenticated review-domain endpoints (#327) by @devtank42 in #372
- fix(api): use the framework ObjectMapper in AnnotationController (#329) by @devtank42 in #373
- perf: index the review/diff foreign-key columns (#330) by @devtank42 in #374
- fix(ui): error boundaries around viewer/panel + lazy routes (#331) by @devtank42 in #376
- refactor: split JobEnqueuer out of JobService to break the handler cycle (#318) by @devtank42 in #377
- refactor: handle xlink:href explicitly in the SVG sanitizer (#338) by @devtank42 in #378
- fix(core): guard getInteger against missing/blank setting values (#340) by @devtank42 in #380
- fix: validate the S3 storage key format before use (#337) by @devtank42 in #381
- fix: give the viewer text layer an accessible label (#341) by @devtank42 in #382
- refactor: typed job-payload (de)serialization via a shared codec (#319) by @devtank42 in #383
- feat: annotations and decisions on the latest version only (#306) by @bigpuritz in #379
- feat: word-accurate diff boxes, collapsible changes rail, card radius by @bigpuritz in #384
- fix(core): persist OidcProviderService.update() with an explicit save (#339) by @devtank42 in #385
- fix(ui): stable diff-list keys and memoized annotation derivations (#334) by @devtank42 in #387
- fix: derive download filename extension from the content type (#328) by @devtank42 in #388
- docs: document accepted upload formats + fix supportedFormats (#345) by @devtank42 in #386
- perf: memoize annotation panel rows to cut re-render overhead (#333) by @devtank42 in #390
- perf(ui): fetch the PDF eagerly from an explicit ?version= (#332) by @devtank42 in #391
- refactor: modernise the re-anchoring core (AnchorResolver) (#320) by @devtank42 in #389
- feat(core): optional annotation classification — type & priority by @bigpuritz in #396
- feat: tasks view — annotations as a kanban board and task list by @bigpuritz in #397
- feat: prominent labeled view tabs for Document / Focus / Tasks / Compare by @bigpuritz in #399
- feat: unseen markers since the participant's last visit by @bigpuritz in #400
- chore: expand the shared test seed — 20-user crowd, 5 teams, Mailpit SMTP by @bigpuritz in #402
- fix: review surfaces — polish & bugfix round (#403) by @bigpuritz in #404
- feat: author-only resolve & annotation-driven workflow (#405) by @bigpuritz in #406
- fix: review UI polish round 2 (#403) by @bigpuritz in #409
- fix: review UI polish round 3 (#403) by @bigpuritz in #414
- feat: review slug URLs & new-review wizard polish (#411, #415) by @bigpuritz in #416
- fix(compose): mount the local Postgres volume at /var/lib/postgresql (#407) by @devtank42 in #417
- feat(platform): observability — job-queue health indicator + Prometheus metrics (#348) by @devtank42 in #418
- feat: per-review anonymity — server-resolved author names & Participant N (#413 pt.1) by @bigpuritz in #419
- feat: thread participation policy — PRIVATE/READ_ONLY/OPEN (#413 pt.2, re-targeted to main) by @bigpuritz in #424
- fix(security): list explicit CORS allowed-headers instead of "*" (#336) by @devtank42 in #425
- fix: hide the reviewer roster from non-owners in anonymous reviews + anonymity marker (#422) by @bigpuritz in #426
- feat(reviews): permalinks for annotations and comments (#412) by @bigpuritz in #428
- feat(reviews): document-scoped (global) annotations without a text anchor (#395) by @bigpuritz in #429
- test(core): AnchorResolver re-anchoring boundary edge cases (#351) by @devtank42 in #430
- fix(core): contain the version-diff cache race in its own transaction (#351) by @devtank42 in #431
- test(review): concurrency, extraction-failure cascade & annotation-decision authz ITs (#351) by @devtank42 in #435
- test(ui): auth-flow coverage — wave 1 of #352 by @devtank42 in #434
- test(core): service-layer authorization & logic suites (#349) by @devtank42 in #433
- test(ui): document-viewer coverage — wave 2 of #352 by @devtank42 in #436
- test(ui): admin-surface coverage — wave 3 of #352 by @devtank42 in #442
- fix(deps): update npm dependencies by @qnop-renovate[bot] in #441
- chore(deps): update dependency vite to v8.1.3 by @qnop-renovate[bot] in #440
- fix(deps): update dependency react-easy-crop to v6.2.0 by @qnop-renovate[bot] in #444
- feat(reviews): render Markdown in annotation & comment bodies (#427) by @bigpuritz in #432
- feat(reviews): Slack-style discussion UI & comment attachments (#445, #446) by @bigpuritz in #447
- feat(reviews): deliver Slack-style discussion UI & comment attachments to main (#445, #446) by @bigpuritz in #448
- feat(reviews): Document/Focus tab merge & focus-view polish round (#403) by @bigpuritz in #449
- docs: tighten working rules — Conventional Commits always, push needs approval (#450) by @bigpuritz in #451
- feat(reviews): task drawer head, resizable drawers & full-screen writing stage (#403) by @bigpuritz in #452
- feat(reviews): Slack-style emoji reactions on annotations and comments (#410) by @bigpuritz in #453
- feat(dashboard): the review command centre (#454) by @bigpuritz in #455
- feat(theme): black-based neutral dark mode, derived greyscale ramp (#423) by @bigpuritz in #456
- feat(reviews): re-attach orphaned annotations by selecting a new passage by @bigpuritz in #459
- feat(reviews): audit extraction outcomes and persist the failure reason (#325) by @devtank42 in #463
- chore(deps): update docker base images by @qnop-renovate[bot] in #439
- chore(deps): update actions/setup-java digest to 0f481fc by @qnop-renovate[bot] in #438
- feat(reviews): email notifications on review events by @bigpuritz in #467
- feat(build): Liquibase seam for enterprise-module schema by @bigpuritz in #468
- feat(ui): gamification polish round — launch pad, wizard, player card, avatars everywhere by @bigpuritz in #474
- feat(reviews): copy to clipboard — viewer selection, quotes & comments by @bigpuritz in #483
- feat(reviews): one flat annotation list with per-card scope markers by @bigpuritz in #484
- feat(users): public profile as a player card — stats, achievements, teams by @bigpuritz in #485
- feat(users): readable profile URLs via an immutable user slug by @bigpuritz in #487
- feat(users): profile hover card (player card) with a hard anonymity gate by @bigpuritz in #489
- fix(reviews): resolve the owner's name on the document, not the directory by @bigpuritz in #490
- fix(reviews): mark clicks glide the panel to their annotation by @bigpuritz in #492
- chore(deps): update dependency vite to v8.1.4 by @qnop-renovate[bot] in #476
- docs: prune all documentation to the current state by @bigpuritz in #499
- feat(release): Docker release pipeline, SPA embedding and snapshot publishing (ADR-0040) by @bigpuritz in #500
- feat: real qnop brand assets (logomark, wordmark, favicon, og-image) by @bigpuritz in #501
- docs(release): the encryption salt must be hex-encoded by @bigpuritz in #502
- fix(deps): update npm dependencies by @qnop-renovate[bot] in #477
- feat(auth): redesign the auth pages and polish the dashboard (#503) by @bigpuritz in #504
- feat: L10n — UTC storage, ISO-offset API timestamps, user-timezone display (#465) by @devtank42 in #507
- feat(reviews): role-gated audit UI over the document audit trail (#466) by @devtank42 in #506
- feat(teams): let team leads self-manage their own teams (#470) by @devtank42 in #505
- feat(auth): review-focused showcase and brand-aligned imagery colors by @bigpuritz in #512
- chore(ui): shell cleanup — drop the Compliance placeholder, reorder admin nav, honest coming-soon triggers by @bigpuritz in #515
- docs: user-facing README and Docker Hub description for the first release by @bigpuritz in #517
- fix(release): replace two unresolvable action SHA pins by @bigpuritz in #519
New Contributors
- @qnop-renovate[bot] made their first contribution in #72
Full Changelog: https://github.com/qnophq/qnop/commits/v1.0.0