# Active Blue Family Law — Build Plan

**Module:** `activeblue_familylaw` (Odoo 18 Community)
**Method:** build in small, independently **verifiable steps**. We do not start step *N+1* until step *N*'s tests are green and its walkthrough passes.
**Companion design docs:** `00`–`11` (architecture → forms & litigation playbook).

---

## The verifiable-step contract

Every step delivers four things, in this order:

1. **Installable code** — the module installs/upgrades cleanly (`-u activeblue_familylaw`) with the step's new models, security, and views.
2. **A walkthrough** — a short click-path you can follow in the UI to *see* the new behaviour end to end.
3. **Tagged unit tests** — automated tests under `tests/`, tagged `familylaw_step<N>`, that prove the step's guarantees (especially the gates).
4. **Done-when** — an explicit pass condition. Green tests + a clean walkthrough = ship; then advance.

Nothing that touches a real client matter ships until the two ethics gates (attorney review; verified citations) are implemented and tested — Steps 3 and 7.

---

## Test harness (how testing works here)

Odoo ships a `unittest`-based runner. Tests live in `activeblue_familylaw/tests/`, subclass `TransactionCase` (each test rolls back in a savepoint, so the DB stays clean), and carry tags so we can run one step at a time.

**Run all tests for the module (install + test):**
```bash
odoo -d <db> -i activeblue_familylaw --test-enable --stop-after-init
```

**Run only one step's tests (against an already-installed module):**
```bash
odoo -d <db> -u activeblue_familylaw --test-enable --test-tags familylaw_step1 --stop-after-init
```

**Conventions:**
- Tag classes `@tagged("post_install", "-at_install", "familylaw", "familylaw_step<N>")`.
- Use `new_test_user(..., groups="base.group_user,activeblue_familylaw.group_familylaw_attorney")` to test group-gated actions; call gated methods with `.with_user(attorney)` / `.with_user(paralegal)`.
- **External APIs are always mocked** in unit tests — Claude (`/v1/messages`), DocuSeal, CourtListener. Tests must never hit a live network. From Step 6 we use `unittest.mock.patch` on the HTTP client method and assert on what got written to Odoo (e.g. "document born in `ai_draft`", "citation born `unverified`").
- Date math (Step 4+) is tested with fixed dates, not `today()`, so results are deterministic.

---

## Architecture recap (so each step lands in the right place)

- **Odoo is the spine:** system of record, workflow/state machines, RBAC, audit (`mail.thread`), deadlines (`ir.cron` + `base.automation`), documents, calendar, UI.
- **AI = Odoo's own HTTPS call to the Claude API** (`api.anthropic.com/v1/messages`), key in `ir.config_parameter`, model pinned in config, wrapped in `queue_job` so it runs async. *No Odoo-AI feature is used.*
- **The one external service** is the optional FastAPI orchestrator for the multi-step **research** loop (Step 7); single-shot AI calls (drafting, summaries) run from Odoo directly.
- **Satellites:** DocuSeal (e-signature, Step 11), MinIO/Synology (file archive, Step 12), CourtListener (citation verification, Step 7).
- **Local Ollama** is a *later* routing option; `_route_model()` is built so flipping high-confidentiality work to local is a config change, not a redesign. Trust/billing reconciliation never reaches any model.

---

## The step sequence

