AI Vibe Coding in Practice: An SMS Suite Prompt and Development Plan
While developing an SMS suite for the CabloyJS fullstack framework—shared infrastructure, verification codes, and authentication—I found both my prompt and Claude Code's development plan representative of a real AI coding workflow. I have put them together here for reference. Here is the prompt: Pl

While developing an SMS suite for the CabloyJS fullstack framework—shared infrastructure, verification codes, and authentication—I found both my prompt and Claude Code's development plan representative of a real AI coding workflow. I have put them together here for reference.
Please carefully analyze the following development task and propose a reasonable plan:
Here is the development plan returned by Claude Code:
Keep the proposed cabloy-sms suite and its four modules, with these layers:
Infrastructure does not depend on verification codes; verification codes do not depend on user authentication; Mock does not change the real business flow.
The current repository is Cabloy Basic. Based on the existing source, reuse Vona's provider/client/scene extension pattern, the a-captcha verification system, and the a-auth authentication chain. There is no need to build another SMS code cache or session system.
However, a-captcha currently lacks safeguards required for SMS login, including phone-number binding and atomic consumption. It needs a bounded set of backward-compatible extensions.
The proposed names follow the current naming rules and can remain unchanged.
A Suite and one of its Modules can share a name. Their full package names are vona-suite-cabloy-sms and vona-module-cabloy-sms, so they remain distinct.
Place corresponding frontend modules that actually contain frontend code under:
There is no requirement to create four empty frontend counterparts. The initial frontend work mainly belongs to sms-captcha for verification interactions and sms-auth for login forms. Mock autofill does not require a separate frontend Mock system.
Whether Mock participates at runtime should be determined by application composition and server configuration, rather than being enabled unconditionally by business modules.
A Provider implements a sending protocol, for example:
It does not generate verification codes, decide between registration and login, or look up users.
Introduce smsProvider and smsScene extension types using the existing decorators, type registration, onion metadata, and CLI templates. There is no need for a separate plugin manager.
vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts:6
A Client is named configuration under a Provider. It is not a new business service and does not need its own bean scene.
For example, one real Provider can have:
Use base + clients under each Provider, retaining the type association between Provider and Client.
The initial release does not need vendor account tables, a credential management console, or a persistent Client registry. Configuration is sufficient for the current consumers.
A Scene represents a stable business intent for sending, such as:
The server-side call could look like this:
// Proposed interface, not an existing API await this. bean. sms. send ({ scene: ' sms-auth:signin ', recipient: normalizedPhone, params: { code, minutes: 5, }, }); Enter fullscreen mode Exit fullscreen mode The caller supplies business parameters; the infrastructure resolves transport configuration. Public requests must not directly specify the Provider, Client, template ID, signature, or credentials.
The same business module may declare and associate both, but they are not interchangeable. A third registry for “SMS verification scenarios” is unnecessary.
Providers and Scenes must resolve effective configuration for the current instance. Never cache the first request's credentials, phone number, or scene configuration in shared bean fields.
The existing onion configuration merge includes instance configuration. Reading static beanOptions.options directly is not equivalent:
vona/src/suite-vendor/a-vona/modules/a-onion/src/service/onion_.ts:252
Keep sending synchronous for the initial release and distinguish:
“Accepted by the vendor” does not mean “received by the phone.” Defer message queues, delivery receipts, automatic failover, and automatic retries. In particular, do not blindly resend after a timeout.
However, its cache currently stores only scene/provider/token/token2, without the recipient phone number. Successful verification uses separate read, compare, and delete operations, allowing multiple concurrent attempts to succeed.
vona/src/suite-vendor/a-captcha/modules/a-captcha/src/bean/bean.captcha.ts:19,:79
Adding a CaptchaProvider that sends SMS is therefore not enough to complete SMS verification.
Add generic, optional capabilities to a-captcha:
sms-captcha owns the SMS-specific rules:
This reuses the OTP system while keeping phone-number rules out of the generic verification module.
The phone number cannot be just a send parameter. A code sent to phone A must never authorize login for phone B, even when the code itself is correct.
The initial release can continue using the existing Redis storage for short-lived secrets, without building another cache just for hashed storage. It must have a short TTL, access isolation, no plaintext logs, and no persistent verification-code history. If hashed storage becomes a requirement, explicitly separate stored verification material from the value returned for Mock autofill; the current interface does not inherently support that distinction.
The existing generic captcha creation, refresh, and immediate-verification endpoints are public:
vona/src/suite-vendor/a-captcha/modules/a-captcha/src/controller/captcha.ts:15
Security rules must therefore live at the shared service boundary, rather than only in a new SMS Controller.
Mock should follow the same chain as real SMS:
Never use a fixed universal code or make Mock login return success directly.
The captcha response already supports an optional token, and the current form writes it into the input:
zova/src/suite/cabloy-basic/modules/basic-captcha/src/component/formFieldCaptcha/controller.tsx:96
There is no need for a second verification-response protocol.
However, showToken currently defaults to enabled in all non-production environments. Real SMS must not inherit that behavior:
vona/src/suite-vendor/a-captcha/modules/a-captcha/src/config/config.ts:3
Returning an SMS code requires all three conditions:
Real SMS must never return the code because of the global showToken setting, even in dev/test. Selecting Mock in production must fail at startup or sending time, rather than silently falling back.
The existing image-captcha component automatically creates a challenge on initialization, refreshes it after a failed submission, and renders the payload as an image. It cannot be used unchanged for paid SMS.
Keep the code only in the current interaction state. Do not put it in localStorage, SSR HTML, or persistent user state.
Sign in after successful phone verification; automatically register if that SMS identity does not exist.
One form can handle both registration and login, matching the basic behavior of the existing generic authentication chain. This remains a product decision requiring confirmation. If registration and login must be strictly separate, define how each operation handles existing and missing identities.
Add a non-OAuth SMS AuthProvider and reuse this chain:
Verify and consume OTP → obtain or create identity and user → existing Passport signin
The framework already supports provider.verify → issuePassport → passport.signin:
vona/src/suite-vendor/a-auth/modules/a-auth/src/service/auth.ts:27
The existing homeUser.mobile is only an optional string. It does not mean “verified phone number”:
vona/src/suite/a-home/modules/home-user/src/entity/user.ts:24
Use the existing authentication identity mapping:
SMS identity namespace + normalized phone number → auth mapping → userId Enter fullscreen mode Exit fullscreen mode This means:
Defer phone binding, phone changes, recovery, and account merging. Explicitly reject associate/migrate inside the Provider so generic entry points cannot trigger them.
Atomic consumption of one code does not guarantee identity uniqueness: a single phone number may have two independent, valid verification requests.
Serialize by current instance and SMS identity, then recheck and atomically complete these writes within a transaction:
Enter the existing signin flow after commit. A transaction alone, or a lock on a row that does not exist, is insufficient to prevent duplicate creation. Do not add business uniqueness constraints spanning tenants.
Prefer reusing the existing identity mapping without a new identity table. If a persisted field such as mobileVerifiedAt is necessary, confirm the owning module's fileVersion strategy before implementation.
Although Mock is fourth in the module list, implement it with the infrastructure so verification and authentication have a runnable consumer chain from the beginning.
Acceptance need not become an enormous matrix, but it must cover:
Keep out of the initial release: vendor management screens, sending-history screens, bulk marketing, queues, receipts, automatic retries/failover, phone-number changes, recovery, and account merging.
Only three groups of product decisions need confirmation:
The names are already reasonable and need no change. Branding or naming preferences can still be accommodated under the same rules.
After confirmation, create the infrastructure and Mock using the existing CLI rather than building directories manually, for example:
npm run vona:create:suite cabloy-sms npm run vona:create:module cabloy-sms -- --suite = cabloy-sms npm run vona:create:module sms-mock -- --suite = cabloy-sms Enter fullscreen mode Exit fullscreen mode Then generate the remaining modules in stages, run focused backend tests, and verify critical E2E flows. Backend contract changes should generate frontend consumers first. For frontend reverse dependencies, build the affected Web/Admin flavors before running npm run deps:vona.
This round only completed analysis and made no file changes. The CLI command implementations were confirmed in source, but attempts to run npm run vona and npm run zova both failed because @cabloy/cli was missing. Node was v24.8.0, below the repository requirement of >=24.11.0. Prepare the runtime and dependencies before implementation. No dependencies were installed, and no builds or tests were run in this round.
Claude Code asked me to confirm three groups of product decisions—registration behavior, phone-number scope, and rollout scope—before developing the plan further. I will leave it here for now to keep the article manageable. If you would like to see what comes next, leave a comment and I will continue putting the material together.