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:
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.
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, },
});
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:
- sms-captcha generates a code and establishes its binding.
- The SMS infrastructure resolves the sms-mock Provider.
- Mock makes no external vendor calls.
- It prints the code to the development console with the phone number masked.
- The verification layer returns the code to the frontend only when permitted.
- 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:
- The actual Provider used for this request is sms-mock.
- The environment is non-production.
- 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
Comments
No comments yet. Start the discussion.