Security at Caolu

How we protect your data and your customers' data. Built for Irish solar professionals who handle sensitive information daily.

Last Updated: April 2026 (v3)
Infrastructure: EU-Only (AWS Ireland)
Encryption: AES-256
1

Infrastructure

EU-Only Data Residency

All data is stored and processed within the European Economic Area. Our primary infrastructure runs on AWS eu-west-1 (Dublin, Ireland) via Supabase. No customer data leaves the EEA unless explicitly configured by the subscriber (e.g., outbound webhook endpoints).

Hosting & Delivery

The application is served via Netlify's EU CDN edge nodes with HTTPS enforced on all connections. There is no on-premise infrastructure — the platform is fully managed cloud.

All customer data resides in AWS eu-west-1 (Dublin, Ireland). No data leaves the EEA unless the subscriber explicitly configures an outbound webhook endpoint outside of it.
2

Encryption

Layer Standard
Data in transit TLS 1.2+ (HTTPS enforced on all endpoints)
Data at rest AES-256 encryption (Supabase/AWS managed)
Sensitive financial data Field-level encryption using pgcrypto (AES-256). Bank IBAN, BIC, and bank name are encrypted at the column level and decrypted server-side only via authenticated Edge Functions.
Property identifiers (Manager Dashboard) Salted SHA-256 hash of (company_id + normalised eircode) stored in the property_hash column. Used for property deduplication in the Manager Dashboard without retaining the eircode in reversible form. The 32-byte salt lives in a private, service-role-only schema with no public grants, so the hash cannot be reversed from outside the database.
Passwords Bcrypt hashing. Plaintext passwords are never stored or logged. Leaked-password protection via HaveIBeenPwned is available on Supabase Auth and enabled at the project level.
Payment card data Not processed by Caolu. All card handling is performed exclusively by Stripe. Card numbers never touch our systems.
3

Access Control

Row-Level Security (RLS)

Every database table has PostgreSQL Row-Level Security policies enforced at the database engine level — not in application code. This means:

  • Users can only access their own data, even if application code has a bug
  • Managers can view data within their own organisation only
  • Company-wide settings (brand, webhook, payment configuration) can only be modified by users with the manager or admin role — enforced at the database level
  • Direct API access is subject to the same RLS policies as the application

Role-Based Access Control

Three tiers of access:

Role Permissions
Rep Create/read/update/delete own assessments and projects. Generate PDFs. No access to company settings, dashboard, or other reps' data.
Manager All rep permissions, plus: view team members' projects, access Manager Dashboard, edit Company Profile (brand, payment, webhook, T&Cs), manage team invitations, mark projects as won/lost with categorised reasons.
Admin All manager permissions. Reserved for account owners.
Database-enforced security: RLS policies operate at the PostgreSQL engine level. Even a bug in application code cannot expose data across user or organisation boundaries.
4

Authentication & Session Management

  • Authentication provider: Supabase Auth (JWT-based)
  • Session timeout: Automatic logout after 30 minutes of inactivity
  • Session warning: Visual warning at 25 minutes with option to extend
  • Re-authentication: Required after session expiry — no silent token refresh beyond timeout
  • Password reset: Secure email-based reset flow with time-limited tokens
5

Audit Trail

Security-relevant events are logged to an immutable audit table:

Event Logged Data
Assessment opened User ID, timestamp, tier
Configuration saved User ID, project reference, system details
PDF generated User ID, customer reference (if consent given), document type
Company profile updated User ID, company ID, timestamp
Session timeout User ID, reason, timestamp
Project status changed User ID, project ID, new status, loss reason (if applicable)
Deal reopened User ID, project ID, previous status, timestamp
Team goal set (Manager Dashboard) Manager user ID, company ID, period, target values
Dashboard identity reveal (Manager Dashboard) Manager user ID, company ID, rep count, period, timestamp. Visible to the affected Reps via their in-app "My Data & Privacy" screen.
Dashboard load / render failure User ID, error message (truncated), company ID, period — used to alert on-call if the Manager Dashboard is failing for any company
Rep self-view Rep user ID, days requested — logged every time a Rep opens the "My Data & Privacy" screen
Rep data export Rep user ID, format (JSON or CSV), company ID — logged every time a Rep exports their own data via the self-service tool
Data export (manager CSV) Manager user ID, period, row count, company ID

Audit records are retained for the lifetime of the account plus 90 days post-cancellation. Deal status history and locked commercial values are retained for 7 years as commercial records in line with Irish Revenue requirements.

5.1

Manager Dashboard Controls

The Manager Dashboard (available on Teams and Enterprise plans) gives managers team performance visibility while applying privacy-by-design guarantees to every sales rep. The following controls are operated by the platform and cannot be disabled by subscribers:

Pseudonymous by Default

When a manager opens the Manager Dashboard, rep cards render with pseudonymous labels (Rep A, Rep B, Rep C) and matching placeholder avatars. Real names and initials do not appear on screen. The names exist in the server response but the client-side renderer only reveals them when the manager explicitly opts in.

