DEV Community

Cover image for AI Vibe Coding in Practice: An SMS Suite Prompt and Development Plan
Uncle Pushui
Uncle Pushui

Posted on

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:

Please carefully analyze the following development task and propose a reasonable plan:

  1. Goal: implement shared SMS infrastructure first, then build multiple business capabilities on top of it.
    • Infrastructure: SMS provider / clients / scene.
    • Business capabilities:
      • sms captcha: SMS verification codes.
      • sms auth: user registration and login.
  2. Suite / module structure:
    • Suite: cabloy-sms.
    • Modules:
      • cabloy-sms: shared SMS infrastructure.
      • sms-captcha: SMS verification codes.
      • sms-auth: user registration and login.
      • sms-mock: a Mock SMS Provider that prints verification codes to the console and sends them to the frontend so it can fill the code input automatically.

Here is the development plan returned by Claude Code:

1. Overall recommendation

Keep the proposed cabloy-sms suite and its four modules, with these layers:

  • cabloy-sms: SMS transport infrastructure, responsible for which provider account and template to use when sending a message.
  • sms-captcha: SMS verification, responsible for the recipient, the intended operation, and secure verification.
  • sms-auth: phone-based authentication, responsible for which account to sign in to after verification and whether to create a new account.
  • sms-mock: an SMS Provider for development and testing. It replaces real transport while retaining the verification and authentication flows.

The most important design principle is:

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.


2. Suite and module structure

The proposed names follow the current naming rules and can remain unchanged.

Layer Name Description
Suite cabloy-sms providerId=cabloy, suiteName=sms
Module cabloy-sms Shared SMS infrastructure
Module sms-captcha SMS verification codes
Module sms-auth SMS registration and login
Module sms-mock Mock SMS Provider

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 backend modules under:

vona/src/suite/cabloy-sms/modules/

Place corresponding frontend modules that actually contain frontend code under:

zova/src/suite/cabloy-sms/modules/

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.

Dependency direction

  • sms-captcha depends on the SMS infrastructure and the existing verification system.
  • sms-auth depends on SMS verification and the existing authentication system.
  • sms-mock only needs the SMS infrastructure.
  • The infrastructure, verification, and authentication modules must not have a hard dependency on sms-mock.

Whether Mock participates at runtime should be determined by application composition and server configuration, rather than being enabled unconditionally by business modules.


3. cabloy-sms: defining provider / clients / scene

1. Provider: implementation of a vendor protocol

A Provider implements a sending protocol, for example:

  • sms-mock:mock.
  • A future Alibaba Cloud SMS Provider.
  • A future Tencent Cloud SMS Provider.

The Provider is responsible for:

  • Converting a unified send request into the vendor's request.
  • Calling the SDK or HTTP API.
  • Converting the vendor's response into a unified result.
  • Hiding vendor errors and sensitive information.

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.

Existing reference:

vona/src/suite-vendor/a-pay/modules/a-pay/src/types/payProvider.ts:6

2. Client: named account configuration under a Provider

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:

  • default: the default account.
  • marketing: another vendor account or dedicated sending configuration.

A Client holds:

  • Credentials.
  • Region and endpoint.
  • Necessary vendor defaults.
  • Settings such as whether it is enabled.

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.

3. Scene: a business sending scenario

A Scene represents a stable business intent for sending, such as:

  • sms-auth:signin.
  • Future order or delivery notifications.

A Scene configures:

  • Which Provider and Client to use.
  • SMS signature and vendor template.
  • Template parameter constraints.
  • Any necessary server-side routing rules.

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.

Also distinguish these concepts:

Concept Purpose
SMS Scene Selects the transport channel, account, and template
Captcha Scene Defines which business operation the verification code can authorize

The same business module may declare and associate both, but they are not interchangeable. A third registry for “SMS verification scenarios” is unnecessary.

4. Instance isolation and send results

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.
  • Explicitly rejected.
  • An uncertain result, such as a timeout.

“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.


4. sms-captcha: reuse verification infrastructure and add SMS semantics

1. Existing capabilities and gaps

a-captcha already provides:

  • A challenge ID.
  • Provider and Scene.
  • Redis storage and TTL.
  • Verification DTOs.
  • Form validation integration.

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.

Reference:

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.

2. Recommended responsibilities

Add generic, optional capabilities to a-captcha:

  • Accept trusted context at creation time.
  • Store verification binding information.
  • Compare it with the expected binding computed by the server at consumption time.
  • Use atomic state transitions to guarantee single consumption.
  • Let Provider/Scene declare policies for controlled issuance, refresh, and token exposure.
  • Remove plaintext tokens from generic verification logs.

sms-captcha owns the SMS-specific rules:

  • Phone-number normalization and format validation.
  • Allowed purposes and scene mapping.
  • Cryptographically secure code generation.
  • Binding to the phone number, purpose, and any necessary subject.
  • Sending cooldowns, quotas, and failed verification attempt limits.
  • Calling the SMS infrastructure.
  • SMS-specific form interactions.

This reuses the OTP system while keeping phone-number rules out of the generic verification module.

3. Recommended verification rules

For the initial release:

