# BLUEPRINT: Stack Billing # Version: 2.0.0 # URL: https://stackbill.app # Updated: 2026-04-17 ## IDENTITY name: Stack Billing description: Voice-first invoicing and time tracking for contractors and freelancers — AI assistant, manual and session-based invoices, clients, PDF preview/download/share, time tracking, calendar, reusable invoice items, settings (account, business, taxes, integrations), and public shared-invoice links. category: finance contact: https://stackbill.app/contact-page ## AUTH provider: firebase method: google-oauth-and-email-password ## ACCESS last-resort: ui ## ROUTES canonical-workspace: /dashboard-page, /assistant-page, /invoices-page, /clients-page, /time-tracking-page, /calendar-page, /calendar-settings-page, /invoice-items-page, /settings-page workspace-aliases: /dashboardpage, /assistant, /assistantpage, /invoicespage, /clientspage, /timetrackingpage, /calendarpage, /calendarsettingspage, /invoiceitemspage, /settingspage (same pages as canonical; prefer *-page slugs in automation) public: /landing-page, /login, /logout, /pricing-page, /contact-page, /faq-page, /how-ai-works-page, /terms-page, /privacy-page, /cookie-policy-page, /shared-invoice?token= ## CAPABILITY: sign-in-google description: Sign in or sign up with Google via Firebase Auth from the login page. input: [] output: - type: confirmation description: Session established; user is redirected to dashboard or the `next` URL query target. auth-required: false scope: auth ### UI steps: 1. NAVIGATE /login 2. WAIT [data-agent-id="login-page-root"] (max: 10s) 3. CLICK [data-agent-id="sign-in-google"] ## CAPABILITY: sign-in-email description: Sign in or create an account with email and password using Firebase Auth. input: - name: email type: string required: true - name: password type: string required: true output: - type: confirmation description: Session established; user is redirected to dashboard or the `next` URL query target. auth-required: false scope: auth ### UI steps: 1. NAVIGATE /login 2. WAIT [data-agent-id="login-page-root"] (max: 10s) 3. INPUT [data-agent-id="sign-in-email"] <> 4. INPUT [data-agent-id="sign-in-password"] <> 5. CLICK [data-agent-id="sign-in-email-submit"] 6. Optional: CLICK [data-agent-id="sign-in-email-toggle-mode"] when the account should be created instead of signing in (toggles sign-up vs sign-in on the same form). ## CAPABILITY: sign-out description: End the Firebase session via the dedicated logout route (redirects to login). input: [] output: - type: confirmation description: User is signed out and sent to the login flow. auth-required: true scope: auth ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /logout 3. WAIT [data-agent-id="login-page-root"] (max: 15s) ## CAPABILITY: view-dashboard description: Open the signed-in home dashboard with shortcuts to AI-assisted and manual invoice creation. input: [] output: - type: confirmation description: Dashboard shell and entry actions are visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /dashboard-page 3. WAIT [data-agent-id="dashboard-page-root"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="dashboard-ai-assisted"] 5. VERIFY selector_exists [data-agent-id="dashboard-manual-entry"] ## CAPABILITY: open-assistant description: Open the AI billing assistant directly (same assistant as the dashboard shortcut; routes /assistant-page, /assistant, and /assistantpage are equivalent). input: [] output: - type: confirmation description: Assistant layout and input area are ready. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /assistant-page 3. WAIT [data-agent-id="assistant-page-root"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="assistant-input"] ## CAPABILITY: create-invoice-ai description: Use the AI assistant to describe work in natural language so the assistant can create or update billing data; confirmed invoices appear in the same Invoices list as the rest of the app. input: - name: job-description type: string required: true description: What the user did, for whom, hours or amounts, and any other details the assistant should use. output: - type: confirmation description: Assistant reply in the chat thread; invoice or related records may be created depending on the conversation. auth-required: true scope: financial-transaction ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /dashboard-page 3. WAIT [data-agent-id="dashboard-ai-assisted"] (max: 10s) 4. CLICK [data-agent-id="dashboard-ai-assisted"] 5. WAIT [data-agent-id="assistant-input"] (max: 10s) 6. INPUT [data-agent-id="assistant-input"] <> 7. CLICK [data-agent-id="assistant-send"] 8. WAIT [data-agent-id="assistant-processing-indicator"] (max: 120s) 9. VERIFY selector_not_exists [data-agent-id="assistant-processing-indicator"] ## CAPABILITY: create-invoice-manual description: Create an invoice through the Create Invoice dialog on the Simple Invoice tab — line items, optional taxes and packing-slip section when enabled, dates, then submit. Select an existing client or create one from the combobox search. Normalize client names for data-agent-id suffixes the same way as invoice numbers (lowercase, spaces to hyphens, only a-z, 0-9, hyphens). input: - name: client-name type: string required: true description: Client to bill — either pick an existing client or type a new name and use the create-from-search control. - name: line-description type: string required: true description: Description text for the first invoice line item (Simple tab). - name: line-price type: string required: true description: Unit price for the line item (quantity defaults to 1 unless changed in the form). output: - type: confirmation description: Invoice is created and the app navigates to the invoices page and opens invoice details. auth-required: true scope: financial-transaction ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /dashboard-page 3. WAIT [data-agent-id="dashboard-manual-entry"] (max: 10s) 4. CLICK [data-agent-id="dashboard-manual-entry"] 5. WAIT [data-agent-id="create-invoice-dialog"] (max: 10s) 6. CLICK [data-agent-id="create-invoice-client-trigger"] 7. INPUT [data-agent-id="create-invoice-client-search"] <> 8. CLICK [data-agent-id="create-invoice-client-option-<>"] when the client already exists, otherwise CLICK [data-agent-id="create-invoice-client-create"] for a brand-new name from search. 9. VERIFY selector_exists [data-agent-id="create-invoice-tab-simple"] 10. INPUT [data-agent-id="create-invoice-line-description"] <> 11. INPUT [data-agent-id="create-invoice-line-price"] <> 12. CLICK [data-agent-id="create-invoice-add-line"] 13. CLICK [data-agent-id="create-invoice-submit"] 14. WAIT [data-agent-id="invoice-detail-dialog"] (max: 30s) 15. VERIFY selector_exists [data-agent-id="invoice-detail-dialog"] ## CAPABILITY: create-invoice-from-sessions description: Create an invoice from billable work sessions for a selected client — opens Create Invoice, picks the client, switches to From Work Sessions, selects session rows by id, then submits. input: - name: client-name type: string required: true description: Existing client (normalized suffix for option selectors matches other flows). - name: session-id type: string required: true description: Numeric work session id as shown in APIs or the UI (used in data-agent-id hooks). output: - type: confirmation description: Invoice created and detail dialog opens or navigation matches the manual flow success path. auth-required: true scope: financial-transaction ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /dashboard-page 3. WAIT [data-agent-id="dashboard-manual-entry"] (max: 10s) 4. CLICK [data-agent-id="dashboard-manual-entry"] 5. WAIT [data-agent-id="create-invoice-dialog"] (max: 10s) 6. CLICK [data-agent-id="create-invoice-client-trigger"] 7. INPUT [data-agent-id="create-invoice-client-search"] <> 8. CLICK [data-agent-id="create-invoice-client-option-<>"] 9. CLICK [data-agent-id="create-invoice-tab-sessions"] 10. WAIT [data-agent-id="create-invoice-session-<>"] (max: 15s) 11. CLICK [data-agent-id="create-invoice-session-<>"] 12. CLICK [data-agent-id="create-invoice-submit"] 13. WAIT [data-agent-id="invoice-detail-dialog"] (max: 30s) 14. VERIFY selector_exists [data-agent-id="invoice-detail-dialog"] ## CAPABILITY: view-invoices description: Open the Invoices page and review the invoice list. input: [] output: - type: confirmation description: Invoices list is visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoices-page 3. WAIT [data-agent-id="invoices-page-heading"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="invoices-list-root"] ## CAPABILITY: preview-invoice-pdf description: Open PDF preview for an invoice from the invoice detail dialog. input: - name: invoice-number type: string required: true description: Invoice number as shown in the list; normalize for row selectors like other flows. output: - type: confirmation description: Preview action invoked (browser may open a new tab or viewer depending on environment). auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoices-page 3. WAIT [data-agent-id="invoices-list-root"] (max: 10s) 4. CLICK [data-agent-id="invoice-details-<>"] 5. WAIT [data-agent-id="invoice-detail-dialog"] (max: 15s) 6. CLICK [data-agent-id="invoice-preview"] ## CAPABILITY: download-invoice-pdf description: Download the invoice PDF from the invoice detail dialog. input: - name: invoice-number type: string required: true output: - type: confirmation description: Download action invoked for the PDF. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoices-page 3. WAIT [data-agent-id="invoices-list-root"] (max: 10s) 4. CLICK [data-agent-id="invoice-details-<>"] 5. WAIT [data-agent-id="invoice-detail-dialog"] (max: 15s) 6. CLICK [data-agent-id="invoice-download"] ## CAPABILITY: send-invoice description: Generate a client-facing share link for an invoice PDF; the app copies the link to the clipboard when the browser allows (SMTP email compose is not available on the invoice detail screen in the current UI). input: - name: invoice-number type: string required: true description: Invoice number shown in the list (used to open the correct row; normalize the same way as data-agent-id suffixes: lowercase, spaces to hyphens, only a-z, 0-9, and hyphens). output: - type: confirmation description: Share link is created and a success toast appears; link may be in the clipboard. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoices-page 3. WAIT [data-agent-id="invoices-list-root"] (max: 10s) 4. CLICK [data-agent-id="invoice-details-<>"] 5. WAIT [data-agent-id="invoice-detail-dialog"] (max: 15s) 6. CLICK [data-agent-id="invoice-share"] 7. VERIFY selector_exists [data-agent-id="invoice-detail-dialog"] ## CAPABILITY: delete-invoice description: Permanently delete an invoice from the detail dialog (confirmation required). input: - name: invoice-number type: string required: true output: - type: confirmation description: Invoice deleted after confirmation. auth-required: true scope: financial-transaction ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoices-page 3. WAIT [data-agent-id="invoices-list-root"] (max: 10s) 4. CLICK [data-agent-id="invoice-details-<>"] 5. WAIT [data-agent-id="invoice-detail-dialog"] (max: 15s) 6. CLICK [data-agent-id="invoice-delete"] 7. WAIT [data-agent-id="invoice-delete-confirm"] (max: 10s) 8. CLICK [data-agent-id="invoice-delete-confirm"] ## CAPABILITY: browse-clients description: Open the Clients directory and view the client list grid. input: [] output: - type: confirmation description: Clients list visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /clients-page 3. WAIT [data-agent-id="clients-page-heading"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="clients-list-root"] ## CAPABILITY: manage-clients description: Add a new client with at least a name from the Clients page. input: - name: client-name type: string required: true description: Name for the new client when using the add flow. output: - type: confirmation description: Client saved after submit; dialog closes. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /clients-page 3. WAIT [data-agent-id="clients-page-heading"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="clients-list-root"] 5. CLICK [data-agent-id="clients-add"] 6. WAIT [data-agent-id="client-form-dialog"] (max: 10s) 7. INPUT [data-agent-id="client-form-name"] <> 8. CLICK [data-agent-id="client-form-submit"] 9. VERIFY selector_not_exists [data-agent-id="client-form-dialog"] ## CAPABILITY: view-client-details description: Open the read-only client profile dialog from a client card (normalize <> for selectors). input: - name: client-name type: string required: true output: - type: confirmation description: Client view dialog is open. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /clients-page 3. WAIT [data-agent-id="clients-list-root"] (max: 10s) 4. CLICK [data-agent-id="client-card-view-<>"] 5. WAIT [data-agent-id="client-view-dialog"] (max: 10s) 6. VERIFY selector_exists [data-agent-id="client-view-dialog"] ## CAPABILITY: edit-client-record description: Open the client editor for an existing client from the directory card actions. input: - name: client-name type: string required: true description: Current client name as shown on the card (normalized suffix). output: - type: confirmation description: Client form dialog opens in edit mode. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /clients-page 3. WAIT [data-agent-id="clients-list-root"] (max: 10s) 4. CLICK [data-agent-id="client-card-edit-<>"] 5. WAIT [data-agent-id="client-form-dialog"] (max: 10s) 6. VERIFY selector_exists [data-agent-id="client-form-dialog"] ## CAPABILITY: delete-client-record description: Delete a client from the directory (irreversible; includes confirmation). input: - name: client-name type: string required: true output: - type: confirmation description: Client removed after confirmation. auth-required: true scope: financial-transaction ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /clients-page 3. WAIT [data-agent-id="clients-list-root"] (max: 10s) 4. CLICK [data-agent-id="client-card-delete-<>"] 5. WAIT [data-agent-id="client-delete-confirm"] (max: 10s) 6. CLICK [data-agent-id="client-delete-confirm"] ## CAPABILITY: time-tracking description: Track billable work sessions — start a timer for a client, stop an active session, browse recent sessions, edit or delete history rows. input: - name: client-name type: string required: false description: For starting a session: existing client option key (normalized) or use create-from-search in the start card combobox. output: - type: confirmation description: Session list or active session card reflects the action. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /time-tracking-page 3. WAIT [data-agent-id="time-tracking-page-root"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="time-tracking-page-root"] ## CAPABILITY: time-tracking-start-session description: Start a new work session from the Time Tracking page after choosing a client (existing row or create-from-search in the combobox). input: - name: client-name type: string required: true output: - type: confirmation description: Active session card appears or timer starts. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /time-tracking-page 3. WAIT [data-agent-id="time-tracking-start-card"] (max: 10s) 4. CLICK [data-agent-id="time-tracking-client-trigger"] 5. INPUT via combobox search UI then CLICK [data-agent-id="time-tracking-client-option-<>"] OR CLICK [data-agent-id="time-tracking-client-create-from-search"] for a new name typed in search. 6. CLICK [data-agent-id="time-tracking-start-session"] ## CAPABILITY: time-tracking-stop-session description: Stop the currently active session from the Time Tracking page. input: [] output: - type: confirmation description: Active session clears and recent list updates. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /time-tracking-page 3. WAIT [data-agent-id="time-tracking-stop-session"] (max: 10s) 4. CLICK [data-agent-id="time-tracking-stop-session"] ## CAPABILITY: time-tracking-edit-session description: Edit a completed or recent session from the list (opens session editor dialog). input: - name: session-id type: string required: true output: - type: confirmation description: Session edit dialog opens. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /time-tracking-page 3. WAIT [data-agent-id="time-tracking-recent-sessions"] (max: 10s) 4. CLICK [data-agent-id="time-tracking-session-edit-<>"] 5. WAIT [data-agent-id="session-edit-dialog"] (max: 10s) 6. VERIFY selector_exists [data-agent-id="session-edit-dialog"] ## CAPABILITY: time-tracking-delete-session description: Delete a session entry from the recent list (opens the destructive confirm dialog in-page). input: - name: session-id type: string required: true output: - type: confirmation description: Session removed after confirmation. auth-required: true scope: financial-transaction ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /time-tracking-page 3. WAIT [data-agent-id="time-tracking-recent-sessions"] (max: 10s) 4. CLICK [data-agent-id="time-tracking-session-delete-<>"] 5. Complete the browser confirmation dialog as required by the app (native confirm). ## CAPABILITY: calendar-view description: View the scheduling calendar, browse internal and connected external events, and open the add-session editor. input: [] output: - type: confirmation description: Calendar grid is visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /calendar-page 3. WAIT [data-agent-id="calendar-page-root"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="calendar-page-heading"] 5. VERIFY selector_exists [data-agent-id="calendar-grid-root"] ## CAPABILITY: calendar-add-session description: Create a new calendar session from the Calendar page (opens the shared session editor dialog). input: [] output: - type: confirmation description: Session editor dialog opens. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /calendar-page 3. WAIT [data-agent-id="calendar-add-session"] (max: 10s) 4. CLICK [data-agent-id="calendar-add-session"] 5. WAIT [data-agent-id="session-edit-dialog"] (max: 10s) 6. VERIFY selector_exists [data-agent-id="session-edit-dialog"] ## CAPABILITY: calendar-session-save description: Save or create a session from the session editor (used from Calendar or Time Tracking edit flows). input: [] output: - type: confirmation description: Dialog closes and data refreshes. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. Preconditions: [data-agent-id="session-edit-dialog"] is open with required fields filled. 3. CLICK [data-agent-id="session-edit-submit"] 4. VERIFY selector_not_exists [data-agent-id="session-edit-dialog"] ## CAPABILITY: calendar-integrations description: Connect Google Calendar or iCloud for synced events (OAuth redirects for Google; iCloud uses app-specific password form). input: [] output: - type: confirmation description: Connection status updates after provider flows complete. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /calendar-settings-page 3. WAIT [data-agent-id="calendar-settings-page-root"] (max: 10s) 4. CLICK [data-agent-id="calendar-settings-google-connect"] when connecting Google (full-screen OAuth handoff). 5. Optional iCloud: CLICK [data-agent-id="calendar-settings-icloud-open"], WAIT [data-agent-id="calendar-settings-icloud-dialog"], INPUT [data-agent-id="calendar-settings-icloud-apple-id"], INPUT [data-agent-id="calendar-settings-icloud-app-password"], CLICK [data-agent-id="calendar-settings-icloud-submit"] ## CAPABILITY: invoice-items-library description: Manage reusable catalog line items — search, add, edit via dialog, import CSV. input: [] output: - type: confirmation description: Library table or dialogs are available. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoice-items-page 3. WAIT [data-agent-id="invoice-items-page-root"] (max: 10s) 4. VERIFY selector_exists [data-agent-id="invoice-items-library-root"] ## CAPABILITY: invoice-item-add description: Create a reusable invoice line item in the library. input: - name: item-name type: string required: true output: - type: confirmation description: Item persists and dialog closes. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoice-items-page 3. WAIT [data-agent-id="invoice-items-add"] (max: 10s) 4. CLICK [data-agent-id="invoice-items-add"] 5. WAIT [data-agent-id="invoice-item-form-dialog"] (max: 10s) 6. INPUT [data-agent-id="invoice-item-form-name"] <> 7. CLICK [data-agent-id="invoice-item-form-submit"] 8. VERIFY selector_not_exists [data-agent-id="invoice-item-form-dialog"] ## CAPABILITY: invoice-items-import-csv description: Import multiple reusable items from a CSV file via the import dialog. input: [] output: - type: confirmation description: Import completes with a success toast when rows are valid. auth-required: true scope: form-submit ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /invoice-items-page 3. WAIT [data-agent-id="invoice-items-import-open"] (max: 10s) 4. CLICK [data-agent-id="invoice-items-import-open"] 5. WAIT [data-agent-id="invoice-items-import-dialog"] (max: 10s) 6. INPUT file via [data-agent-id="invoice-items-import-file"] (attach local CSV) 7. CLICK [data-agent-id="invoice-items-import-submit"] ## CAPABILITY: settings-account description: Open Settings on the Account tab (profile, email preferences as implemented). input: [] output: - type: confirmation description: Account tab content visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /settings-page?tab=account 3. WAIT [data-agent-id="settings-page-root"] (max: 10s) 4. CLICK [data-agent-id="settings-tab-account"] 5. VERIFY selector_exists [data-agent-id="settings-page-root"] ## CAPABILITY: settings-business description: Open Settings on the Business tab (business profile for invoices). input: [] output: - type: confirmation description: Business tab content visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /settings-page?tab=business 3. WAIT [data-agent-id="settings-page-root"] (max: 10s) 4. CLICK [data-agent-id="settings-tab-business"] 5. VERIFY selector_exists [data-agent-id="settings-page-root"] ## CAPABILITY: settings-taxes description: Open Settings on the Taxes tab. input: [] output: - type: confirmation description: Taxes tab content visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /settings-page?tab=taxes 3. WAIT [data-agent-id="settings-page-root"] (max: 10s) 4. CLICK [data-agent-id="settings-tab-taxes"] 5. VERIFY selector_exists [data-agent-id="settings-page-root"] ## CAPABILITY: settings-integrations description: Open Settings on the Integrations tab (third-party connections as implemented). input: [] output: - type: confirmation description: Integrations tab content visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /settings-page?tab=integrations 3. WAIT [data-agent-id="settings-page-root"] (max: 10s) 4. CLICK [data-agent-id="settings-tab-integrations"] 5. VERIFY selector_exists [data-agent-id="settings-page-root"] ## CAPABILITY: settings-feedback description: Open Settings on the Feedback tab. input: [] output: - type: confirmation description: Feedback tab content visible. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /settings-page?tab=feedback 3. WAIT [data-agent-id="settings-page-root"] (max: 10s) 4. CLICK [data-agent-id="settings-tab-feedback"] 5. VERIFY selector_exists [data-agent-id="settings-page-root"] ## CAPABILITY: settings-admin description: Open the Admin tab inside Settings (restricted to the service operator account; most users will not see this tab). input: [] output: - type: confirmation description: Admin tab visible only for authorized operator accounts. auth-required: true scope: read-only ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /settings-page?tab=admin 3. WAIT [data-agent-id="settings-page-root"] (max: 10s) 4. CLICK [data-agent-id="settings-tab-admin"] 5. VERIFY selector_exists [data-agent-id="settings-page-root"] ## CAPABILITY: view-pricing description: Read public pricing and plan information (beta messaging as deployed). input: [] output: - type: confirmation description: Pricing content visible. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /pricing-page 2. WAIT [data-agent-id="pricing-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="pricing-page-root"] ## CAPABILITY: contact-support description: Reach support through the public contact page (email copy and contact form UI). input: [] output: - type: confirmation description: Contact page rendered. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /contact-page 2. WAIT [data-agent-id="contact-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="contact-page-root"] ## CAPABILITY: view-shared-invoice description: Recipient-facing PDF viewer for a shared invoice link (token query parameter required). No login. input: - name: share-token type: string required: true description: Token from the share URL query string. output: - type: confirmation description: Invoice PDF renders or an error state is shown. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /shared-invoice?token=<> 2. WAIT [data-agent-id="shared-invoice-page-root"] (max: 15s) 3. VERIFY selector_exists [data-agent-id="shared-invoice-download"] ## CAPABILITY: view-landing description: Marketing landing experience for signed-out visitors (authenticated users are redirected to the dashboard). input: [] output: - type: confirmation description: Landing content visible when not signed in. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /landing-page 2. WAIT [data-agent-id="landing-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="landing-page-root"] ## CAPABILITY: read-faq description: Public frequently asked questions content. input: [] output: - type: confirmation description: FAQ page visible. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /faq-page 2. WAIT [data-agent-id="faq-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="faq-page-root"] ## CAPABILITY: read-how-ai-works description: Public explanation of how the AI assistant processes requests. input: [] output: - type: confirmation description: How AI Works page visible. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /how-ai-works-page 2. WAIT [data-agent-id="how-ai-works-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="how-ai-works-page-root"] ## CAPABILITY: read-terms description: Terms of Service document (legal). input: [] output: - type: confirmation description: Terms page visible. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /terms-page 2. WAIT [data-agent-id="terms-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="terms-page-root"] ## CAPABILITY: read-privacy description: Privacy Policy document (legal). input: [] output: - type: confirmation description: Privacy page visible. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /privacy-page 2. WAIT [data-agent-id="privacy-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="privacy-page-root"] ## CAPABILITY: read-cookie-policy description: Cookie Policy document (legal). input: [] output: - type: confirmation description: Cookie policy page visible. auth-required: false scope: read-only ### UI steps: 1. NAVIGATE /cookie-policy-page 2. WAIT [data-agent-id="cookie-policy-page-root"] (max: 10s) 3. VERIFY selector_exists [data-agent-id="cookie-policy-page-root"]