Audit-Logged Identity Reveal

To see real rep names, the manager must click the "Reveal names" button above the team tab, confirm a consent dialog, and accept that the action is being recorded. On confirmation, the platform:

  • Writes a dashboard_identities_revealed event to the immutable audit log, including the manager's user ID, company ID, number of reps viewed, and the period being reviewed
  • Displays an amber warning banner across the top of the Team tab stating that identity reveal is active
  • Re-renders the rep cards and add-on matrix with real names
  • Starts a 30-minute auto-expire timer

Every Rep can see the audit log of identity reveals for their company in the in-app "My Data & Privacy" screen. This is a deliberate transparency mechanism: reps are told (via the Privacy Policy and the employee notification their employer sends) that they can check, at any time, which managers have de-pseudonymised the dashboard and when.

Auto-Expiring Reveal Window

The reveal state is not persistent. It auto-expires after 30 minutes or when the manager closes the dashboard, whichever is sooner. Every new dashboard session starts pseudonymous again. This prevents habitual or background surveillance and forces each review session to be a conscious, auditable act.

No Automated Scoring or Evaluative Labels

The Manager Dashboard displays only raw work-product metrics (assessment count, PDF rate, battery attach rate, average system size, estimated pipeline). It does not compute composite scores, tier classifications, or any evaluative labels about individual reps. This is a deliberate design choice: GDPR Article 22 restricts automated individual decision-making with significant effects on a data subject, and by removing the evaluative layer entirely we ensure Article 22 is not engaged.

No In-App Coaching Notes

Caolú does not provide a free-text coaching notes feature inside the platform. Managers record coaching conversations in their own HR system. This keeps evaluative commentary about individual employees out of Caolú's scope entirely and reduces the data categories we hold on behalf of subscribers.

Team-Level Alerts Only

The Manager Dashboard Alerts tab surfaces only team-level patterns (e.g. "Team battery attach below 40% target", "Team volume dropped more than 20% vs previous period"). The platform does not generate alerts that name or implicitly identify individual reps. This prevents the dashboard from acting as a passive surveillance system.

Automated 90-Day Retention at Individual Resolution

A scheduled nightly job (nightly_anonymise_dashboard_data, running at 03:17 UTC via pg_cron) sets the anonymised_at marker on:

  • Every assessment_events row older than 90 days
  • Every in-progress saved_configs row older than 90 days

Identifying metadata keys are stripped from the row at the same time (customer names, addresses, eircodes, installer names, labels). After anonymisation, the row still contributes to team-aggregate statistics but cannot be linked to a specific Rep. Won and lost commercial deal rows are exempt from this process and retain their locked commercial values for the 7-year Irish Revenue retention period.

Rep Self-Service: My Data & Privacy Screen

Every user, regardless of role, can open the "My Data & Privacy" screen from their profile dropdown. This screen shows:

  • The Rep's own profile (name, role, company, account creation date)
  • Their own performance metrics for the last 90 days (assessments, configs saved, battery attach rate, average kWp, estimated pipeline, total annual savings quoted)
  • Their own deal pipeline status (in progress, won, lost)
  • The identity-reveal access log — every time a manager in the same company clicked "Reveal names" in the Manager Dashboard, who did it, and in what period — for the last 90 days
  • The retention policy applied to the data

A single "Export my data (JSON)" button downloads the whole dataset as a timestamped JSON file tagged with the GDPR Article 15 legal basis. This is first-class GDPR Article 15 (right of access) and Article 20 (right to data portability) support built directly into the product, so Reps do not need to file a formal request to see their data.

Manager-Initiated Erasure Handler

When a Rep exercises their GDPR Article 17 right to erasure via [email protected], Caolú engineering can invoke a service-role function (erase_user_performance_data) that:

  • Sets the anonymised_at marker on every assessment_events row for that user and strips identifying metadata keys
  • Anonymises the Rep's in-progress saved configurations (nulls out rep_name and cust_name, strips PII keys from config_data)
  • Scrubs the Rep's profile (full_name becomes "Former rep (erased)", phone number and SEAI installer number are nulled)
  • Preserves locked commercial values on won/lost deal rows for the 7-year Revenue retention — the Rep's name is scrubbed but the commercial figure remains

Server-Side Access Gate

The Manager Dashboard data is returned by a PostgreSQL function (get_manager_dashboard) that runs as SECURITY DEFINER and explicitly verifies, before returning any data, that the calling user is authenticated, has the manager or admin role, and belongs to the company whose dashboard is being requested. A rep-role user cannot receive any team data even if they attempt to call the function directly.

No Cross-Company Leakage

Row-Level Security policies, in addition to the function-level guard above, ensure that a manager of Company A cannot read any row belonging to Company B. This is enforced at the PostgreSQL engine level and has been verified via adversarial testing.

