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

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

என்ன புதிது.

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

  1. · kamo-internal

    "All leads / accounts / applications" on a campaign, at any size

    Each id box on the campaign editor now has an "All …" box beside it. Ticked, the box folds into a live panel for everyone of that kind the signed-in member can see, with how many addresses that comes to — counted for a small organization, inferred for a large one ("≈ 4.9 billion ± 2%") and refining in place as EmailService announces a better figure. A box the member can't use says why. Nothing in the editor holds the whole list any more: - The saved list is a server-paged grid (search by address, filter by status, mark rows to take off), and Save sends the page's changes as slices with a progress bar — not the list. - "Preview as" is a search across this page's new addresses, the saved list and each ticked audience, a page at a time, instead of a menu of the first fifty addresses loaded in the browser. - The recipient summary adds the list, what Save will add and each audience, and says plainly that nobody is emailed twice and opt-outs come off as it sends. - A sending campaign shows how far each audience has been gathered. The staged outbox, the workspace's outbox summary and the editor's outbox slice no longer poll: they re-read on the campaigns socket's progress frames.

  2. · EmailService

    A campaign can go to every lead, account or application a member can see

    "All leads / accounts / applications" is a rule, not a list. It is stored with the campaign (the bulk-provider blob, campaignAudiences — no DDL), runs on the access of whoever set it or pressed Send, and is gathered by the dispatcher sweep only a few thousand recipients ahead of what the outbound hosts can take, so an audience of billions never exists as a list anywhere. - Reach: exactly what the member could read unmasked — the lead screens' rule (own leads; others' with View contact info of others; unassigned also needs View unassigned leads or a free-for-all product), accounts with View Accounts that agreed to marketing, applications with a pipeline. - Reading: small organizations through their own index by id; large ones by hash-bucket sweep of the table (yb_hash_code on the primary key, pinned with a hint) — the only range these hash-sharded tables can seek. - Counting: exact for small organizations, inferred for large ones from random hash buckets with a 95% range, refined live over NATS (email-audience) and cached per reach in Redis. - Gathered rows are ordinary recipients, opt-out checked, inserted ON CONFLICT DO NOTHING (never an address twice) and marked so unticking a source takes back only what it staged. A campaign is not finished while its audience is still being gathered; cancelling everything left stops it. - The send list is paged (/recipients/page, a seek on the address index) and changed in slices (/recipients/append, /recipients/remove); delete and duplicate no longer load it, and release times are assigned a page at a time. - Preview: /campaigns/audience/browse pages an audience with an id lookup and a time-boxed search. - PHI tenants get the lead grid's per-record access trail for every lead an audience reads.

  3. · EmailService

    The preference page in every language the product speaks

    The page behind every unsubscribe link only spoke English. It now speaks all 22 languages the product UI ships: English, Chinese, Hindi, Spanish, French, Arabic, Bengali, Russian, Portuguese, Indonesian, German, Japanese, Swahili, Turkish, Tamil, Vietnamese, Korean, Italian, Thai, Polish, Ukrainian and Romanian. - Every sentence the page says itself now lives in a message bundle, **************** with English as the source and the fallback for anything missing. Numbers take the right plural form for each language, and dates are written the language's own way (UTC). - The language is chosen per request: a lang parameter wins, then the browser's Accept-Language (quality values honoured, pt-BR falls back to pt), then English. A language the reader picks stays picked through every form and redirect. The page sets <html lang>, Content-Language and Vary, and lists every language, named in itself, at the bottom as plain links. - Arabic is laid out right to left: dir="rtl", logical CSS, a mirrored switch, and the organization's own words (name, subject, address) kept in their own direction. Those words are never translated. - On wide screens the page now uses the full width: who it is for and why on one side, the choices beside it in columns, the notes and footer below. Under 720px it is the same single column as before. - Nothing else changes: every value is still escaped (translated text around it too), no script, the same locked-down headers, GET still never changes anything, and a link that names nobody still gets the same neutral page, now in the reader's language. Tests check that every bundle has exactly the English keys and placeholders and a branch for each plural form of its language, and cover the language negotiation, right-to-left output, dates, escaping, and the language surviving a save and its redirect.

  4. · kamo-internal

    Pages refetch on org change events instead of loading once

    Every successful write through forwardToApi now publishes rt.org.{orgId}.{domain} on core NATS (the domain is the first backend path segment, skipping security/). MediaService relays it to /topic/rt/org/{orgId}/{domain}, and useOrgChanges subscribes over the shared socket, coalesces bursts and fires again after a reconnect. The los, billing and oauth-config routes, which do not go through forwardToApi, publish themselves. Pages that loaded once now refetch silently when their domain changes: no skeleton flash, and never over unsaved input. - Accounts: assign, and the account view (overview, history, leads, members, notes, orders) - Notes - Commerce: orders, agreements, bookings, procurement, requests, service jobs, service requests, signups, subscriptions, personal loans and the aging report - Loans, loan detail and offers - Knowledge base home and article - Careers, legal and compliance - Settings, account settings, integrations, the document category page, and the market and subscription plan pages The calendar coalesces its existing change feed. Achievements follow the member's unlock topic.

  5. · EmailService

    An unsubscribe by email is honoured, not dropped

    Every bulk and shared-article message offered unsubscribe@<sender's domain> in its List-Unsubscribe header, but nothing read that mailbox - for a tenant it was not even our domain - so every opt-out sent that way was lost. - The mailto now names unsubscribe@hello.kamocrm.com **************** for every org, with the recipient's token in the subject: **************** The https one-click link and List-Unsubscribe-Post are unchanged. - POST /api/internal/unsubscribe/mail takes what arrives there, as reported by the mail server's sidecar. It finds the token in the plus-address, the subject (with Re:, in capitals, left URL-encoded, or RFC 2047 encoded) or a forwarded link, resolves it exactly as the preference page does, and unsubscribes that address for that org through the opt-out ledger (source "mailto", with the Message-ID). A campaign row still waiting to be sent is pulled, as with the one-click link. Doing it twice changes nothing. - A message without a token that names somebody changes nothing: nobody is unsubscribed by a guess from the From address, which anyone can write. Nothing is ever sent back. The log keeps the outcome, org, sender domain and Message-ID, never the subject or body. - It sits behind InternalAuthFilter like the rest of /api/internal, refuses requests over 64 KiB, and tries at most five candidate tokens per message.

  6. · kamo-internal

    The Opt Out tab and the lead chip update live

    Both subscribe to **************** (EmailService and SecurityService publish after every committed change; MediaService relays), so a recipient unsubscribing, a bounce or a colleague's edit shows at once instead of on the next load. The org id is the string accessor, never a rounded number. A half-made change in the editor is kept when the address moves underneath it, with a note saying so. Also drops the width caps the tab had on a select and two paragraphs.

  7. · EmailService

    Opt-out screens refresh live when anyone changes the list

    The ledger now tells OptOutChangePublisher after every committed change - a recipient on the preference page, a bounce, a member in Settings - and it publishes rt.org.{orgId}.email-opt-outs on core NATS for MediaService to relay. The frame carries no address; the screen re-reads what its viewer may see.

  8. · SecurityService

    A lead's opt-out change refreshes open screens live

    The ledger here tells OptOutChangePublisher after the change commits, which publishes rt.org.{orgId}.email-opt-outs on core NATS (this service's JetStream stream is chat.>), relayed by MediaService. No address in the frame.

  9. · kamo-shared-library

    The opt-out ledger says when an organization's list changed

    An optional listener, told after the change commits, so the screens showing the list can refresh live instead of loading once. It carries only the organization: who opted out is behind its own right, so the screen re-reads what its viewer may see. The existing constructors are unchanged.

  10. · KlusterServices

    Mail to unsubscribe@hello.kamocrm.com reaches EmailService

    Every bulk and shared-article message offers an unsubscribe by email (List-Unsubscribe mailto), but mail to that address went to postmaster and was never acted on. Now postfix hands exactly that address, and unsubscribe+anything@ on the same domain, to a small pipe that spools the message, and a new unsubscribe-mail sidecar posts it to EmailService's /api/internal/unsubscribe/mail. EmailService finds the recipient's token in the subject (or the plus-address, or the forwarded link) and unsubscribes them exactly as the one-click link does; anything without a valid token is accepted and dropped. - Every other address is routed as before: the one regexp line matching unsubscribe@hello.kamocrm.com sits above the postmaster catch-all, and transport_maps names only the pseudo-domain it rewrites to. - Nothing is ever bounced or replied to: the pipe only ever answers "delivered" or "try later", and caps its spool at 5000 messages. - The sidecar reuses the postfix-bulk-delivery-events copy of the internal secret, optionally, and never exits, so it can not keep postfix from starting or take the pod out of its Service.

  11. · AIService

    The sales agent honours the organization's email opt-out list

    Before any email touch the outbound gate now asks the organization's email opt-out ledger about the contact's address. The address is the one the contact key points at: the lead's email for lead:<uid>, the member's (or its user's) for member:<id>, and only when that lead or member belongs to the same organization. An address on the do-not-email list, or paused, is refused as SUPPRESSED_OPT_OUT with a reason that starts EMAIL_OPTED_OUT_ORG_LIST. It is checked straight after the contact's own opt-out and ahead of everything incidental, and it applies even to a contact the agent has never touched. If the list cannot be read the email is refused too (EMAIL_OPT_OUT_CHECK_FAILED): agent outreach is unsolicited, so an unanswered check must never become a send. Other channels are unchanged. An opt-out recorded through recordOptOut for email, or for every channel, now also puts the address on the organization's do-not-email list (reason UNSUBSCRIBE, source ai-agent-opt-out, context AI_CONTACT with the contact key), so every sender in the organization and the lead page see it. Ledger reads and writes run in a transaction of their own and never throw. The ledger is transactional itself, and an exception inside the caller's transaction would roll back the refusal's audit row or the contact's own opt-out. A failed write is logged and the contact's own opt-out still stands. The ledger is declared as a bean over its three repositories. Its probe for the new opt-out tables is built from the primary DataSource, the only one this service has. com.kamo.z.shared.email joins the repository scan; the bean and the scan must change together.

  12. · MediaService

    Relay org change events to /topic/rt/org/{orgId}/{domain}

    Writers publish rt.org.{orgId}.{domain} on core NATS after a successful change; every pod relays it to the org's topic so open screens refetch instead of loading once. SUBSCRIBE is checked against the session org, and client SEND to the prefix is refused.

  13. · kamo-marketing

    A hidden, per-visitor site hunt for a capped promotion, and signals that lead visitors into it

    The hunt: seven locks per visitor, generated from a seed and HUNT_SECRET, enciphered with the previous answer, hidden on a page that moves every UTC midnight, with time gates and a 72-hour minimum. Stateless signed tokens; the prize is a personal code issued by SecurityService from a template promotion, derived from the solver's seed so a retry never takes a second slot. scripts/check-hunt.ts plays 400 hunts to the end and fails the build if any stage cannot be solved from what a solver is shown. The way in, for someone who has never heard of it: three signals. A word in the landing page's copy glitches; finding it names the next page (Pricing first) and links there, the nav link to it glows, a pill keeps the count across pages, and the third opens the hunt. Desktop exit intent once per session, and "start free" at every step. Each step is an analytics hunt-* event. Everything fails shut: no template, no secrets or no codes left means no footer line, no signals and /api/hunt answers CLOSED. /hunt states the terms exactly as the template defines them.

  14. · SecurityService

    Issue personal single-use codes from a template promotion

    The kamocrm.com site hunt hands each solver a code of their own, and only the first N solvers ever get one. A shared code could not do that: the first solver to post it would hand the discount to everyone. - PromotionCodeIssuer: an INACTIVE promotion is the template; its maxRedemptions is how many personal codes may be issued. Slots are taken by a conditional UPDATE so two replicas cannot over-issue. A caller may name the code, and asking again for an issued code returns it without taking a second slot. - **************** on the cluster internal secret. - The public promotions feed drops single-use codes, so a personal code can never be listed or advertised in the homepage hero.

  15. · EmailService

    A real preference page behind every unsubscribe link

    The unsubscribe link opened a bare confirm-or-leave card. Someone who only wanted fewer emails had no way to say so, and nothing told them why they were being mailed, what would keep arriving, or that their choice was kept on record. The link now opens a preference page for that address and sender. Unsubscribing from everything comes first and is one press. After it, the reader can switch off one kind of mail (when there is more than one to choose between, or one is already off) or pause everything for 30, 60 or 90 days. Once unsubscribed they can resubscribe with one button, or tell the sender why they left. The page says why the email came, what they will still receive, and that each change is recorded. Every change goes through the opt-out ledger together with the request it came from, so the history shows the choice was the reader's own. Opening the page records a view and changes nothing. One-click requests from mail clients (RFC 8058) still unsubscribe from everything, always answer 200, and still pull a queued campaign row from its send. A link that names nobody gets the same neutral page on every route and never reaches the ledger. The page is plain HTML forms with no script. It is drawn in the sender's brand colour, adjusted until it meets WCAG contrast in both light and dark themes, and it works from 320px wide up. Every response carries a strict content security policy, no referrer (the token is in the URL), no-store, noindex and a frame ban. Rendering lives in suppression/page: a view record, a pure renderer that tests and previews call directly, and a service that resolves tokens and talks to the ledger. The controller only routes and sets headers.

  16. · kamo-internal

    Email opt-out chip and panel on the lead page

    Beside the lead's email address there is now a chip saying whether the person may be emailed: Emails allowed, Opted out of all email, Paused until a date, Some emails off, or No email address. It opens a panel that explains the current state in plain words (who changed it, when and why), with switches for each kind of email, an "opt out of all email" switch, a 30/60/90-day pause or ending one, and the recent history with the request details behind a toggle. Whenever a change would let email reach the person again, the note becomes required, says why, and Save waits for it. A member who may not change it is told why and sees everything read-only; before the history tables exist the panel says so calmly instead of failing. The email quick action now asks first when the person opted out of all email or paused it, and lets the member write anyway for a one-to-one reply. Adds the proxy route for **************** passing the server's field and code through so the panel can put an error beside the right input.

  17. · SecurityService

    See and change a lead's email opt-out from the lead

    A member working a lead can now see whether that person may be emailed, and change it, without the org-wide opt-out settings list. GET **************** answers with the address's state on the organization's opt-out ledger, its ten most recent changes and the topics an address can stop. Who may read it follows the lead itself (401/404/403 as for opening the lead, free-for-all leads included). A caller whose view of the lead's contact details is masked gets the address masked the same way and no IP, browser or session details on the history rows. PUT on the same path changes it. It is allowed exactly when editing this lead's contact details is allowed (the assignee, or EDIT_LEAD_CONTACT_INFO_OTHERS plus VIEW_UNASSIGNED_LEADS for an unassigned lead) and never while the address is masked. The change is recorded as MANUAL from "lead:<id>", with the member, the request's addresses and browser, and a hash of the session. Allowing email again needs a note, which the ledger enforces (400 with field "comment"); until the history tables exist a change is refused with 503 HISTORY_UNAVAILABLE. Each change also leaves a row on the lead's own History tab. The ledger is declared here with its own schema probe, as EmailService does.

  18. · EmailService

    An org admin can see and change the whole opt-out list

    Settings -> Email -> Opt Out now has its API under /api/email/opt-outs, behind MANAGE_EMAIL_OPT_OUTS (god bypasses): a summary with the last 30 days, the list filtered by state, reason and address, one address with its full history and everywhere else it appears in the organization, the org-wide activity, a CSV export, and changes and notes made through the opt-out ledger. Every change is recorded against the member, the client address the proxy passed on, and a hash of their session. Ids are sent as strings and times as ISO-8601, as the web app expects. Until the history tables exist the list, summary, address and export still work from the do-not-email list alone, and a change answers 503 with HISTORY_UNAVAILABLE instead of being half made. The schema probe now builds its query over the primary database. It was being given the only JdbcTemplate bean in this service, the mail server's MySQL one, so it could never see the opt-out tables and every member's change would have been refused.

  19. · kamo-internal

    Settings -> Email -> Opt Out, the organization's do-not-email list

    Everyone who asked not to be emailed, in one place. A masthead says how many are off all email and why (unsubscribed, bounced, marked as spam, asked us to stop), how many stopped only some kinds or paused, and how the list moved over thirty days. The list is searchable and filterable; an address opens beside it with: what they receive one row for all email, one per kind of mail, and a pause, saved as a draft. Letting mail reach someone again needs a note saying who asked and when, because that note is the record of their consent. known as the lead, contact, campaign sends, job application, job alerts and AI assistant opt-out that share the address history every change as a timeline: what moved (before/after), who did it and through what, the note, and the request it came from (network address, forwarding chain, browser, language) Plus an org-wide activity feed, adding an address by hand, and a CSV export. Gated by MANAGE_EMAIL_OPT_OUTS (a child of MANAGE_EMAIL_SETTINGS), mirrored in RoleRightType.ts and rightsHierarchy.ts; the tab, the menu entry and the settings card only appear with it.

  20. · kamo-internal

    Square, bevelled buttons and a 2px-cornered thumb on every scrollbar

    The bar's four buttons (jump to start, step back, step forward, jump to end) are now 20px squares with hard corners, and the thumb keeps only a 2px radius. Both carry a one-pixel inset bevel - light along the top and left, dark along the bottom and right - in translucent white and black, so the same bevel sits on the page's slate, a brand tint, the terminal's dark palette. The skin's single `rounding` fraction becomes two pixel radii, thumbRadius and buttonRadius, because "a couple of pixels" is an absolute. The square key is geometry rather than skin: it holds on a short bar (10x10 on a 72px strip) and on the arcade skin, whose look is otherwise unchanged.

  21. · EmailService

    Every suppression check and bounce goes through the opt-out ledger

    SuppressionService now asks EmailOptOutLedger, so a check sees the do-not-email list, pauses and topics alike, and a bounce lands in the same history as an unsubscribe. Callers name the kind of mail they are about to send: campaigns (materialize, restore, the late gate) ask about MARKETING_CAMPAIGNS, article shares about SHARED_ARTICLES. Bounces carry the server's answer and the campaign into the history row. OptOutSchemaProbe tells the ledger whether KamoInitializerService has created the two new tables yet; until it has, sending honours the list alone instead of failing on a missing table.

  22. · kamo-shared-library

    One opt-out ledger, topics, pauses and a history of every change

    The do-not-email list could be written to but not read, changed or explained. This adds the one place it is read and written from, for every service: email_optout_topics an address that stopped one kind of mail, or paused all of it email_optout_events insert-only history: who (recipient, member, system), from where (client IP, the whole X-Forwarded-For chain, user agent, language, host, referer, session hash), why (reason, source, note, feedback), through what (campaign, lead), and the state before and after email_suppressions keeps its meaning, so every sender that already honours it still does. EmailOptOutLedger answers "may this be sent" from all three and writes one history row per part of the state a change actually moved. A member allowing mail again must say why; that note is the record of consent. Until the new tables exist the ledger falls back to the list alone and refuses changes it cannot record, rather than failing sends. Plain class, not a @Service: every service scans com.kamo, and one without the email repositories would fail to start constructing it. Each service declares it with @Bean. Also MANAGE_EMAIL_OPT_OUTS (320), the org right for Settings -> Email -> Opt Out, a child of MANAGE_EMAIL_SETTINGS.

  23. · kamo-internal

    Outbound e-mail hosts, send windows, per-host warm-up and the staged outbox

    - Settings → Platform → Configuration gains an Outbound E-Mail Hosts tab, behind the platform right MANAGE_OUTBOUND_EMAIL_HOSTS: the hosts shared with every organization and the ones kept for the platform organization, with every connection setting, availability, connection checks, test sends and each host's warm-up. - Settings → Email → Bulk Email Sender is rebuilt on GET bulk-provider/overview: the rotation of the organization's own hosts and the platform's (switchable per organization), a round-robin view, the sender, a send window editor (weekdays, several time ranges, overnight ranges, its own time zone or the organization's), and a plain-language warm-up report per host. The warm-up can no longer be switched off. - /marketing/email/outbox lists every staged email — composed only when a host can take it — and cancels single emails, a selection, or everything remaining, with undo. The workspace, the pacing banner and the campaign editor link to it and read the new per-host capacity. - Shared host editor with live preflight (resolved addresses, duplicate and private-address refusals), the outbound hosts and outbox API clients, and the recipient status CANCELLED.

  24. · EmailService

    Several outbound hosts per org, sent round-robin, each warmed on its own, inside a send window

    An organization's campaign mail now leaves through any number of outbound hosts, one message at a time in rotation, instead of one bulk provider. - Hosts: an organization's own (outboundHosts in its bulk provider blob) and the platform's (platformOutboundHosts in the platform organization's blob), SHARED with every organization or PLATFORM_ONLY. Every SMTP setting is explicit: security, SASL mechanism, TLS verification and protocols, HELO name, envelope sender, timeouts, hourly/daily limits, DSN, 8BITMIME, SOCKS. HostSessionFactory builds the session from them; EmailSmtpService.sendVia sends through it. - The same server is never added twice (same name or any shared address, whatever the port or login), and an organization's host must be a public server: private and in-cluster names and addresses are refused on save and again before every connection. - Warm-up is per host and always on. WarmupService works on a WarmupHandle; a platform host has one warm-up shared by every organization using it. New runs start at the local start of day. - WarmupReleaser is the only sender: round-robin across each organization's hosts, skipping a host waiting for its slot, at its cap, braked, at its own limit or backing off after failing to connect. A connection, TLS or sign-in failure no longer counts an attempt against the recipient. - Send window per organization (days, one or more ranges, own zone or the org's). WarmupPacer spreads each day's cap across the window's open time only. - Staged outbox: /api/email/campaigns/outbox lists queued recipients and cancels or restores them. A cancelled recipient is SUPPRESSED with a note (no status DDL) and reads back as CANCELLED. - Endpoints: **************** platform hosts at **************** behind MANAGE_OUTBOUND_EMAIL_HOSTS. The one-host writes answer 410. - OutboundHostBackfill seeds the k3m1 relay as a PLATFORM_ONLY host and migrates one-host blobs. No schema changes.

  25. · KlusterServices

    Postfix-bulk accepts any sender from EmailService [skip ci]

    The relay is now a platform outbound host that every organization's campaign mail may go through, as whatever From that organization sends as. Only the null sender is still refused, with a 4xx. Reachability is unchanged: mynetworks and the NetworkPolicy limit it to EmailService pods. Applied directly (kubectl apply -f ****************

  26. · kamo-shared-library

    MANAGE_OUTBOUND_EMAIL_HOSTS, the platform console's outbound e-mail hosts

    A platform right for the outbound e-mail hosts campaign mail leaves through: the hosts shared with every organization and the ones kept for the platform organization, their credentials, availability and warm-ups. Enforced by EmailService's PlatformOutboundHostsController through PlatformRightsResolver. Appended, so no existing right is renumbered.

  27. · kamo-internal

    Delete, filter and switch off NoReply Outbound rows

    The audit page gains a subsystem column and filter, checkbox selection with "select all" and "select all matching", and deletes for one row, the selected rows, everything matching the filters, or everything, each behind a confirmation that names the table the rows are removed from. "Recording & retention" switches each subsystem's recording on or off and sets how long rows are kept. The request each delete becomes, and how the grid's selection model is read, live in **************** with their own tests.

  28. · EmailService

    The NoReply ledger can be filtered by subsystem, pruned, and told what to record

    Each row now names the subsystem that sent it and, for a template send, the template key. EmailTemplateService and the campaign sender open a NoReplyOutboundSource scope around their SMTP send; anything else is UNATTRIBUTED. NoReplySubsystem maps the canonical template keys to subsystems, and a test fails if a canonical template maps to none. Deletes go to the table itself through NoReplyOutboundLedger: one row, up to 1000 selected rows, every row matching the list's filters, or the whole ledger (TRUNCATE), which has to be asked for with confirmAll. Bulk deletes run in chunks of 500. NoReplyOutboundSettings stores a recording switch per subsystem and the retention (30 days by default, 0 keeps rows until deleted), cached for 15 seconds per pod. NoReplyOutboundRetentionSweep purges hourly on one pod. All new endpoints are god-only, like the list.

  29. · InitializerService

    The unique (campaign, address) index, for a fresh environment

    EmailService used to create **************** on every startup; DDL on this cluster belongs here instead. Idempotent, auto-committed (YugabyteDB builds indexes online), and duplicates are counted and logged, never deleted - a contacted row is a campaign's permanent record of an address. EmailService now only checks for the index by this name.

  30. · kamo-internal

    The campaign editor writes edge to edge, merge tokens in their own column

    The subject sits under the campaign title and the audience beside the status chip, so the compose step is the email body alone, filling the middle of the page, with the merge tokens in a column on the right. Nothing saves on its own, so the page now marks edits the server has not seen and asks before leaving would discard them; TemplateInlineEditor reports the member's own body edits apart from Quill's load-time normalization so that mark is not raised by merely opening a campaign.

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

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

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