···11{
22 "db_name": "PostgreSQL",
33- "query": "\n SELECT rb.blob_cid, rb.record_uri\n FROM record_blobs rb\n LEFT JOIN blobs b ON rb.blob_cid = b.cid AND b.created_by_user = rb.repo_id\n WHERE rb.repo_id = $1 AND b.cid IS NULL AND rb.blob_cid > $2\n ORDER BY rb.blob_cid\n LIMIT $3\n ",
33+ "query": "\n SELECT rb.blob_cid, rb.record_uri\n FROM record_blobs rb\n LEFT JOIN blobs b ON rb.blob_cid = b.cid\n WHERE rb.repo_id = $1 AND b.cid IS NULL AND rb.blob_cid > $2\n ORDER BY rb.blob_cid\n LIMIT $3\n ",
44 "describe": {
55 "columns": [
66 {
···2626 false
2727 ]
2828 },
2929- "hash": "6f88c5e63c1beb47733daed5295492d59c649a35ef78414c62dcdf4d0b2a3115"
2929+ "hash": "ec51d224b9fcd73fd04eebaf2215423d7b1d528b5aba87a0d2f5fe4636af0adf"
3030}
···14141515This software isn't an afterthought by a company with limited resources.
16161717-It is a superset of the reference PDS, including: passkeys and 2FA (WebAuthn/FIDO2, TOTP, backup codes, trusted devices), did:web support (PDS-hosted subdomains or bring-your-own), multi-channel communication (email, discord, telegram, signal) for verification and alerts, granular OAuth scopes with a consent UI showing human-readable descriptions, app passwords with granular permissions (read-only, post-only, or custom scopes), account delegation (letting others manage an account with configurable permission levels), and a built-in web UI for account management, OAuth consent, repo browsing, and admin.
1717+It is a superset of the reference PDS, including: passkeys and 2FA (WebAuthn/FIDO2, TOTP, backup codes, trusted devices), did:web support (PDS-hosted subdomains or bring-your-own), multi-channel communication (email, discord, telegram, signal) for verification and alerts, granular OAuth scopes with a consent UI showing human-readable descriptions, app passwords with granular permissions (read-only, post-only, or custom scopes), account delegation (letting others manage an account with configurable permission levels), automatic backups to s3-compatible object storage (configurable retention and frequency, one-click restore), and a built-in web UI for account management, OAuth consent, repo browsing, and admin.
18181919The PDS itself is a single small binary with no node/npm runtime. It does require postgres, valkey, and s3-compatible storage, which makes setup heavier than the reference PDS's sqlite. The tradeoff is that these are battle-tested pieces of infra that we already know how to scale, back up, and monitor.
2020
+2-15
TODO.md
···2233## Active development
4455-### Migration tool
66-Seamless account migration built into the UI, inspired by pdsmoover. Users shouldn't need external tools or brain surgery on half-done account states.
77-88-- [x] Inbound UI wizard: login to old PDS -> choose handle -> import -> PLC token flow
99-- [x] Support `createAccount` with existing DID + service auth token
1010-- [x] Progress tracking with resume capability
1111-- [ ] Scheduled automatic backups (CAR export)
1212-- [ ] One-click restore from backup
1313-1414-Outbound migration wizard exists but is disabled. Rethinking the approach: instead of a managed flow with `migratingTo` state, pds-hosted did:web users should just have direct control over their DID document. They can independently update serviceEndpoint, add/remove keys, export their repo, deactivate their account.
1515-1616-- [ ] Remove `migratingTo` field and related state machine
1717-- [ ] Let did:web users edit their DID doc fields (serviceEndpoint, keys) whenever
1818-- [ ] Repo export as standalone feature, not tied to migration wizard
1919-205### Plugin system
216Extensible architecture allowing third-party plugins to add functionality. Going with wasm-based rather than scripting language.
227···6954App password scopes: Granular permissions for app passwords using the same scope system as OAuth. Preset buttons for common use cases (full access, read-only, post-only), scope stored in session and preserved across token refresh, explicit RPC/repo/blob scope enforcement for restricted passwords.
70557156Account Delegation: Delegated accounts controlled by other accounts instead of passwords. OAuth delegation flow (authenticate as controller), scope-based permissions (owner/admin/editor/viewer presets), scope intersection (tokens limited to granted permissions), `act` claim for delegation tracking, creating delegated account flow, controller management UI, "act as" account switcher, comprehensive audit logging with actor/controller tracking, delegation-aware OAuth consent with permission limitation notices.
5757+5858+Migration: OAuth-based inbound migration wizard with PLC token flow, offline restore from CAR file + rotation key for disaster recovery, scheduled automatic backups, standalone repo/blob export, did:web DID document editor for self-service identity management.
···1717 "dashboard": "Dashboard",
1818 "backToDashboard": "← Dashboard",
1919 "copied": "Copied!",
2020- "copyToClipboard": "Copy to Clipboard"
2020+ "copyToClipboard": "Copy to Clipboard",
2121+2222+ "verifying": "Verifying...",
2323+ "saving": "Saving...",
2424+ "creating": "Creating...",
2525+ "updating": "Updating...",
2626+ "sending": "Sending...",
2727+ "authenticating": "Authenticating...",
2828+ "checking": "Checking...",
2929+ "redirecting": "Redirecting...",
3030+3131+ "signIn": "Sign In",
3232+ "verify": "Verify",
3333+ "remove": "Remove",
3434+ "revoke": "Revoke",
3535+ "resendCode": "Resend Code",
3636+ "startOver": "Start Over",
3737+ "tryAgain": "Try Again",
3838+3939+ "password": "Password",
4040+ "email": "Email",
4141+ "emailAddress": "Email Address",
4242+ "handle": "Handle",
4343+ "did": "DID",
4444+ "verificationCode": "Verification Code",
4545+ "inviteCode": "Invite Code",
4646+ "newPassword": "New Password",
4747+ "confirmPassword": "Confirm Password",
4848+4949+ "enterSixDigitCode": "Enter 6-digit code",
5050+ "passwordHint": "At least 8 characters",
5151+ "enterPassword": "Enter your password",
5252+ "emailPlaceholder": "you@example.com",
5353+5454+ "verified": "Verified",
5555+ "disabled": "Disabled",
5656+ "available": "Available",
5757+ "deactivated": "Deactivated",
5858+ "unverified": "Unverified",
5959+6060+ "backToLogin": "Back to Login",
6161+ "backToSettings": "Back to Settings",
6262+ "alreadyHaveAccount": "Already have an account?",
6363+ "createAccount": "Create account",
6464+6565+ "passwordsMismatch": "Passwords do not match",
6666+ "passwordTooShort": "Password must be at least 8 characters"
2167 },
2268 "login": {
2369 "title": "Sign In",
···4995 "codeLabel": "Verification Code",
5096 "codePlaceholder": "Enter 6-digit code",
5197 "verifyButton": "Verify Account",
5252- "verifying": "Verifying...",
5353- "resendButton": "Resend Code",
5454- "resending": "Resending...",
5555- "resent": "Verification code resent!",
5656- "backToLogin": "Back to Login"
9898+ "resent": "Verification code resent!"
5799 },
58100 "register": {
59101 "title": "Create Account",
···124166 "inviteCodePlaceholder": "Enter your invite code",
125167 "inviteCodeRequired": "required",
126168 "createButton": "Create Account",
127127- "creating": "Creating account...",
128169 "alreadyHaveAccount": "Already have an account?",
129170 "signIn": "Sign in",
130171 "wantPasswordless": "Want passwordless security?",
···179220 "navAdminDesc": "Server stats and admin operations",
180221 "navDidDocument": "DID Document",
181222 "navDidDocumentDesc": "Manage your DID document for external migrations",
223223+ "navDidDocumentDescActive": "Edit your DID document settings",
224224+ "navBackup": "Download Backup",
225225+ "navBackupDesc": "Download your repository as a CAR file",
226226+ "downloadingBackup": "Downloading...",
227227+ "backupFailed": "Failed to download backup",
182228 "migrated": "Migrated",
183229 "migratedTitle": "Account Migrated",
184230 "migratedMessage": "Your account has migrated to {pds}. Your DID document is still hosted here, and you can update it for future migrations.",
···208254 "serviceEndpointDesc": "The PDS that currently hosts your account data. Update this when migrating.",
209255 "currentPds": "Current PDS URL",
210256 "save": "Save Changes",
211211- "saving": "Saving...",
212257 "success": "DID document updated successfully",
213258 "saveFailed": "Failed to save DID document",
214259 "loadFailed": "Failed to load DID document",
···246291 "yourDomain": "Your Domain",
247292 "yourDomainPlaceholder": "example.com",
248293 "verifyAndUpdate": "Verify & Update Handle",
249249- "verifying": "Verifying...",
250294 "newHandle": "New Handle",
251295 "newHandlePlaceholder": "yourhandle",
252296 "changeHandleButton": "Change Handle",
···262306 "exportData": "Export Data",
263307 "exportDataDescription": "Download your entire repository as a CAR (Content Addressable Archive) file. This includes all your posts, likes, follows, and other data.",
264308 "downloadRepo": "Download Repository",
309309+ "downloadBlobs": "Download Media",
265310 "exporting": "Exporting...",
311311+ "backups": {
312312+ "title": "Backups",
313313+ "description": "Your repository is automatically backed up daily. You can also create manual backups or restore from a previous backup.",
314314+ "enableAutomatic": "Enable automatic backups",
315315+ "enabled": "Automatic backups enabled",
316316+ "disabled": "Automatic backups disabled",
317317+ "toggleFailed": "Failed to update backup setting",
318318+ "noBackups": "No backups available yet.",
319319+ "blocks": "blocks",
320320+ "download": "Download",
321321+ "delete": "Delete",
322322+ "createNow": "Create Backup Now",
323323+ "created": "Backup created successfully",
324324+ "createFailed": "Failed to create backup",
325325+ "downloadFailed": "Failed to download backup",
326326+ "deleted": "Backup deleted",
327327+ "deleteFailed": "Failed to delete backup",
328328+ "restoreTitle": "Restore from Backup",
329329+ "restoreDescription": "Upload a CAR file to restore your repository. This will overwrite your current data.",
330330+ "selectFile": "Select CAR file",
331331+ "selectedFile": "Selected file",
332332+ "restore": "Restore",
333333+ "restoring": "Restoring...",
334334+ "restored": "Repository restored successfully",
335335+ "restoreFailed": "Failed to restore repository"
336336+ },
266337 "deleteAccount": "Delete Account",
267338 "deleteWarning": "This action is irreversible. All your data will be permanently deleted.",
268339 "requestDeletion": "Request Account Deletion",
···291362 "deleteConfirmation": "Are you absolutely sure you want to delete your account? This cannot be undone.",
292363 "deletionFailed": "Failed to delete account",
293364 "repoExported": "Repository exported successfully",
294294- "exportFailed": "Failed to export repository",
365365+ "blobsExported": "Media files exported successfully",
366366+ "noBlobsToExport": "No media files to export",
367367+ "exportFailed": "Failed to export",
295368 "confirmDelete": "Are you absolutely sure you want to delete your account? This cannot be undone."
296369 }
297370 },
···306379 "noPasswords": "No app passwords yet",
307380 "revoke": "Revoke",
308381 "revoking": "Revoking...",
309309- "creating": "Creating...",
310382 "revokeConfirm": "Revoke app password \"{name}\"? Apps using this password will no longer be able to access your account.",
311383 "saveWarningTitle": "Important: Save this app password!",
312384 "saveWarningMessage": "This password is required to sign into apps that don't support passkeys or OAuth. You will only see it once.",
···354426 "used": "Used by @{handle}",
355427 "disabled": "Disabled",
356428 "usedBy": "Used by",
357357- "creating": "Creating...",
358429 "disableConfirm": "Disable this invite code? It can no longer be used.",
359430 "created": "Invite Code Created",
360431 "copy": "Copy",
···482553 "verifyButton": "Verify",
483554 "verifyCodePlaceholder": "Enter verification code",
484555 "submit": "Submit",
485485- "saving": "Saving...",
486556 "savePreferences": "Save Preferences",
487557 "preferencesSaved": "Communication preferences saved",
488558 "verifiedSuccess": "{channel} verified successfully",
···521591 "noCollectionsYet": "No collections yet. Create your first record to get started.",
522592 "loadMore": "Load More",
523593 "recordJson": "Record JSON",
524524- "saving": "Saving...",
525594 "updateRecord": "Update Record",
526595 "collectionNsid": "Collection (NSID)",
527596 "recordKeyOptional": "Record Key (optional)",
528597 "autoGenerated": "Auto-generated if empty (TID)",
529598 "autoGeneratedHint": "Leave empty to auto-generate a TID-based key",
530530- "creating": "Creating...",
531599 "demoPostText": "Hello from my PDS! This is my first post.",
532600 "demoDisplayName": "Your Display Name",
533601 "demoBio": "A short bio about yourself."
···551619 "secondaryLight": "Secondary (Light Mode)",
552620 "secondaryDark": "Secondary (Dark Mode)",
553621 "configSaved": "Server configuration saved",
554554- "saving": "Saving...",
555622 "saveConfig": "Save Configuration",
556623 "serverStats": "Server Statistics",
557624 "users": "Users",
···639706 "title": "Two-Factor Authentication",
640707 "subtitle": "Additional verification is required",
641708 "usePasskey": "Use Passkey",
642642- "useTotp": "Use Authenticator App",
643643- "verifying": "Verifying..."
709709+ "useTotp": "Use Authenticator App"
644710 },
645711 "twoFactorCode": {
646712 "title": "Two-Factor Authentication",
647713 "subtitle": "A verification code has been sent to your {channel}. Enter the code below to continue.",
648714 "codeLabel": "Verification Code",
649715 "codePlaceholder": "Enter 6-digit code",
650650- "verify": "Verify",
651651- "verifying": "Verifying...",
652716 "errors": {
653717 "missingRequestUri": "Missing request_uri parameter",
654718 "verificationFailed": "Verification failed",
···660724 "title": "Enter Authenticator Code",
661725 "subtitle": "Enter the 6-digit code from your authenticator app",
662726 "codePlaceholder": "Enter 6-digit code",
663663- "verify": "Verify",
664664- "verifying": "Verifying...",
665727 "useBackupCode": "Use backup code instead",
666728 "backupCodePlaceholder": "Enter backup code",
667729 "trustDevice": "Trust this device for 30 days",
···691753 "codeLabel": "Verification Code",
692754 "codeHelp": "Copy the entire code from your message, including dashes",
693755 "verifyButton": "Verify Account",
694694- "verify": "Verify",
695695- "verifying": "Verifying...",
696756 "pleaseWait": "Please wait...",
697697- "resendCode": "Resend Code",
698698- "resending": "Resending...",
699699- "sending": "Sending...",
700757 "codeResent": "Verification code resent!",
701758 "codeResentDetail": "Verification code sent! Check your inbox.",
702702- "backToLogin": "Back to Login",
703703- "backToSettings": "Back to Settings",
704759 "verifyingAccount": "Verifying account: @{handle}",
705760 "startOver": "Start over with a different account",
706761 "noPending": "No pending verification found.",
···746801 "resetButton": "Reset Password",
747802 "resetting": "Resetting...",
748803 "success": "Password reset successfully!",
749749- "backToLogin": "Back to Sign In",
750804 "requestNewCode": "Request New Code",
751805 "passwordsMismatch": "Passwords do not match",
752806 "passwordLength": "Password must be at least 8 characters"
···790844 "howItWorks": "How it works",
791845 "howItWorksDetail": "We'll send a secure link to your registered notification channel. Click the link to set a temporary password. Then you can sign in and add a new passkey.",
792846 "sendRecoveryLink": "Send Recovery Link",
793793- "sending": "Sending...",
794794- "backToLogin": "Back to Sign In"
847847+ "sending": "Sending..."
795848 },
796849 "registerPasskey": {
797850 "title": "Create Passkey Account",
···814867 "inviteCode": "Invite Code",
815868 "inviteCodePlaceholder": "Enter your invite code",
816869 "createButton": "Create Account",
817817- "creating": "Creating...",
818870 "continue": "Continue",
819871 "back": "Back",
820872 "alreadyHaveAccount": "Already have an account?",
···911963 "useTotp": "Use Authenticator",
912964 "passwordPlaceholder": "Enter your password",
913965 "totpPlaceholder": "Enter 6-digit code",
914914- "verify": "Verify",
915915- "verifying": "Verifying...",
916966 "authenticating": "Authenticating...",
917967 "passkeyPrompt": "Click the button below to authenticate with your passkey.",
918968 "cancel": "Cancel"
···947997 "handle": "Handle",
948998 "emailOptional": "Email (optional)",
949999 "yourAccessLevel": "Your Access Level",
950950- "creating": "Creating...",
9511000 "createAccount": "Create Account",
9521001 "createDelegatedAccountButton": "+ Create Delegated Account",
9531002 "accountCreated": "Created delegated account: {handle}",
···10591108 "navDesc": "Move your account to or from another PDS",
10601109 "migrateHere": "Migrate Here",
10611110 "migrateHereDesc": "Move your existing AT Protocol account to this PDS from another server.",
10621062- "migrateAway": "Migrate Away",
10631063- "migrateAwayDesc": "Move your account from this PDS to another server.",
10641064- "loginRequired": "Login required",
10651111 "bringDid": "Bring your DID and identity",
10661112 "transferData": "Transfer all your data",
10671113 "keepFollowers": "Keep your followers",
10681068- "exportRepo": "Export your repository",
10691069- "transferToPds": "Transfer to new PDS",
10701070- "updateIdentity": "Update your identity",
10711114 "whatIsMigration": "What is account migration?",
10721115 "whatIsMigrationDesc": "Account migration allows you to move your AT Protocol identity between Personal Data Servers (PDSes). Your DID (decentralized identifier) stays the same, so your followers and social connections are preserved.",
10731116 "beforeMigrate": "Before you migrate",
···10771120 "beforeMigrate4": "Your old PDS will be notified to deactivate your account",
10781121 "importantWarning": "Account migration is a significant action. Make sure you trust the destination PDS and understand that your data will be moved. If something goes wrong, recovery may require manual intervention.",
10791122 "learnMore": "Learn more about migration risks",
10801080- "comingSoon": "Coming soon",
11231123+ "offlineRestore": "Offline Restore",
11241124+ "offlineRestoreDesc": "Restore from backup when your old PDS is unavailable.",
11251125+ "offlineFeature1": "Use a CAR file backup",
11261126+ "offlineFeature2": "Prove ownership with rotation key",
11271127+ "offlineFeature3": "Recovery for shutdown servers",
10811128 "oauthCompleting": "Completing authentication...",
10821129 "oauthFailed": "Authentication Failed",
10831130 "tryAgain": "Try Again",
···10861133 "incomplete": "You have an incomplete migration in progress:",
10871134 "direction": "Direction",
10881135 "migratingHere": "Migrating here",
10891089- "migratingAway": "Migrating away",
10901136 "from": "From",
10911137 "to": "To",
10921138 "progress": "Progress",
···12291275 "error": {
12301276 "title": "Migration Error",
12311277 "desc": "An error occurred during migration.",
12321232- "startOver": "Start Over"
12781278+ "startOver": "Start Over",
12791279+ "unknown": "An unknown error occurred."
12331280 },
12341281 "common": {
12351282 "back": "Back",
···12471294 "warning3": "Your old account will be deactivated after migration"
12481295 }
12491296 },
12501250- "outbound": {
12971297+ "offline": {
12511298 "welcome": {
12521252- "title": "Migrate Away from This PDS",
12531253- "desc": "Move your account to another Personal Data Server.",
12541254- "warning": "After migration, your account here will be deactivated.",
12551255- "didWebNotice": "did:web Migration Notice",
12561256- "didWebNoticeDesc": "Your account uses a did:web identifier ({did}). After migrating, this PDS will continue to serve your DID document pointing to the new PDS. Your identity will remain functional as long as this server is online.",
12571257- "understand": "I understand the risks and want to proceed"
12991299+ "title": "Offline Restore",
13001300+ "desc": "Restore your account when your old PDS is unavailable. This is for disaster recovery when you cannot contact your previous server.",
13011301+ "warningTitle": "Advanced Recovery Method",
13021302+ "warningDesc": "This method requires your rotation key private key. Only use this if your previous PDS has shut down or you cannot access it.",
13031303+ "requirementsTitle": "You will need:",
13041304+ "requirement1": "Your DID (did:plc:...)",
13051305+ "requirement2": "A CAR file backup of your repository",
13061306+ "requirement3": "Your rotation key (private key in hex, base58, or JWK format)",
13071307+ "understand": "I understand this is for offline recovery only"
12581308 },
12591259- "targetPds": {
12601260- "title": "Choose Target PDS",
12611261- "desc": "Enter the URL of the PDS you want to migrate to.",
12621262- "url": "PDS URL",
12631263- "urlPlaceholder": "https://pds.example.com",
12641264- "validate": "Validate & Continue",
13091309+ "provideDid": {
13101310+ "title": "Enter Your DID",
13111311+ "desc": "Enter the DID of the account you want to restore.",
13121312+ "label": "Your DID",
13131313+ "hint": "Your decentralized identifier (e.g., did:plc:abc123...)"
13141314+ },
13151315+ "uploadCar": {
13161316+ "title": "Upload Repository Backup",
13171317+ "desc": "Upload the CAR file containing your repository data.",
13181318+ "label": "CAR File",
13191319+ "hint": "This should be a .car file from a previous backup of your repository",
13201320+ "reuploadWarningTitle": "CAR File Required",
13211321+ "reuploadWarning": "Your session was restored, but you need to re-upload your CAR file. For security reasons, file contents are not stored between sessions."
13221322+ },
13231323+ "rotationKey": {
13241324+ "title": "Provide Rotation Key",
13251325+ "desc": "Enter your rotation key to prove ownership of this DID.",
13261326+ "securityWarningTitle": "Security Warning",
13271327+ "securityWarning1": "Your rotation key is extremely sensitive - anyone with it can take over your identity",
13281328+ "securityWarning2": "Only enter it on trusted devices and connections",
13291329+ "securityWarning3": "The key will not be stored after migration",
13301330+ "label": "Rotation Key",
13311331+ "placeholder": "Paste your rotation key (hex, base58, or JWK)...",
13321332+ "hint": "Supports 64-character hex, base58, or JWK format",
13331333+ "valid": "Rotation key verified! You have control of this DID.",
13341334+ "invalid": "This key is not a valid rotation key for this DID.",
12651335 "validating": "Validating...",
12661266- "connected": "Connected to {name}",
12671267- "inviteRequired": "Invite code required",
12681268- "privacyPolicy": "Privacy Policy",
12691269- "termsOfService": "Terms of Service"
13361336+ "validate": "Validate Key"
12701337 },
12711271- "newAccount": {
12721272- "title": "New Account Details",
12731273- "desc": "Set up your account on the new PDS.",
12741274- "handle": "Handle",
12751275- "availableDomains": "Available domains",
12761276- "email": "Email",
12771277- "password": "Password",
12781278- "confirmPassword": "Confirm Password",
12791279- "inviteCode": "Invite Code"
13381338+ "chooseHandle": {
13391339+ "migratingDid": "Restoring DID"
12801340 },
12811341 "review": {
12821282- "title": "Review Migration",
12831283- "desc": "Please review and confirm your migration details.",
12841284- "currentHandle": "Current Handle",
12851285- "newHandle": "New Handle",
12861286- "sourcePds": "This PDS",
12871287- "targetPds": "Target PDS",
12881288- "confirm": "I confirm I want to migrate my account",
12891289- "startMigration": "Start Migration"
13421342+ "desc": "Please confirm the details of your offline restoration.",
13431343+ "carFile": "CAR File",
13441344+ "rotationKey": "Rotation Key",
13451345+ "warning": "After you click \"Start Migration\", your repository will be imported and your DID will be updated to point to this PDS.",
13461346+ "plcWarningTitle": "Point of No Return",
13471347+ "plcWarning": "Once you start, your DID document will be updated to point to this PDS. If something goes wrong, you can use your rotation key to recover, but you should complete the migration to avoid a broken identity state."
12901348 },
12911349 "migrating": {
12921292- "title": "Migrating Your Account",
12931293- "desc": "Please wait while we transfer your data..."
12941294- },
12951295- "plcToken": {
12961296- "title": "Verify Your Identity",
12971297- "desc": "A verification code has been sent to your email."
13501350+ "title": "Restoring Account",
13511351+ "desc": "Please wait while your account is being restored...",
13521352+ "creating": "Creating account",
13531353+ "importing": "Importing repository",
13541354+ "plcSigning": "Signing identity update",
13551355+ "activating": "Activating account"
12981356 },
12991299- "finalizing": {
13001300- "title": "Finalizing Migration",
13011301- "desc": "Please wait while we complete the migration...",
13021302- "updatingForwarding": "Updating DID document forwarding..."
13571357+ "blobs": {
13581358+ "title": "Migrating Blobs",
13591359+ "desc": "Attempting to recover images and media from your old PDS...",
13601360+ "migrating": "Migrating blobs",
13611361+ "failedTitle": "Some blobs could not be migrated",
13621362+ "failedDesc": "{count} blobs could not be fetched from your old PDS. This may happen if the server is unreachable or the files were deleted.",
13631363+ "sourceUnreachableTitle": "Source PDS Unreachable",
13641364+ "sourceUnreachable": "Could not connect to your old PDS to fetch media files. This is common when migrating from a shut-down server. Your posts will work, but some images may be missing."
13031365 },
13041366 "success": {
13051305- "title": "Migration Complete!",
13061306- "desc": "Your account has been successfully migrated to your new PDS.",
13071307- "newHandle": "New Handle",
13081308- "newPds": "New PDS",
13091309- "nextSteps": "Next Steps",
13101310- "nextSteps1": "Sign in to your new PDS",
13111311- "nextSteps2": "Update any apps with your new credentials",
13121312- "nextSteps3": "Your followers will automatically see your new location",
13131313- "loggingOut": "Logging you out in {seconds} seconds..."
13671367+ "desc": "Your account has been successfully restored to this PDS."
13141368 }
13151369 },
13161370 "progress": {
+154-100
frontend/src/locales/fi.json
···1717 "dashboard": "Hallintapaneeli",
1818 "backToDashboard": "← Hallintapaneeli",
1919 "copied": "Kopioitu!",
2020- "copyToClipboard": "Kopioi"
2020+ "copyToClipboard": "Kopioi",
2121+2222+ "verifying": "Vahvistetaan...",
2323+ "saving": "Tallennetaan...",
2424+ "creating": "Luodaan...",
2525+ "updating": "Päivitetään...",
2626+ "sending": "Lähetetään...",
2727+ "authenticating": "Todennetaan...",
2828+ "checking": "Tarkistetaan...",
2929+ "redirecting": "Ohjataan...",
3030+3131+ "signIn": "Kirjaudu sisään",
3232+ "verify": "Vahvista",
3333+ "remove": "Poista",
3434+ "revoke": "Peruuta",
3535+ "resendCode": "Lähetä koodi uudelleen",
3636+ "startOver": "Aloita alusta",
3737+ "tryAgain": "Yritä uudelleen",
3838+3939+ "password": "Salasana",
4040+ "email": "Sähköposti",
4141+ "emailAddress": "Sähköpostiosoite",
4242+ "handle": "Käsittely",
4343+ "did": "DID",
4444+ "verificationCode": "Vahvistuskoodi",
4545+ "inviteCode": "Kutsukoodi",
4646+ "newPassword": "Uusi salasana",
4747+ "confirmPassword": "Vahvista salasana",
4848+4949+ "enterSixDigitCode": "Syötä 6-numeroinen koodi",
5050+ "passwordHint": "Vähintään 8 merkkiä",
5151+ "enterPassword": "Syötä salasanasi",
5252+ "emailPlaceholder": "sinä@esimerkki.com",
5353+5454+ "verified": "Vahvistettu",
5555+ "disabled": "Poistettu käytöstä",
5656+ "available": "Saatavilla",
5757+ "deactivated": "Deaktivoitu",
5858+ "unverified": "Vahvistamaton",
5959+6060+ "backToLogin": "Takaisin kirjautumiseen",
6161+ "backToSettings": "Takaisin asetuksiin",
6262+ "alreadyHaveAccount": "Onko sinulla jo tili?",
6363+ "createAccount": "Luo tili",
6464+6565+ "passwordsMismatch": "Salasanat eivät täsmää",
6666+ "passwordTooShort": "Salasanan on oltava vähintään 8 merkkiä"
2167 },
2268 "login": {
2369 "title": "Kirjaudu sisään",
···4995 "codeLabel": "Vahvistuskoodi",
5096 "codePlaceholder": "Syötä 6-numeroinen koodi",
5197 "verifyButton": "Vahvista tili",
5252- "verifying": "Vahvistetaan...",
5353- "resendButton": "Lähetä koodi uudelleen",
5454- "resending": "Lähetetään uudelleen...",
5555- "resent": "Vahvistuskoodi lähetetty uudelleen!",
5656- "backToLogin": "Takaisin kirjautumiseen"
9898+ "resent": "Vahvistuskoodi lähetetty uudelleen!"
5799 },
58100 "register": {
59101 "title": "Luo tili",
···124166 "inviteCodePlaceholder": "Syötä kutsukoodisi",
125167 "inviteCodeRequired": "vaaditaan",
126168 "createButton": "Luo tili",
127127- "creating": "Luodaan tiliä...",
128169 "alreadyHaveAccount": "Onko sinulla jo tili?",
129170 "signIn": "Kirjaudu sisään",
130171 "wantPasswordless": "Haluatko salasanattoman turvallisuuden?",
···179220 "navAdminDesc": "Palvelintilastot ja ylläpitotoiminnot",
180221 "navDidDocument": "DID-dokumentti",
181222 "navDidDocumentDesc": "Hallitse DID-dokumenttiasi ulkoisia siirtoja varten",
223223+ "navDidDocumentDescActive": "Muokkaa DID-dokumentin asetuksia",
224224+ "navBackup": "Lataa varmuuskopio",
225225+ "navBackupDesc": "Lataa tietovarastosi CAR-tiedostona",
226226+ "downloadingBackup": "Ladataan...",
227227+ "backupFailed": "Varmuuskopion lataus epäonnistui",
182228 "migrated": "Siirretty",
183229 "migratedTitle": "Tili siirretty",
184230 "migratedMessage": "Tilisi on siirretty palvelimelle {pds}. DID-dokumenttisi isännöidään edelleen täällä, ja voit päivittää sen tulevia siirtoja varten.",
···208254 "serviceEndpointDesc": "PDS, joka tällä hetkellä isännöi tilitietojasi. Päivitä tämä siirron yhteydessä.",
209255 "currentPds": "Nykyinen PDS-URL",
210256 "save": "Tallenna muutokset",
211211- "saving": "Tallennetaan...",
212257 "success": "DID-dokumentti päivitetty onnistuneesti",
213258 "saveFailed": "DID-dokumentin tallennus epäonnistui",
214259 "loadFailed": "DID-dokumentin lataus epäonnistui",
···246291 "yourDomain": "Verkkotunnuksesi",
247292 "yourDomainPlaceholder": "esimerkki.fi",
248293 "verifyAndUpdate": "Vahvista ja päivitä käyttäjänimi",
249249- "verifying": "Vahvistetaan...",
250294 "newHandle": "Uusi käyttäjänimi",
251295 "newHandlePlaceholder": "käyttäjänimesi",
252296 "changeHandleButton": "Vaihda käyttäjänimi",
···262306 "exportData": "Vie tiedot",
263307 "exportDataDescription": "Lataa koko tietovarastosi CAR-tiedostona (Content Addressable Archive). Tämä sisältää kaikki julkaisusi, tykkäyksesi, seuraamisesi ja muut tiedot.",
264308 "downloadRepo": "Lataa tietovarasto",
309309+ "downloadBlobs": "Lataa media",
265310 "exporting": "Viedään...",
311311+ "backups": {
312312+ "title": "Varmuuskopiot",
313313+ "description": "Tietovarastosi varmuuskopioidaan automaattisesti päivittäin. Voit myös luoda manuaalisia varmuuskopioita tai palauttaa aiemmasta varmuuskopiosta.",
314314+ "enableAutomatic": "Ota automaattiset varmuuskopiot käyttöön",
315315+ "enabled": "Automaattiset varmuuskopiot käytössä",
316316+ "disabled": "Automaattiset varmuuskopiot pois käytöstä",
317317+ "toggleFailed": "Varmuuskopioasetuksen päivitys epäonnistui",
318318+ "noBackups": "Varmuuskopioita ei ole vielä saatavilla.",
319319+ "blocks": "lohkoa",
320320+ "download": "Lataa",
321321+ "delete": "Poista",
322322+ "createNow": "Luo varmuuskopio nyt",
323323+ "created": "Varmuuskopio luotu onnistuneesti",
324324+ "createFailed": "Varmuuskopion luonti epäonnistui",
325325+ "downloadFailed": "Varmuuskopion lataus epäonnistui",
326326+ "deleted": "Varmuuskopio poistettu",
327327+ "deleteFailed": "Varmuuskopion poisto epäonnistui",
328328+ "restoreTitle": "Palauta varmuuskopiosta",
329329+ "restoreDescription": "Lataa CAR-tiedosto palauttaaksesi tietovarastosi. Tämä korvaa nykyiset tietosi.",
330330+ "selectFile": "Valitse CAR-tiedosto",
331331+ "selectedFile": "Valittu tiedosto",
332332+ "restore": "Palauta",
333333+ "restoring": "Palautetaan...",
334334+ "restored": "Tietovarasto palautettu onnistuneesti",
335335+ "restoreFailed": "Tietovaraston palautus epäonnistui"
336336+ },
266337 "deleteAccount": "Poista tili",
267338 "deleteWarning": "Tämä toiminto on peruuttamaton. Kaikki tietosi poistetaan pysyvästi.",
268339 "requestDeletion": "Pyydä tilin poistoa",
···291362 "deleteConfirmation": "Oletko täysin varma, että haluat poistaa tilisi? Tätä ei voi perua.",
292363 "deletionFailed": "Tilin poisto epäonnistui",
293364 "repoExported": "Tietovarasto viety",
294294- "exportFailed": "Tietovaraston vienti epäonnistui",
365365+ "blobsExported": "Mediatiedostot viety",
366366+ "noBlobsToExport": "Ei vietäviä mediatiedostoja",
367367+ "exportFailed": "Vienti epäonnistui",
295368 "confirmDelete": "Oletko täysin varma, että haluat poistaa tilisi? Tätä ei voi perua."
296369 }
297370 },
···306379 "noPasswords": "Ei vielä sovellusten salasanoja",
307380 "revoke": "Peruuta",
308381 "revoking": "Peruutetaan...",
309309- "creating": "Luodaan...",
310382 "revokeConfirm": "Peruuta sovelluksen salasana \"{name}\"? Sovellukset, jotka käyttävät tätä salasanaa, eivät enää pääse tilillesi.",
311383 "saveWarningTitle": "Tärkeää: Tallenna tämä sovelluksen salasana!",
312384 "saveWarningMessage": "Tämä salasana tarvitaan kirjautumiseen sovelluksiin, jotka eivät tue pääsyavaimia tai OAuthia. Näet sen vain kerran.",
···354426 "used": "Käyttänyt @{handle}",
355427 "disabled": "Poistettu käytöstä",
356428 "usedBy": "Käyttänyt",
357357- "creating": "Luodaan...",
358429 "disableConfirm": "Poista tämä kutsukoodi käytöstä? Sitä ei voi enää käyttää.",
359430 "created": "Kutsukoodi luotu",
360431 "copy": "Kopioi",
···482553 "verifyButton": "Vahvista",
483554 "verifyCodePlaceholder": "Syötä vahvistuskoodi",
484555 "submit": "Lähetä",
485485- "saving": "Tallennetaan...",
486556 "savePreferences": "Tallenna asetukset",
487557 "preferencesSaved": "Viestintäasetukset tallennettu",
488558 "verifiedSuccess": "{channel} vahvistettu",
···521591 "noCollectionsYet": "Ei vielä kokoelmia. Luo ensimmäinen tietueesi aloittaaksesi.",
522592 "loadMore": "Lataa lisää",
523593 "recordJson": "Tietueen JSON",
524524- "saving": "Tallennetaan...",
525594 "updateRecord": "Päivitä tietue",
526595 "collectionNsid": "Kokoelma (NSID)",
527596 "recordKeyOptional": "Tietueavain (valinnainen)",
528597 "autoGenerated": "Luodaan automaattisesti jos tyhjä (TID)",
529598 "autoGeneratedHint": "Jätä tyhjäksi luodaksesi TID-pohjaisen avaimen automaattisesti",
530530- "creating": "Luodaan...",
531599 "demoPostText": "Hei PDS:ltäni! Tämä on ensimmäinen julkaisuni.",
532600 "demoDisplayName": "Näyttönimesi",
533601 "demoBio": "Lyhyt kuvaus itsestäsi."
···548616 "primaryLight": "Ensisijainen (vaalea tila)",
549617 "primaryDark": "Ensisijainen (tumma tila)",
550618 "configSaved": "Palvelinasetukset tallennettu",
551551- "saving": "Tallennetaan...",
552619 "saveConfig": "Tallenna asetukset",
553620 "serverStats": "Palvelintilastot",
554621 "users": "Käyttäjät",
···639706 "title": "Kaksivaiheinen tunnistautuminen",
640707 "subtitle": "Lisävahvistus vaaditaan",
641708 "usePasskey": "Käytä pääsyavainta",
642642- "useTotp": "Käytä todentajasovellusta",
643643- "verifying": "Vahvistetaan..."
709709+ "useTotp": "Käytä todentajasovellusta"
644710 },
645711 "twoFactorCode": {
646712 "title": "Kaksivaiheinen tunnistautuminen",
647713 "subtitle": "Vahvistuskoodi on lähetetty {channel}. Syötä koodi alla jatkaaksesi.",
648714 "codeLabel": "Vahvistuskoodi",
649715 "codePlaceholder": "Syötä 6-numeroinen koodi",
650650- "verify": "Vahvista",
651651- "verifying": "Vahvistetaan...",
652716 "errors": {
653717 "missingRequestUri": "Puuttuva request_uri-parametri",
654718 "verificationFailed": "Vahvistus epäonnistui",
···660724 "title": "Syötä todentajakoodi",
661725 "subtitle": "Syötä 6-numeroinen koodi todentajasovelluksestasi",
662726 "codePlaceholder": "Syötä 6-numeroinen koodi",
663663- "verify": "Vahvista",
664664- "verifying": "Vahvistetaan...",
665727 "useBackupCode": "Käytä varakoodia sen sijaan",
666728 "backupCodePlaceholder": "Syötä varakoodi",
667729 "trustDevice": "Luota tähän laitteeseen 30 päivää",
···691753 "codeLabel": "Vahvistuskoodi",
692754 "codeHelp": "Kopioi koko koodi viestistäsi, mukaan lukien väliviivat",
693755 "verifyButton": "Vahvista tili",
694694- "verify": "Vahvista",
695695- "verifying": "Vahvistetaan...",
696756 "pleaseWait": "Odota...",
697697- "sending": "Lähetetään...",
698698- "resendCode": "Lähetä koodi uudelleen",
699699- "resending": "Lähetetään uudelleen...",
700757 "codeResent": "Vahvistuskoodi lähetetty uudelleen!",
701758 "codeResentDetail": "Vahvistuskoodi lähetetty! Tarkista saapuneet-kansiosi.",
702759 "verified": "Vahvistettu!",
···706763 "identifierLabel": "Sähköposti tai tunniste",
707764 "identifierPlaceholder": "sinä@esimerkki.fi",
708765 "identifierHelp": "Sähköpostiosoite tai tunniste, johon koodi lähetettiin",
709709- "backToLogin": "Takaisin kirjautumiseen",
710766 "verifyingAccount": "Vahvistetaan tiliä: @{handle}",
711767 "startOver": "Aloita alusta toisella tilillä",
712768 "noPending": "Odottavaa vahvistusta ei löytynyt.",
713769 "noPendingInfo": "Jos loit tilin äskettäin ja sinun on vahvistettava se, sinun on ehkä luotava uusi tili. Jos olet jo vahvistanut tilisi, voit kirjautua sisään.",
714770 "createAccount": "Luo tili",
715771 "signIn": "Kirjaudu sisään",
716716- "backToSettings": "Takaisin asetuksiin",
717772 "emailUpdateCodeHelp": "Koodi lähetettiin nykyiseen sähköpostiosoitteeseesi",
718773 "emailUpdateFailed": "Sähköpostiosoitteen päivitys epäonnistui",
719774 "emailUpdateRequiresAuth": "Sinun on kirjauduttava sisään päivittääksesi sähköpostiosoitteesi.",
···746801 "resetButton": "Palauta salasana",
747802 "resetting": "Palautetaan...",
748803 "success": "Salasana palautettu!",
749749- "backToLogin": "Takaisin kirjautumiseen",
750804 "requestNewCode": "Pyydä uusi koodi",
751805 "passwordsMismatch": "Salasanat eivät täsmää",
752806 "passwordLength": "Salasanan on oltava vähintään 8 merkkiä"
···790844 "howItWorks": "Miten se toimii",
791845 "howItWorksDetail": "Lähetämme suojatun linkin rekisteröityyn ilmoituskanavaasi. Klikkaa linkkiä asettaaksesi väliaikaisen salasanan. Sitten voit kirjautua sisään ja lisätä uuden pääsyavaimen.",
792846 "sendRecoveryLink": "Lähetä palautuslinkki",
793793- "sending": "Lähetetään...",
794794- "backToLogin": "Takaisin kirjautumiseen"
847847+ "sending": "Lähetetään..."
795848 },
796849 "registerPasskey": {
797850 "title": "Luo pääsyavaintili",
···812865 "externalDid": "Sinun did:web",
813866 "externalDidPlaceholder": "did:web:verkkotunnuksesi.fi",
814867 "createButton": "Luo tili",
815815- "creating": "Luodaan...",
816868 "alreadyHaveAccount": "Onko sinulla jo tili?",
817869 "signIn": "Kirjaudu sisään",
818870 "wantPassword": "Haluatko käyttää salasanaa?",
···911963 "useTotp": "Käytä todentajaa",
912964 "passwordPlaceholder": "Syötä salasanasi",
913965 "totpPlaceholder": "Syötä 6-numeroinen koodi",
914914- "verify": "Vahvista",
915915- "verifying": "Vahvistetaan...",
916966 "authenticating": "Todennetaan...",
917967 "passkeyPrompt": "Klikkaa alla olevaa painiketta todentaaksesi pääsyavaimellasi.",
918968 "cancel": "Peruuta"
···9671017 "handle": "Käyttäjänimi",
9681018 "emailOptional": "Sähköposti (valinnainen)",
9691019 "yourAccessLevel": "Käyttöoikeustasosi",
970970- "creating": "Luodaan...",
9711020 "createAccount": "Luo tili",
9721021 "createDelegatedAccountButton": "+ Luo delegoitu tili",
9731022 "accountCreated": "Delegoitu tili luotu: {handle}",
···10591108 "navDesc": "Siirrä tilisi toiseen tai toisesta PDS:stä",
10601109 "migrateHere": "Siirrä tänne",
10611110 "migrateHereDesc": "Siirrä olemassa oleva AT Protocol -tilisi tähän PDS:ään toiselta palvelimelta.",
10621062- "migrateAway": "Siirrä pois",
10631063- "migrateAwayDesc": "Siirrä tilisi tästä PDS:stä toiselle palvelimelle.",
10641064- "loginRequired": "Kirjautuminen vaaditaan",
10651111 "bringDid": "Tuo DID ja identiteettisi",
10661112 "transferData": "Siirrä kaikki tietosi",
10671113 "keepFollowers": "Säilytä seuraajasi",
10681068- "exportRepo": "Vie tietovarastosi",
10691069- "transferToPds": "Siirrä uuteen PDS:ään",
10701070- "updateIdentity": "Päivitä identiteettisi",
10711114 "whatIsMigration": "Mikä on tilin siirto?",
10721115 "whatIsMigrationDesc": "Tilin siirto mahdollistaa AT Protocol -identiteettisi siirtämisen henkilökohtaisten datapalvelimien (PDS) välillä. DID (hajautettu tunniste) pysyy samana, joten seuraajasi ja sosiaaliset yhteytesi säilyvät.",
10731116 "beforeMigrate": "Ennen siirtoa",
···10771120 "beforeMigrate4": "Vanhalle PDS:llesi ilmoitetaan tilisi deaktivoinnista",
10781121 "importantWarning": "Tilin siirto on merkittävä toimenpide. Varmista, että luotat kohde-PDS:ään ja ymmärrät, että tietosi siirretään. Jos jokin menee pieleen, palautus voi vaatia manuaalista toimenpidettä.",
10791122 "learnMore": "Lue lisää siirron riskeistä",
10801080- "comingSoon": "Tulossa pian",
11231123+ "offlineRestore": "Offline-palautus",
11241124+ "offlineRestoreDesc": "Palauta varmuuskopiosta, kun vanha PDS ei ole käytettävissä.",
11251125+ "offlineFeature1": "Käytä CAR-tiedoston varmuuskopiota",
11261126+ "offlineFeature2": "Todista omistajuus rotaatioavaimella",
11271127+ "offlineFeature3": "Palautus suljetuille palvelimille",
10811128 "oauthCompleting": "Viimeistellään todennusta...",
10821129 "oauthFailed": "Todennus epäonnistui",
10831130 "tryAgain": "Yritä uudelleen",
···10861133 "incomplete": "Sinulla on keskeneräinen siirto:",
10871134 "direction": "Suunta",
10881135 "migratingHere": "Siirretään tänne",
10891089- "migratingAway": "Siirretään pois",
10901136 "from": "Mistä",
10911137 "to": "Minne",
10921138 "progress": "Edistyminen",
···12291275 "error": {
12301276 "title": "Siirtovirhe",
12311277 "desc": "Siirron aikana tapahtui virhe.",
12321232- "startOver": "Aloita alusta"
12781278+ "startOver": "Aloita alusta",
12791279+ "unknown": "Tuntematon virhe tapahtui."
12331280 },
12341281 "common": {
12351282 "back": "Takaisin",
···12471294 "warning3": "Vanha tilisi deaktivoidaan siirron jälkeen"
12481295 }
12491296 },
12501250- "outbound": {
12971297+ "offline": {
12511298 "welcome": {
12521252- "title": "Siirrä pois tästä PDS:stä",
12531253- "desc": "Siirrä tilisi toiseen henkilökohtaiseen datapalvelimeen.",
12541254- "warning": "Siirron jälkeen tilisi täällä deaktivoidaan.",
12551255- "didWebNotice": "did:web-siirtoilmoitus",
12561256- "didWebNoticeDesc": "Tilisi käyttää did:web-tunnistetta ({did}). Siirron jälkeen tämä PDS jatkaa DID-dokumenttisi tarjoamista osoittaen uuteen PDS:ään. Identiteettisi toimii niin kauan kuin tämä palvelin on päällä.",
12571257- "understand": "Ymmärrän riskit ja haluan jatkaa"
12991299+ "title": "Palauta varmuuskopiosta",
13001300+ "desc": "Palauta tilisi CAR-tiedoston varmuuskopiolla ja rotaatioavaimella. Käytä tätä, kun edellinen PDS ei ole käytettävissä.",
13011301+ "warningTitle": "Milloin käyttää tätä menetelmää",
13021302+ "warningDesc": "Tämä offline-palautus on katastrofipalautukseen, kun vanha PDS on suljettu, tavoittamattomissa tai sinut on lukittu ulos. Jos vanha PDS on edelleen käytettävissä, käytä normaalia siirtoa.",
13031303+ "requirementsTitle": "Tarvitset",
13041304+ "requirement1": "CAR-tiedoston varmuuskopion tietovarastostasi",
13051305+ "requirement2": "Rotaatioavaimesi (DID:n yksityinen avain)",
13061306+ "requirement3": "DID:si (did:plc:xxx)",
13071307+ "understand": "Ymmärrän ja haluan jatkaa"
12581308 },
12591259- "targetPds": {
12601260- "title": "Valitse kohde-PDS",
12611261- "desc": "Syötä sen PDS:n URL, johon haluat siirtyä.",
12621262- "url": "PDS URL",
12631263- "urlPlaceholder": "https://pds.example.com",
12641264- "validate": "Vahvista ja jatka",
12651265- "validating": "Vahvistetaan...",
12661266- "connected": "Yhdistetty: {name}",
12671267- "inviteRequired": "Kutsukoodi vaaditaan",
12681268- "privacyPolicy": "Tietosuojakäytäntö",
12691269- "termsOfService": "Käyttöehdot"
13091309+ "provideDid": {
13101310+ "title": "Syötä DID:si",
13111311+ "desc": "Syötä palautettavan tilin DID.",
13121312+ "label": "DID:si",
13131313+ "hint": "Hajautettu tunnistesi (esim. did:plc:abc123)"
12701314 },
12711271- "newAccount": {
12721272- "title": "Uuden tilin tiedot",
12731273- "desc": "Määritä tilisi uudessa PDS:ssä.",
12741274- "handle": "Käyttäjätunnus",
12751275- "availableDomains": "Käytettävissä olevat verkkotunnukset",
12761276- "email": "Sähköposti",
12771277- "password": "Salasana",
12781278- "confirmPassword": "Vahvista salasana",
12791279- "inviteCode": "Kutsukoodi"
13151315+ "uploadCar": {
13161316+ "title": "Lataa CAR-tiedosto",
13171317+ "desc": "Lataa tietovaraston varmuuskopiotiedostosi.",
13181318+ "label": "CAR-tiedosto",
13191319+ "hint": "Valitse .car-tiedosto varmuuskopiostasi",
13201320+ "reuploadWarningTitle": "CAR-tiedosto vaaditaan",
13211321+ "reuploadWarning": "Istuntosi palautettiin, mutta sinun täytyy ladata CAR-tiedostosi uudelleen. Turvallisuussyistä tiedostosisältöä ei tallenneta istuntojen välillä."
12801322 },
12811281- "review": {
12821282- "title": "Tarkista siirto",
12831283- "desc": "Tarkista ja vahvista siirtotietosi.",
12841284- "currentHandle": "Nykyinen käyttäjätunnus",
12851285- "newHandle": "Uusi käyttäjätunnus",
12861286- "sourcePds": "Tämä PDS",
12871287- "targetPds": "Kohde-PDS",
12881288- "confirm": "Vahvistan haluavani siirtää tilini",
12891289- "startMigration": "Aloita siirto"
13231323+ "rotationKey": {
13241324+ "title": "Anna rotaatioavain",
13251325+ "desc": "Anna rotaatioavaimesi todistaaksesi tämän DID:n omistajuuden.",
13261326+ "securityWarningTitle": "Turvallisuusvaroitus",
13271327+ "securityWarning1": "Rotaatioavaimesi on erittäin arkaluonteinen - kohtele sitä kuten pääsalasanaa",
13281328+ "securityWarning2": "Syötä se vain luotetuilla laitteilla ja verkoilla",
13291329+ "securityWarning3": "Tätä avainta ei tallenneta siirron jälkeen",
13301330+ "label": "Rotaatioavain",
13311331+ "placeholder": "Syötä yksityinen avain (hex, base58 tai JWK)",
13321332+ "hint": "Yksityinen avain, joka vastaa yhtä DID-dokumentin rotaatioavaimista",
13331333+ "valid": "Avain on kelvollinen ja vastaa DID:si rotaatioavainta",
13341334+ "invalid": "Avain ei vastaa mitään DID-dokumentin rotaatioavainta",
13351335+ "validating": "Vahvistetaan avainta...",
13361336+ "validate": "Vahvista avain"
12901337 },
12911291- "migrating": {
12921292- "title": "Siirretään tiliäsi",
12931293- "desc": "Odota, kun siirrämme tietojasi..."
13381338+ "chooseHandle": {
13391339+ "migratingDid": "Palautetaan DID"
12941340 },
12951295- "plcToken": {
12961296- "title": "Vahvista henkilöllisyytesi",
12971297- "desc": "Vahvistuskoodi on lähetetty sähköpostiisi."
13411341+ "review": {
13421342+ "desc": "Tarkista offline-palautuksen tiedot.",
13431343+ "carFile": "CAR-tiedosto",
13441344+ "rotationKey": "Rotaatioavain",
13451345+ "warning": "Kun aloitat palautuksen, identiteettisi päivitetään osoittamaan tähän PDS:ään. Tätä ei voi helposti perua.",
13461346+ "plcWarningTitle": "Ei paluuta",
13471347+ "plcWarning": "Kun aloitat, DID-dokumenttisi päivitetään osoittamaan tähän PDS:ään. Jos jokin menee pieleen, voit käyttää rotaatioavaintasi palautumiseen, mutta sinun tulisi suorittaa siirto loppuun välttääksesi rikkinäisen identiteettitilan."
12981348 },
12991299- "finalizing": {
13001300- "title": "Viimeistellään siirtoa",
13011301- "desc": "Odota, kun viimeistelemme siirtoa...",
13021302- "updatingForwarding": "Päivitetään DID-dokumentin uudelleenohjausta..."
13491349+ "migrating": {
13501350+ "title": "Palautetaan tiliä",
13511351+ "desc": "Odota, tiliäsi palautetaan...",
13521352+ "creating": "Luodaan tili",
13531353+ "importing": "Tuodaan tietovarastoa",
13541354+ "plcSigning": "Päivitetään identiteettiä",
13551355+ "activating": "Aktivoidaan tili"
13031356 },
13041357 "success": {
13051305- "title": "Siirto valmis!",
13061306- "desc": "Tilisi on siirretty onnistuneesti uuteen PDS:ääsi.",
13071307- "newHandle": "Uusi käyttäjätunnus",
13081308- "newPds": "Uusi PDS",
13091309- "nextSteps": "Seuraavat vaiheet",
13101310- "nextSteps1": "Kirjaudu uuteen PDS:ääsi",
13111311- "nextSteps2": "Päivitä sovellukset uusilla tunnuksillasi",
13121312- "nextSteps3": "Seuraajasi näkevät automaattisesti uuden sijaintisi",
13131313- "loggingOut": "Kirjaudutaan ulos {seconds} sekunnin kuluttua..."
13581358+ "desc": "Tilisi on palautettu onnistuneesti tähän PDS:ään."
13591359+ },
13601360+ "blobs": {
13611361+ "title": "Siirretään blob-tiedostoja",
13621362+ "desc": "Yritetään palauttaa kuvia ja mediaa vanhasta PDS:stäsi...",
13631363+ "migrating": "Siirretään blob-tiedostoja",
13641364+ "failedTitle": "Joitain blob-tiedostoja ei voitu siirtää",
13651365+ "failedDesc": "{count} blob-tiedostoa ei voitu hakea vanhasta PDS:stäsi. Tämä voi tapahtua, jos palvelin ei ole tavoitettavissa tai tiedostot on poistettu.",
13661366+ "sourceUnreachableTitle": "Lähde-PDS ei tavoitettavissa",
13671367+ "sourceUnreachable": "Ei voitu yhdistää vanhaan PDS:ääsi mediatiedostojen hakemiseksi. Tämä on yleistä siirrettäessä suljetulta palvelimelta. Julkaisusi toimivat, mutta joitain kuvia saattaa puuttua."
13141368 }
13151369 },
13161370 "progress": {
···1717 "dashboard": "대시보드",
1818 "backToDashboard": "← 대시보드",
1919 "copied": "복사됨!",
2020- "copyToClipboard": "클립보드에 복사"
2020+ "copyToClipboard": "클립보드에 복사",
2121+ "verifying": "확인 중...",
2222+ "saving": "저장 중...",
2323+ "creating": "생성 중...",
2424+ "updating": "업데이트 중...",
2525+ "sending": "전송 중...",
2626+ "authenticating": "인증 중...",
2727+ "checking": "확인 중...",
2828+ "redirecting": "리디렉션 중...",
2929+ "signIn": "로그인",
3030+ "verify": "확인",
3131+ "remove": "삭제",
3232+ "revoke": "취소",
3333+ "resendCode": "코드 재전송",
3434+ "startOver": "처음부터 다시",
3535+ "tryAgain": "다시 시도",
3636+ "password": "비밀번호",
3737+ "email": "이메일",
3838+ "emailAddress": "이메일 주소",
3939+ "handle": "핸들",
4040+ "did": "DID",
4141+ "verificationCode": "인증 코드",
4242+ "inviteCode": "초대 코드",
4343+ "newPassword": "새 비밀번호",
4444+ "confirmPassword": "비밀번호 확인",
4545+ "enterSixDigitCode": "6자리 코드 입력",
4646+ "passwordHint": "8자 이상",
4747+ "enterPassword": "비밀번호를 입력하세요",
4848+ "emailPlaceholder": "you@example.com",
4949+ "verified": "인증됨",
5050+ "disabled": "비활성화됨",
5151+ "available": "사용 가능",
5252+ "deactivated": "비활성화됨",
5353+ "unverified": "미인증",
5454+ "backToLogin": "로그인으로 돌아가기",
5555+ "backToSettings": "설정으로 돌아가기",
5656+ "alreadyHaveAccount": "이미 계정이 있으신가요?",
5757+ "createAccount": "계정 만들기",
5858+ "passwordsMismatch": "비밀번호가 일치하지 않습니다",
5959+ "passwordTooShort": "비밀번호는 8자 이상이어야 합니다"
2160 },
2261 "login": {
2362 "title": "로그인",
···4988 "codeLabel": "인증 코드",
5089 "codePlaceholder": "6자리 코드 입력",
5190 "verifyButton": "계정 인증",
5252- "verifying": "인증 중...",
5353- "resendButton": "코드 다시 보내기",
5454- "resending": "전송 중...",
5555- "resent": "인증 코드를 다시 보냈습니다!",
5656- "backToLogin": "로그인으로 돌아가기"
9191+ "resent": "인증 코드를 다시 보냈습니다!"
5792 },
5893 "register": {
5994 "title": "계정 만들기",
···124159 "inviteCodePlaceholder": "초대 코드 입력",
125160 "inviteCodeRequired": "필수",
126161 "createButton": "계정 만들기",
127127- "creating": "계정 생성 중...",
128162 "alreadyHaveAccount": "이미 계정이 있으신가요?",
129163 "signIn": "로그인",
130164 "wantPasswordless": "비밀번호 없는 보안을 원하시나요?",
···179213 "navAdminDesc": "서버 통계 및 관리 작업",
180214 "navDidDocument": "DID 문서",
181215 "navDidDocumentDesc": "DID 문서 및 키 관리",
216216+ "navDidDocumentDescActive": "DID 문서 설정 편집",
217217+ "navBackup": "백업 다운로드",
218218+ "navBackupDesc": "저장소를 CAR 파일로 다운로드",
219219+ "downloadingBackup": "다운로드 중...",
220220+ "backupFailed": "백업 다운로드 실패",
182221 "migrated": "마이그레이션됨",
183222 "migratedTitle": "계정 마이그레이션됨",
184223 "migratedMessage": "계정이 {pds}로 마이그레이션되었습니다. DID 문서는 여전히 여기에서 호스팅됩니다.",
···208247 "serviceEndpointDesc": "현재 계정 데이터를 호스팅하는 PDS입니다. 마이그레이션할 때 업데이트하세요.",
209248 "currentPds": "현재 PDS URL",
210249 "save": "변경사항 저장",
211211- "saving": "저장 중...",
212250 "success": "DID 문서가 업데이트되었습니다",
213251 "saveFailed": "DID 문서 저장에 실패했습니다",
214252 "loadFailed": "DID 문서 로드에 실패했습니다",
···246284 "yourDomain": "도메인",
247285 "yourDomainPlaceholder": "example.com",
248286 "verifyAndUpdate": "확인 후 핸들 업데이트",
249249- "verifying": "확인 중...",
250287 "newHandle": "새 핸들",
251288 "newHandlePlaceholder": "yourhandle",
252289 "changeHandleButton": "핸들 변경",
···262299 "exportData": "데이터 내보내기",
263300 "exportDataDescription": "전체 저장소를 CAR (Content Addressable Archive) 파일로 다운로드합니다. 모든 게시물, 좋아요, 팔로우 및 기타 데이터가 포함됩니다.",
264301 "downloadRepo": "저장소 다운로드",
302302+ "downloadBlobs": "미디어 다운로드",
265303 "exporting": "내보내기 중...",
304304+ "backups": {
305305+ "title": "백업",
306306+ "description": "자동 백업을 관리하고 계정 데이터를 복원하세요. 백업에는 모든 기록과 blob이 포함됩니다.",
307307+ "enableAutomatic": "자동 백업",
308308+ "enabled": "활성화됨",
309309+ "disabled": "비활성화됨",
310310+ "toggleFailed": "백업 설정 변경 실패",
311311+ "noBackups": "아직 백업이 없습니다",
312312+ "blocks": "블록",
313313+ "download": "다운로드",
314314+ "delete": "삭제",
315315+ "createNow": "지금 백업 생성",
316316+ "created": "백업이 생성되었습니다",
317317+ "createFailed": "백업 생성 실패",
318318+ "downloadFailed": "백업 다운로드 실패",
319319+ "deleted": "백업이 삭제되었습니다",
320320+ "deleteFailed": "백업 삭제 실패",
321321+ "restoreTitle": "백업에서 복원",
322322+ "restoreDescription": "이전에 내보낸 CAR 파일에서 계정 데이터를 복원합니다. 이렇게 하면 현재 저장소가 업로드한 백업으로 교체됩니다.",
323323+ "selectFile": "CAR 파일 선택",
324324+ "selectedFile": "선택된 파일",
325325+ "restore": "백업 복원",
326326+ "restoring": "복원 중...",
327327+ "restored": "백업이 성공적으로 복원되었습니다",
328328+ "restoreFailed": "백업 복원 실패"
329329+ },
266330 "deleteAccount": "계정 삭제",
267331 "deleteWarning": "이 작업은 되돌릴 수 없습니다. 모든 데이터가 영구적으로 삭제됩니다.",
268332 "requestDeletion": "계정 삭제 요청",
···291355 "deleteConfirmation": "정말로 계정을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.",
292356 "deletionFailed": "계정 삭제에 실패했습니다",
293357 "repoExported": "저장소를 내보냈습니다",
294294- "exportFailed": "저장소 내보내기에 실패했습니다",
358358+ "blobsExported": "미디어 파일을 내보냈습니다",
359359+ "noBlobsToExport": "내보낼 미디어 파일이 없습니다",
360360+ "exportFailed": "내보내기에 실패했습니다",
295361 "confirmDelete": "정말로 계정을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다."
296362 }
297363 },
···306372 "noPasswords": "앱 비밀번호가 아직 없습니다",
307373 "revoke": "취소",
308374 "revoking": "취소 중...",
309309- "creating": "생성 중...",
310375 "revokeConfirm": "앱 비밀번호 \"{name}\"을(를) 취소하시겠습니까? 이 비밀번호를 사용하는 앱은 더 이상 계정에 액세스할 수 없습니다.",
311376 "saveWarningTitle": "중요: 이 앱 비밀번호를 저장하세요!",
312377 "saveWarningMessage": "이 비밀번호는 패스키 또는 OAuth를 지원하지 않는 앱에 로그인하는 데 필요합니다. 한 번만 볼 수 있습니다.",
···354419 "used": "@{handle}이(가) 사용함",
355420 "disabled": "비활성화됨",
356421 "usedBy": "사용자",
357357- "creating": "생성 중...",
358422 "disableConfirm": "이 초대 코드를 비활성화하시겠습니까? 더 이상 사용할 수 없습니다.",
359423 "created": "초대 코드가 생성되었습니다",
360424 "copy": "복사",
···482546 "verifyButton": "인증",
483547 "verifyCodePlaceholder": "인증 코드 입력",
484548 "submit": "제출",
485485- "saving": "저장 중...",
486549 "savePreferences": "설정 저장",
487550 "preferencesSaved": "통신 설정이 저장되었습니다",
488551 "verifiedSuccess": "{channel} 인증 완료",
···521584 "noCollectionsYet": "컬렉션이 아직 없습니다. 첫 번째 레코드를 만들어 시작하세요.",
522585 "loadMore": "더 불러오기",
523586 "recordJson": "레코드 JSON",
524524- "saving": "저장 중...",
525587 "updateRecord": "레코드 업데이트",
526588 "collectionNsid": "컬렉션 (NSID)",
527589 "recordKeyOptional": "레코드 키 (선택사항)",
528590 "autoGenerated": "비워두면 자동 생성 (TID)",
529591 "autoGeneratedHint": "비워두면 TID 기반 키가 자동 생성됩니다",
530530- "creating": "생성 중...",
531592 "demoPostText": "안녕하세요, 제 PDS에서 보내는 첫 번째 게시물입니다!",
532593 "demoDisplayName": "표시 이름",
533594 "demoBio": "간단한 자기소개를 작성하세요."
···548609 "primaryLight": "기본 (라이트 모드)",
549610 "primaryDark": "기본 (다크 모드)",
550611 "configSaved": "서버 설정이 저장되었습니다",
551551- "saving": "저장 중...",
552612 "saveConfig": "설정 저장",
553613 "serverStats": "서버 통계",
554614 "users": "사용자",
···639699 "title": "2단계 인증",
640700 "subtitle": "추가 확인이 필요합니다",
641701 "usePasskey": "패스키 사용",
642642- "useTotp": "인증 앱 사용",
643643- "verifying": "확인 중..."
702702+ "useTotp": "인증 앱 사용"
644703 },
645704 "twoFactorCode": {
646705 "title": "2단계 인증",
647706 "subtitle": "{channel}(으)로 인증 코드를 보냈습니다. 아래에 코드를 입력하여 계속하세요.",
648707 "codeLabel": "인증 코드",
649708 "codePlaceholder": "6자리 코드 입력",
650650- "verify": "확인",
651651- "verifying": "확인 중...",
652709 "errors": {
653710 "missingRequestUri": "request_uri 매개변수가 없습니다",
654711 "verificationFailed": "인증에 실패했습니다",
···660717 "title": "인증 코드 입력",
661718 "subtitle": "인증 앱의 6자리 코드를 입력하세요",
662719 "codePlaceholder": "6자리 코드 입력",
663663- "verify": "확인",
664664- "verifying": "확인 중...",
665720 "useBackupCode": "백업 코드 사용",
666721 "backupCodePlaceholder": "백업 코드 입력",
667722 "trustDevice": "이 기기를 30일간 신뢰",
···691746 "codeLabel": "인증 코드",
692747 "codeHelp": "메시지에서 하이픈을 포함한 전체 코드를 복사하세요",
693748 "verifyButton": "계정 인증",
694694- "verify": "인증",
695695- "verifying": "인증 중...",
696749 "pleaseWait": "잠시 기다려 주세요...",
697697- "sending": "전송 중...",
698698- "resendCode": "코드 다시 보내기",
699699- "resending": "전송 중...",
700750 "codeResent": "인증 코드를 다시 보냈습니다!",
701751 "codeResentDetail": "인증 코드가 전송되었습니다! 받은 편지함을 확인하세요.",
702752 "verified": "인증 완료!",
···706756 "identifierLabel": "이메일 또는 식별자",
707757 "identifierPlaceholder": "you@example.com",
708758 "identifierHelp": "코드가 전송된 이메일 주소 또는 식별자",
709709- "backToLogin": "로그인으로 돌아가기",
710759 "verifyingAccount": "인증 중인 계정: @{handle}",
711760 "startOver": "다른 계정으로 다시 시작",
712761 "noPending": "보류 중인 인증이 없습니다.",
713762 "noPendingInfo": "최근에 계정을 만들고 인증이 필요한 경우 새 계정을 만들어야 합니다. 이미 계정을 인증한 경우 로그인할 수 있습니다.",
714763 "createAccount": "계정 만들기",
715764 "signIn": "로그인",
716716- "backToSettings": "설정으로 돌아가기",
717765 "emailUpdateCodeHelp": "코드가 현재 이메일 주소로 전송되었습니다",
718766 "emailUpdateFailed": "이메일 주소 업데이트 실패",
719767 "emailUpdateRequiresAuth": "이메일 주소를 업데이트하려면 로그인해야 합니다.",
···746794 "resetButton": "비밀번호 재설정",
747795 "resetting": "재설정 중...",
748796 "success": "비밀번호가 재설정되었습니다!",
749749- "backToLogin": "로그인으로 돌아가기",
750797 "requestNewCode": "새 코드 요청",
751798 "passwordsMismatch": "비밀번호가 일치하지 않습니다",
752799 "passwordLength": "비밀번호는 8자 이상이어야 합니다"
···790837 "howItWorks": "작동 방식",
791838 "howItWorksDetail": "등록된 알림 채널로 보안 링크를 보냅니다. 링크를 클릭하여 임시 비밀번호를 설정합니다. 그런 다음 로그인하여 새 패스키를 추가할 수 있습니다.",
792839 "sendRecoveryLink": "복구 링크 보내기",
793793- "sending": "전송 중...",
794794- "backToLogin": "로그인으로 돌아가기"
840840+ "sending": "전송 중..."
795841 },
796842 "registerPasskey": {
797843 "title": "패스키 계정 만들기",
···812858 "externalDid": "귀하의 did:web",
813859 "externalDidPlaceholder": "did:web:yourdomain.com",
814860 "createButton": "계정 만들기",
815815- "creating": "생성 중...",
816861 "alreadyHaveAccount": "이미 계정이 있으신가요?",
817862 "signIn": "로그인",
818863 "wantPassword": "비밀번호를 사용하시겠습니까?",
···911956 "useTotp": "인증 앱 사용",
912957 "passwordPlaceholder": "비밀번호 입력",
913958 "totpPlaceholder": "6자리 코드 입력",
914914- "verify": "확인",
915915- "verifying": "확인 중...",
916959 "authenticating": "인증 중...",
917960 "passkeyPrompt": "아래 버튼을 클릭하여 패스키로 인증하세요.",
918961 "cancel": "취소"
···9851028 "createAccount": "계정 생성",
9861029 "createDelegatedAccount": "위임 계정 생성",
9871030 "createDelegatedAccountButton": "+ 위임 계정 생성",
988988- "creating": "생성 중...",
9891031 "emailOptional": "이메일 (선택사항)",
9901032 "failedToAddController": "컨트롤러 추가에 실패했습니다",
9911033 "failedToCreateAccount": "위임 계정 생성에 실패했습니다",
···10591101 "navDesc": "다른 PDS로 또는 다른 PDS에서 계정 이동",
10601102 "migrateHere": "여기로 마이그레이션",
10611103 "migrateHereDesc": "기존 AT Protocol 계정을 다른 서버에서 이 PDS로 이동합니다.",
10621062- "migrateAway": "다른 곳으로 마이그레이션",
10631063- "migrateAwayDesc": "이 PDS에서 다른 서버로 계정을 이동합니다.",
10641064- "loginRequired": "로그인 필요",
10651104 "bringDid": "DID와 아이덴티티 가져오기",
10661105 "transferData": "모든 데이터 전송",
10671106 "keepFollowers": "팔로워 유지",
10681068- "exportRepo": "저장소 내보내기",
10691069- "transferToPds": "새 PDS로 전송",
10701070- "updateIdentity": "아이덴티티 업데이트",
10711107 "whatIsMigration": "계정 마이그레이션이란?",
10721108 "whatIsMigrationDesc": "계정 마이그레이션을 통해 AT Protocol 아이덴티티를 개인 데이터 서버(PDS) 간에 이동할 수 있습니다. DID(분산 식별자)는 동일하게 유지되므로 팔로워와 소셜 연결이 보존됩니다.",
10731109 "beforeMigrate": "마이그레이션 전 확인사항",
···10771113 "beforeMigrate4": "이전 PDS에 계정 비활성화가 통보됩니다",
10781114 "importantWarning": "계정 마이그레이션은 중요한 작업입니다. 대상 PDS를 신뢰하고 데이터가 이동된다는 것을 이해하세요. 문제가 발생하면 수동 복구가 필요할 수 있습니다.",
10791115 "learnMore": "마이그레이션 위험에 대해 자세히 알아보기",
10801080- "comingSoon": "곧 출시 예정",
11161116+ "offlineRestore": "오프라인 복원",
11171117+ "offlineRestoreDesc": "이전 PDS를 사용할 수 없을 때 백업에서 복원합니다.",
11181118+ "offlineFeature1": "CAR 파일 백업 사용",
11191119+ "offlineFeature2": "회전 키로 소유권 증명",
11201120+ "offlineFeature3": "종료된 서버 복구",
10811121 "oauthCompleting": "인증 완료 중...",
10821122 "oauthFailed": "인증 실패",
10831123 "tryAgain": "다시 시도",
···10861126 "incomplete": "완료되지 않은 마이그레이션이 있습니다:",
10871127 "direction": "방향",
10881128 "migratingHere": "여기로 마이그레이션 중",
10891089- "migratingAway": "다른 곳으로 마이그레이션 중",
10901129 "from": "출발지",
10911130 "to": "목적지",
10921131 "progress": "진행 상황",
···12291268 "error": {
12301269 "title": "마이그레이션 오류",
12311270 "desc": "마이그레이션 중 오류가 발생했습니다.",
12321232- "startOver": "처음부터 다시 시작"
12711271+ "startOver": "처음부터 다시 시작",
12721272+ "unknown": "알 수 없는 오류가 발생했습니다."
12331273 },
12341274 "common": {
12351275 "back": "뒤로",
···12471287 "warning3": "마이그레이션 후 이전 계정은 비활성화됩니다"
12481288 }
12491289 },
12501250- "outbound": {
12901290+ "offline": {
12511291 "welcome": {
12521252- "title": "이 PDS에서 마이그레이션",
12531253- "desc": "계정을 다른 개인 데이터 서버로 이동합니다.",
12541254- "warning": "마이그레이션 후 이 PDS에서 계정이 비활성화됩니다.",
12551255- "didWebNotice": "did:web 마이그레이션 알림",
12561256- "didWebNoticeDesc": "귀하의 계정은 did:web 식별자({did})를 사용합니다. 마이그레이션 후 이 PDS는 새 PDS를 가리키는 DID 문서를 계속 제공합니다. 이 서버가 온라인인 한 아이덴티티는 계속 작동합니다.",
12571257- "understand": "위험을 이해하고 계속 진행합니다"
12921292+ "title": "백업에서 복원",
12931293+ "desc": "CAR 파일 백업과 회전 키를 사용하여 계정을 복원합니다. 이전 PDS를 사용할 수 없을 때 사용하세요.",
12941294+ "warningTitle": "이 방법을 사용해야 할 때",
12951295+ "warningDesc": "이 오프라인 복원은 이전 PDS가 종료되었거나, 접근할 수 없거나, 잠긴 경우의 재해 복구용입니다. 이전 PDS가 여전히 사용 가능하면 표준 마이그레이션을 사용하세요.",
12961296+ "requirementsTitle": "필요한 것",
12971297+ "requirement1": "저장소의 CAR 파일 백업",
12981298+ "requirement2": "회전 키 (DID의 개인 키)",
12991299+ "requirement3": "당신의 DID (did:plc:xxx)",
13001300+ "understand": "이해하고 계속 진행합니다"
12581301 },
12591259- "targetPds": {
12601260- "title": "대상 PDS 선택",
12611261- "desc": "마이그레이션할 PDS의 URL을 입력하세요.",
12621262- "url": "PDS URL",
12631263- "urlPlaceholder": "https://pds.example.com",
12641264- "validate": "확인 및 계속",
12651265- "validating": "확인 중...",
12661266- "connected": "{name}에 연결됨",
12671267- "inviteRequired": "초대 코드 필요",
12681268- "privacyPolicy": "개인정보 처리방침",
12691269- "termsOfService": "서비스 약관"
13021302+ "provideDid": {
13031303+ "title": "DID 입력",
13041304+ "desc": "복원할 계정의 DID를 입력하세요.",
13051305+ "label": "당신의 DID",
13061306+ "hint": "분산 식별자 (예: did:plc:abc123)"
12701307 },
12711271- "newAccount": {
12721272- "title": "새 계정 세부 정보",
12731273- "desc": "새 PDS에서 계정을 설정합니다.",
12741274- "handle": "핸들",
12751275- "availableDomains": "사용 가능한 도메인",
12761276- "email": "이메일",
12771277- "password": "비밀번호",
12781278- "confirmPassword": "비밀번호 확인",
12791279- "inviteCode": "초대 코드"
13081308+ "uploadCar": {
13091309+ "title": "CAR 파일 업로드",
13101310+ "desc": "저장소 백업 파일을 업로드하세요.",
13111311+ "label": "CAR 파일",
13121312+ "hint": "백업에서 .car 파일을 선택하세요",
13131313+ "reuploadWarningTitle": "CAR 파일 필요",
13141314+ "reuploadWarning": "세션이 복원되었지만 CAR 파일을 다시 업로드해야 합니다. 보안상의 이유로 파일 내용은 세션 간에 저장되지 않습니다."
12801315 },
12811281- "review": {
12821282- "title": "마이그레이션 검토",
12831283- "desc": "마이그레이션 세부 정보를 검토하고 확인하세요.",
12841284- "currentHandle": "현재 핸들",
12851285- "newHandle": "새 핸들",
12861286- "sourcePds": "이 PDS",
12871287- "targetPds": "대상 PDS",
12881288- "confirm": "계정 마이그레이션을 확인합니다",
12891289- "startMigration": "마이그레이션 시작"
13161316+ "rotationKey": {
13171317+ "title": "회전 키 제공",
13181318+ "desc": "이 DID의 소유권을 증명하기 위해 회전 키를 입력하세요.",
13191319+ "securityWarningTitle": "보안 경고",
13201320+ "securityWarning1": "회전 키는 매우 민감합니다 - 마스터 비밀번호처럼 취급하세요",
13211321+ "securityWarning2": "신뢰할 수 있는 장치와 네트워크에서만 입력하세요",
13221322+ "securityWarning3": "이 키는 마이그레이션 완료 후 저장되지 않습니다",
13231323+ "label": "회전 키",
13241324+ "placeholder": "개인 키 입력 (hex, base58 또는 JWK)",
13251325+ "hint": "DID 문서의 회전 키 중 하나에 해당하는 개인 키",
13261326+ "valid": "키가 유효하고 DID의 회전 키와 일치합니다",
13271327+ "invalid": "키가 DID 문서의 어떤 회전 키와도 일치하지 않습니다",
13281328+ "validating": "키 검증 중...",
13291329+ "validate": "키 검증"
12901330 },
12911291- "migrating": {
12921292- "title": "계정 마이그레이션 중",
12931293- "desc": "데이터를 전송하는 중입니다..."
13311331+ "chooseHandle": {
13321332+ "migratingDid": "DID 복원 중"
12941333 },
12951295- "plcToken": {
12961296- "title": "신원 확인",
12971297- "desc": "이메일로 인증 코드가 전송되었습니다."
13341334+ "review": {
13351335+ "desc": "오프라인 복원 세부 정보를 확인하세요.",
13361336+ "carFile": "CAR 파일",
13371337+ "rotationKey": "회전 키",
13381338+ "warning": "복원을 시작하면 아이덴티티가 이 PDS를 가리키도록 업데이트됩니다. 이것은 쉽게 되돌릴 수 없습니다.",
13391339+ "plcWarningTitle": "되돌릴 수 없는 지점",
13401340+ "plcWarning": "시작하면 DID 문서가 이 PDS를 가리키도록 업데이트됩니다. 문제가 발생하면 회전 키를 사용하여 복구할 수 있지만, 손상된 아이덴티티 상태를 피하려면 마이그레이션을 완료해야 합니다."
12981341 },
12991299- "finalizing": {
13001300- "title": "마이그레이션 완료 중",
13011301- "desc": "마이그레이션을 완료하는 중입니다...",
13021302- "updatingForwarding": "DID 문서 포워딩 업데이트 중..."
13421342+ "migrating": {
13431343+ "title": "계정 복원 중",
13441344+ "desc": "계정을 복원하는 중입니다...",
13451345+ "creating": "계정 생성 중",
13461346+ "importing": "저장소 가져오는 중",
13471347+ "plcSigning": "아이덴티티 업데이트 중",
13481348+ "activating": "계정 활성화 중"
13031349 },
13041350 "success": {
13051305- "title": "마이그레이션 완료!",
13061306- "desc": "계정이 새 PDS로 성공적으로 마이그레이션되었습니다.",
13071307- "newHandle": "새 핸들",
13081308- "newPds": "새 PDS",
13091309- "nextSteps": "다음 단계",
13101310- "nextSteps1": "새 PDS에 로그인",
13111311- "nextSteps2": "새 인증 정보로 앱 업데이트",
13121312- "nextSteps3": "팔로워가 자동으로 새 위치를 확인할 수 있습니다",
13131313- "loggingOut": "{seconds}초 후 로그아웃됩니다..."
13511351+ "desc": "계정이 이 PDS에 성공적으로 복원되었습니다."
13521352+ },
13531353+ "blobs": {
13541354+ "title": "Blob 마이그레이션 중",
13551355+ "desc": "이전 PDS에서 이미지와 미디어를 복구하는 중...",
13561356+ "migrating": "Blob 마이그레이션 중",
13571357+ "failedTitle": "일부 Blob을 마이그레이션할 수 없음",
13581358+ "failedDesc": "{count}개의 Blob을 이전 PDS에서 가져올 수 없습니다. 서버에 연결할 수 없거나 파일이 삭제되었을 수 있습니다.",
13591359+ "sourceUnreachableTitle": "원본 PDS에 연결할 수 없음",
13601360+ "sourceUnreachable": "이전 PDS에 연결하여 미디어 파일을 가져올 수 없습니다. 종료된 서버에서 마이그레이션할 때 흔히 발생합니다. 게시물은 작동하지만 일부 이미지가 누락될 수 있습니다."
13141361 }
13151362 },
13161363 "progress": {
+147-100
frontend/src/locales/sv.json
···1717 "dashboard": "Kontrollpanel",
1818 "backToDashboard": "← Kontrollpanel",
1919 "copied": "Kopierat!",
2020- "copyToClipboard": "Kopiera"
2020+ "copyToClipboard": "Kopiera",
2121+ "verifying": "Verifierar...",
2222+ "saving": "Sparar...",
2323+ "creating": "Skapar...",
2424+ "updating": "Uppdaterar...",
2525+ "sending": "Skickar...",
2626+ "authenticating": "Autentiserar...",
2727+ "checking": "Kontrollerar...",
2828+ "redirecting": "Omdirigerar...",
2929+ "signIn": "Logga in",
3030+ "verify": "Verifiera",
3131+ "remove": "Ta bort",
3232+ "revoke": "Återkalla",
3333+ "resendCode": "Skicka kod igen",
3434+ "startOver": "Börja om",
3535+ "tryAgain": "Försök igen",
3636+ "password": "Lösenord",
3737+ "email": "E-post",
3838+ "emailAddress": "E-postadress",
3939+ "handle": "Användarnamn",
4040+ "did": "DID",
4141+ "verificationCode": "Verifieringskod",
4242+ "inviteCode": "Inbjudningskod",
4343+ "newPassword": "Nytt lösenord",
4444+ "confirmPassword": "Bekräfta lösenord",
4545+ "enterSixDigitCode": "Ange 6-siffrig kod",
4646+ "passwordHint": "Minst 8 tecken",
4747+ "enterPassword": "Ange ditt lösenord",
4848+ "emailPlaceholder": "du@exempel.se",
4949+ "verified": "Verifierad",
5050+ "disabled": "Inaktiverad",
5151+ "available": "Tillgänglig",
5252+ "deactivated": "Avaktiverad",
5353+ "unverified": "Overifierad",
5454+ "backToLogin": "Tillbaka till inloggning",
5555+ "backToSettings": "Tillbaka till inställningar",
5656+ "alreadyHaveAccount": "Har du redan ett konto?",
5757+ "createAccount": "Skapa konto",
5858+ "passwordsMismatch": "Lösenorden matchar inte",
5959+ "passwordTooShort": "Lösenordet måste vara minst 8 tecken"
2160 },
2261 "login": {
2362 "title": "Logga in",
···4988 "codeLabel": "Verifieringskod",
5089 "codePlaceholder": "Ange 6-siffrig kod",
5190 "verifyButton": "Verifiera konto",
5252- "verifying": "Verifierar...",
5353- "resendButton": "Skicka kod igen",
5454- "resending": "Skickar igen...",
5555- "resent": "Verifieringskod skickad igen!",
5656- "backToLogin": "Tillbaka till inloggning"
9191+ "resent": "Verifieringskod skickad igen!"
5792 },
5893 "register": {
5994 "title": "Skapa konto",
···124159 "inviteCodePlaceholder": "Ange din inbjudningskod",
125160 "inviteCodeRequired": "krävs",
126161 "createButton": "Skapa konto",
127127- "creating": "Skapar konto...",
128162 "alreadyHaveAccount": "Har du redan ett konto?",
129163 "signIn": "Logga in",
130164 "wantPasswordless": "Vill du ha lösenordsfri säkerhet?",
···179213 "navAdminDesc": "Serverstatistik och administratörsoperationer",
180214 "navDidDocument": "DID-dokument",
181215 "navDidDocumentDesc": "Hantera ditt DID-dokument och nycklar",
216216+ "navDidDocumentDescActive": "Redigera dina DID-dokumentinställningar",
217217+ "navBackup": "Ladda ner säkerhetskopia",
218218+ "navBackupDesc": "Ladda ner ditt dataförvar som en CAR-fil",
219219+ "downloadingBackup": "Laddar ner...",
220220+ "backupFailed": "Kunde inte ladda ner säkerhetskopia",
182221 "migrated": "Flyttad",
183222 "migratedTitle": "Konto flyttat",
184223 "migratedMessage": "Ditt konto har flyttats till {pds}. Ditt DID-dokument finns fortfarande här.",
···208247 "serviceEndpointDesc": "PDS som för närvarande lagrar din kontodata. Uppdatera detta vid migrering.",
209248 "currentPds": "Nuvarande PDS-URL",
210249 "save": "Spara ändringar",
211211- "saving": "Sparar...",
212250 "success": "DID-dokumentet har uppdaterats",
213251 "saveFailed": "Kunde inte spara DID-dokument",
214252 "loadFailed": "Kunde inte ladda DID-dokument",
···246284 "yourDomain": "Din domän",
247285 "yourDomainPlaceholder": "exempel.se",
248286 "verifyAndUpdate": "Verifiera och uppdatera användarnamn",
249249- "verifying": "Verifierar...",
250287 "newHandle": "Nytt användarnamn",
251288 "newHandlePlaceholder": "dittanvändarnamn",
252289 "changeHandleButton": "Ändra användarnamn",
···262299 "exportData": "Exportera data",
263300 "exportDataDescription": "Ladda ner hela ditt arkiv som en CAR-fil (Content Addressable Archive). Detta inkluderar alla dina inlägg, gillanden, följningar och annan data.",
264301 "downloadRepo": "Ladda ner arkiv",
302302+ "downloadBlobs": "Ladda ner media",
265303 "exporting": "Exporterar...",
304304+ "backups": {
305305+ "title": "Säkerhetskopior",
306306+ "description": "Hantera automatiska säkerhetskopior och återställ din kontodata. Säkerhetskopior inkluderar alla poster och blobbar.",
307307+ "enableAutomatic": "Automatiska säkerhetskopior",
308308+ "enabled": "Aktiverad",
309309+ "disabled": "Inaktiverad",
310310+ "toggleFailed": "Kunde inte ändra säkerhetskopieringsinställning",
311311+ "noBackups": "Inga säkerhetskopior ännu",
312312+ "blocks": "block",
313313+ "download": "Ladda ner",
314314+ "delete": "Radera",
315315+ "createNow": "Skapa säkerhetskopia nu",
316316+ "created": "Säkerhetskopia skapad",
317317+ "createFailed": "Kunde inte skapa säkerhetskopia",
318318+ "downloadFailed": "Kunde inte ladda ner säkerhetskopia",
319319+ "deleted": "Säkerhetskopia raderad",
320320+ "deleteFailed": "Kunde inte radera säkerhetskopia",
321321+ "restoreTitle": "Återställ från säkerhetskopia",
322322+ "restoreDescription": "Återställ din kontodata från en tidigare exporterad CAR-fil. Detta ersätter ditt nuvarande dataförvar med den uppladdade säkerhetskopian.",
323323+ "selectFile": "Välj CAR-fil",
324324+ "selectedFile": "Vald fil",
325325+ "restore": "Återställ säkerhetskopia",
326326+ "restoring": "Återställer...",
327327+ "restored": "Säkerhetskopia återställd",
328328+ "restoreFailed": "Kunde inte återställa säkerhetskopia"
329329+ },
266330 "deleteAccount": "Radera konto",
267331 "deleteWarning": "Denna åtgärd är oåterkallelig. All din data kommer att raderas permanent.",
268332 "requestDeletion": "Begär kontoradering",
···291355 "deleteConfirmation": "Är du helt säker på att du vill radera ditt konto? Detta kan inte ångras.",
292356 "deletionFailed": "Kunde inte radera kontot",
293357 "repoExported": "Arkiv exporterat",
294294- "exportFailed": "Kunde inte exportera arkiv",
358358+ "blobsExported": "Mediafiler exporterade",
359359+ "noBlobsToExport": "Inga mediafiler att exportera",
360360+ "exportFailed": "Export misslyckades",
295361 "confirmDelete": "Är du helt säker på att du vill radera ditt konto? Detta kan inte ångras."
296362 }
297363 },
···306372 "noPasswords": "Inga applösenord ännu",
307373 "revoke": "Återkalla",
308374 "revoking": "Återkallar...",
309309- "creating": "Skapar...",
310375 "revokeConfirm": "Återkalla applösenord \"{name}\"? Appar som använder detta lösenord kommer inte längre att kunna komma åt ditt konto.",
311376 "saveWarningTitle": "Viktigt: Spara detta applösenord!",
312377 "saveWarningMessage": "Detta lösenord krävs för att logga in i appar som inte stöder passkeys eller OAuth. Du ser det bara en gång.",
···354419 "used": "Använd av @{handle}",
355420 "disabled": "Inaktiverad",
356421 "usedBy": "Använd av",
357357- "creating": "Skapar...",
358422 "disableConfirm": "Inaktivera denna inbjudningskod? Den kan inte längre användas.",
359423 "created": "Inbjudningskod skapad",
360424 "copy": "Kopiera",
···482546 "verifyButton": "Verifiera",
483547 "verifyCodePlaceholder": "Ange verifieringskod",
484548 "submit": "Skicka",
485485- "saving": "Sparar...",
486549 "savePreferences": "Spara inställningar",
487550 "preferencesSaved": "Kommunikationsinställningar sparade",
488551 "verifiedSuccess": "{channel} verifierad",
···521584 "noCollectionsYet": "Inga samlingar ännu. Skapa din första post för att komma igång.",
522585 "loadMore": "Ladda fler",
523586 "recordJson": "Post-JSON",
524524- "saving": "Sparar...",
525587 "updateRecord": "Uppdatera post",
526588 "collectionNsid": "Samling (NSID)",
527589 "recordKeyOptional": "Postnyckel (valfri)",
528590 "autoGenerated": "Genereras automatiskt om tom (TID)",
529591 "autoGeneratedHint": "Lämna tom för att automatiskt generera en TID-baserad nyckel",
530530- "creating": "Skapar...",
531592 "demoPostText": "Hej från min PDS! Detta är mitt första inlägg.",
532593 "demoDisplayName": "Ditt visningsnamn",
533594 "demoBio": "En kort presentation om dig själv."
···548609 "primaryLight": "Primär (ljust läge)",
549610 "primaryDark": "Primär (mörkt läge)",
550611 "configSaved": "Serverkonfiguration sparad",
551551- "saving": "Sparar...",
552612 "saveConfig": "Spara konfiguration",
553613 "serverStats": "Serverstatistik",
554614 "users": "Användare",
···639699 "title": "Tvåfaktorsautentisering",
640700 "subtitle": "Ytterligare verifiering krävs",
641701 "usePasskey": "Använd nyckel",
642642- "useTotp": "Använd autentiseringsapp",
643643- "verifying": "Verifierar..."
702702+ "useTotp": "Använd autentiseringsapp"
644703 },
645704 "twoFactorCode": {
646705 "title": "Tvåfaktorsautentisering",
647706 "subtitle": "En verifieringskod har skickats till din {channel}. Ange koden nedan för att fortsätta.",
648707 "codeLabel": "Verifieringskod",
649708 "codePlaceholder": "Ange 6-siffrig kod",
650650- "verify": "Verifiera",
651651- "verifying": "Verifierar...",
652709 "errors": {
653710 "missingRequestUri": "Saknar request_uri-parameter",
654711 "verificationFailed": "Verifiering misslyckades",
···660717 "title": "Ange autentiseringskod",
661718 "subtitle": "Ange den 6-siffriga koden från din autentiseringsapp",
662719 "codePlaceholder": "Ange 6-siffrig kod",
663663- "verify": "Verifiera",
664664- "verifying": "Verifierar...",
665720 "useBackupCode": "Använd reservkod istället",
666721 "backupCodePlaceholder": "Ange reservkod",
667722 "trustDevice": "Lita på denna enhet i 30 dagar",
···691746 "codeLabel": "Verifieringskod",
692747 "codeHelp": "Kopiera hela koden från ditt meddelande, inklusive bindestreck",
693748 "verifyButton": "Verifiera konto",
694694- "verify": "Verifiera",
695695- "verifying": "Verifierar...",
696749 "pleaseWait": "Vänta...",
697697- "sending": "Skickar...",
698698- "resendCode": "Skicka kod igen",
699699- "resending": "Skickar igen...",
700750 "codeResent": "Verifieringskod skickad igen!",
701751 "codeResentDetail": "Verifieringskod skickad! Kontrollera din inkorg.",
702752 "verified": "Verifierad!",
···706756 "identifierLabel": "E-post eller identifierare",
707757 "identifierPlaceholder": "du@exempel.se",
708758 "identifierHelp": "E-postadressen eller identifieraren koden skickades till",
709709- "backToLogin": "Tillbaka till inloggning",
710759 "verifyingAccount": "Verifierar konto: @{handle}",
711760 "startOver": "Börja om med ett annat konto",
712761 "noPending": "Ingen väntande verifiering hittades.",
713762 "noPendingInfo": "Om du nyligen skapade ett konto och behöver verifiera det kan du behöva skapa ett nytt konto. Om du redan verifierat ditt konto kan du logga in.",
714763 "createAccount": "Skapa konto",
715764 "signIn": "Logga in",
716716- "backToSettings": "Tillbaka till inställningar",
717765 "emailUpdateCodeHelp": "Koden skickades till din nuvarande e-postadress",
718766 "emailUpdateFailed": "Kunde inte uppdatera e-postadress",
719767 "emailUpdateRequiresAuth": "Du måste vara inloggad för att uppdatera din e-postadress.",
···746794 "resetButton": "Återställ lösenord",
747795 "resetting": "Återställer...",
748796 "success": "Lösenord återställt!",
749749- "backToLogin": "Tillbaka till inloggning",
750797 "requestNewCode": "Begär ny kod",
751798 "passwordsMismatch": "Lösenorden matchar inte",
752799 "passwordLength": "Lösenordet måste vara minst 8 tecken"
···790837 "howItWorks": "Så fungerar det",
791838 "howItWorksDetail": "Vi skickar en säker länk till din registrerade meddelandekanal. Klicka på länken för att ställa in ett tillfälligt lösenord. Sedan kan du logga in och lägga till en ny nyckel.",
792839 "sendRecoveryLink": "Skicka återställningslänk",
793793- "sending": "Skickar...",
794794- "backToLogin": "Tillbaka till inloggning"
840840+ "sending": "Skickar..."
795841 },
796842 "registerPasskey": {
797843 "title": "Skapa nyckelkonto",
···812858 "externalDid": "Din did:web",
813859 "externalDidPlaceholder": "did:web:dindomän.se",
814860 "createButton": "Skapa konto",
815815- "creating": "Skapar...",
816861 "alreadyHaveAccount": "Har du redan ett konto?",
817862 "signIn": "Logga in",
818863 "wantPassword": "Vill du använda ett lösenord?",
···911956 "useTotp": "Använd autentiserare",
912957 "passwordPlaceholder": "Ange ditt lösenord",
913958 "totpPlaceholder": "Ange 6-siffrig kod",
914914- "verify": "Verifiera",
915915- "verifying": "Verifierar...",
916959 "authenticating": "Autentiserar...",
917960 "passkeyPrompt": "Klicka på knappen nedan för att autentisera med din passkey.",
918961 "cancel": "Avbryt"
···9851028 "createAccount": "Skapa konto",
9861029 "createDelegatedAccount": "Skapa delegerat konto",
9871030 "createDelegatedAccountButton": "+ Skapa delegerat konto",
988988- "creating": "Skapar...",
9891031 "emailOptional": "E-post (valfritt)",
9901032 "failedToAddController": "Kunde inte lägga till kontrollant",
9911033 "failedToCreateAccount": "Kunde inte skapa delegerat konto",
···10591101 "navDesc": "Flytta ditt konto till eller från en annan PDS",
10601102 "migrateHere": "Flytta hit",
10611103 "migrateHereDesc": "Flytta ditt befintliga AT Protocol-konto till denna PDS från en annan server.",
10621062- "migrateAway": "Flytta bort",
10631063- "migrateAwayDesc": "Flytta ditt konto från denna PDS till en annan server.",
10641064- "loginRequired": "Inloggning krävs",
10651104 "bringDid": "Ta med din DID och identitet",
10661105 "transferData": "Överför all din data",
10671106 "keepFollowers": "Behåll dina följare",
10681068- "exportRepo": "Exportera ditt arkiv",
10691069- "transferToPds": "Överför till ny PDS",
10701070- "updateIdentity": "Uppdatera din identitet",
10711107 "whatIsMigration": "Vad är kontoflyttning?",
10721108 "whatIsMigrationDesc": "Kontoflyttning låter dig flytta din AT Protocol-identitet mellan personliga dataservrar (PDS). Din DID (decentraliserad identifierare) förblir densamma, så dina följare och sociala kopplingar bevaras.",
10731109 "beforeMigrate": "Innan du flyttar",
···10771113 "beforeMigrate4": "Din gamla PDS kommer att meddelas om kontoinaktivering",
10781114 "importantWarning": "Kontoflyttning är en betydande åtgärd. Se till att du litar på mål-PDS och förstår att din data kommer att flyttas. Om något går fel kan manuell återställning krävas.",
10791115 "learnMore": "Läs mer om flyttningsrisker",
10801080- "comingSoon": "Kommer snart",
11161116+ "offlineRestore": "Offline-återställning",
11171117+ "offlineRestoreDesc": "Återställ från backup när din gamla PDS inte är tillgänglig.",
11181118+ "offlineFeature1": "Använd en CAR-fil backup",
11191119+ "offlineFeature2": "Bevisa ägande med rotationsnyckel",
11201120+ "offlineFeature3": "Återställning för nedstängda servrar",
10811121 "oauthCompleting": "Slutför autentisering...",
10821122 "oauthFailed": "Autentisering misslyckades",
10831123 "tryAgain": "Försök igen",
···10861126 "incomplete": "Du har en ofullständig flytt pågående:",
10871127 "direction": "Riktning",
10881128 "migratingHere": "Flyttar hit",
10891089- "migratingAway": "Flyttar bort",
10901129 "from": "Från",
10911130 "to": "Till",
10921131 "progress": "Framsteg",
···12291268 "error": {
12301269 "title": "Flyttfel",
12311270 "desc": "Ett fel uppstod under flytten.",
12321232- "startOver": "Börja om"
12711271+ "startOver": "Börja om",
12721272+ "unknown": "Ett okänt fel uppstod."
12331273 },
12341274 "common": {
12351275 "back": "Tillbaka",
···12471287 "warning3": "Ditt gamla konto kommer att inaktiveras efter flytten"
12481288 }
12491289 },
12501250- "outbound": {
12901290+ "offline": {
12511291 "welcome": {
12521252- "title": "Flytta från denna PDS",
12531253- "desc": "Flytta ditt konto till en annan personlig dataserver.",
12541254- "warning": "Efter flytten kommer ditt konto här att inaktiveras.",
12551255- "didWebNotice": "did:web-flyttmeddelande",
12561256- "didWebNoticeDesc": "Ditt konto använder en did:web-identifierare ({did}). Efter flytten kommer denna PDS att fortsätta servera ditt DID-dokument som pekar till den nya PDS. Din identitet kommer att fungera så länge denna server är online.",
12571257- "understand": "Jag förstår riskerna och vill fortsätta"
12921292+ "title": "Återställ från backup",
12931293+ "desc": "Återställ ditt konto med en CAR-fil backup och rotationsnyckel. Använd detta när din tidigare PDS inte är tillgänglig.",
12941294+ "warningTitle": "När du ska använda denna metod",
12951295+ "warningDesc": "Denna offline-återställning är för katastrofåterställning när din gamla PDS har stängts ner, är oåtkomlig eller du blev utelåst. Om din gamla PDS fortfarande är tillgänglig, använd standardflytten istället.",
12961296+ "requirementsTitle": "Du behöver",
12971297+ "requirement1": "En CAR-fil backup av ditt arkiv",
12981298+ "requirement2": "Din rotationsnyckel (privat nyckel för ditt DID)",
12991299+ "requirement3": "Ditt DID (did:plc:xxx)",
13001300+ "understand": "Jag förstår och vill fortsätta"
12581301 },
12591259- "targetPds": {
12601260- "title": "Välj mål-PDS",
12611261- "desc": "Ange URL:en för PDS du vill flytta till.",
12621262- "url": "PDS URL",
12631263- "urlPlaceholder": "https://pds.example.com",
12641264- "validate": "Validera och fortsätt",
12651265- "validating": "Validerar...",
12661266- "connected": "Ansluten till {name}",
12671267- "inviteRequired": "Inbjudningskod krävs",
12681268- "privacyPolicy": "Integritetspolicy",
12691269- "termsOfService": "Användarvillkor"
13021302+ "provideDid": {
13031303+ "title": "Ange ditt DID",
13041304+ "desc": "Ange DID för kontot du vill återställa.",
13051305+ "label": "Ditt DID",
13061306+ "hint": "Din decentraliserade identifierare (t.ex. did:plc:abc123)"
12701307 },
12711271- "newAccount": {
12721272- "title": "Nya kontouppgifter",
12731273- "desc": "Konfigurera ditt konto på den nya PDS.",
12741274- "handle": "Användarnamn",
12751275- "availableDomains": "Tillgängliga domäner",
12761276- "email": "E-post",
12771277- "password": "Lösenord",
12781278- "confirmPassword": "Bekräfta lösenord",
12791279- "inviteCode": "Inbjudningskod"
13081308+ "uploadCar": {
13091309+ "title": "Ladda upp CAR-fil",
13101310+ "desc": "Ladda upp din arkiv-backupfil.",
13111311+ "label": "CAR-fil",
13121312+ "hint": "Välj .car-filen från din backup",
13131313+ "reuploadWarningTitle": "CAR-fil krävs",
13141314+ "reuploadWarning": "Din session har återställts, men du måste ladda upp din CAR-fil igen. Av säkerhetsskäl lagras inte filinnehåll mellan sessioner."
12801315 },
12811281- "review": {
12821282- "title": "Granska flytt",
12831283- "desc": "Granska och bekräfta dina flyttdetaljer.",
12841284- "currentHandle": "Nuvarande användarnamn",
12851285- "newHandle": "Nytt användarnamn",
12861286- "sourcePds": "Denna PDS",
12871287- "targetPds": "Mål-PDS",
12881288- "confirm": "Jag bekräftar att jag vill flytta mitt konto",
12891289- "startMigration": "Starta flytt"
13161316+ "rotationKey": {
13171317+ "title": "Ange rotationsnyckel",
13181318+ "desc": "Ange din rotationsnyckel för att bevisa ägande av detta DID.",
13191319+ "securityWarningTitle": "Säkerhetsvarning",
13201320+ "securityWarning1": "Din rotationsnyckel är extremt känslig - behandla den som ett huvudlösenord",
13211321+ "securityWarning2": "Ange den endast på betrodda enheter och nätverk",
13221322+ "securityWarning3": "Denna nyckel kommer inte att lagras efter att flytten slutförts",
13231323+ "label": "Rotationsnyckel",
13241324+ "placeholder": "Ange privat nyckel (hex, base58 eller JWK)",
13251325+ "hint": "Den privata nyckeln som motsvarar en av rotationsnycklarna i ditt DID-dokument",
13261326+ "valid": "Nyckeln är giltig och matchar en rotationsnyckel i ditt DID",
13271327+ "invalid": "Nyckeln matchar inte någon rotationsnyckel i ditt DID-dokument",
13281328+ "validating": "Validerar nyckel...",
13291329+ "validate": "Validera nyckel"
12901330 },
12911291- "migrating": {
12921292- "title": "Flyttar ditt konto",
12931293- "desc": "Vänta medan vi överför din data..."
13311331+ "chooseHandle": {
13321332+ "migratingDid": "Återställer DID"
12941333 },
12951295- "plcToken": {
12961296- "title": "Verifiera din identitet",
12971297- "desc": "En verifieringskod har skickats till din e-post."
13341334+ "review": {
13351335+ "desc": "Granska dina offline-återställningsuppgifter.",
13361336+ "carFile": "CAR-fil",
13371337+ "rotationKey": "Rotationsnyckel",
13381338+ "warning": "När du startar återställningen kommer din identitet att uppdateras för att peka på denna PDS. Detta kan inte enkelt ångras.",
13391339+ "plcWarningTitle": "Ingen återvändo",
13401340+ "plcWarning": "När du startar kommer ditt DID-dokument att uppdateras för att peka på denna PDS. Om något går fel kan du använda din rotationsnyckel för att återställa, men du bör slutföra flytten för att undvika ett trasigt identitetstillstånd."
12981341 },
12991299- "finalizing": {
13001300- "title": "Slutför flytt",
13011301- "desc": "Vänta medan vi slutför flytten...",
13021302- "updatingForwarding": "Uppdaterar DID-dokumentvidarebefordran..."
13421342+ "migrating": {
13431343+ "title": "Återställer konto",
13441344+ "desc": "Vänta medan ditt konto återställs...",
13451345+ "creating": "Skapar konto",
13461346+ "importing": "Importerar arkiv",
13471347+ "plcSigning": "Uppdaterar identitet",
13481348+ "activating": "Aktiverar konto"
13031349 },
13041350 "success": {
13051305- "title": "Flytt klar!",
13061306- "desc": "Ditt konto har framgångsrikt flyttats till din nya PDS.",
13071307- "newHandle": "Nytt användarnamn",
13081308- "newPds": "Ny PDS",
13091309- "nextSteps": "Nästa steg",
13101310- "nextSteps1": "Logga in på din nya PDS",
13111311- "nextSteps2": "Uppdatera dina appar med nya uppgifter",
13121312- "nextSteps3": "Dina följare kommer automatiskt se din nya plats",
13131313- "loggingOut": "Loggar ut om {seconds} sekunder..."
13511351+ "desc": "Ditt konto har framgångsrikt återställts till denna PDS."
13521352+ },
13531353+ "blobs": {
13541354+ "title": "Flyttar blobbar",
13551355+ "desc": "Försöker återställa bilder och media från din gamla PDS...",
13561356+ "migrating": "Flyttar blobbar",
13571357+ "failedTitle": "Vissa blobbar kunde inte flyttas",
13581358+ "failedDesc": "{count} blobbar kunde inte hämtas från din gamla PDS. Detta kan hända om servern är otillgänglig eller om filerna raderades.",
13591359+ "sourceUnreachableTitle": "Käll-PDS otillgänglig",
13601360+ "sourceUnreachable": "Kunde inte ansluta till din gamla PDS för att hämta mediafiler. Detta är vanligt vid flytt från en nedstängd server. Dina inlägg kommer att fungera, men vissa bilder kan saknas."
13141361 }
13151362 },
13161363 "progress": {
···183183 <h3>Delegate without sharing passwords</h3>
184184 <p>Let team members or tools manage your account with specific permission levels. They authenticate with their own credentials, you see everything they do in an audit log.</p>
185185 </div>
186186+187187+ <div class="feature">
188188+ <h3>Automatic backups</h3>
189189+ <p>Your repository is backed up daily to object storage. Download any backup or restore with one click. You own your data, even if the worst happens.</p>
190190+ </div>
186191 </div>
187192188193 <h2>Everything in one place</h2>
···11+ALTER TABLE users ADD COLUMN backup_enabled BOOLEAN NOT NULL DEFAULT TRUE;
22+33+CREATE TABLE account_backups (
44+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
55+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
66+ storage_key TEXT NOT NULL,
77+ repo_root_cid TEXT NOT NULL,
88+ repo_rev TEXT NOT NULL,
99+ block_count INT NOT NULL,
1010+ size_bytes BIGINT NOT NULL,
1111+ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
1212+);
1313+1414+CREATE INDEX idx_account_backups_user_id ON account_backups(user_id);
1515+CREATE INDEX idx_account_backups_created_at ON account_backups(created_at);
+6-3
scripts/install-debian.sh
···4444 sudo -u postgres psql -c "DROP DATABASE IF EXISTS pds;" 2>/dev/null || true
4545 sudo -u postgres psql -c "DROP USER IF EXISTS tranquil_pds;" 2>/dev/null || true
46464747- log_info "Removing minio bucket..."
4747+ log_info "Removing minio buckets..."
4848 if command -v mc &>/dev/null; then
4949 mc rb local/pds-blobs --force 2>/dev/null || true
5050+ mc rb local/pds-backups --force 2>/dev/null || true
5051 mc alias remove local 2>/dev/null || true
5152 fi
5253 systemctl stop minio 2>/dev/null || true
···7879 echo " - PostgreSQL database 'pds' and all data"
7980 echo " - All Tranquil PDS configuration and credentials"
8081 echo " - All source code in /opt/tranquil-pds"
8181- echo " - MinIO bucket 'pds-blobs' and all blobs"
8282+ echo " - MinIO buckets 'pds-blobs' and 'pds-backups' and all data"
8283 echo ""
8384 read -p "Type 'NUKE' to confirm: " CONFIRM_NUKE
8485 if [[ "$CONFIRM_NUKE" == "NUKE" ]]; then
···274275mc alias remove local 2>/dev/null || true
275276mc alias set local http://localhost:9000 minioadmin "${MINIO_PASSWORD}" --api S3v4
276277mc mb local/pds-blobs --ignore-existing
277277-log_success "minio bucket created"
278278+mc mb local/pds-backups --ignore-existing
279279+log_success "minio buckets created"
278280279281log_info "Installing rust..."
280282if [[ -f "$HOME/.cargo/env" ]]; then
···382384S3_ENDPOINT=http://localhost:9000
383385AWS_REGION=us-east-1
384386S3_BUCKET=pds-blobs
387387+BACKUP_S3_BUCKET=pds-backups
385388AWS_ACCESS_KEY_ID=minioadmin
386389AWS_SECRET_ACCESS_KEY=${MINIO_PASSWORD}
387390VALKEY_URL=redis://localhost:6379
···312312 r#"
313313 SELECT rb.blob_cid, rb.record_uri
314314 FROM record_blobs rb
315315- LEFT JOIN blobs b ON rb.blob_cid = b.cid AND b.created_by_user = rb.repo_id
315315+ LEFT JOIN blobs b ON rb.blob_cid = b.cid
316316 WHERE rb.repo_id = $1 AND b.cid IS NULL AND rb.blob_cid > $2
317317 ORDER BY rb.blob_cid
318318 LIMIT $3
+4-2
src/api/repo/record/batch.rs
···345345 let rkey = rkey
346346 .clone()
347347 .unwrap_or_else(|| Tid::now(LimitedU32::MIN).to_string());
348348+ let record_ipld = crate::util::json_to_ipld(value);
348349 let mut record_bytes = Vec::new();
349349- if serde_ipld_dagcbor::to_writer(&mut record_bytes, value).is_err() {
350350+ if serde_ipld_dagcbor::to_writer(&mut record_bytes, &record_ipld).is_err() {
350351 return (StatusCode::BAD_REQUEST, Json(json!({"error": "InvalidRecord", "message": "Failed to serialize record"}))).into_response();
351352 }
352353 let record_cid = match tracking_store.put(&record_bytes).await {
···409410 }
410411 };
411412 all_blob_cids.extend(extract_blob_cids(value));
413413+ let record_ipld = crate::util::json_to_ipld(value);
412414 let mut record_bytes = Vec::new();
413413- if serde_ipld_dagcbor::to_writer(&mut record_bytes, value).is_err() {
415415+ if serde_ipld_dagcbor::to_writer(&mut record_bytes, &record_ipld).is_err() {
414416 return (StatusCode::BAD_REQUEST, Json(json!({"error": "InvalidRecord", "message": "Failed to serialize record"}))).into_response();
415417 }
416418 let record_cid = match tracking_store.put(&record_bytes).await {
+2-1
src/api/repo/record/utils.rs
···382382 let commit = jacquard_repo::commit::Commit::from_cbor(&commit_bytes)
383383 .map_err(|e| format!("Failed to parse commit: {:?}", e))?;
384384 let mst = Mst::load(Arc::new(tracking_store.clone()), commit.data, None);
385385+ let record_ipld = crate::util::json_to_ipld(record);
385386 let mut record_bytes = Vec::new();
386386- serde_ipld_dagcbor::to_writer(&mut record_bytes, record)
387387+ serde_ipld_dagcbor::to_writer(&mut record_bytes, &record_ipld)
387388 .map_err(|e| format!("Failed to serialize record: {:?}", e))?;
388389 let record_cid = tracking_store
389390 .put(&record_bytes)
+4-2
src/api/repo/record/write.rs
···297297 let rkey = input
298298 .rkey
299299 .unwrap_or_else(|| Tid::now(LimitedU32::MIN).to_string());
300300+ let record_ipld = crate::util::json_to_ipld(&input.record);
300301 let mut record_bytes = Vec::new();
301301- if serde_ipld_dagcbor::to_writer(&mut record_bytes, &input.record).is_err() {
302302+ if serde_ipld_dagcbor::to_writer(&mut record_bytes, &record_ipld).is_err() {
302303 return (
303304 StatusCode::BAD_REQUEST,
304305 Json(json!({"error": "InvalidRecord", "message": "Failed to serialize record"})),
···550551 }
551552 }
552553 let existing_cid = mst.get(&key).await.ok().flatten();
554554+ let record_ipld = crate::util::json_to_ipld(&input.record);
553555 let mut record_bytes = Vec::new();
554554- if serde_ipld_dagcbor::to_writer(&mut record_bytes, &input.record).is_err() {
556556+ if serde_ipld_dagcbor::to_writer(&mut record_bytes, &record_ipld).is_err() {
555557 return (
556558 StatusCode::BAD_REQUEST,
557559 Json(json!({"error": "InvalidRecord", "message": "Failed to serialize record"})),
+15-44
src/api/server/account_status.rs
···567567#[serde(rename_all = "camelCase")]
568568pub struct DeactivateAccountInput {
569569 pub delete_after: Option<String>,
570570- pub migrating_to: Option<String>,
571570}
572571573572pub async fn deactivate_account(
···618617619618 let did = auth_user.did;
620619621621- let migrating_to = if let Some(ref url) = input.migrating_to {
622622- let url = url.trim().trim_end_matches('/');
623623- if url.is_empty() || !did.starts_with("did:web:") {
624624- None
625625- } else {
626626- if !url.starts_with("https://") {
627627- return ApiError::InvalidRequest("migratingTo must start with https://".into())
628628- .into_response();
629629- }
630630- Some(url.to_string())
631631- }
632632- } else {
633633- None
634634- };
635635-636620 let handle = sqlx::query_scalar!("SELECT handle FROM users WHERE did = $1", did)
637621 .fetch_optional(&state.db)
638622 .await
639623 .ok()
640624 .flatten();
641625642642- let result = if let Some(ref pds_url) = migrating_to {
643643- sqlx::query!(
644644- "UPDATE users SET deactivated_at = NOW(), delete_after = $2, migrated_to_pds = $3, migrated_at = NOW() WHERE did = $1",
645645- did,
646646- delete_after,
647647- pds_url
648648- )
649649- .execute(&state.db)
650650- .await
651651- } else {
652652- sqlx::query!(
653653- "UPDATE users SET deactivated_at = NOW(), delete_after = $2 WHERE did = $1",
654654- did,
655655- delete_after
656656- )
657657- .execute(&state.db)
658658- .await
659659- };
660660-661661- let status = if migrating_to.is_some() {
662662- "migrated"
663663- } else {
664664- "deactivated"
665665- };
626626+ let result = sqlx::query!(
627627+ "UPDATE users SET deactivated_at = NOW(), delete_after = $2 WHERE did = $1",
628628+ did,
629629+ delete_after
630630+ )
631631+ .execute(&state.db)
632632+ .await;
666633667634 match result {
668635 Ok(_) => {
669636 if let Some(ref h) = handle {
670637 let _ = state.cache.delete(&format!("handle:{}", h)).await;
671638 }
672672- if let Err(e) =
673673- crate::api::repo::record::sequence_account_event(&state, &did, false, Some(status))
674674- .await
639639+ if let Err(e) = crate::api::repo::record::sequence_account_event(
640640+ &state,
641641+ &did,
642642+ false,
643643+ Some("deactivated"),
644644+ )
645645+ .await
675646 {
676676- warn!("Failed to sequence account {} event: {}", status, e);
647647+ warn!("Failed to sequence account deactivated event: {}", e);
677648 }
678649 (StatusCode::OK, Json(json!({}))).into_response()
679650 }