All checks were successful
CD / Build and push images (push) Successful in 2m56s
CI / Lint, typecheck, test (push) Successful in 2m5s
CI / Auth e2e pack (push) Successful in 2m26s
CI / Build container images (push) Has been skipped
CD / Deploy to Test (push) Successful in 9s
CD / Smoke tests against Test (push) Successful in 1m13s
CD / Promote to Int (push) Successful in 12s
Introduce pond-scoped hierarchical labels as the foundation for M4 organization and, later, M5 label-scoped permissions. - shared: `labels.ts` with the label schemas/views and the pure tree helpers (buildLabelTree, collectSubtreeIds, collectAncestorIds, labelDepth, subtreeHeight). These are the single hierarchy walk the label API and the future permission resolver both build on (permissions.md: a grant on a label applies to all its descendants). - prisma: `Label` (self-referential parent_id, unique per (pond, parent, name), cascade to subtree) and `PageLabel` assignment table; migration. - api: `LabelsService` + controller. Tree endpoint returns the hierarchy in one call; create/rename/recolor/move/delete and page assign/unassign. Validation: cycle prevention on move, depth limit 6, unique name per (pond, parent) — enforced under a per-pond advisory lock so root-label uniqueness holds despite Postgres treating NULL parents as distinct. Delete cascades the subtree and requires `?force=true` when pages are assigned. Assignment rejects labels from a different pond. Access gated through InterimAccessService on the owning pond. - i18n: label error codes and the colour validation message (de + en). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PGdhRiwU1WRL4XxJfZYipY
57 lines
2.8 KiB
JSON
57 lines
2.8 KiB
JSON
{
|
|
"bad_request": "The request is invalid.",
|
|
"unauthorized": "Please sign in to continue.",
|
|
"forbidden": "You do not have permission for this action.",
|
|
"not_found": "The requested resource does not exist.",
|
|
"conflict": "The request conflicts with the current state.",
|
|
"gone": "This resource is no longer available.",
|
|
"payload_too_large": "The submitted data is too large.",
|
|
"rate_limited": "Too many requests — please try again later.",
|
|
"internal_error": "Internal server error.",
|
|
"registration_closed": "Registration is currently closed on this instance.",
|
|
"token_invalid": "This link is invalid or has expired.",
|
|
"login_failed": "Username/e-mail or password is incorrect.",
|
|
"login_backoff": "Too many failed attempts — please wait a few minutes.",
|
|
"email_unverified": "Please confirm your e-mail address first.",
|
|
"account_disabled": "This account has been disabled.",
|
|
"password_incorrect": "The current password is incorrect.",
|
|
"csrf_origin_mismatch": "The request came from an unexpected origin.",
|
|
"cannot_revoke_current_session": "Use sign-out to end your current session.",
|
|
"personal_pond_undeletable": "The personal pond cannot be deleted.",
|
|
"quota_exceeded": "The quota has been reached (limit: {{limit}}).",
|
|
"slug_taken": "This slug is already taken in this pond.",
|
|
"page_document_too_large": "The page is too large (limit: {{limitBytes}} bytes).",
|
|
"invalid_page_state": "The submitted page content is invalid.",
|
|
"page_trashed": "This page has been moved to the trash.",
|
|
"label_name_taken": "A label with this name already exists at this level.",
|
|
"label_cycle": "A label cannot be moved into its own subtree.",
|
|
"label_depth_exceeded": "Labels can be nested at most {{max}} levels deep.",
|
|
"label_has_pages": "This label still has pages assigned; confirm to detach them.",
|
|
"label_wrong_pond": "This label belongs to a different pond.",
|
|
"unsupported_file_type": "This file type is not supported.",
|
|
"file_too_large": "The file is too large (limit: {{limitBytes}} bytes).",
|
|
"network": "The server could not be reached.",
|
|
"validation": {
|
|
"required": "This field is required.",
|
|
"taken": "This value is already taken.",
|
|
"username": {
|
|
"tooShort": "The username needs at least 3 characters.",
|
|
"tooLong": "The username can have at most 32 characters.",
|
|
"charset": "Only letters, digits, and hyphens are allowed."
|
|
},
|
|
"password": {
|
|
"tooShort": "The password needs at least 10 characters.",
|
|
"tooLong": "The password can have at most 128 characters.",
|
|
"tooCommon": "This password is too common."
|
|
},
|
|
"email": {
|
|
"invalid": "Please enter a valid e-mail address."
|
|
},
|
|
"displayName": {
|
|
"required": "Please enter a display name."
|
|
},
|
|
"labelColor": "Please enter a colour like #a1b2c3.",
|
|
"tooLong": "The input is too long."
|
|
}
|
|
}
|