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

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

என்ன புதிது.

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

  1. · kamo-internal

    Recognise both platform apexes wherever the app tells a platform host from a tenant's

    kamouniverse.com is now the platform's primary apex and kamocrm.com stays fully served, so every check that asks "is this one of the platform's hosts?" has to answer yes for both, by whole label: - proxy.ts: on a platform host the page's img-src names theme.<apex> and *.<apex> for EVERY platform apex. internal.kamouniverse.com (live today) blocked every stored theme.kamocrm.com picture, and internal.kamocrm.com would block the theme.kamouniverse.com URLs servers build on the primary apex. A tenant's own apex still names only itself. - networkModel.isCustomDomain, which FirstOrgCta now reuses instead of a copy: acme.kamouniverse.com read as a custom domain, so Enter opened **************** — no such host. - OrgOAuthAppSection: a callback on api.kamouniverse.com was described as the org's own domain. - LeadVendorManager: SecurityService builds apply.<primary apex> for an org without a domain, and the check only knew apply.kamocrm.com, so the platform's form read as the org's own host. - /api/org/[...domain]: the platform's client-credentials entry exists under every platform apex. - next.config allowedDevOrigins and the CSP image-host guard accept kamouniverse.com too. Built on isPlatformHost / PLATFORM_APEXES from app/lib/platformApex.ts; no new list of apexes.

  2. · DocsService

    The platform's careers site is careers.kamouniverse.com, and careers.kamocrm.com keeps its board

    kamouniverse.com is the platform's primary apex; kamocrm.com stays a fully served legacy apex. - careers.platform-apex (where a job advert, an applicant's receipt, a talent-alert letter and a network-board card point for an organization with no live domain of its own) now defaults to **************** in all five classes, and k8s/configmap.yaml sets it to kamouniverse.com explicitly so the running value does not wait on a rebuild. careers.kamouniverse.com serves with a valid certificate and resolves to the platform organization exactly as careers.kamocrm.com does. - CareersPublicController recognised the platform's careers site by the ONE configured apex, so moving the setting would have taken the cross-org network board away from careers.kamocrm.com (a 404, fail-closed). It now accepts careers.<every PlatformDomains apex> plus the configured one, comparing the whole apex so careers.acme.kamocrm.com and careers.evil-kamocrm.com are still refused. Tests: **************** pins both doors and the look-alikes; DocsAliasHostTest gains the kamouniverse.com cases for the aliasgroup1 change in fab3d80; the three link tests that pinned the platform-console fallback now expect internal.kamouniverse.com, which is what OrgLinkHosts answers since kamo-shared-library 0e8cf90f. mvn clean test: 848 run, 0 failures.

  3. · SecurityService

    Kamouniverse.com is the primary apex, and a domain is verified by where it resolves

    "Changed the domain from kamocrm.com to kamouniverse.com on /setup/dns. It said it set it but could not verify anything, and after a refresh it still said kamocrm.com." There were three faults. 1. The org's domain was chosen alphabetically. The platform org holds both apexes as verified roots, and kamocrm.com sorts first, so links, sign-in, Behavior & Labeling and the DNS page could never follow the brand. OrgDomains now shares shared-lib **************** which ranks the primary apex first. PLATFORM_APEX is kamouniverse.com. PlatformApexes is kamouniverse.com,kamocrm.com, primary first, and every kamo.platform.apex default reads the constant. Domainless workspaces now open on internal.kamouniverse.com from either door, and login.kamocrm.com keeps working. The domains list also returns primaryDomain and platformApexes, so the page stops re-deriving them. 2. Verification compared a CNAME's target with the literal "kamocrm.com". Every host on kamouniverse.com CNAMEs to kamouniverse.com, so all of them failed. So did an A record straight at the platform, and a CNAME chain. verifyPointsAtPlatform replaces it everywhere: verify-dns, both DomainVerificationWatcher sweeps, and the provisioning target. It follows the host through any A record or CNAME chain to its final addresses and compares them with what kamouniverse.com resolves to now. That address is read live and cached for 60s, with the last good reading kept for an hour if a read fails; it is never configured. A stray AAAA fails the check, because Let's Encrypt prefers IPv6. An unreadable platform address, NXDOMAIN or SERVFAIL are pending, never error. verify-dns returns cnameTarget and platformAddresses so the page can offer the A-record alternative. 3. "Change domain" meant deleting the domain in use. For a platform apex that is refused (409 PLATFORM_APEX, a5bcbd2); the page stops offering it. Recognition stays add-only: ApplicationChatOriginService allows apply. on both apexes, because loan-application links on kamocrm.com live on in sent emails. apply.kamocrm.com has no DNS record today, so the fallback link moving to apply.kamouniverse.com (which serves) also fixes links that were dead.

  4. · KlusterServices

    Auto-cert pre-issues analytics, desktop and myloan on kamouniverse.com

    - STATIC_DOMAINS gains analytics.kamouniverse.com, desktop.kamouniverse.com and myloan.kamouniverse.com, twins of kamocrm.com hosts that are reached only through a link. A host with no certificate never produces the access-log line the dynamic scan needs. analytics.: kamo-internal frames analytics.<its own apex>. desktop.: KamoDesktop's new route. myloan.: SecurityService PortalUrls builds https://myloan.<live root>, and the platform's live root is now kamouniverse.com. myloan has no DNS record yet; the loop skips it until the owner adds the CNAME. - ALWAYS_ALLOW_APEXES names kamouniverse.com outright next to kamocrm.com, so hosts under the primary apex stay allowed whatever STATIC_DOMAINS holds. - Comments and one log line stop calling the static list "kamocrm-specific", and the SUBDOMAINS note says the labels serve both platform apexes. The default certificate (tls-kamocrm-com) is unchanged on purpose: it is what an SNI-less client calling kamocrm.com validates against.

  5. · KlusterServices

    Serve desktop.kamouniverse.com, and bounce a bare computers.kamouniverse.com to its login

    desktop.kamouniverse.com had DNS but no route, so it answered Traefik's 404 behind the default certificate. It now serves KamoDesktop through desktop-https-kamouniverse. That route has the same four rules, priorities and middlewares as the desktop.kamocrm.com routes, uses tls: {}, and bounces a bare visit to login.kamouniverse.com. It lives in traefik/routes/ because a push to desktop/ restarts SecurityService, re-runs the Guacamole bootstrap job and re-applies the KubeVirt VM. desktop.kamocrm.com is untouched. computers.kamouniverse.com is served by the org-domain routes, and it is now where SecurityService sends the platform organization, because the platform's live root domain is kamouniverse.com. hc-to-login only recognised computers.kamocrm.com, so a bare visit showed Guacamole's password box, which can never succeed. The new hc-to-login-kamouniverse sends it to login.kamouniverse.com. Every other organization's host matches neither regex and behaves as before.

  6. · kamo-shared-library

    Kamouniverse.com is the platform's primary apex

    The brand moved from kamocrm.com to kamouniverse.com, but nothing the platform generates could follow it. Every "which of this org's domains" rule ranked by fewest labels then alphabetical, so the platform organization, which holds both apexes as verified roots, always came out as kamocrm.com. Changing the domain on /setup/dns therefore never took. PlatformDomains is now the one list: PRIMARY_APEX kamouniverse.com, LEGACY_APEX kamocrm.com, and ROOT_PREFERENCE, which ranks the primary apex first. OrgApiHosts, OrgThemeAssets and SecurityService OrgDomains share that rule. **************** the host a link falls back to for an org without a live domain of its own, is the primary apex. OrgApiHosts.PLATFORM_API_HOST deliberately stays api.kamocrm.com. The platform's OAuth apps are registered there in Google's, Microsoft's and RingCentral's consoles. Moving it needs those consoles changed first.

  7. · kamo-register

    The sign-up screens credit KamoUniverse and fall back to its apex

    kamouniverse.com is now the platform's primary apex (kamocrm.com stays a fully served legacy apex): - Theme.tsx: PLATFORM_APEX, the theme host used before the browser knows its host or on a host with no apex, is kamouniverse.com. Any real host still asks theme.<its own apex>. - RegisterFlow: the server-render placeholders for the sign-in link and the org domain are login.kamouniverse.com / kamouniverse.com. The browser replaces both with this site's own login.<apex> on mount, as before. - "Powered by / Built on / Running on" pill names KamoUniverse on every door without an apex brand of its own and links to www.kamouniverse.com (its business-OS page and product line stand in for kamocrm.com's /product and /features, which that site does not have). - ThemeLogo's default alt is a neutral "Logo" (it paints any org's logo). - The sorry page's "Contact Support" is support@kamouniverse.com: the mail stream verified kamouniverse.com inbound is live and aliased to the same mailbox. Kept: JAVA_API_BASE = api.kamocrm.com in the BFF routes. It is the shared platform API host (OrgApiHosts.PLATFORM_API_HOST stays) and a server-to-server call; api.kamouniverse.com routes identically, so moving it buys nothing. Cookie scoping and the checkout hand-off are host-derived and untouched.

  8. · kamo-login

    The sign-in screen credits KamoUniverse and falls back to its apex

    kamouniverse.com is now the platform's primary apex (kamocrm.com stays a fully served legacy apex): - Theme.tsx: PLATFORM_APEX, the theme host used before the browser knows its host or on a host with no apex (localhost), is kamouniverse.com. A page browsed on any real host still asks theme.<its own apex>, so login.kamocrm.com keeps reading theme.kamocrm.com. - "Powered by / Built on / Running on" pill names KamoUniverse on every door without an apex brand of its own (white-labelled tenants and the legacy kamocrm.com door) and links to www.kamouniverse.com. That site has no /product or /features, so those variants go to its business-OS page and its product line (both verified 200 in every locale). The KamoUniverse door's own override is unchanged. - ThemeLogo's default alt is a neutral "Logo": the image is whichever organization's logo the screen paints, so "KamoCRM Logo" was wrong for every tenant. The theme folder the kamouniverse.com door paints, cookie scoping and the checkout hand-off are host-derived and untouched.

  9. · kamo-internal

    The All tab and badges reload when anyone writes a note on the lead

    The lead's Communications opens on All, whose timeline reloaded only when this member posted a note from it, so a note written by someone else (another member, a Hot Reassign, an AI member's tool) still needed a page reload there. useLeadNoteWritten follows /topic/media/feed/<orgId> on the tab's shared media socket, learns the lead's stream from its feed, and calls back (coalesced, and after a reconnect) for a note in that stream; LeadCommunications reloads the timeline and the badge counts with it.

  10. · kamo-internal

    A lead's Notes reloads when a note is written in its own stream

    MediaStream (a lead's Notes, the Clubhouse feed) listened on /topic/media/feed/<orgId> but reacted only to POST_CREATED/POST_UPDATED — and nothing was ever relayed there. MediaService now relays the org's media.feed events, where a new note or post is COMMENT_ADDED naming its stream. The feed remembers the stream it lists (the response's new streamGuid, or its posts' guid) and reloads, quietly, only for a note in that stream: a Hot Reassign note now appears for another viewer of the lead without a reload. The rule is app/lib/mediaFeedEvents.ts.

  11. · SecurityService

    A feed names the stream it lists (streamGuid)

    The browser's feed reloads when /topic/media/feed/<orgId> says a note was written in its own stream. A lead with no notes yet has no post whose guid names that stream, so the first note another member wrote there (a Hot Reassign note, typically) could never appear live. GET /api/security/media/feed now returns streamGuid for the lead feed and the org feed.

  12. · MediaService

    Relay media.feed.<orgId> to /topic/media/feed/<orgId>, guarded by org

    A new post or lead note is announced on media.feed.<orgId>, and kamo-internal's MediaStream (a lead's Notes, the Clubhouse feed) listens on /topic/media/feed/<orgId> — but nothing ever relayed one to the other, so a note one member wrote (Hot Reassign included) appeared for another viewer of the lead only after a reload. MediaFeedStompRelayController subscribes media.feed.* on core NATS with no queue group (every pod delivers to its own sockets) and relays only a numeric org id. StompDestinationAuthz now guards the topic like the social feed: SUBSCRIBE by the session's own org only, no client SEND.

  13. · KlusterServices

    Svc_media may subscribe media.feed.* to relay the org feed to the browser

    SecurityService and MediaService announce a new post or lead note on media.feed.<orgId>, and the browser's feed (the lead view's notes, the Clubhouse feed) listens on /topic/media/feed/<orgId>. Nothing connected the two: svc_media could publish media.feed.> but not subscribe to it, so no relay could exist. MediaService's new MediaFeedStompRelayController subscribes media.feed.* (one token: the org id; media.feed.lead.* is not relayed).

  14. · kamo-internal

    AI invitees join by themselves; meeting history link; keep-AI-transcripts setting

    The meeting dialog's invitee picker reads SecurityService's by-department answer under membersByDepartment (it read the top level, found nothing and never showed a picker when opened without a member list). An AI invitee wears the AI chip and brings the joins-by-itself hint from every entry point: the Interaction Center and member list pass the flag, and a member preselected from a conversation or member card is flagged from the picker's list. The invitation subject is sent as the meeting title. Meeting history is offered with VIEW_MEETINGS and goes through navIntent. Recording settings gain the AI companion transcript switch, outside the recording block; meet setting hints meet WCAG AA contrast.

  15. · KlusterServices

    Kamo Meet bridge — Jigasi transport and endpoint, PIN dial-in on 7800, trusted entry for AI members

    No user- or caller-typed text enters a dialplan expression: the room checks compare lengths and the AI's display name is filtered before it is tested (a quote in a typed room name could otherwise turn the check false and dial the filtered room). The resolver header is set once, before the PIN retry loop.

  16. · kamo-internal

    The assistant streams its answers, with REST as the fallback

    The assistant had been REST-only since before KamoAI: its WebSocket context reported "connected", opened no socket, and posted each message, so the whole answer arrived at once. It now opens AIService's /ws/ai-chat on api.<the org's domain> with a one-time key (/api/generate-otk?purpose=ws) and shows the answer as it is written: - TOKEN frames stream into the answer bubble; MESSAGE_COMPLETE's saved answer (with its citations) replaces it, and a frame without text keeps what streamed; - a TOOL_RESULT files the text before the tool call and the tool's row, as the transcript reads on reload; - messages go one at a time, so two answers never stream into one bubble; frames of another conversation on the same socket are ignored; - REST stays the fallback when the socket cannot be opened (no key, no api host, a refused or slow handshake); a socket that drops mid-answer ends it with an error instead of asking again; - the socket opens with the first message and closes after five idle minutes. The 501 /api/ai/ws placeholder, which said the socket could not be reached, is removed. SP99-T10.

  17. · KlusterServices

    A workstation probe that never prints the MCP token

    SP11's acceptance read an AI workstation's descriptor and probed its MCP bridge by hand, and one diagnostic line printed a live bearer token into a session transcript (SP11 Task 30 review, finding 2). canary/workstation-probe.sh does both. describe prints the descriptor with the token as "<present>" or null (--refresh mints a new one); probe runs initialize, the tool names, a screenshot's type and a wrong token from an ephemeral container in the Tool Plane's pod, and every line it prints, its errors included, is masked. The token lives in a shell variable and the probe's stdin only. The tests fake kubectl with a known token and run the generated probe with curl against a local bridge.

  18. · kamo-login

    Send a universe sign-up to its checkout, or to create its organization

    kamo-register parks a paid sign-up's plan in sp_checkout_plan, and the KamoUniverse site's plans are the universes' own (family_premium, community_starter, personal_pro, ...). planCheckoutUrl only honoured starter|business|enterprise, so a buyer who had just verified their email and signed in was dropped on the home screen instead of checkout. planCheckoutUrl moves to lib/planCheckout.ts and accepts the shared contract **************** It forwards the universe to **************** — always the PLAN's universe, since that is the ladder it is sold from — whenever the plan belongs to Family, Community or Personal or kamo-register parked sp_checkout_universe; it clears that cookie with the plan and code. A FREE sign-up into Family, Community or Personal parks a universe and no plan. With no explicit ?next= and no job advert, it now lands on /network/create?universe=<u> in the workspace, where the create page preselects that universe; the cookie is spent on use. Business is the create page's own default, so a Business sign-up lands wherever it always did. The Business funnel is unchanged: **************** still yields **************** with no universe on it. tests/planCheckout.test.mjs pins it (node --experimental-strip-types --test tests/*.test.mjs).

  19. · kamo-register

    Carry a universe plan and its universe into checkout

    The KamoUniverse site signs people up as **************** and its paid plans are the universes' own: family_premium, community_starter, personal_pro and so on. The completion handler only parked starter|business|enterprise, so every universe sign-up that had chosen a paid plan finished registration and was never sent to checkout. The hand-off moves into lib/checkoutHandoff.ts and accepts the shared contract **************** (free plans need no checkout and park nothing). It also parks sp_checkout_universe from a valid ?universe= — with or without a plan, since a free sign-up into a universe still has to reach "create your organization" with that universe chosen, which kamo-login now does. Same cookie attributes and apex rule as before, so kamo-login clears what this writes. The Business funnel is byte-for-byte what it was: ?plan=starter|business| enterprise[&code=] writes exactly the same cookies. `npm run guard:checkout` pins that, and the rest of the contract. A sign-up that names a universe says so under the step counter: "You're starting a Family universe".

  20. · kamo-internal

    Ask which universe a customer's organization belongs to, and read plans by type

    The platform now sells four plan ladders — Business, Family, Community and Personal — and an organization's universe decides which one it is offered. /network/create asks the question, once, where it belongs: only when the organization is being created directly under the platform (the session's organization is top-level), which is where a customer's first organization is made. Everywhere else the new organization is a branch of an existing customer and SecurityService gives it its parent's universe, so no picker is shown and no `universe` is sent. The parent is read from /api/org/current rather than the shell's OrgContext, which on the shared host starts as the platform and would flash the question at somebody creating a branch of their own company. The picker starts answered — Business, or whatever the KamoUniverse site's hand-off link named **************** — so it can never block a launch. A paid plan from that link that belongs to the chosen universe is carried through `/validate?next=` into the NEW organization's billing console with the plan already selected, keyed on the creator's own membership there. `universe` rides on POST /api/security/org only when it was asked; SecurityService parses that body field by field, so the key is ignored until the universe-aware SecurityService lands. The plan surfaces compared codes: `planCode === 'FREE'` (MyPlanWidget, PlanUpgradeDelta, PlanStandingHero, /myplan) and `=== 'ENTERPRISE'` (SubscriptionOrderWizard). On a Family organization there is no FREE — its floor is FAMILY_FREE — so the page found no floor to measure a trial against and offered the free plan as an upgrade. They now ask planLadder: the floor is plan_type FREE or a code that names it (every answer given before is kept), and a negotiated plan is ENTERPRISE or <UNIVERSE>_ENTERPRISE. The billing console was already catalog-driven and needed nothing. /myplan shows the organization's universe as a read-only chip on the org line. An absent `universe` — every organization created before universes — reads as Business (universeOrDefault). Keys: kamo-translation-dictionary 1fcb6274 (pushed first).

  21. · APIService

    The public subscription catalog takes ?universe=

    The KamoUniverse site shows the Family, Community and Personal plan ladders, and the public catalog proxy only forwarded locale, so it could only ever return the business plans. **************** and **************** now forward an optional universe (letters only; anything else is a 400 before it reaches the upstream query string). SecurityService decides what it names and reads an absent one as business, so kamocrm.com, which sends none, gets the same upstream URL and the same four plans as before.

  22. · BillingService

    The billing console sells an organization its own universe's plans

    KamoUniverse adds Family, Community and Personal ladders beside the business one, and BillingService assumed a single catalog: "the Free plan" was the code FREE, "negotiated" was the code ENTERPRISE, and the market was the root's first one. - resolveBillingMarketId: a Family/Community/Personal org buys from its universe market (KamoFamily, ...), so the console lists that ladder only. Business unchanged. - create/update refuse a plan from another universe than the target org's, so a family cannot post the KamoCRM market id and buy the business ladder. - Free-plan checks go by plan type (FAMILY_FREE, ...) or the business FREE code; an expired trial or a lapsed plan falls back to the org universe's Free plan. - Seat ceilings: business keeps "25 on any plan, Enterprise above"; the new ladders cap each plan at its own seat count and point at the next plan up, with only the negotiated plan uncapped (Personal has none: Pro's 5 is the end). - EnterprisePlanGuard guards every plan_type CUSTOM plan on the platform org, not only the one coded ENTERPRISE. - The shared add-ons (mail, phone, storage) filed under the KamoCRM market are listed on a universe market when compatible with its plans, and a business promotion is not advertised on a universe market. Plan DTOs carry "universe". Needs kamo-shared-library's UniversePlans (pushed first).

  23. · SecurityService

    Organizations are created in a KamoUniverse universe and bill from its catalog

    KamoUniverse sells Business, Family, Community and Personal plan ladders from the platform org. SecurityService decides which ladder an organization is on, and every place that assumed "the Free plan" or "Enterprise" now asks per universe. - POST /api/security/org takes an optional "universe" (business | family | community | personal, case-insensitive; unknown is a 400). Absent, a branch inherits its parent's unless the parent is the platform or a platform product; otherwise BUSINESS (stored null, like every existing org). - Org payloads (/org/current, /org/{id}, /org/domain/{host}, /org/ref/{ref}) carry "universe" through the entity; the /network rows (my-networks, all-networks) carry it too. "BUSINESS" for every org that predates universes. - /pos/subscription-catalog and /pos/subscription-promotions take ?universe=. Absent is BUSINESS, so kamocrm.com and the public proxy see exactly today's catalog. List prices are withheld from every plan_type CUSTOM plan, not only the one coded ENTERPRISE. - EntitlementService: the Free floor is the member org universe's Free plan (a family's floor no longer carries the CRM); a trial grants the whole catalog for BUSINESS as before and the universe's top tier elsewhere. - BillingSetupService seeds a new org onto its universe's Free plan, in that universe's market (KamoFamily, ...), instead of FREE in KamoCRM. Needs kamo-shared-library's UniverseType / UniversePlans (pushed first).

  24. · InitializerService

    The Family, Community and Personal catalogs beside KamoCRM's business ladder

    KamoUniverse sells four catalogs out of the platform org's one plan table. This lands the schema and the data for the three new ones. - UniverseColumnsMigration (@Order 0): orgs.universe_type and **************** nullable INT, no default - null is BUSINESS, so nothing is backfilled and no existing row changes meaning. - UniverseCatalogMigration (@Order 50), insert-if-missing and scoped by org_id: the KamoFamily / KamoCommunity / KamoPersonal SUBSCRIPTION markets; the twelve plans (FAMILY_*, COMMUNITY_*, PERSONAL_*) with universe_type and an explicit market_id, so KamoCRMMarketBackfillLoader never absorbs them into KamoCRM; their monthly/annual/triennial per-seat prices; USERS (seat ceiling, unlimited on the negotiated plans) and STORAGE (4 GB/seat) rows; the "Add-on" mail and phone rows; compatibility for the five add-ons every plan may buy (both mail, both phone, extra storage); and Community Premium's 51-250 seat band at 15% off. - UniversePackages: which apps each new plan includes, read by both **************** (the authority, which writes the rows) and **************** so they cannot disagree. No CRM on the Family or Personal ladders; mail, the origination systems, patient records and Hosted Computers on no universe tier. - The origination/EHR/Hosted Computers add-ons are made compatible with BUSINESS negotiated plans only when first created, never the Family/Community ones. - The totality test's "commerce children sit exactly with POS" rule is the business ladder's history; it now checks business codes, and a new check keeps every universe tier from bundling a commerce child without POS.

  25. · kamo-shared-library

    Organizations and plans belong to a KamoUniverse universe

    KamoUniverse sells the platform to four audiences - Business, Family, Community, Personal - each on its own plan ladder with packages that fit it (a family gets no CRM). Nothing could tell those catalogs apart: every org resolved its Free floor from the root's plan coded FREE, which includes the CRM and applies whatever the org pays for, so a Family org would have held the CRM forever. - UniverseType (BUSINESS 1, FAMILY 2, COMMUNITY 3, PERSONAL 4) persisted by id through UniverseTypeConverter (unknown id reads null), JSON by name. Null means BUSINESS everywhere; business keeps being stored as null. - Organization.universe (orgs.universe_type) and SubscriptionPlan.universe **************** both nullable. Organization's getter never returns null, so every org payload says "universe":"BUSINESS" for the orgs that predate it. The columns were added and verified in Yugabyte by KamoInitializer's UniverseColumnsMigration before this was pushed. - UniversePlans: pure helpers (no new bean) for a universe's Free plan, top tier, negotiated plan and self-serve seat ceiling. - **************** the Free floor is the org universe's Free plan; a trial grants everything for BUSINESS (unchanged) and the universe's top tier elsewhere. - **************** universe) / getPromotions(..., universe): plans filtered to the universe (null = BUSINESS), add-ons/bundles/promotions pruned to the ones naming its plans; a row naming no plan is business-only. For BUSINESS the result is exactly the pre-universe catalog. Plan DTOs carry "universe".

  26. · KlusterServices

    Dev.kamouniverse.com forwards to www

    The site is live on www.kamouniverse.com, so its pre-launch host stops serving it and 301s to https://www.kamouniverse.com with path and query kept, so existing links keep working. A redirectRegex middleware does it (kamo-nowww only canonicalises a bare apex); priority 300 outranks the site's own IngressRoute, which drops dev in a follow-up. The dev cert stays in STATIC_DOMAINS so https links still forward.

  27. · kamo-register

    Register.kamouniverse.com wears the KamoUniverse brand

    register.kamouniverse.com is the platform's KamoUniverse sign-up door. Its host resolves to the platform organization, so the by-host lookup would answer "crm" and paint KamoCRM's logo, colours, title and favicon over it. A platform apex with a brand of its own now names its theme folder directly: kamouniverse.com -> public/kamouniverse/ (reserved as an alias in SecurityService, provisioned in the theme bucket). getThemePath answers it synchronously so the first paint is already right, and the host lookup is skipped there. A ?org= still paints that organization's own branding. The "Powered by" pill names and links KamoUniverse on that apex, and analytics counts register.kamouniverse.com beside register.kamocrm.com (platform doors only; the hostname keeps them separable). Same change as kamo-login's.

  28. · kamo-login

    Login.kamouniverse.com wears the KamoUniverse brand

    login.kamouniverse.com is the platform's KamoUniverse sign-in door. Its host resolves to the platform organization, so the by-host lookup would answer "crm" and paint KamoCRM's logo, colours, title and favicon over it. A platform apex with a brand of its own now names its theme folder directly: kamouniverse.com -> public/kamouniverse/ (reserved as an alias in SecurityService, provisioned in the theme bucket). getThemePath answers it synchronously so the first paint is already right, and the host lookup is skipped there. A ?org= still paints that organization's own branding, on this door as on any other. The "Powered by" pill names and links KamoUniverse on that apex, and analytics counts login.kamouniverse.com beside login.kamocrm.com (platform doors only; the hostname keeps them separable).

  29. · SecurityService

    Kamouniverse.com is a platform apex, not a tenant domain

    login.kamouniverse.com and register.kamouniverse.com become the platform's KamoUniverse sign-in and sign-up doors, backed by a root org_domains row on the platform organization beside kamocrm.com. Judged against kamocrm.com alone, that host resolves to the platform organization and takes the HOST-SCOPED path: only the platform's own members could sign in there, ?org= was ignored, and a member of any other workspace was refused. PlatformApexes holds the list (kamo.platform.apexes, default kamocrm.com,kamouniverse.com; kamo.platform.apex stays the PRIMARY): - isPlatformHost: every platform apex offers the workspace picker. - The fallback workspace host for a domainless organization is internal.<primary apex> whichever door the password was typed at — on the password path, the picker's /session/select, and after a second factor. The platform organization itself still lands on internal.kamocrm.com (OrgDomains.preferred: kamocrm.com sorts first). - OrgNetworkEnterPolicy skips platform apex rows, so a platform root row awaiting certificates can no longer mark the platform "setup incomplete" by winning the unordered first-root-row race. - DomainController's Kamo-owned-zone special cases and the SPF / DKIM / DMARC advisories recognise *.kamouniverse.com as they do *.kamocrm.com. - "kamouniverse" is a reserved alias: it is the theme folder those two doors paint, and an organization holding it would rewrite that screen with its first branding save.

  30. · kamo-marketing

    Let visitors talk to the chat — allow the mic and turn on hands-free

    The hosted chat widget (1.3.1) can take spoken questions and read its answers aloud. Two things stood between it and www.kamocrm.com: - Permissions-Policy said microphone=(), which denies the mic to every frame including this document, where <kamo-chat> runs; the widget detects that and hides its mic button entirely. It is now microphone=(self): this origin only, embedded third-party frames stay blocked, and the browser still asks the visitor before any audio is captured. - The embed now passes voice="hands-free" (mic in the composer, a hands-free conversation toggle and read-aloud), plus the page's locale, so a visitor on /es is listened to and answered in Spanish rather than in the org default.

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

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

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