# Project pack: Monica @ 32028ce

Facts about **Monica** for an AI following the [BespokeAI handover guide](https://handoff.bespokeai.software/guide/v1.md). This pack is pinned to one version and never changes after publication.

> Monica is a private address book with a memory. Keep notes about friends and family: how you met, their children's names, their pets, gift ideas, money you lent and what you talked about last time. It emails you before birthdays and other dates, nudges you to stay in touch, and has a journal for your own life. It is for your eyes only, never a social network, and it runs on your own server. The pinned code is Monica 4, the stable version.

## Version and source
- Repository: https://github.com/monicahq/monica
- Pinned commit: `32028ce3ce79cef38df5d27a297e5b20680f0065`. Use exactly this version.
- Get it: `git clone https://github.com/monicahq/monica monica && cd monica && git checkout 32028ce3ce79cef38df5d27a297e5b20680f0065`
- Or download a zip: https://github.com/monicahq/monica/archive/32028ce3ce79cef38df5d27a297e5b20680f0065.zip
- Official docs: https://github.com/monicahq/monica/tree/4.x/docs
- Licence: **AGPL-3.0-or-later**. Free to use and change. If you run a changed version that other people use over the internet (not just you or your household), you must offer them your source code under the same licence. Private use has no extra obligations.

## Running it
- Easiest:

  ```sh
  docker network create monica
  docker run -d --name monica-db --network monica -e MYSQL_RANDOM_ROOT_PASSWORD=true -e MYSQL_DATABASE=monica -e MYSQL_USER=homestead -e MYSQL_PASSWORD=secret -v monica-db:/var/lib/mysql mariadb:11
  docker run -d --name monica --network monica -e DB_HOST=monica-db -e APP_KEY="base64:$(openssl rand -base64 32)" -v monica-data:/var/www/html/storage -p 8080:80 monica
  # wait for the database setup to finish, then open http://localhost:8080 and register.
  # Copy APP_KEY from `docker inspect monica` and keep it safe. Change the database password before real use.
  ```

- Needs: Docker, or PHP 8.1+, Composer, a web server (Apache, Nginx or Caddy) and MySQL or MariaDB, Node.js 20 and Yarn 1 to build the front end, About 1.5 GB of RAM for builds and updates
- Develop: `docker-compose -f docker-compose.dev.yml up --build   # app on :8080, phpMyAdmin on :3000, MailHog on :8025 (settings in .env.dev)`
- Test: `yarn test   # migrates the 'testing' database, then runs phpunit, phpstan and psalm`
- Check/lint: `yarn lint   # eslint for the Vue and JavaScript code`
- Stack: php, javascript, vue (Laravel 9, Vue 2, Laravel Mix, Bootstrap 4, Laravel Passport, sabre/dav). Difficulty for a non-developer with an AI: **moderate**. A classic Laravel app. Pages are Blade templates in resources/views/ with Vue 2 components in resources/js/components/. Logic lives in app/Services/, web and API controllers in app/Http/Controllers/, models in app/Models/. Which sections show on a contact page, genders, contact field types, activity types and reminder rules are all settings.

## Customisation points (settings → extend → code)
- **contact-page-sections** [settings]: Choose which sections appear on a contact page, e.g. hide Debts and Activities, keep Notes and Pets. → `Settings → Personalization → Modules (app/Http/Controllers/Settings/ModulesController.php, resources/js/components/settings/Modules.vue)`
- **lists-and-types** [settings]: Make the options fit your family and culture, e.g. add a Signal or WhatsApp field. → `Settings → Personalization (resources/views/settings/personalization/index.blade.php) → genders, contact field types, activity types, life event types`
- **reminder-rules** [settings]: How many days before a date you get an email, and at what time of day. → `Settings → Personalization → Reminder rules (7 and 30 days before by default) and Settings → reminder time (app/Http/Controllers/Settings/ReminderRulesController.php)`
- **stay-in-touch** [settings]: Get an email when you haven't been in touch with someone for a set number of days. → `Stay in touch on each contact page (resources/js/components/people/StayInTouch.vue, app/Jobs/StayInTouch/ScheduleStayInTouch.php)`
- **users** [settings]: Invite a partner or relative by email. Every user of an account sees all its contacts. → `Settings → Users (resources/views/settings/users/, app/Http/Controllers/SettingsController.php)`
- **preferences** [settings]: Personal display preferences, in 27 languages. → `Settings (resources/views/settings/index.blade.php) → language, currency, name order, time zone, temperature`
- **import-export** [extend]: Bring in contacts from your phone or another app, and take everything out again. → `Settings → Import (vCard upload, app/Jobs/AddContactFromVCard.php), Settings → Export (SQL or JSON), and a vCard per contact`
- **carddav-caldav** [extend]: Sync contacts and birthdays with your phone's address book and calendar. → `Settings → DAV, served at /dav with /.well-known/carddav and /.well-known/caldav (app/Http/Controllers/DAV/, app/Providers/DAVServiceProvider.php)`
- **api** [extend]: Read and write contacts, notes, calls, reminders, gifts, debts, tasks, journal entries and more from scripts or other apps. → `REST API at /api (routes/api.php, app/Http/Controllers/Api/) with tokens from Settings → API (resources/js/components/passport/PersonalAccessTokens.vue)`
- **contact-features** [code]: New sections or behaviour on a contact page. → `app/Http/Controllers/Contacts/ + app/Services/Contact/ + resources/views/people/ + resources/js/components/people/`
- **dashboard-and-journal** [code]: New dashboard tabs, lists or journal features. → `app/Http/Controllers/DashboardController.php, JournalController.php + resources/views/dashboard/, resources/views/journal/`
- **text-and-emails** [code]: Wording and the look of reminder emails. → `resources/lang/en/*.php and resources/lang/*.json, app/Notifications/ (e.g. UserReminded.php), resources/views/vendor/mail/`

## Must keep working
- Existing contacts, notes, photos and documents. Back up the database and storage folder first.
- APP_KEY. Changing or losing it makes encrypted data unreadable.
- Account separation. Every query must stay inside the current user's account.
- Database changes need a Laravel migration in database/migrations/; don't change existing columns.
- Reminder and stay-in-touch sending (send:reminders and send:stay_in_touch in app/Console/Kernel.php) and the cron and queue workers that run them.
- The public API in routes/api.php. Phone apps and scripts depend on it, so add endpoints rather than change existing ones.

## Staying updatable
Modules, custom lists, reminder rules, stay-in-touch, CardDAV and the full REST API cover most personal needs without a fork. Build extras as small scripts against the API where you can. Monica 4.x is the maintained stable line; the next major version (5) is being developed upstream with a different design and database, so moving to it later needs a migration plan.

## Data, costs and safety
- Personal data: **yes**. Stored in: A MySQL or MariaDB database plus uploaded photos and documents in storage/ (the monica-data volume in Docker). This is sensitive personal data about other people. Back up the database and storage folder, keep APP_KEY safe, and test a restore before upgrading or changing code. Settings → Export gives you an SQL or JSON copy of your account.
- Service: Email (SMTP) (optional, free with most providers): Birthday, reminder and stay-in-touch emails, and inviting other users. Without it, reminders are not sent.
- Service: LocationIQ (optional, free tier): Turns contacts' addresses into map coordinates (ENABLE_GEOLOCATION).
- Service: WeatherAPI (optional, free tier): Shows the weather where a contact lives (ENABLE_WEATHER, needs geolocation too).
- Service: Amazon S3 or compatible storage (optional, pay-per-use): Store photos and documents outside the server (FILESYSTEM_DISK=s3).
- Setting `APP_KEY` (**secret**: the person enters it themselves, never in chat): Encryption key (base64 plus 32 random bytes). The Docker image makes one if unset, but set your own and save it. Never paste it into an AI chat.
- Setting `APP_URL`: The address you open Monica at (needed for links in emails and for phone sync).
- Setting `HASH_SALT` (**secret**: the person enters it themselves, never in chat): Random text of 20 or more characters used to hide database IDs in links.
- Setting `DB_HOST`: Your MySQL or MariaDB server. DB_PORT, DB_DATABASE and DB_USERNAME go with it.
- Setting `DB_PASSWORD` (**secret**: the person enters it themselves, never in chat): Database password. Change it from the default 'secret'. Never paste it into an AI chat.
- Setting `APP_DISABLE_SIGNUP`: Set to true after creating your account so strangers can't register.
- Setting `MAIL_MAILER`: How emails are sent (smtp for real emails). Set MAIL_HOST, MAIL_PORT, MAIL_USERNAME, MAIL_ENCRYPTION and MAIL_FROM_ADDRESS too.
- Setting `MAIL_PASSWORD` (**secret**: the person enters it themselves, never in chat): Password for your email account. Never paste it into an AI chat.
- Setting `DAV_ENABLED`: CardDAV and CalDAV for phone sync (true by default).
- Setting `DEFAULT_MAX_STORAGE_SIZE`: Upload space per account in MB (default 512).
- Setting `CHECK_VERSION`: Daily check with monicahq.com for new versions (true by default). Set to false to stay fully offline.
- Monica holds private details about other people. Keep it on your own server, use HTTPS, and set APP_DISABLE_SIGNUP=true.
- Change the default database password ('secret') before real use.
- Back up before every update, and run php artisan monica:update afterwards.
- Never paste APP_KEY, the database or mail passwords, or API tokens into an AI chat.

---

# Customising Monica

Monica 4 is a classic Laravel app: Blade pages with Vue 2 components on top. **Much of what you see is configurable in Settings**, especially which sections appear on a contact page. It also has a full REST API, so many extras can be small scripts instead of code changes. Exhaust levels 1 and 2 before touching code.

> The pinned commit is on the `4.x` branch, the maintained stable line, and matches the official `monica` Docker image. Upstream is building version 5 on `main` with a different design and database. Moving to it later is a migration, not an update.

## Level 1: Settings (no code)
- **Contact page sections:** Settings → Personalization → *Modules*. Switch sections on or off: relationships, pets, contact information, addresses, how you met, work, food preferences, notes, calls, activities, reminders, tasks, gifts, debts, conversations, documents.
- **Your own lists:** Settings → Personalization: genders, contact field types (e.g. add WhatsApp or Signal), activity types and life event types.
- **Reminder rules:** Settings → Personalization → *Reminder rules*. By default you get emails 30 and 7 days before each date, plus one on the day. Set the time of day on the main Settings page.
- **Stay in touch:** on any contact page, choose how many days can pass before Monica emails you to get in touch.
- **People:** Settings → Users. Invite a partner or relative by email. Everyone in an account sees all its contacts.
- **Preferences:** language (27 available), currency, name order, time zone, temperature scale (Settings).
- **Sign-ups:** `APP_DISABLE_SIGNUP=true` once your account exists.

## Level 2: Extend (no fork)
- **CardDAV/CalDAV** at `/dav` (with `/.well-known/carddav` and `/.well-known/caldav` redirects): sync contacts and birthdays with your phone. Settings → DAV shows your addresses. Code in `app/Http/Controllers/DAV/`. Guide: `docs/user/carddav.md`.
- **Import and export:** Settings → Import takes a `.vcf` file. Settings → Export gives an SQL or JSON copy. Each contact can be downloaded as a vCard.
- **REST API** at `/api` (`routes/api.php`). Create a personal access token in Settings → API, then send it as `Authorization: Bearer <token>`. It covers contacts, notes, calls, activities, reminders (including `GET /api/reminders/upcoming/{month}`), tasks, gifts, debts, pets, tags, relationships, journal entries, documents and photos. OAuth clients are managed on the same page.
- **Good API jobs:** a weekly email of upcoming birthdays, a printable gift list from `GET /api/gifts`, a "who haven't I called" list from each contact's `last_called` and `stay_in_touch_frequency`.

## Level 3: Code
Pages are Blade templates; the interactive parts are Vue 2 components. Business logic is in `app/Services/`, one class per action.

| Change | Where |
|---|---|
| New section on a contact page | `app/Http/Controllers/Contacts/` + `app/Services/Contact/<Thing>/` + `resources/views/people/` + `resources/js/components/people/` |
| Dashboard | `app/Http/Controllers/DashboardController.php` + `resources/views/dashboard/` |
| Journal | `app/Http/Controllers/JournalController.php` + `resources/views/journal/` + `resources/js/components/journal/` |
| Settings screens | `app/Http/Controllers/Settings/` + `resources/views/settings/` + `resources/js/components/settings/` |
| API endpoints | `routes/api.php` + `app/Http/Controllers/Api/` + `app/Http/Resources/` |
| Routes | `routes/web.php`, `routes/api.php` |
| New data | `database/migrations/` + models in `app/Models/` |
| Text | `resources/lang/en/*.php` and `resources/lang/en.json` (other languages alongside) |
| Reminder emails | `app/Notifications/UserReminded.php`, `StayInTouchEmail.php`, layout in `resources/views/vendor/mail/` |
| Reminder sending | `app/Console/Commands/SendReminders.php`, `SendStayInTouch.php`, `app/Jobs/Reminder/`, scheduled in `app/Console/Kernel.php` |

## Running locally
- **Just use it (Docker):**
  1. `docker network create monica`
  2. Start MariaDB: `docker run -d --name monica-db --network monica -e MYSQL_RANDOM_ROOT_PASSWORD=true -e MYSQL_DATABASE=monica -e MYSQL_USER=homestead -e MYSQL_PASSWORD=secret -v monica-db:/var/lib/mysql mariadb:11`
  3. Start Monica: `docker run -d --name monica --network monica -e DB_HOST=monica-db -e APP_KEY="base64:$(openssl rand -base64 32)" -v monica-data:/var/www/html/storage -p 8080:80 monica`
  4. Wait for the database setup to finish (`docker logs -f monica`), then open http://localhost:8080 and register.
  5. Save the `APP_KEY` (`docker inspect monica`). For reminders, run a second container with the same settings and the command `cron.sh`. Change the database password before real use.
- **Develop:** `docker-compose -f docker-compose.dev.yml up --build` builds from your code (settings in `.env.dev`). App on http://localhost:8080, phpMyAdmin on :3000, MailHog (catches emails) on :8025.
- **Check:** `yarn test` (migrates the `testing` database, then PHPUnit, PHPStan and Psalm) and `yarn lint` (ESLint). Front-end changes need `yarn dev` or `yarn production` to rebuild assets.

## Pitfalls
- Back up the database **and** `storage/` before updates or code changes. After updating code, run `php artisan monica:update --force`.
- Keep `APP_KEY` safe. Without it, encrypted data cannot be read.
- Reminders need the scheduler (`php artisan schedule:run` every minute, or `cron.sh` in Docker) and working email. Without them nothing is sent.
- Only MySQL and MariaDB are supported.
- Every query must stay inside the current user's account. Use the existing services, which check this.
- Don't change existing API responses; phone apps and scripts rely on them. Add new endpoints instead.

---
Machine-readable: [bespoke.yaml](https://handoff.bespokeai.software/p/monica/32028ce/bespoke.yaml) · Agent skill: [SKILL.md](https://handoff.bespokeai.software/p/monica/32028ce/SKILL.md)
