Build spec · beta
Request access: how to build it
The page at getarca.co/private asks what the creator wants, collects goal details then financial context, shows a preliminary answer, and asks for contact last. Live booking is Cal.com with an ARCA reference code (no figures in the URL). The Prototype tab is the working reference.
Beta decision. There is no listing link and no screenshot or photo upload. The creator types the details of what they want, and every number used in a calculation is typed or confirmed by them. No extraction, OCR or file storage is part of this build.
1. Principles
- Desire first, data second, contact last. No name, email or phone before the first answer is shown.
- A human path (Jada) exists on the first screen and stays available on the answer, contact and success screens.
- Never a dead end. Any failed lookup, unusual goal or incalculable result falls back to "Tell us in your own words" or to the Jada path.
- Do not fabricate precision. If ARCA cannot answer well, it says so.
- Self-reported numbers are never presented or stored as verified.
2. Screen map
| Id | Screen | Writes to session | Events |
|---|---|---|---|
goal | Screen 1. Choose the goal, or choose the Jada path | goal_type | request_access_clicked, goal_flow_started, goal_selected, jada_chat_selected |
details | Screen 2. Goal details (per goal) | goal_details | goal_details_completed |
ctx0…ctx1 | Screen 3. Minimum financial context (1 or 2 steps) | financial_inputs | financial_context_started, financial_context_completed |
thinking | Transition. Quiet "Looking at what you told me" text, minimum 1.2 s | preliminary_result, result_status | none |
answer | Screen 4. First answer (or fallback) | none | preliminary_answer_shown or answer_fallback_shown |
contact | Screen 6. Contact capture | contact, converted_at | email_submitted |
success | Screen 7. Success and next step | none | none |
jada, jadaDone | Path B. Talk it through with Jada, scheduling, confirmation | jada | jada_chat_selected, jada_call_scheduled |
3. Session model
A server-side session is created on the first goal selection and referenced by an httpOnly cookie (arca_sid, 24 hour sliding expiry). Save on every step with a debounced PATCH, so a refresh or a return visit resumes where the user left off.
intake_session {
session_id text pk // "sess_" + random
created_at, updated_at, last_step
goal_type enum // see section 4
goal_details jsonb // per goal, see prototype fields
financial_inputs jsonb // integers in dollars, enums for ranges
preliminary_result jsonb null // see section 5
result_status enum null // user_reported_estimate | plaid_derived | verified
contact { first_name, email, phone? } null
converted_at timestamptz null // set when email is captured
jada { note?, slot?, booking_id? } null
utm, referrer, user_agent_hash
}
4. Goal types
Enum: apartment, home, car, quit_job, savings, grow_business, custom. Changing goal after Back clears goal_details and financial_inputs.
| Goal | Needed to calculate | Optional |
|---|---|---|
| apartment | monthly rent, monthly income | location, move-in, landlord requirement, income type, savings, credit range, housing cost, guarantor |
| home | price, annual income, down payment available | location, timing, desired down payment, credit range, monthly debts, housing payment |
| car | price, annual income | make, model, year, timing, cash or finance, down payment, credit range, debts |
| quit_job | target (months or amount), monthly spending, savings, monthly income | target date |
| savings | target (months or amount), monthly spending, savings, monthly income | timing |
| grow_business | amount needed, current cash, monthly revenue | purpose, timing, obligations |
| custom | nothing. Always returns the fallback answer in beta | free text, income, savings |
5. Calculation layer
Run on the server (POST /api/intake/sessions/:id/result) so formulas and constants can change without a front-end release. The prototype contains a client-side copy of the same rules so the flow can be tried end to end.
result {
label "Your apartment"
headline "You’re close." // human answer, shown largest
metric "You make about 2.9× the monthly rent."
explanation string
helping[] string[] // only when we can name them
holding_back[] string[]
next "ARCA can help you …"
calc { formula, inputs, value, assumptions } // never shown as the headline
confidence "estimate" | "none"
}
| Goal | Rule used in the prototype (placeholders, finance to confirm) |
|---|---|
| apartment | ratio = monthly income ÷ rent. At least 3.2 → "You’re there." 2.6 to 3.2 → "You’re close." Below 2.6 → "This is a stretch." |
| home | down payment needed = desired down payment, else 10% of price. Months to go = shortfall ÷ (20% of monthly income). Window = a 3 month range starting that many months from today. Price ÷ income above 4.5 reads as a stretch. |
| car | Payment on the financed amount at 7% over 60 months. Payment ÷ monthly income at or under 10% → "This fits." |
| quit_job, savings | Target = months × spending, or the stated amount. Months to go = shortfall ÷ (income − spending). If income does not cover spending → "Not at this pace." |
| grow_business | Months to go = shortfall ÷ (15% of monthly revenue). |
Status separation. Everything computed from this flow is stamped result_status = user_reported_estimate. Plaid-derived numbers become plaid_derived; numbers confirmed against tax or income documents become verified. A result may only be promoted to a stronger status when every input has that status. Never overwrite a self-reported value with a derived one silently: keep both, show the source.
6. Goal details input
- Goal details are typed or chosen from options. There is no listing URL field, no image upload and no extraction anywhere in this flow.
- Every field is a plain input (money, text or option chips). Optional fields are tagged "optional" and never block Continue.
- If listing or image support is added later, it may only suggest values that the user then confirms. It should not become a dependency of the first answer.
7. Email capture and conversion
- No account before screen 6 unless technically required. Flow: temporary session → preliminary result → email → convert session into lead/user.
- Conversion is a single transaction: write
contact, setconverted_at, create or upsert the lead by email, link the session. Idempotent on(session_id, email). - Preserve every prior answer. The user never re-enters anything.
- Validate email client-side and server-side. Phone is optional and never required.
- Bot protection on session creation and on submit (invisible challenge plus rate limit per IP).
8. Jada scheduling
Three entry points open the same scheduling flow: goal ("Talk it through with Jada"), answer and contact ("Rather talk it through? Schedule time with Jada"), and success ("Schedule time with Jada"). The optional note ("Anything you want Jada to know?") is stored as jada.note.
- No financial questions before scheduling on this path.
- If the user has not given an email, the scheduling tool captures name and email. Create a lead from the booking webhook and link it to the session.
- If the session has goal data, include it in the booking notes and in Slack so Jada has context.
- Tool choice is open (Cal.com, Calendly or similar). It must offer a webhook for
booking.createdand prefill of name and email.
9. Beta Slack handoff
On email_submitted (and on jada_call_scheduled when no email was captured earlier), post one message to the beta intake channel through the existing failsafe workflow. The Slack tab in the prototype renders this message from the live session.
| Block | Content |
|---|---|
| Creator | name, email, phone if given |
| Goal | goal type, goal details |
| Financial context | income, savings, credit range, expenses and debts, any other answer. Marked "self-reported" |
| ARCA preliminary answer | headline, metric, calculation inputs and assumptions |
| Missing information | unanswered fields plus standard gaps (connected accounts, tax documents, income history) |
| Actions | Open user · Edit goal · Correct financial inputs · Add data · Recalculate · Schedule / follow up |
Actions are Slack interactive buttons that call the internal API with the session_id. "Correct financial inputs" and "Recalculate" must write a new result with its own timestamp and keep the previous one.
10. Analytics
| Event | When | Properties |
|---|---|---|
request_access_clicked | Homepage CTA click | source (hero, closing), utm |
goal_flow_started | First goal selected | session_id |
goal_selected | Goal chosen | goal_type |
goal_details_completed | Leaving screen 2 | goal_type, fields_filled |
financial_context_started | Entering first context step | goal_type |
financial_context_completed | Leaving last context step | goal_type, fields_filled |
preliminary_answer_shown | Real answer rendered | goal_type, headline, result_status |
answer_fallback_shown | "I need a little more context" rendered | goal_type, reason |
email_submitted | Contact form submitted | goal_type, has_phone |
jada_chat_selected | Any Jada entry point clicked | source (goal_select, answer, contact, success) |
jada_call_scheduled | Booking confirmed | source, had_session |
flow_abandoned | Page hidden or closed before success | goal_type, last_step, saw_answer |
Primary funnel: visitors → reached a meaningful answer (preliminary_answer_shown) → chose to book or email the result (email_submitted or jada_call_scheduled after an answer). Email conversion by itself is not the headline metric. Fallback answers do not count as "reached an answer".
11. Failsafes
| Situation | Behavior |
|---|---|
| Anything optional is left blank | Silent. Manual fields are always visible. No error banner. |
| Unusual goal | "Something else" with free text. Always reaches the fallback answer and the Jada or follow-up options. |
| A needed number is missing | Continue is never disabled. The answer screen shows "I need a little more context to answer this well." with Talk it through with Jada and Tell us where to send the follow-up. |
| Calculation errors or times out (6 s) | Same fallback. Log answer_fallback_shown with the reason. |
| Session cookie lost | Start a new session. Offer to resume if a recent session exists for the same browser. |
| Slack post fails | Retry with backoff. The user still sees success. Alert internally if retries are exhausted. |
12. Open questions
- Scheduling tool and its webhook (Cal.com, Calendly or other).
- Retention for anonymous sessions. Suggested 30 days if never converted, then delete.
- Calculation constants (10% down, 20% savings rate, 7% APR, 15% revenue set-aside) are placeholders and need sign-off before the answers are shown to real users.
- Whether "Close" should offer to save and resume by email once the user has seen an answer.