Any authenticated user can invite an e-mail address; the mailed single-use token lets exactly one signup through even while registration is closed. Open (pending, unexpired) invitations count against the new instance setting invitations.maxOpenPerUser (default 5, 0 disables inviting) — plus a 20/day per-user rate limit so a revoke-and-recreate loop cannot become a mail cannon. Only the SHA-256 token hash is stored (auth-tokens pattern); a failed signup (taken username) un-redeems the token so the invitee can retry. Surfaces: invitations section in the user settings (list, invite, revoke, quota line; wide table in a focusable .table-scroll region), signup page reads ?invitation=<token> (preview banner, e-mail prefill, closed-mode gate opens only for a previewed-valid token), admin general card gets the quota field (flat RHF name per #322; VS-NfD marked and hideable). Governance: audit actions invitation.created/revoked/accepted (catalogue 1.10), VS-NfD profile entry (compliant: 0) + hardening-guide row, i18n de+en including the invitation mail template. Tests: api e2e-db (mail link, closed-mode single-use signup with un-redeem on failure, quota + revoke frees slot, quota 0 = 403, auth matrix), new web e2e pack invitations.spec.ts (full UI loop through Mailpit, wired into ci.yml with its own rate-limit reset), a11y scan waits for the new section. Full api suite (107 files / 607 tests), auth/admin-settings/a11y packs green against a fresh local stack. Closes #332
71 lines
3.5 KiB
JSON
71 lines
3.5 KiB
JSON
{
|
|
"common": {
|
|
"greeting": "Hello {{displayName}},",
|
|
"signoff": "Your Dorfteich",
|
|
"ignoreHint": "If you did not request this e-mail, you can safely ignore it."
|
|
},
|
|
"verifyEmail": {
|
|
"subject": "Confirm your e-mail address",
|
|
"body": "welcome to Dorfteich! Please confirm your e-mail address to activate your account:",
|
|
"action": "Confirm e-mail address",
|
|
"expiry": "The link is valid for 24 hours."
|
|
},
|
|
"resetPassword": {
|
|
"subject": "Reset your password",
|
|
"body": "someone (hopefully you) requested a password reset for your account. Use this link to set a new password:",
|
|
"action": "Set new password",
|
|
"expiry": "The link is valid for one hour. Your current password stays valid until you set a new one."
|
|
},
|
|
"invitation": {
|
|
"subject": "You are invited: Dorfteich",
|
|
"body": "{{inviterName}} invites you to a Dorfteich - a shared place for pages and notes. Use this link to create your account:",
|
|
"action": "Accept invitation",
|
|
"expiry": "The link is valid for 14 days and can only be used once."
|
|
},
|
|
"smtpTest": {
|
|
"subject": "SMTP test message",
|
|
"body": "this test message confirms that your Dorfteich can send e-mail through the configured SMTP server. You can reach your instance here:",
|
|
"action": "Open Dorfteich",
|
|
"expiry": "You can simply delete this e-mail."
|
|
},
|
|
"backupFailed": {
|
|
"subject": "[{{instance}}] Backup failed ({{backupId}})",
|
|
"intro": "The nightly backup run on {{instance}} failed.",
|
|
"backupId": "Backup id: {{backupId}}",
|
|
"error": "Error: {{error}}",
|
|
"lastSuccess": "Last successful backup: {{finishedAt}}",
|
|
"lastSuccessNever": "Last successful backup: none yet",
|
|
"hint": "Check the sidecar logs (docker compose logs backup) and status.json on the backups volume."
|
|
},
|
|
"backupUploadFailed": {
|
|
"subject": "[{{instance}}] Backup upload to Nextcloud failed ({{backupId}})",
|
|
"intro": "The local backup on {{instance}} succeeded, but uploading it to the Nextcloud target failed.",
|
|
"backupId": "Backup id: {{backupId}}",
|
|
"error": "Error: {{error}}",
|
|
"lastSuccess": "Last successful upload: {{finishedAt}}",
|
|
"lastSuccessNever": "Last successful upload: none yet",
|
|
"hint": "Check the Nextcloud connection settings in the admin panel (test connection) and the sidecar logs (docker compose logs backup)."
|
|
},
|
|
"backupMirrorFailed": {
|
|
"subject": "[{{instance}}] Backup mirror to the private host failed",
|
|
"intro": "The local backup on {{instance}} succeeded, but mirroring the sets via rsync failed.",
|
|
"backupId": "Component: rsync mirror (issue #84)",
|
|
"error": "Error: {{error}}",
|
|
"lastSuccess": "Last successful mirror: {{finishedAt}}",
|
|
"lastSuccessNever": "Last successful mirror: none yet",
|
|
"hint": "Check the tunnel to the mirror host, the SSH key in the secrets volume, and the sidecar logs (docker compose logs backup). Setup: deploy/backup-basel.md."
|
|
},
|
|
"digest": {
|
|
"subject": "Dorfteich: {{count}} updates for you",
|
|
"intro": "Here is what happened on pages you watch ({{count}} updates):",
|
|
"changes_one": "{{count}} change",
|
|
"changes_other": "{{count}} changes",
|
|
"comments_one": "{{count}} comment",
|
|
"comments_other": "{{count}} comments",
|
|
"openApp": "Open Dorfteich: {{link}}",
|
|
"unsubscribe": "Stop these digest mails: {{link}}",
|
|
"unsubscribedTitle": "Digest mails disabled",
|
|
"unsubscribedBody": "You will no longer receive notification digests. You can re-enable them anytime in your account settings after signing in."
|
|
}
|
|
}
|