Item Recommendation
Code Six digits, handled as a string and generated securely
Validity Five minutes, configurable
Resend cooldown 60 seconds, configurable
Failed attempts An explicit limit, such as five
Expiry Lookups and incorrect attempts never extend the original expiry
Resend A new challenge replaces the old one; the old proof becomes invalid
Consumption A correct code can succeed at most once
Binding Current instance + normalized phone number + purpose; add subject binding as required
Abuse prevention Phone cooldowns/quotas + IP rate limits + verification attempt limits

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.

4. Prevent bypasses through generic endpoints

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.

For the initial release:

  • Generic create(scene) must not create an SMS challenge without trusted context.
  • Generic refresh(id, scene) must not resend while bypassing the SMS cooldown.
  • Refreshing an expired or missing ID must not fall back to unrestricted sending.
  • SMS scenes should initially disable verifyImmediate → token2, avoiding another replayable proof.
  • SMS verification must fail when the expected phone/purpose binding is absent.

5. sms-mock: simulate transport while preserving business validation

1. Correct runtime behavior

Mock should follow the same chain as real SMS:

  1. sms-captcha generates a code and establishes its binding.
  2. The SMS infrastructure resolves the sms-mock Provider.
  3. Mock makes no external vendor calls.
  4. It prints the code to the development console with the phone number masked.
  5. The verification layer returns the code to the frontend only when permitted.
  6. Submission still enforces expiry, attempt limits, binding, and single consumption.

Never use a fixed universal code or make Mock login return success directly.

2. Autofill can reuse the existing response field

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:

  1. The actual Provider used for this request is sms-mock.
  2. The environment is non-production.
  3. Development autofill is explicitly enabled.

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.

3. The frontend needs SMS-specific interactions

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.

The SMS component should provide:

  • A phone-number input.
  • An explicit “Send code” button.
  • A cooldown based on server time.
  • Autofill after a successful Mock send.
  • Clearing the challenge and code when the phone number changes.
  • No automatic retry after a send failure.
  • No automatic sending on page initialization or ordinary form errors.

Keep the code only in the current interaction state. Do not put it in localStorage, SSR HTML, or persistent user state.


6. sms-auth: reuse authentication and establish a trusted phone identity

1. Recommended product behavior

For the initial release, I recommend:

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.

2. Authentication flow

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

Key requirements:

  • Consume the OTP at the Provider's verification boundary, rather than only in a new Controller.
  • Keep Provider, Client, and intention under server control.
  • Do not merge the entire request into authentication configuration.
  • Do not create a separate JWT, Cookie, or session storage system.

3. Never claim an account automatically through an old mobile field

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:

  • A trusted SMS mapping exists: sign in to its associated user.
  • No mapping exists: register or reject according to the confirmed policy.
  • An old account has the same mobile value: never automatically associate, merge, or take over that account.
  • A mapping exists but its user is missing: return an error; do not silently recreate the account.

Defer phone binding, phone changes, recovery, and account merging. Explicitly reject associate/migrate inside the Provider so generic entry points cannot trigger them.

4. Handle concurrent first registrations separately

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:

  • User creation.
  • Normal role relationships.
  • The auth mapping.
  • Any necessary projection into the mobile profile field.

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.

5. Frontend login integration

  • sms-auth provides the SMS login form and business wrapper.
  • Keep integration with the existing Home Login page minimal.
  • Reuse Passport's post-login handling instead of copying token writes and returnTo logic.
  • Web/Admin share authentication identities; a different page or vendor Client must not create duplicate users.
  • New users follow an explicit ordinary-user role policy. Successful SMS registration does not grant administrative permissions.

7. Recommended delivery order and acceptance

Stage Deliverables Exit criteria
1. Infrastructure + Mock Provider/Client/Scene, send facade, Mock Ordinary template messages can be sent through Mock; instance configuration is isolated; failure semantics are explicit
2. SMS verification Required captcha extensions, issuance/resend, abuse prevention, SMS component Autofill works; phone/purpose binding and atomic consumption are enforced; generic endpoints cannot bypass them
3. SMS registration and login SMS AuthProvider, identity creation boundary, login entry Registration and subsequent login work; old mobile values are not claimed; concurrent requests do not create duplicate accounts; sessions are reused
4. First real Provider Integration with the selected vendor Mock and real transport follow the same contract; real SMS never returns or logs codes

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:

  • Verification fails across phone numbers, purposes, and instances, and for expired or replayed codes.
  • At most one concurrent consumption of the same challenge succeeds.
  • Two independent valid OTPs used concurrently for first login produce exactly one user and identity mapping.
  • Generic captcha and authentication entry points cannot bypass security rules.
  • Changing the phone number clears the old proof.
  • Real SMS never exposes codes in any environment.
  • Mock prints and autofills codes only behind explicit development gates.
  • Disabled users cannot sign in, and existing password/GitHub login does not regress.
  • Sending timeouts never trigger blind retries.

8. Initial scope and decisions to confirm

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:

  1. Registration: should SMS login automatically register a new user? Recommended.
  2. Phone-number scope: mainland China only initially, or international numbers too? Either way, require an explicit calling code and normalize consistently. Never prepend +86 to every input by default.
  3. Rollout: Web first, or Admin at the same time? Should the initial release deliver only the complete Mock flow and defer real vendors?

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.


Closing note

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.

Top comments (0)