| Step | Goal (vertical slice) | Key models / files | Proves (tests) | Design doc |
|---|---|---|---|---|
| **1 ✅** | **Case spine + lifecycle state machine + attorney gates** | `familylaw.case`, security groups, case views | state transitions, conflict-clearance gate, attorney-only actions, illegal-transition rejection, audit logging | 02, 03 |
| 2 | Parties, children, issues | `familylaw.party`, `.child`, `.issue` | relations, DOB/constraint validation | 02, 03 |
| 3 | **Documents + the review gate** | `familylaw.document` (`ai_draft→attorney_review→approved`) | only attorney approves; can't file/send unapproved (THE gate) | 03, 04 |
| 4 | Deadline engine | `familylaw.deadline`, `base.automation`, `ir.cron`, `calendar.event` mirror | 20/45/30-day math, weekend roll, overdue detection | 02, 11 |
| 5 | Mandatory disclosure (Rule 12.285) | `disclosure.item`, `financial.affidavit`, `fin.line` | 12.902(b) vs (c) by income, 45-day due date, can't-waive flags | 02, 11 |
| 6 | **Claude client + `ai.task` ledger** (single-shot) | `familylaw.ai.client`, `ai.task`, drafting agent, `queue_job` | (mocked API) doc born `ai_draft`, task logged, citations born `unverified` | 04, 09 |
| 7 | **Citation ledger + filing gate** + research loop | `familylaw.citation`, `action_request_filing`, FastAPI orchestrator | filing blocked on any unverified citation; allowed when all verified | 06 |
| 8 | **Discovery + subpoena workflow** (12.351 gate + pro-se/attorney branch) | `discovery.request`, subpoena objection-window gate | objection-window hard gate, same-day Notice of Issuance, clerk-vs-attorney routing | 11 (A.6, C) |
| 9 | Child-support **modification** workflow (Playbook Scenario 2, end to end) | wires Steps 1–8 for `support_modification` | 15%/$50 threshold, 20-day answer clock, DOR-case flag, retroactivity note | 11 (B.2) |
| 10 | **Emergency** workflow (12.941 pick-up / removal — Scenario 1) | emergency motion records + required-attachment checks | the have-order-vs-not fork; missing-attachment block | 11 (B.1) |
| 11 | DocuSeal e-signature | `action_send_for_signature`, webhook controller | (mocked) only `approved` can send; webhook flips to `signed` | 05 |
| 12 | File archive + calendar layers | `ir.attachment` + `familylaw.archive` metadata; calendar categories | SHA-256 checksum, retention class, per-layer filtering | (new) |
| 13 | Miami-Dade auto-seed (AO 14-13) | Status Quo Order, parenting-course + mediation obligations on case open | obligations seed on open; course-before-judgment guard | 11 (D) |
| 14 | Comms agent + AI-assisted billing flag + hardening | `comms` drafts, `time.entry.ai_assisted`, encryption/backup pass | (mocked) comms never auto-sends; AI ratio reportable | 04, 08 |

**Suggested MVP to run a real solo practice:** Steps 1–6 + 8 + 11. Add 7 (research/verification) next. 9/10 are the headline workflows; 12–14 round it out.

---

## STEP 1 — delivered ✅

**What's in it**
- `familylaw.case` — the matter record: identity (`name`, `client_id`, `case_type`), team (`attorney_id`, `paralegal_id`), the **`representation`** flag (attorney / pro_se — drives the Step 8 subpoena branch), the **`conflict_check_cleared`** gate, and the **`state`** lifecycle: `intake → engaged → disclosure → discovery → mediation → hearing → closed`.
- A **guarded state machine**: each transition checks the current stage and refuses illegal jumps; `action_mark_conflict_cleared` and `action_close`/`action_reopen` are **attorney-only** (enforced in Python *and* hidden via `groups=` on the buttons).
- Security groups **Family Law / Staff** and **Family Law / Attorney** (attorney implies staff implies internal user) + model access rules (staff can't delete; attorney can).
- List, form (statusbar + transition buttons + audit chatter), and search views; a **Family Law** app menu.
- `mail.thread` audit trail — every stage change and the conflict clearance post to the chatter.

**Install**
```bash
# copy the module into your addons path, then:
odoo -d <db> -i activeblue_familylaw --stop-after-init
# (or install "Active Blue Family Law" from the Apps menu)
```

**Run Step 1 tests**
```bash
odoo -d <db> -i activeblue_familylaw --test-enable --test-tags familylaw_step1 --stop-after-init
```
Ten tests cover: initial state, the conflict-clearance gate (engage blocked until cleared; only an attorney can clear), illegal-transition rejection, the full forward path, attorney-only close/reopen, and audit logging.

**Walkthrough (click-path)**
1. Family Law → Cases → **New**. Enter a matter name, pick Client A, set Case Type = *Child Support Modification*, assign yourself as attorney. Save. → it's in **Intake**.
2. As a **staff** user, the *Clear Conflict Check* and *Close* buttons are hidden; try the flow and you can't engage yet.
3. As an **attorney**, click **Clear Conflict Check** → the boolean ticks and a chatter note appears. Now **Engage** → stage moves to *Engaged*.
4. Walk **Start Disclosure → Start Discovery → Start Mediation → Set for Hearing**; the statusbar advances and each change is logged.
5. **Close Case** (attorney only) → *Closed*; **Reopen** sends it back to *Engaged*.

**Done-when:** the 10 tests pass and the walkthrough behaves as above. ✅ → ready for Step 2 (parties, children, issues).

---

## Notes / known-small-things
- The form uses the explicit `oe_chatter` div for cross-release safety. Odoo 18 also supports the shorthand `<chatter/>` tag; swap if preferred.
- An app icon can be added later at `static/description/icon.png` and referenced via `web_icon` on the root menu (left off now to keep install dependency-free).
- Record-level isolation between attorneys (multi-attorney record rules) is intentionally deferred; Step 1 grants the two groups company-wide access. We tighten this when the data model warrants it.
