# CLAUDE.md — activeblue_familylaw This file gives Claude Code the context it needs to work effectively on this project. Read this before making any changes. --- ## What This Is **ActiveBlue Family Law** (`activeblue_familylaw`) is a custom Odoo 18 Community module for Florida family law case management targeting **pro se litigants and full law firm operations** in Miami-Dade County (11th Circuit). The module runs an entire law firm within Odoo: intake, case tracking, AI-assisted legal research, paralegal task management, discovery, court document generation, billing, and case closure. It is not a lightweight helper — it is the primary practice management system. Repo: `https://git.activeblue.net/tocmo0nlord/famlaw` Module root: `activeblue_familylaw/` Author: Active Blue LLC — `https://avc.activeblue.net` Odoo version: **18.0** License: LGPL-3 --- ## Deployment Context | Item | Value | |---|---| | Odoo instance | `192.168.2.9:8069` (Docker, local network only) | | Target database | `db1` (accessed at `192.168.2.9:8069` — no public hostname) | | Odoo version | 18.0 Community | | AI inference | Claude API — `claude-sonnet-4-20250514` | | Git remote | `https://git.activeblue.net/tocmo0nlord/famlaw` | > **Note:** This instance is local-only on the `192.168.2.x` network. There is no external > hostname or reverse proxy for this deployment. Traefik is not in use here. All access is > direct to `192.168.2.9:8069`. Do not reference CT 112, `192.168.1.53`, or `avc.activeblue.net` > for this module. --- ## AI Agent Architecture This module uses **two distinct AI agents** backed by the Claude API (`claude-sonnet-4-20250514`). Both agents write to the `fl.case` chatter for full auditability. All API calls must handle `anthropic.APIError` and `anthropic.APIConnectionError` gracefully — never let AI failures block user workflow. Log failures to chatter as a warning. ### Paralegal Agent (`fl_paralegal_agent.py`) Handles procedural intelligence. Runs automatically on case stage transitions and can be triggered manually from any case. Responsibilities: - Florida Rules of Civil Procedure deadline calculation (service by mail +5 days, holidays excluded via Python `holidays` library, judicial holidays for 11th Circuit) - Task batch generation per stage (see Stage Machine below) - Statute cross-reference for active issue tags on the case - Mandatory disclosure checklist generation (FL-12.932) - Chatter summary after every bulk action - Non-billable AI time logging to `fl.timesheet` for audit trail Prompt strategy: always include `case_type`, `complexity`, `issue_tag_ids`, active deadlines, and current stage. Keep system prompt under 800 tokens — pass case context as user message. ### Attorney Agent (`fl_attorney_agent.py`) Handles substantive legal reasoning. Fires on demand (button on AI tab of `fl.case`). Never runs automatically — always a deliberate user action. Responsibilities: - Full case questionnaire analysis → strategy memo stored in `fl.analysis` - Top 3–5 applicable FL statutes identified and linked to `fl.statute` records - Top 3–5 relevant case law entries linked to `fl.caselaw` records - Argument drafting for the case's primary issue tags - Risk flag narrative (DV, hidden assets, income imputation, unrepresented respondent) - Child support modification: auto-detect substantial change of circumstances (§61.30(1)(b)), pull last 3 years of support schedule from case history Prompt strategy: include full intake questionnaire responses, parties, children, financial data summary, and any prior `fl.analysis` records so the agent builds on prior work. ### Rule-Based Fallback Both agents fall back to rule-based logic when the Claude API is unavailable. The fallback must cover: complexity scoring, basic deadline calculation, and a minimal task batch. Never surface a raw API error to the user. --- ## Module Structure ``` activeblue_familylaw/ ├── __manifest__.py ├── __init__.py ├── models/ │ ├── fl_ai_engine.py ← Shared Claude API client + retry logic │ ├── fl_paralegal_agent.py ← Paralegal AI agent (procedural) │ ├── fl_attorney_agent.py ← Attorney AI agent (substantive) │ ├── fl_analysis.py ← AI analysis records │ ├── fl_argument.py ← Legal argument tracking │ ├── fl_case.py ← Core case model (fl.case) + stage machine │ ├── fl_caselaw.py ← FL case law library │ ├── fl_child.py ← Minor children records │ ├── fl_conflict_check.py ← Conflict of interest check engine │ ├── fl_deadline.py ← Procedural deadline tracking + auto-calc │ ├── fl_deposition.py ← Deposition scheduling │ ├── fl_discovery.py ← Discovery requests/responses │ ├── fl_document.py ← Court document management │ ├── fl_efiling.py ← FL 11th Circuit e-filing portal integration │ ├── fl_expense_case.py ← Case-linked expense tracking │ ├── fl_fee_waiver.py ← Fee waiver eligibility │ ├── fl_hearing.py ← Hearing calendar integration │ ├── fl_income_withholding.py ← Income withholding orders │ ├── fl_party.py ← Petitioner/Respondent parties │ ├── fl_signature_request.py ← E-signature workflow (external, spec-compliant) │ ├── fl_statute.py ← FL statute reference index │ ├── fl_support.py ← FL 61.30 child support calc │ └── fl_timesheet.py ← Billable hours + AI audit time (wraps account.analytic.line) ├── wizard/ │ ├── fl_intake_wizard.py ← Guided case creation + fires Attorney agent on finish │ ├── fl_analysis_wizard.py ← Trigger AI analysis │ ├── fl_generate_packet_wizard.py ← Generate filing packet │ ├── fl_discovery_suggest_wizard.py ← Complexity-driven discovery suggestions │ └── fl_efiling_wizard.py ← Prepare and submit to FL e-Filing Portal ├── views/ │ ├── fl_case_views.xml ← Kanban + form + list views, stage bar │ ├── fl_conflict_check_views.xml │ ├── fl_discovery_suggest_views.xml │ ├── fl_efiling_views.xml │ ├── fl_signature_request_views.xml │ ├── fl_timesheet_views.xml │ ├── menu_views.xml │ ├── portal_*.xml ← Client-facing portal templates │ └── website_intake_templates.xml ├── report/ ← 12 QWeb PDF court documents │ ├── report_financial_affidavit_short.xml ← FL-12.902(b) │ ├── report_financial_affidavit_long.xml ← FL-12.902(c) │ ├── report_child_support_worksheet.xml ← FL-12.902(e) │ ├── report_motion_to_modify.xml │ ├── report_notice_deposition.xml │ ├── report_motion_to_compel.xml │ ├── report_income_withholding.xml │ ├── report_fee_waiver.xml │ ├── report_notice_ssn.xml ← FL-12.930(a) │ ├── report_mandatory_disclosure.xml ← FL-12.932 │ ├── report_default_motion.xml │ └── report_parenting_plan.xml ├── data/ │ ├── fl_support_schedule.xml ← Basic Support Obligation table │ ├── fl_statute_data.xml ← FL statute index seeds │ ├── fl_caselaw_data.xml ← 23 pre-loaded FL cases │ ├── fl_deadline_rules.xml ← Procedural deadline rules │ ├── fl_issue_tags.xml ← Issue taxonomy │ ├── fl_stage_data.xml ← Case stage records (Kanban) │ ├── ir_sequence.xml ← Case number sequences │ ├── mail_templates.xml │ └── case_task_templates.xml ├── security/ │ ├── fl_security.xml │ └── ir.model.access.csv ├── controllers/ ← Portal + website intake + e-filing webhook routes └── static/src/ ├── css/familylaw_portal.css └── js/ ├── fl_calculator.js ← Interactive FL 61.30 widget └── fl_timeline.js ← Visual case timeline ``` --- ## Core Domain Models All models use the `fl.` prefix. | Model | Description | |---|---| | `fl.case` | Root entity — case type, parties, status, stage, AI complexity score | | `fl.party` | Petitioner or Respondent (links to `res.partner`) | | `fl.child` | Minor children on the case | | `fl.support` | FL 61.30 child support calculation | | `fl.deadline` | Procedural deadlines with calendar sync + auto-calculation | | `fl.hearing` | Scheduled hearings | | `fl.discovery` | Individual discovery requests/responses | | `fl.discovery.suggest.wizard` | Complexity-driven discovery suggestion engine | | `fl.discovery.suggest.line` | One suggested discovery item | | `fl.deposition` | Deposition scheduling and tracking | | `fl.document` | Court-filed documents (linked to reports) | | `fl.analysis` | AI case analysis records (both agents write here) | | `fl.caselaw` | Florida case law library entries | | `fl.statute` | FL statute reference index | | `fl.fee.waiver` | Fee waiver eligibility and form data | | `fl.income.withholding` | Income withholding order records | | `fl.argument` | Legal argument tracking (linked to case law) | | `fl.conflict.check` | Conflict of interest check result per intake | | `fl.signature.request` | E-signature request linked to a court document | | `fl.efiling.submission` | FL e-Filing Portal submission record | | `fl.timesheet` | Billable hours + AI audit entries (wraps `account.analytic.line`) | ### Key Fields on `fl.case` - `case_type`: `modification` | `dissolution` | `paternity` - `stage_id`: Many2one `fl.case.stage` — drives Kanban and Paralegal agent task batches - `complexity`: `low` | `medium` | `high` | `extreme` (set by Attorney agent or rule-based fallback) - `issue_tag_ids`: Many2many `fl.issue.tag` — used by both agents and discovery suggestion wizard - `domestic_violence_flag`, `respondent_has_counsel`, `income_imputation_concern`: boolean flags that affect discovery templates and Attorney agent prompt - `conflict_check_passed`: Boolean — case cannot move past Intake stage until True - `attorney_memo_id`: Many2one `fl.analysis` — current Attorney agent strategy memo --- ## Case Stage Machine Stages are defined in `fl_stage_data.xml` and drive the Kanban view on `fl.case`. Each stage transition triggers the **Paralegal agent** to generate the next task batch. | Stage | Trigger | Paralegal Task Batch Generated | |---|---|---| | `Intake` | Case created | Conflict check, questionnaire completion, fee waiver assessment | | `Active` | Intake complete + conflict check passed | Service of process, mandatory disclosure (FL-12.932), initial hearings | | `Discovery` | Attorney fires analysis; complexity ≥ medium | Interrogatories, production requests, depositions per discovery suggest wizard | | `Pre-Trial` | Discovery closed | Pretrial statement, exhibit list, witness list, mediation scheduling | | `Closed` | Final order filed | Archive checklist, billing reconciliation, file retention notice | Stage transitions validate preconditions (e.g., cannot enter `Active` without `conflict_check_passed`). Use `_check_stage_transition()` on `fl.case` — raise `UserError` with a clear message, never silent. --- ## Conflict of Interest Check (`fl_conflict_check.py`) Run automatically on `fl.case` creation before any other action. Logic: 1. Collect `name` from all `fl.party` records on the new case (petitioner + respondent). 2. Query all active `fl.party` records on other open cases. 3. Check for name overlap (exact + fuzzy — use `difflib.SequenceMatcher`, threshold 0.85). 4. If a match is found: create a `fl.conflict.check` record with `status = 'conflict'`, log to chatter with matched case reference, and set `fl.case.conflict_check_passed = False`. 5. If no match: set `status = 'clear'` and `conflict_check_passed = True` automatically. 6. A user with group `fl_group_manager` can manually override a conflict with a written justification stored on the `fl.conflict.check` record. Never silently pass a conflict. Always surface it to the user. --- ## E-Signature Workflow (`fl_signature_request.py`) > **Important:** Odoo Sign is **not within spec** for Florida court document e-signatures. > Florida courts require specific PDF/A-compliant documents with court-approved signature > fields per the FL Supreme Court Administrative Order AOSC09-30 (amended). Do not use > Odoo Sign for court filings. Architecture: - `fl.signature.request` links to one `fl.document` and one `res.partner` (signer). - On creation, generate the QWeb PDF, flatten form fields except the signature block, and store as `ir.attachment` with `mimetype = 'application/pdf'`. - The signature block coordinates are document-type-specific — define them in a `_SIGNATURE_COORDS` dict keyed by report template XML ID: ```python _SIGNATURE_COORDS = { 'activeblue_familylaw.report_financial_affidavit_short': {'page': 1, 'x': 72, 'y': 680, 'w': 200, 'h': 30}, # ... one entry per report } ``` - Delivery: email the PDF to the signer via Odoo mail with a portal link. The portal page (`/familylaw/sign/`) uses an HTML5 canvas signature pad (no external JS dependency — draw to canvas, export as PNG, embed via PyMuPDF into the PDF at the defined coordinates). - On completion: write signature PNG into the PDF at correct coordinates, update `fl.signature.request.state = 'signed'`, attach the signed PDF to `fl.document`, and log to chatter. - For documents going to the FL e-Filing Portal, the signed PDF must pass: `pikepdf` validation for PDF/A compliance before submission is allowed. Never use DocuSign, HelloSign, or any external e-signature SaaS — all processing must be self-hosted per HIPAA and data sovereignty requirements. --- ## FL 11th Circuit E-Filing Integration (`fl_efiling.py`) The Florida Courts e-Filing Portal (`eportal.flcourts.org`) exposes a REST API. Full programmatic filing is the target; the current phase implements preparation and assisted submission. ### Phase 1 (current): Assisted submission - `fl_efiling_wizard.py` walks the user through preparation steps. - Auto-generate the court-compliant filename per 11th Circuit convention: `{LastName}_{CaseNumber}_{DocumentType}_{YYYYMMDD}.pdf` Example: `Smith_2024-DR-012345_MotionToModify_20240915.pdf` - Validate PDF/A compliance via `pikepdf` before allowing submission. - One-click button opens `eportal.flcourts.org` deep-linked to the correct case (append `?caseNumber={fl.case.court_case_number}` if available). - Store `fl.efiling.submission` record with status `pending_manual`. ### Phase 2 (planned): API submission - FL e-Filing Portal API endpoint: `https://api.eportal.flcourts.org/` (confirm current base URL from portal documentation before implementing). - Authentication: username/password token exchange stored in `ir.config_parameter` (keys: `fl_efiling.username`, `fl_efiling.password`) — never hardcoded. - On successful API submission: update `fl.efiling.submission.status = 'submitted'`, store the portal confirmation number, log to chatter. - On failure: log full error to chatter, set status `failed`, surface error message to user — never silent failure. --- ## Deadline Engine (`fl_deadline.py`) `_compute_due_date()` must handle: - Florida Rules of Civil Procedure Part II service windows: - 20-day answer period after service - 45-day mandatory disclosure window (FL-12.932) - 30-day response to interrogatories - Service by mail: add 5 days (Fla. R. Civ. P. 1.090(e)) - Holiday exclusion: use Python `holidays` library with `holidays.US(state='FL')` plus 11th Circuit judicial holidays (hardcode the annual list in `fl_deadline_rules.xml` and merge at runtime). - `_recalculate_all(case_id)`: callable by Paralegal agent — recalculates all open deadlines on a case when a new event is logged (hearing date set, service confirmed, etc.). - Calendar sync: write to `calendar.event` for every `fl.deadline` — use `_sync_to_calendar()` called in `create` and `write`. --- ## Time Tracking + Billing (`fl_timesheet.py`) `fl.timesheet` wraps `account.analytic.line` and adds case context. Key fields: - `case_id`: Many2one `fl.case` (required) - `employee_id`: Many2one `hr.employee` - `is_billable`: Boolean (default True; False for AI audit entries) - `ai_agent`: Selection `paralegal` | `attorney` | None — set when the Paralegal or Attorney agent auto-logs time - `duration_hours`: Float (maps to `unit_amount` on `account.analytic.line`) Usage: - Attorneys and paralegals log time manually from the case form (Timesheet tab). - Both AI agents log non-billable entries automatically for audit trail. - The case form shows a computed `total_billable_hours` and `total_billable_amount` (rate from `hr.employee` or a default firm rate in `ir.config_parameter`). - Invoicing flows through standard Odoo Accounting — `account.analytic.line` entries are picked up by `account.move` generation as usual. --- ## Odoo Dependencies Declared in `__manifest__.py`: ```python 'depends': [ 'base', 'mail', 'portal', 'website', 'contacts', 'calendar', 'project', 'crm', 'account', 'hr_expense', 'analytic', # 'sign' — DO NOT enable: not within FL court e-signature spec # 'queue_job' — OCA, install separately if needed for async AI calls ] ``` `sign` is intentionally excluded — Florida court e-signatures require custom PDF handling outside Odoo Sign's capabilities. `queue_job` is optional for async Claude API calls. --- ## Development Conventions ### Odoo 18 Patterns - Use `fields.Html` for rich text, `fields.Text` for plain - `@api.depends` for computed fields; always set `store=True` if used in search/group - Use `_inherit` not `_name` for extending existing Odoo models - All new models need entries in `ir.model.access.csv` AND `fl_security.xml` - XML IDs must be unique across the module — prefix everything with `fl_` ### Views - Actions must be declared before `` references in `menu_views.xml` - Portal templates go in `views/portal_*.xml` - Website intake templates go in `views/website_intake_templates.xml` - Always test QWeb reports with `wkhtmltopdf` — paper sizes matter for court forms - Kanban view on `fl.case` must show: case number, case type, complexity badge, next deadline, and conflict check status badge ### Claude API (`fl_ai_engine.py`) - Use the `anthropic` Python library — `pip install anthropic` - API key stored in `ir.config_parameter` key `fl_ai.claude_api_key` — never hardcoded - Model: always `claude-sonnet-4-20250514` — do not make this a user-configurable field - Always handle `anthropic.APIError`, `anthropic.APIConnectionError`, `anthropic.RateLimitError` - Log all AI calls (model, tokens used, latency) to chatter as an internal note - Use the rule-based fallback in `fl_ai_engine._fallback_complexity()` when API unavailable - Never block user workflow on AI failure ### Discovery Suggest Wizard - Add new discovery templates to `_get_templates()` in `fl_discovery_suggest_wizard.py` - Each template: `type`, `directed_to`, `description`, `rationale`, `trigger`, `min_complexity` - Triggers are string labels — keep consistent with existing ones - `action_create_selected` posts a chatter summary — keep it ### Reports (QWeb) - Court form dimensions: US Letter (8.5×11 in) — set `paperformat_id` appropriately - Florida court forms reference: FL Supreme Court forms at `www.flcourts.gov` - Field labels must match official form labels exactly - All reports used for e-filing must be PDF/A compliant — validate with `pikepdf` in CI ### Security Groups | Group | Access | |---|---| | `fl_group_user` | Create/edit own cases, read all | | `fl_group_paralegal` | All of above + manage deadlines, tasks, discovery | | `fl_group_attorney` | All of above + fire Attorney agent, manage arguments | | `fl_group_manager` | Full access + conflict override + billing | --- ## Out of Scope for This Repo - Odoo AI agent / Master AI system → `tocmo0nlord/odoo-ai` (separate repo) - IRC bot → `tocmo0nlord/irc-bot` - Infrastructure config → handled at Docker/network layer, not this module - HIPAA training eLearning module → different Odoo addon - Traefik configuration → not in use on `.2.1` network for this module --- ## Running / Testing ```bash # Restart Odoo to pick up module changes docker compose restart odoo # Update module (from Odoo container or Settings → Apps) # Technical → Update Apps List first if adding new files # Check logs docker compose logs -f odoo | grep activeblue_familylaw # Validate PDF/A compliance on a generated report (requires pikepdf) python3 -c "import pikepdf; pdf = pikepdf.open('/tmp/test.pdf'); print(pdf.docinfo)" ``` Module installs via **Apps → Upload a Module** or by placing it in the addons path. After any model change: **Settings → Activate Developer Mode → Technical → Update Apps List → Upgrade**. ### Claude API key setup ```bash # In Odoo shell (Settings → Technical → Parameters → System Parameters) # Key: fl_ai.claude_api_key # Value: sk-ant-... ```