Summary: The Manager Dashboard is a team visibility tool, not a surveillance system. Every design choice — pseudonymisation by default, audit-logged reveals, 30-minute reveal windows, no scoring, no coaching notes, team-level alerts only, 90-day anonymisation, Rep self-service — pushes the feature toward privacy-by-design compliance with GDPR Article 25 and the Article 29 Working Party guidelines on employee monitoring.
6

Webhook Security

Enterprise subscribers can configure outbound webhooks to transmit assessment data to CRM systems. Webhook payloads are:

  • Signed: Optional HMAC-SHA256 signing using a subscriber-configured secret. The receiving system verifies the X-Caolu-Signature header to confirm payload authenticity.
  • Subscriber-controlled: Caolu transmits to the endpoint configured by the subscriber. The subscriber is responsible for ensuring the receiving system meets their security and GDPR requirements.
  • Non-blocking: Webhook failures do not affect platform operation. Failed deliveries are logged but not retried.
7

AI-Assisted Development & Tooling

Caolú engineers use AI coding assistants — currently Anthropic's Claude, including the Claude Code command-line tool — to help author, review, and debug the Caolú codebase. Because these tools are external processors, we apply strict data-minimisation controls to ensure no real subscriber or customer Personal Data is ever shared with them.

Scope of Use

  • AI assistants are used by Caolú engineering only, during development. They are not embedded into the Caolú product and do not process any subscriber or end-customer data at runtime.
  • Permitted inputs are limited to source code, SQL migration files, configuration, technical documentation, commit history, and error traces.
  • Prohibited inputs include: real customer names, addresses, eircodes, MPRNs, phone numbers, email addresses, GDPR consent records, saved quotations, exported CSV data, webhook payloads, or screenshots containing real customer identifiers.

Data Minimisation Controls

  • Synthetic data only. All development and testing sessions use anonymised or fabricated records. Production rows are never copied into a prompt.
  • No direct production access. AI tools are not granted read access to the live production Supabase database. Where the Supabase Model Context Protocol (MCP) integration is used, it is scoped to schema inspection, non-sensitive tables, and read-only operations against development or sanitised snapshots where possible.
  • Redact-before-share. Engineers must redact or substitute any potentially identifying value in a bug report, log extract, or file dump before pasting it into an AI prompt.
  • Separation of duties. AI tools authenticate against our development environment only. Production deployment still requires a human-reviewed git push to the main branch, so no AI-generated code reaches production without human sign-off.

Article 28 Compliance Posture

GDPR Article 28 requires a written Data Processing Agreement (DPA) with any processor of Personal Data on our behalf. We satisfy this on two fronts, depending on the Anthropic plan in use at the time of development:

  • Where Caolú engineering operates under Anthropic's Commercial Terms of Service (Claude Team, Claude Enterprise, or the Claude API), Anthropic's DPA with Standard Contractual Clauses is automatically incorporated — so a processor contract is in place for any data that might be transmitted.
  • Where Caolú engineering operates under Anthropic's Consumer Terms of Service (Claude Free, Pro, Max, and Claude Code accessed via those plans), no Anthropic DPA is in force — so we treat the tool as out-of-scope for Personal Data processing entirely, and the "synthetic data only" rule above is enforced as a bright line.

A full written policy covering these controls is maintained internally as the Claude Workflow Data Minimisation Policy. Subscribers with audit rights under our DPA may request to review this policy by contacting [email protected].

8

Incident Response

Breach Notification

  • Internal detection → immediate escalation to Caolu security lead
  • Subscriber notification: within 24 hours of confirmed breach
  • Data Protection Commission (DPC) notification: within 72 hours as required by GDPR Article 33
  • Data Subject notification: without undue delay where required by GDPR Article 34

Breach Notification Includes

  • Nature and scope of the breach
  • Categories and approximate number of records affected
  • Likely consequences
  • Measures taken or proposed to mitigate
9

Availability

Caolu targets 99.5% monthly uptime for the application at app.caolu.ie, excluding:

  • Scheduled maintenance (communicated 48 hours in advance)
  • Force majeure events
  • Third-party service outages (Supabase, Stripe, Google Maps, ESB Networks)

Current infrastructure status is available at our hosting provider's status page. We are evaluating a dedicated status page for future deployment.

10

Compliance Roadmap

Standard Status
GDPR Compliant. DPA available. DPO contactable at [email protected]
Data Protection Act 2018 (Ireland) Compliant
Consumer Rights Act 2022 Reflected in default T&Cs template (14-day cooling-off period)
SOC 2 Type II Under evaluation for 2027
ISO 27001 Under evaluation for 2027
11

Responsible Disclosure

If you discover a security vulnerability in the Caolu platform, please report it responsibly to [email protected]. We commit to:

  • Acknowledging receipt within 2 working days
  • Investigating and providing an initial assessment within 7 working days
  • Not pursuing legal action against good-faith security researchers
  • Crediting researchers (with consent) after remediation
12

Contact

Data Protection Officer:
Caolu Consultants · CRO No. 783041 · Republic of Ireland
[email protected] · Company details

Caolu Consultants — Security

CRO No. 783041 · Republic of Ireland · Company details