மாற்று பதிவேடு
என்ன புதிது.
அது கப்பல்கள் போல், தளத்தில் ஒவ்வொரு மேம்பாடு.
· KlusterServices
Require the API key and admit only RAGService
· EmailService
Sending mail needs a seat, for people and AI members alike
A member without a licensed seat is refused with the shared 403 SEAT_REQUIRED body before anything is sent: POST /api/email/send, the shared-mailbox send, and the four meeting-invite routes (send, update, cancel, reply). A calendar event save asks for the seat only when it invites its guests by email (sendInvites true, notifyByEmail not false): the calendar dialog and KamoMobile send notifyByEmail true on every save, so a plain calendar entry stays open to everyone. Internal routes never ask. The deployment also takes the service's own NATS login (nats-user-email), the Redis ACL login (redis-auth) and the KamoAI internal secret.
· MediaService
Meetings, group chats, attachments and calls need the seat that includes them
· kamo-internal
The chat picker lists only the models the member may pick
The picker read the administrator's model list (403 without MANAGE_AI_MODELS) and offered providers, which never selected a model. It now reads GET /api/ai/models/selectable through a new BFF route, drops the provider options, moves a provider-pinned conversation back to Auto, and keeps the provider order AIService sends (the organization's priority) instead of re-sorting it by name.
· InitializerService
Migration for org_alias_domains, seeding the platform org's two
Creates **************** and seeds the platform org (is_top_level) with kamouniverse.com (default, carrying forward the old hardcoded platform.mail.domain) and kontak.kamocrm.com (additional, not default). Applied directly to production ahead of this commit — this service is run manually against the DB, not deployed — so the table already exists; this is the source of record for the next fresh environment or re-run. kamo-shared-library bumped to 1.6.2 for ****************
· EmailService
Read the composer's alias-domain default from org_alias_domains
**************** used one hardcoded domain (platform.mail.domain, kamouniverse.com) as a synthetic send-as default, and only for the platform org **************** Reads OrgAliasDomainRepository instead: any org can register any number of alias domains now, each offered as a send-as identity on the member's primary mailbox, with the org's default-flagged row still prepended as the composer's default exactly as kamouniverse.com was. kamo-shared-library bumped to 1.6.2 for ****************
· kamo-shared-library
Add org_alias_domains, the per-org form of the platform mail domain
Generalizes the single hardcoded platform.mail.domain (kamouniverse.com, and only for the platform org) into a table any org can hold any number of rows in. EmailService's SendableMailboxService reads it to offer each domain as a send-as identity on every member's primary mailbox, same mechanism as before.
· SecurityService
The AI kill switch can be read by whoever holds its right
· kamo-internal
AI Platform Services and AI Kill Switch platform rights
· kamo-internal
The AI Workforce app and its four rights; the app-mirror guard reads Java again
· AIService
One route table decides who may call every AIService route
· kamo-shared-library
A private inbox prefix for new services, and the LOS webhook worker is opt-in
· kamo-shared-library
Services log in to Redis with a username and password when given one
· kamo-shared-library
One seat rule for the console and every service that enforces it
The resolver reads the member with its organization fetched and opens no transaction of its own, so a seat is decided correctly on a thread with no persistence context (the AI WebSocket) and a failed read really fails open instead of throwing UnexpectedRollbackException past the catch.
· KlusterServices
Log in to Redis as mail_rspamd
rspamd reads its password from Secret mail/rspamd-redis-auth, included into local.d/redis.conf. The pod gains fsGroup 11333: the image runs as 11333:11333 and a root:root 0440 Secret file is a fatal Permission denied at config load.
· kamo-shared-library
AI platform services and kill switch rights, and the switch's column
· KlusterServices
ACL users for the platform, rspamd and operators (default still open)
· kamo-shared-library
View, supervise, approve and manage the AI workforce (329-332)
· KlusterServices
One login per workload in the KAMO account, beside kamo_svc
· kamo-shared-library
AI Workforce app, outside the PHI boundary and never automatic
· kamo-internal
Choose how a published application asks its questions
"Publish this application" (Settings → Features → CRM → Vendors & Products) now carries three choices beside the chat, each a pair of cards that say what they mean: - Type: Normal (a few related questions per step) or Squeeze (one question per screen, each explained in plain words). - Contact info: Start (name, email and phone first, saved the moment they are entered, so an abandoned application is still a lead) or Last (the loan first, contact details just before sending; nothing saved until then). - Fields: Full or Basic (only what a first call needs). A live preview beside them redraws the first screen, the section order (contact visibly slides to the end) and what the borrower will meet — how many questions, and when the lead is saved. The dialog is `md` so both fit side by side. The choices travel on the existing PUT …/application (securityservice d345869), round-trip through the vendor list, and prefill when the dialog is reopened. Reopening a live page now says "Save changes" / "Application settings saved." rather than publishing it again, and its row icon is a settings slider rather than a chat bubble, since it opens more than the chat.
· kamo-apps
The lender's layout choices — squeeze, contact first or last, basic
The mortgage application now lays itself out as the product was published (Settings → Features → CRM → Publish this application): - Type. NORMAL is the five grouped steps as before. SQUEEZE asks one question per screen: an eyebrow saying where you are, the question in the display face, a plain-language line on what it means and why it is asked, then one answer. Fields share a screen only when they are parts of one answer (a name, an address, an agent and their company). Tapping a choice moves on after a beat; the keyboard selects with arrows and moves on with Enter. The rail fills question by question. - Contact info. START asks who the borrower is first, and saves the lead the moment there is a name and an email — behind an invisible proof-of-work, the same the send button needs — then adds each later answer to that lead through a token, and the final send finishes it rather than filing a second. The page says so beside the contact questions. LAST moves contact to just before consent, and nothing is saved until the form is sent. - Fields. BASIC keeps name, email, phone, purpose, how the home will be used, state and ZIP, price or value, down payment or balance, and credit. Help text assumes the reader knows nothing: down payment, credit score, HOA, taxes, insurance, the loan programs and the property types are each explained where they are asked. Unanswered yes/no questions stay null (skipped or not yet reached) instead of arriving as "no". Also fixed, both live today: the consent paragraph never named the lender ("you give your express written consent to contact you" — a function passed as an ICU argument rendered nothing), and the receipt's "A copy is on its way to ." dropped the address the same way. The consent lead-in no longer starts with a lowercase "someone". Proxies: **************** (POST) and /progress/{token} (PUT), sharing the X-Forwarded-For handling with the submission. Needs securityservice d345869 for the layout and the progress endpoints; against an older backend the form is the grouped, full, contact-first form and the first early save 404s once and stops.
· kamo-internal
The session tab stops wearing Guacamole's icon
A session tab is Guacamole's document, so its own <link rel="icon" href="images/logo-64.png"> owns the tab, and a member opening their company's computer watches the icon turn into a third party's. Keeping the tab on Kamo's origin and framing the session would have kept the organization's icon; the gateway answers every computers.* route with X-Frame-Options: DENY, so that is not available. The gateway answers for those two files instead. WHOSE ICON IS DECIDED FROM THE HOST, AND SOMETIMES THE ANSWER IS NOBODY'S. An icon request is a plain image GET issued while the browser renders a third party's document. It carries no session and no token, so the host is the only signal there is. On an organization's own computers.<domain> that is a complete answer. On the shared platform host it is not: resolving by host there names the PLATFORM, as layout.tsx already says — "which is nobody's tenant". So the platform host deliberately resolves to no organization and gets an unbranded glyph. Every organization whose domain is not yet live shares that host, and painting KamoCRM's mark on a tenant's tab is the exact thing a white label exists to prevent — while looking, from here, indistinguishable from working. It is also indistinguishable from the correct answer for KamoCRM's own members, which is why there is no exception carved out for them. Nothing has to change for an organization to get its own icon: the moment its computers host is live, the host names it and the route resolves it. The glyph is a plain monitor outline in slate, no brand at all, at the two sizes Guacamole declares. An organization's own icon is resolved alias -> config.json -> favicon set, the same chain DynamicMetaLoader uses, and every failure along it falls back to the glyph: a favicon is not worth failing a page over, and a wrong brand is worse than no brand. THE ROUTE LIVES IN kamo, NOT BESIDE THE REST OF THE GATEWAY IN hosted-computers. Traefik runs with allowCrossNamespace and allowExternalNameServices both at their default of false, so an IngressRoute over there cannot reach kamowebinternal-service, and turning on either flag is a cluster-wide change to reach one favicon. The certificate is already issued in this namespace, so the route sits beside the service it forwards to and CI applies it with the code. themePublicBase is extracted so the bucket's layout is written down once: Theme.tsx is "use client" and the server needed the same shape.
· kamo-internal
Arive in CRM markets, on the lead page, and on member profiles
- Markets: "Arive" joins the MLOS dropdown, and its Configure dialog holds the four Zapier hooks (write-only, masked), the Arive → Kamo addresses to paste into Zaps, the stage → status map, the lead-creation and stage-push switches, a setup guide and the connection's activity log. Configure is now an allow-list: a provider with nothing to configure no longer gets an enabled button that does nothing. - Lead page: LosHeaderActions renders each provider's states — MeridianLink unchanged; Arive create → waiting for Arive (resendable after 15 min, with a confirmation) → open in Arive with its stage, convert for an Arive lead, and a sync-problem chip. A pending link re-reads the market config every 10 s so it turns into "Open in Arive" without a reload. - Profile: the Lender credentials card saves again (it could not since the profile rebuild, c20bac57). Each market row edits on its own: MeridianLink takes username + secret, Arive the member's Arive login e-mail. - MarketConfig.mlosProvider is the provider union, not a bare string. Spec: ****************
· SecurityService
Layout choices, and saving contact details as they go
The publish dialog now chooses how the public mortgage application lays itself out (kamo-shared-library ac83bea1): NORMAL or SQUEEZE, contact details at the START or LAST, FULL or BASIC questions. - PUT **************** takes applicationLayout, applicationContactStep and applicationFieldSet; a missing one keeps what is stored, so retiring a page never resets its layout. The response echoes them. - GET /public/loan-application/{p} answers layout {type, contactStep, fieldSet}, always resolved. - POST **************** — for a START product only (404 otherwise): *** fail-closed, submission IP budget, name + email required. Creates the lead with source "Online Loan Application (unfinished)" and answers a 256-bit token held in Redis for a day, written inside the transaction so a Redis failure rolls the lead back rather than guaranteeing a duplicate. - PUT **************** adds answers to that lead through updateLead (absent = unchanged). Token bound to the product. - POST /public/loan-application/{p} with progressToken finishes that lead (source "Online Loan Application", receipt as before) instead of filing a second one; an unknown or expired token files a new lead as before. - Lead ownership is checked BEFORE updateLead rather than by catching its exception: it is @Transactional and would mark the request rollback-only. Ratchet baseline: startProgress and saveProgress added with their reasons, and byHost (added on main by 81e0756 without a line, which left the ratchet red).
· kamo-shared-library
Layout choices for a published loan application
Three columns on LEAD_VENDOR_PRODUCTS, chosen on the publish dialog and read by kamo-apps to lay the public mortgage form out: - APPLICATION_LAYOUT NORMAL (grouped steps) | SQUEEZE (one question per screen) - APPLICATION_CONTACT_STEP START (contact first, saved as they go) | LAST - APPLICATION_FIELD_SET FULL | BASIC Plain strings, not @Enumerated, so no ddl-auto CHECK constraint freezes the value set. Null reads as NORMAL / START / FULL, the form as it was. The DTO carries the resolved values; setProductApplication gains an overload taking the options, with null members meaning "keep", and the old signature delegates to it unchanged. DDL already applied to the cluster as the owner: ALTER TABLE public.lead_vendor_products ADD COLUMN IF NOT EXISTS application_layout varchar(16); ALTER TABLE public.lead_vendor_products ADD COLUMN IF NOT EXISTS application_contact_step varchar(16); ALTER TABLE public.lead_vendor_products ADD COLUMN IF NOT EXISTS application_field_set varchar(16);
· InitializerService
The columns and activity log the Arive integration maps
**************** (unique), the Arive link fields on lead_los_links (kind, GUID, deep link, stage, pending-since, last error) and los_sync_events. All nullable, no backfill; @Order(0) because the entities map them. Already applied to Yugabyte by hand (as the owner, kamo) before the shared-library push; this keeps a fresh environment in step.
· APIService
The public address Zapier posts Arive events to
POST **************** trigger> forwards to SecurityService's AriveInboundController, which owns the token check. The query string (the event) crosses the hop, a form body the container already parsed is rebuilt from its parameters, and SecurityService's status is passed through as-is: Zapier shows a non-2xx task as errored, which is where the people maintaining the Zap will look. A malformed token never leaves the edge.
· SecurityService
Arive through Zapier — connection, inbound events, and per-lead actions
A market bound to Arive gets a connection (four Zapier Catch Hooks for create-loan, update-loan, update-lead and convert-lead, plus one inbound URL whose token is stored as a hash) at **************** with an activity log, token rotation and "send a sample" so Zapier can learn each hook's fields. Arive's triggers post to **************** JSON or form bodies (Zapier's default), recognised by our crmReferenceId, the Arive GUID, the display id, or — for a lead converted inside Arive — the borrower e-mail. Recognised records apply Arive-wins; a new stage moves the Kamo status through the connection's stage map; unknown records become leads assigned to the member Arive names as officer, and our uid is sent back. Every outcome is logged, and nothing answers a silent 200. The lead page's create/open dispatches on the market: Arive answers 202 PENDING (it confirms asynchronously) and adds /convert. Members map themselves to their Arive e-mail (no secret, no NMLS, one member per e-mail per market). The LO-XML apply endpoint now refuses non-MeridianLink providers instead of applying an all-null patch.
· kamo-internal
Start a coder session in the cloud, and show it on the window
which lists the git checkouts on the dev machine (most recently worked in member's model and effort. The machine builds the command, with CCR_FORCE_BUNDLE=1 so the local checkout is uploaded rather than cloned from a GitHub remote we do not have. The terminal it opens carries `cloud: true` in its props, and the title bar and maximized tab draw a cloud over its terminal icon (windowIcon). A prop rather than an icon node, so it survives a reload; reopening from the terminal list carries the machine's own mark back to the window.

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