LaraContact · Documentation

User Guide

Walks through every feature in LaraContact from the user's perspective. If you're a developer installing the app, see the Installation Guide first.

Contacts Two-way SMS Calls Email + tracking AI Reminders Teams

1Signing in

Forgot your password? Click Forgot? on the login page. A reset link is emailed to you (provided mail is configured).

2The dashboard

The dashboard is your daily home. Top to bottom:

3Working with contacts

3.1 Adding a contact

  1. Manually: Click Add contact on the dashboard or /contacts. Fill in the form. Only Name is required.
  2. From a paste: On the create page, paste an email signature, LinkedIn snippet, or business card text into the AI-assisted fill box and click Suggest fields. The form auto-populates name, email, phone, company, job title, website, and LinkedIn.
  3. From CSV: See Β§4 Importing from CSV.

3.2 The contact form fields

3.3 Viewing a contact

Open any contact to see:

3.4 Searching and filtering

3.5 Bulk operations

Select multiple contacts via the checkbox column. A sticky action bar appears:

3.6 Duplicate merge

Open a contact, look for the ⚠ Potential duplicates banner. Click Review & merge, check the boxes for the duplicates you want to absorb, and submit. Behavior:

The whole operation runs in a transaction β€” if any step fails, nothing changes.

4Importing from CSV

  1. From the dashboard, click Template to download contacts-import-template.csv with the right headers + one example row.
  2. Fill in your rows. Required column: Name. Optional: Email, Phone, Company, Job title, Website, Address, Notes, Tags (comma-separated, e.g. vip, follow-up).
  3. Click Import (dashboard) or Import CSV (/contacts/import).
  4. Upload your file. The preview page auto-detects which CSV column maps to which contact field. Adjust if needed.
  5. Optionally assign the entire batch to a group via the dropdown.
  6. Click Import contacts.
Tags column behavior If a tag doesn't exist in your workspace yet, it's created on the fly with auto-slug.

5Communication

5.1 SMS and WhatsApp

In fake mode (no Twilio credentials configured), messages are recorded with a FAKE... SID and the UI shows a banner. Inbound webhook still works β€” useful for testing.

5.2 Calls

5.3 Email

6Bulk sends

Send a single composed message β€” Email, SMS, or WhatsApp β€” to many contacts at once, with mail-merge personalization.

6.1 Composing a bulk send

  1. Go to Contacts, tick the checkboxes for the contacts you want to message.
  2. In the sticky action bar that appears, click Send message.
  3. Pick a channel:
    • Email β€” HTML/plain via your configured mail driver. Has a Subject field.
    • SMS β€” Twilio SMS. Messages over 160 chars split into segments.
    • WhatsApp β€” Twilio WhatsApp Business. No hard length cap.
  4. Compose your body using merge tokens to personalize per recipient:
    • {{first_name}} β€” first word of the contact's name
    • {{name}} β€” full name
    • {{company}}
    • {{email}}
    • {{phone}}
  5. Hit Send. Contacts missing the channel's required field (no email / no phone) are silently skipped β€” the toast tells you how many.

6.2 Tracking progress

After sending, you land on the Bulk send detail page (/bulk-sends/{id}) which shows:

The page auto-refreshes every 4 seconds while the send is still running.

6.3 Past sends

Open Bulk sends in the sidebar (under Communication) for a paginated history with status badges, sent/failed counts, and preview text. Click any row to drill in.

6.4 Reusable templates

On the composer, tick Save as template for next time and give it a name. Next time you open the composer, the saved templates appear as clickable chips at the top β€” click one to instantly populate the channel, subject (email only), and body. Templates are workspace-scoped, so every member sees the same library.

Delete a template via DELETE /bulk-sends/templates/{id} or by removing it from the chip strip on the composer (UI hover).

Rate limiting Bulk sends are queued through Laravel's rate limiter: 60 jobs/min per channel by default (configurable in app/Providers/AppServiceProvider.php). Every successful send creates a normal Message or EmailMessage row, so each send still shows up in the contact's history.
Queue worker recommended For batches over ~10 recipients, run php artisan queue:work under a process supervisor (systemd, Supervisor) so messages dispatch in the background instead of during the HTTP request.

7AI-assisted workflows

LaraContact integrates with Anthropic Claude for four user-facing features. All work in fake mode (heuristic fallbacks) if no API key is set.

FeatureWhere to use itWhat it does
Contact enrichment/contacts/create β†’ AI-assisted fill cardPaste signature/text β†’ extracts name, email, phone, company, title, website, LinkedIn
Spell-check & grammar fixSMS thread composer β†’ Fix buttonRewrites your message correctly without changing voice
TranslationSMS thread composer β†’ Translate button9 languages (English, Spanish, French, German, Italian, Portuguese, Chinese, Japanese, Arabic)
Tag suggestion/contacts/create β†’ Tags card β†’ Suggest from contextPicks the best-fitting tags from your workspace's library based on notes + company + title

Configure your Anthropic API key in Settings β†’ AI. Click Test AI connection to verify.

8Reminders and follow-ups

7.1 List view (/reminders)

Pending reminders grouped by:

Each row has a circle to mark complete and a Delete button. The footer shows recently completed reminders, dimmed and struck through.

7.2 Calendar view (/reminders/calendar)

Monthly grid. Click any day to schedule a reminder for that date β€” a modal pops up. Each day shows up to 3 reminder chips colored by status. Use the arrows to navigate months, or the Today button to jump back.

7.3 Notifications

Reminders fire via the reminders:send-due scheduled command (runs every 5 minutes). When a reminder is due:

Each reminder is notified only once, then marked notified_at.

9Workspace and team invitations

