உள்ளடக்கத்திற்குச் செல்லவும்
KAMOUniverse

மாற்று பதிவேடு

என்ன புதிது.

அது கப்பல்கள் போல், தளத்தில் ஒவ்வொரு மேம்பாடு.

  1. · kamo-shared-library

    Add per-member assignments and per-document progress

    The document row is the join that makes N e-sign envelopes read as one package. The badge count comes off the assignment status, not e-sign status: recipient status has no VOIDED or EXPIRED, void never touches recipient rows, and an acknowledge-only package has no envelopes at all.

  2. · kamo-shared-library

    Freeze package content into immutable versions

    Pins the ImgDat blob id and its SHA-256, not just imgId — a Docs save repoints the same Img at new bytes, so imgId alone would let two members sign different documents under identical ids. Snapshots the design too, so execution never depends on resolveDesignJson's fall-back to the newest layout.

  3. · kamo-shared-library

    Target a package at departments, job types or named members

    Shaped on SystemUserAccess. Adds the audience resolver to TeamMemberRepo, which was an empty interface; the ACTIVE + recordState predicate is what keeps terminated staff and unhired candidates out of a delivery.

  4. · kamo-shared-library

    Add the legal package template entities

    A package is an ordered set of binders plus an audience. Binder references are soft ids because binders are user-deletable and cascade their items. The attestation wording is stored in full with its hash — a pointer cannot prove what a member agreed to.

  5. · kamo-internal

    Make the binder store aware of its collection

    The store is a module singleton, so it now tracks the active scope, clears on a scope change, and drops stale in-flight responses.

  6. · DocsService

    List and create binders within one collection

    Scopes the visible-binder query to the DocManager's (assocType, assocObjectId), stamps the scope on create, inherits it on duplicate, and bumps last_modified from the item mutations that never write the binders row.

  7. · DocsService

    Carry the collection scope on the binder wire contract

  8. · InitializerService

    Backfill the collection each existing binder belongs to

    Derives the scope from the first DOC item's Img; empty binders fall back to the owner's My Docs. Applies NOT NULL only after the backfill.

  9. · kamo-shared-library

    Narrow binder visibility to one document collection

    Replaces findVisibleToMember with a scoped variant and drops the two unreferenced finders that sorted by the dead date_updated column.

  10. · kamo-shared-library

    Give a binder the document collection it belongs to

    Binders had no assoc scoping, so every DocManager rendered the same global per-member pool and a binder built under Marketing could be filled with HR documents. Stores the ImageAssocType ordinal to match Img.assocId. Also adds an app-managed last_modified: BaseEntity.dateUpdated is **************** so the list's sort-by-modified has always been sorting by creation time.

  11. · kamo-internal

    Group the meeting-invite fields by meaning when maximized

    Splitting the form into equal halves used the wrong unit. It stretched a date input across half the window and stranded its All-day box at the far edge, left two short time inputs trailing several hundred pixels of nothing, and pushed Add a full window-width from the Reminders it belongs to — while fields that read as one thought sat rows apart. Claim tracks off a 12-column grid instead, sized to what each field is: Title full width, the headline field Date + All day | Time | TZ the whole "when" cluster on one line Location | Meeting URL where it is and how to join Reminders label, entries and Add flowing inline Reminders alone gets a row back: two short selects no longer cost a line each. The timezone widens to absorb the Time field's tracks on an all-day meeting so that line still spans the width. Field order is untouched — the grouping comes from spans, so what you tab through stays what you see, in both layouts.

  12. · kamo-internal

    Keep the quoted original out of the editable body

    Replying dropped the whole quoted message into the Quill editor as body text. Quill can only model a simple grid, so every layout table in the quote was flattened into one — and layout tables are how signatures and virtually all marketing mail are built, which is why a quoted signature came back as a bare grid of cells with no way to get the original back. The quote now travels beside the body rather than inside it. Reply, reply-all and forward hand it over as `quotedHtml`; the composer shows it below the signature, exactly where it lands in the sent mail, rendered through the same sandboxed iframe the reading pane uses — so it looks as it did when it arrived, and its CSS cannot leak into the composer around it. At send it is appended after the signature. It is collapsed to start, because on a long thread the quote dwarfs the reply. Two actions sit beside it: remove it from the reply, or move it into the body as ordinary text. The second exists because taking the quote out of the editor took away the ability to trim a thread down to the line being answered — doing that still costs the layout, but it is now an explicit choice rather than the unavoidable default. Sanitised on the way out. Routing the quote around the editor also routed it around the implicit scrubbing the editor was doing, so sanitizeEmailHtml now runs on it before it is re-sent. Deliberately NOT put through makeHtmlLegible: that guard judges colour against the composer's white canvas, which is right for text written there and wrong for a quote that keeps its own <style> and renders on its own background. Inverting a dark-themed newsletter's white text would have made it dark-on-dark. The quote rides in the tool-window snapshot so a reload does not lose it, and is concatenated onto the body when saving a draft — the drafts endpoint stores one body, and a reopened draft holding the quote as text beats losing the thread.

  13. · kamo-internal

    Pair the meeting-invite fields into two columns when maximized

    The invite form stacks eight full-width rows, which in a maximized compose window pushed the body editor most of the way off screen while leaving half the window's width empty either side of the inputs. Maximized, the fields now flow into two tracks in their existing DOM order — Title|Date, Time|Timezone, Location|URL — halving the form's height without reordering anything or touching the narrow layout. Reminders keep the full width in both: the list grows a row per reminder, and half a column would make the whole form jump in height each time one is added. Tracks are minmax(0, 1fr) rather than 1fr, or a grid track's default min-width:auto would refuse to shrink below its content and let the URL row's input and Generate button push past half the width.

  14. · ESigService

    Apply page operations and modifiers to the signed document

    The designer has always offered page rotate, delete, reorder and add-blank, plus watermark, page-number and label modifiers, and the flatten read none of it: it stamped field values onto the source pages and appended certificates. A page you deleted still shipped, a watermark you configured never appeared. All of it is now applied. The pipeline composes in the order a reader's expectations require — blank pages inserted so the design's index space matches the document, each page turned, behind-modifiers drawn, field values stamped, above-watermarks drawn, deleted pages dropped and the rest reordered, certificates appended last. Certificates carry no page number or watermark: they are the audit record of the document, not part of it. Page numbering is resolved against the finished sequence, so a document that drops a page numbers its survivors 1..n rather than leaving a gap. The designer now resolves that sequence identically (kamo-internal pageSequence.ts mirrors EsignPageLayout, case for case) so the preview cannot promise a number the delivered document will not carry. Modifiers are placed against the page as the reader sees it, which on a turned page means mapping display coordinates back into user space and pre-turning the content so it does not come out sideways — EsignPageFrame does that, and its four rotations are pinned by corner tests. Watermarks use the org's own logo from the theme bucket. Most orgs hold SVG only and PDFBox draws rasters, so SVG is transcoded through Batik with external resource loading refused — an uploaded logo is tenant-supplied content and rasterizing is not sanitizing. An org with no logo gets no watermark; the platform's default mark is never substituted onto a tenant's agreement. Hardening throughout: design JSON is parsed totally, so anything malformed, out of range or from a newer designer is dropped rather than thrown and the signatures still land. Deleting every page is refused — PDF has no valid zero-page form and an agreement with no pages is not a document. Inherited page attributes are pinned before the page tree is restructured. A field on a deleted page is not stamped onto some other page. Text keeps its accents instead of being flattened to ASCII, per character, against what the font can encode. 59 tests, 17 of them driving real PDFBox end to end and reading the result back.

  15. · kamo-internal

    Give every popup tool window 40px more room in both axes

    Each tool's defaultSize and minSize in the registry grows by 40x40, and the geometry that was hardcoded alongside it moves with it rather than drifting out of agreement: - CalculatorTool's per-mode size table, which mirrors the calculator's registry default. - AiChatWindow's restore-from-maximized size. At 420x520 it was already a hair under the old minimum; against the new 360x540 it would have restored the window smaller than a drag-resize is allowed to make it. - restoreWindows() now replays a persisted size only for a tool the reader can actually resize. For a fixed-size tool the snapshot merely echoes back the registry default of whichever build wrote it, so a tab reloading across this change would have restored the old 320x650 and kept it for the rest of its life. The same guard fixes a case that predates this change: a window the relayout had clamped down to fit a short viewport was persisted at the clamped size and never grew back afterwards. The dock's own placement — findDockX, relayoutWindows, the makeRoom rect and the hexhead engine's avoidance — all measure live geometry, so they follow the new sizes with nothing to update. Also fixes the AI chat maximize button, which chose its action from `height > 800` while drawing its icon from `isMaximized`. On any viewport shorter than 800px maximizing could never satisfy that threshold, so the button offered to restore and then maximized again — the window could not be brought back down at all. Both now read the same value.

  16. · kamo-internal

    Drag, cut, copy and paste recipient chips between To, Cc and Bcc

    Moving someone from To to Bcc meant deleting the chip and typing the address again from memory. Chips are now selectable and can be dragged or carried on the clipboard from any of the three fields into any other. - click selects a chip; ctrl/cmd-click toggles and shift-click takes a range. The info card moves from click to double-click, so a single click can do what it does in every other mail client — pick the chip up. - drag one chip or a whole selection to another field. Ctrl or Alt held makes it a copy; an insertion caret shows where it will land, and dropping inside the same field reorders. A multi-chip drag carries a count rather than showing the - Ctrl+X / Ctrl+C / Ctrl+V move chips between fields. text/plain is always written, so a chip dragged or copied into the body — or into another mail client entirely — arrives as an ordinary address list; a private flavour alongside it keeps the name, photo and contact link for a paste back into Kamo. - keyboard: arrows walk the chips (shift extends), Ctrl+A takes the field, Delete removes the selection and lands on the next chip, Escape returns to the input. Backspace in an empty input now steps onto the last chip instead of deleting it outright, so what is about to go is visible first. - pasting into the input chips every complete address it finds, including a single one. A half-typed fragment still falls through to the text input. The cross-field half needs the three fields to act on each other, which a field owning only its own list cannot do; RecipientTransferProvider holds the registry and performs the move. A field rendered without it — the campaign editor uses one on its own — keeps selection, reordering and the clipboard, and simply has nowhere to transfer to. parseRecipientList now requires a domain rather than just an '@'. parseAddress is deliberately lax because it keys an avatar cache off whatever a header carried; a chip is something we will try to deliver to, and pasting "bob@" produced one that could never be sent.

  17. · kamo-internal

    Rotate the field overlay with the page, flag unread imports, order fields for reading

    Three things that only start to matter once a document arrives carrying forty detected fields instead of two hand-placed ones. Page rotation: rotating a page turned the canvas but left fields and annotations behind, so they slid off the content they were anchored to. The two layers now turn with the page, keeping their coordinates in the page's own unrotated space because that is what the backend positions against. Every pointer interaction is mapped back out of screen space through the new pageGeometry helpers — dragging, resizing, annotation drawing, and dropping a new field from the toolbox — and unrotated: those are placed against the page frame, not its content. Unreviewed marker: auto-placed fields carry a dashed ring until the user clicks one, so a large import reads as a checklist. Session-only, never saved. Reading order: detected fields are sorted down the page and across each line, with a tolerance so a slightly misaligned row still sorts left to right. Widget order in the file is an authoring-tool artefact and often is not reading order. Also fixes an option-value collision of my own making: two radio buttons whose printed captions match (two "Yes" on one question) were given the same value, and the signer lights a button by comparing the group value to the button's own, so both would have lit at once.

  18. · kamo-internal

    Read Acrobat format actions when detecting fillable fields

    Acrobat stores a field's intended format as JavaScript in /AA, which pdf.js surfaces as actions.Format. That is the author's declaration rather than a guess off the field name, so it now outranks the name/caption heuristic: - AFNumber_Format -> currency when it carries a currency string, else number - AFDate_Format/AFDate_FormatEx -> date, AFTime_Format -> time - AFPercent_Format -> number - AFSpecial_Format(n) -> zip / zip+4 / phone / SSN - a Calculate action means the field is computed, so it imports read-only Also: a signature or initial widget thinner than the control needs now grows upward from its bottom edge, since a PDF signature field is often only as tall as the printed rule it sits on and ink belongs above the line; and a pure XFA document is reported as such instead of reading as "no fillable fields", because its fields live in XML that AcroForm detection cannot see. Verified against real pdf.js 4.10.38 alongside the unit suite.

  19. · kamo-internal

    Insert a new meeting link at the coder from the composer

    Adds a footer action to the compose window that creates a meeting with the organization's configured provider and writes its join link into the body wherever the caret happens to be. Distinct from the meeting-invite toggle beside it: that attaches a calendar invitation with a time, attendees and reminders, while this is the one-click "here is a room, come whenever" case that only needs a URL in the prose. The caret is tracked across the blur the click would otherwise cause, so the link lands where the member was typing rather than at the top of the message. The create-and-linkify step the invite composer already had is now shared, so there is one definition of how a meeting becomes a link — Kamo's own /meet/join/<id> redirect, which is provider-aware and signs Kamo members in at click time.

  20. · kamo-internal

    Rebuild a fillable PDF's AcroForm fields as native Kamo fields

    Opening an editable PDF in the document editor now reads its AcroForm widget annotations off the pdf.js document and recreates each one as a DesignField on the same page, at the same position and size, with the closest matching Kamo field type. On an untouched design the fields are placed automatically (one undo step, with an Undo action on the notice); otherwise the toolbox offers a review dialog that skips anything already covered by a placed field. - app/lib/esign/acroform.ts: pure detection. Widget rects are converted through the page viewport so page /Rotate is honoured. Structural mapping covers Sig/Btn/Ch/Tx (push buttons and hidden widgets dropped); text widgets get a semantic pass over the tooltip, field name and the caption printed beside them on the page, so "Borrower Signature" becomes a signature box and "Signature Date" a date. Radio buttons keep their individual boxes and are tied together through a shared linkedGroupId. - DesignField gains optional options[], matching the field option contract the signer app already accepts; the properties panel now edits them, and can also reassign a field to another signer. Verified against real pdf.js 4.10.38 parsing a real pdf-lib-built form, in addition to the unit suite.

  21. · InitializerService

    Create the email search_vector column and its inverted index

    **************** never existed. EmailService's own V1__email_metadata_schema.sql declares it, but that migration never ran -- the table came from this service's entity scan, and SearchIndexEntity omits the field because Hibernate cannot map TSVECTOR, so ddl-auto could not add it. **************** therefore failed with SQLSTATE 42703 on every message, and because that UPDATE shares a transaction with the row insert, the insert rolled back too. The table has always been empty and email search has never returned a result.

  22. · kamo-internal

    A contact card behind every name on a message

    Every person shown in a read view was a dead end. To and Cc rendered as displayNameFor(a).join(', ') — a comma wall of display names with no address, no hover, no actions. Three things were wrong with that. The address was unrecoverable, and display names are attacker-controlled header text, so two people called Chris were indistinguishable and copying the address of someone who was CC'd meant opening a reply and inspecting the chip. Everything the organization already knows about that person — colleague records, address books, avatars, live presence — resolves by address and none of it reached the screen. And a fourteen-recipient thread rendered as one unreadable line. Hovering a name now opens a card. The address plate is its centrepiece rather than a grey subtitle, because the address is what the card exists to hand over: full width, mono, local part in ink and domain lighter, the whole plate a copy control that sweeps the messages accent across itself on success, and still selectable for anyone who would rather drag. Around it, only rows that have something in them: job title, employer, department, numbers that dial the softphone, a colleague's extension, and their local time before you call them. Colleagues carry a live presence dot from the existing presence and availability contexts. Automated senders say so, and a no-reply address does not offer a reply the mailbox would refuse. Recipient lists past five names collapse behind a count. The mechanics live in useHoverCard, away from the card, because none of it is about people: hover intent so a pointer crossing a header does not fire cards, a close grace period so the diagonal path to the card does not dismiss it, one card open at a time, re-measurement when the pane scrolls or the record lands, and real buttons so keyboard and touch reach it at all. Only keyboard focus opens — acting on click focus would open the card in the same tick the click toggles it shut, and the chip would look inert to a mouse. Records come from correspondentStore, keyed by address and never merged onto message objects: both list views poll every thirty seconds and replace their message array wholesale, which would wipe anything carried there twice a minute. Unlike avatars they resolve lazily — a whole header is prefetched when a message opens, and hovering covers anything that missed — so the card is normally already filled when it animates in. formatAgo moves out of MemberItem so the roster and the card describe the same absence the same way.

  23. · EmailService

    Resolve the people behind the addresses on a message

    A message header knows an address and whatever display name the sender chose to put beside it. The organization already knows far more — colleagues, address books, extensions, timezones — and none of it reached the mailbox. POST **************** answers a batch of addresses with the person behind each: colleague (with job title, department, extension, timezone and a member id that unlocks presence and chat), saved contact (with employer, title and numbers), or an explicit EXTERNAL so the caller can cache the answer instead of re-asking on every hover. Deliberately separate from the avatar endpoint rather than folded into it. That one is two-phase by necessity — a full miss can mean DNS plus four HTTP calls to third parties — and this is a handful of local, indexed, org-scoped reads that can answer completely on the first call. Sharing an endpoint would force the synchronous half to inherit an "ask again later" contract it does not need. Keyed on the bare address and never on the display name, which is attacker-controlled text: an outsider can set theirs to a colleague's real name, and this record carries that colleague's direct-dial extension. The normalizer that enforces that is now shared with the avatar endpoint (MailboxAddress), so the two cannot drift apart and miss each other's cache entries. The organization comes from the session, never the request — the endpoint answers "does this tenant hold a record for this address", which is a membership oracle if the caller picks the tenant. Ids serialize as strings: CockroachDB row ids run past MAX_SAFE_INTEGER, and EmailService has no global Long-to-string mapper because message uids are longs the mailbox front end genuinely treats as numbers.

  24. · kamo-internal

    Resources tab is the org's HR document library

    Replaces the Resources placeholder with DocManager on a document collection of its own — ImageAssocType.HR_RESOURCE, bucket imaging-hr-resources — org-scoped the way Marketing Materials is, and deliberately separate from it: a marketing flyer and an employee handbook do not belong in one library. The assoc type is sent as the enum's ORDINAL (13), not its id (15). The imaging backends resolve it with values()[assocType] and the two diverge because the enum skips id 6; sending the id would write into another collection's bucket, which is how the My Docs surface once shipped documents it could not read back. HR_RESOURCE_ASSOC_TYPE carries that reasoning next to the constant. DocsService and ConversionService were rebuilt for the new constant first — the frontend is the only thing that sends 13, so it lands last.

  25. · kamo-shared-library

    HR_RESOURCE assoc type for the org HR resource library

    The /hr Resources tab publishes handbooks, policies, forms and reference material to the whole team, and no existing assoc type fits: MY_DOCS is a person's own area, SYSTEM_WIDE's bucket is e-sign templates, and MATERIALS is the marketing library — a flyer and an employee handbook do not belong together. Org-scoped like MATERIALS, with delete/overwrite/folders on because HR curates this by hand. Doc types are allowed but optional (isAllowDocType=false, isAllowDocTypeOpt=true), so an org that wants Handbook / Policy / Form categories can turn them on without every other org being forced to file one. Appended last, so no existing ordinal shifts. Its ORDINAL is 13 while its id is 15 — the enum skips id 6, and callers send the ordinal, so the test pins 13 and anchors MATERIALS/CATALOG_SOURCE either side of it. ConversionService and DocsService index the enum by ordinal and need rebuilding before anything sends 13, or values()[13] throws on their shorter array.

  26. · kamo-internal

    Human Resources module shell with five route-backed tabs

    Adds /hr with the accounts-page chrome in its route-backed form (the same one /marketing already uses): a layout owning the gradient hero and underlined tab bar, an index that lands on the first reachable tab, and a page each for Overview, Attendance, Legal & Compliance, Training, and Resources. Two gates, both required. organization.isHrs — the HRS toggle under /settings/account?tab=apps — bounces the route home when the app is off, since with it off /hr is not a place that exists for the org. With the app on, the eleven existing ServiceType.HRS rights decide: a new hasAnyHrRight compound gate joins **************** and each tab carries an OR-group predicate (HR has no single view right the way Marketing does). Tabs the member fails are hidden from the bar and refused on direct URL entry. Registers 'hr' in the nav registry above Settings, defaulting to the primary rail; the home-launchpad card and command-palette entry follow from registry membership. Registry order alone only governs first-run members, though — orderZone appended never-arranged ids, so anyone who had ever touched their nav would have got HR *below* Settings. mergeCanonicalOrder now inserts such ids at the position the registry asks for and useHomeLayout uses the same rule, so the declared placement holds for existing members and every future option too. Tab bodies are placeholders: there is no HR data model anywhere in the backend yet (no employee, attendance, payroll, training or compliance entity in SecurityService, APIService or the shared library), so each tab names itself and what it will hold. Spec in docs/superpowers/specs.

  27. · kamo-internal

    Complete the Communications tab

    Each sub-tab now holds its own data, and All interleaves every channel by date. Notes keeps MediaStream, because notes are authored here — but readOnlyChrome strips the social affordances a customer record has no use for: the PUBLIC / PRIVATE accessor in the composer and on each post, the author edit/delete menu, and the like / comment / share row with its comment thread. Chat keeps the live SocialConversationView. All, Calls, Texts and Emails render the new EmailEntry collapses a message to one line — sender, subject, opening words — and expands in place. A lead's correspondence can run to hundreds of messages and rendering them at full height makes the tab unusable. The body is not fetched until the row is opened, because every read is a live provider round trip; it then renders through the same SanitizedEmailRenderer /messages uses, so there is no second, less-audited path for untrusted HTML. Fixed along the way: PostCard's Edit menu item called handleMenuClose, so it had never opened the editor; and MediaStream dropped PostCard's onPostDeleted / onPostUpdated entirely, so a deleted or edited post stayed on screen in its old form until a full reload. Hardcoded "Public"/"Private"/"Post" in the composer now use the dictionary keys that already existed.

  28. · SecurityService

    Unified communications timeline API

    GET **************** returns one date-ordered page across notes, calls, voicemails, texts, e-mails and chat; ?channel= narrows it. Three sources are merged. Calls, voicemails, texts and e-mails come from the LEAD_COMMUNICATIONS associations; notes and chat are read directly from the lead's media stream and social session, because both are already lead-keyed — mirroring them would have added a dual-write consistency problem and, with no back-fill, lost every note and chat message that already exists. Paging is keyset, not offset. Offset across merged sources is wrong past page one: how many rows each source contributes varies, so "skip 25" does not land on strictly older, so every page costs the same and nothing is skipped or repeated even when several entries share a timestamp. Authorisation mirrors the lead-detail gate exactly, and has to — an entry is largely the lead's own contact value plus the content exchanged, so a caller without VIEW_LEAD_CONTACT_INFO_OTHERS on someone else's lead must not be able to read off this endpoint what the masked lead view withholds. Denials are audited, not just successes. The e-mail body endpoint resolves the mailbox from the association rather than from the caller: lead mail is org-wide, so the message often lives in a colleague's mailbox, and UIDs are unique only within a folder — a browser-driven fetch would silently return an unrelated message from the viewer's own mailbox. MediaAssetUrls extracts the avatar/image URL builders that were private to MediaStreamController, so a post author renders identically in the Notes tab and the All tab.

  29. · DaemonService

    Drive the mail-to-lead association sweep

    Five-minute tick against EmailService's internal sweep endpoint, mirroring VoipGlobalSyncJob. The schedule lives here because EmailService runs several pods and a @Scheduled bean there would have every replica sweeping every mailbox at once. @DisallowConcurrentExecution plus finite HTTP timeouts: a sweep over every mailbox can exceed the tick, and without the guard Quartz would stack runs until every worker thread sat inside EmailService. The timeouts matter for the same reason — with the concurrency guard in place, one indefinitely-hung call would stop the sweep from ever running again until the pod restarted.

  30. · EmailService

    Associate lead correspondence, and fix the dead push indexer

    Adds the mail half of the lead Communications tab, plus the ingestion it needed to exist at all. The platform has no working mail push: IMAP IDLE is hardcoded to Dovecot, there is no Graph change-notification or Gmail watch, and MessageIndexer discarded every notification it ever received because the IDLE publisher omitted the UID its uid<=0 guard rejects — it also resolved the member from the sender rather than the mailbox owner. Both are fixed here, but a hook on that path alone would still have done nothing for most tenants, so association is driven by a sweep over each mailbox through MailReader, which is provider-agnostic by construction. The sweep pages on a timestamp, not a UID. UIDs are monotonic only within an IMAP UIDVALIDITY epoch; a ratcheting high-water mark risks silencing a mailbox re-examining is free because linking is idempotent. CompanyAddressResolver implements the owner's rule: never associate a message where the lead's matched address and every other participant are all company-owned — otherwise adding a colleague's work address to a lead would expose their internal mail. It fails CLOSED: an inventory it could not load answers "unknown" and association is skipped, rather than answering "external" and silently disabling the guard. **************** fetches a body on behalf of the mailbox that holds it. The ordinary endpoint resolves the provider for the caller, and UIDs are unique only within a folder, so aiming it at another member's UID returns an unrelated message instead of an error. Authorisation lives in SecurityService, which resolves the mailbox from the association rather than from the browser. Linking at send time was tried and removed: SMTP returns neither a Message-ID nor a Sent UID, so every outbound mail to a lead collapsed onto one association with no locator to expand. The sweep owns it.

உங்கள் உலகம் காத்திருக்கிறது.

நிமிடங்களில் இலவசமாகத் தொடங்கவும். நீங்கள் தயாராக இருக்கும் போது பொருட்களை சேர்க்கவும் - எந்த மாற்றமும் இல்லை, புதிய உள்நுழைவுகள் இல்லை.

எப்பொழுதும் இலவசம் — கடன் அட்டை தேவையில்லை