LaraContact supports multiple workspaces per user. Each workspace has its own contacts, tags, groups, settings, and audit log.

9.0 Exporting your workspace

Top-right of the Members page, click Export data. You'll download a ZIP containing CSV files of every contact, message, email, reminder, group, and tag in the current workspace, plus a README.txt manifest with row counts. Great for backups, migrations, or buyer offboarding.

9.1 Inviting a teammate

8.2 Removing a member

Owner only. Click Remove on any member row. The owner cannot be removed. If the removed user had the workspace set as their current workspace, they're auto-switched to their personal workspace.

8.3 Switching workspaces

Click the workspace name in the sidebar header β†’ dropdown lists every workspace you belong to β†’ click to switch. Your current workspace ID is saved on your user record.

8.4 Public registration toggle

The owner can disable public registration in Settings β†’ General. When off, the /register URL returns 404 and the Create account link disappears from the login page. The only way to onboard new users becomes a team invitation.

10Library: Groups and Tags

9.1 Groups

A contact can belong to at most one group. Use for big-picture buckets (Customers, Leads, Partners). Each group has a color shown in the contact list.

9.2 Tags

A contact can have many tags. Use for flexible labels (VIP, hot, follow-up, referral). Each tag has an accent color and an auto-generated slug.

11Audit log

/audit shows every change to every contact in this workspace: who, what, when. The diff renders old and new values for every changed field.

Powered by spatie/laravel-activitylog. The Contact model uses logOnlyDirty and dontSubmitEmptyLogs so the log isn't spammed with no-op saves.

12Two-factor authentication

Optional but recommended. Adds a 6-digit code prompt after every password sign-in.

12.1 Setup

  1. Profile β†’ Two-factor authentication β†’ Set up 2FA.
  2. Scan the QR with any TOTP app (Google Authenticator, 1Password, Authy, Bitwarden, iOS Passwords).
  3. Save the 8 recovery codes shown below the QR β€” each is single-use and required if you lose access to your authenticator.
  4. Enter the 6-digit code your authenticator shows, then Confirm.

12.2 Sign-in challenge

On every login attempt against an account with confirmed 2FA, after the password is validated the user is redirected to /two-factor-challenge. They enter the OTP (or toggle to Use a recovery code instead) to finish signing in. The session is held in two_factor.pending_user_id until verification β€” failed verifications don't authenticate them.

12.3 Recovery codes

Eight codes generated at setup, encrypted at rest. Each is consumed on use; remaining count is shown on the Profile β†’ Two-factor page. Out of codes? Disable 2FA from the same page and re-enable to get a fresh set.

12.4 Locked out

Lost the authenticator AND all recovery codes? An admin with database access can clear the user's 2FA fields:

php artisan tinker --execute='\App\Models\User::where("email","you@example.com")->update(["two_factor_secret"=>null,"two_factor_confirmed_at"=>null,"two_factor_recovery_codes"=>null]);'

That user can then sign in normally with just their password.

Clock drift tolerance LaraContact accepts OTPs from Β±60 seconds (window=2) to handle small clock skew between server and authenticator. Bump the window in App\Support\TwoFactor::verify() if your environment needs more.

13Settings reference

Click your avatar β†’ Settings, or the Settings link in the sidebar.

General

Branding

Mail

Twilio

AI

14Public JSON API

LaraContact exposes a Sanctum-protected JSON API.

Creating a token

Endpoints

MethodPathDescription
GET/api/userCurrent authenticated user
GET/api/contactsPaginated contacts (?q=, ?per_page=25)
GET/api/contacts/{id}One contact with relations
POST/api/contactsCreate contact
PUT/api/contacts/{id}Update contact
DELETE/api/contacts/{id}Soft-delete contact

Example

curl -H "Authorization: Bearer YOUR_TOKEN" \
     -H "Accept: application/json" \
     https://yourdomain.com/api/contacts

Rate limit

60 requests/minute per token. Exceeded requests get 429 Too Many Requests with a Retry-After header.

15Keyboard shortcuts

ShortcutAction
⌘K / Ctrl+KOpen command palette (global search + nav)
↑ / ↓Navigate within command palette
EnterOpen selected result
EscClose any modal or palette

16Frequently asked questions

My SMS sends say FAKE... and don't actually arrive on phones.

You're in fake mode (no Twilio credentials). Go to Settings β†’ Twilio, paste your Account SID, Auth Token, and phone number, and uncheck Fake mode.

I added an Anthropic API key but AI still seems to fall back.

Make sure Fake mode is unchecked in Settings β†’ AI. Also use the Test AI connection button to confirm the key works.

How do I export my contacts?

Not currently built into the UI. You can pull them via the JSON API, or run SELECT * FROM contacts WHERE team_id = ? against your database. CSV export is on the roadmap.

Can I import vCards?

Not yet β€” only CSV. vCard support is on the roadmap.

Reminders never email me even though they're overdue.

Verify the scheduler is running. On a managed host that's a cron entry; in dev that's php artisan schedule:work in a separate terminal. See the Installation Guide.

Where are uploaded logos stored?

storage/app/public/branding/. Make sure you ran php artisan storage:link so they're served from public/storage/branding/.

Can I customize the email templates?

Yes β€” they live in resources/views/emails/. Edit them directly. The current templates are minimal inline-styled HTML.

Does it work on mobile browsers?

Yes. The sidebar collapses into a slide-over on small screens, tables hide secondary columns, and the dashboard re-stacks into a single column.

Is dark mode supported?

Yes β€” toggle it via the moon/sun icon in the top bar. Your preference is saved in localStorage and respected on next visit. System preference is honored on first load.

Can the same user belong to multiple workspaces?

Yes. Accept multiple team invitations, then use the workspace switcher in the sidebar header to flip between them.