driving_consent

Automotive-grade privacy consent model with Jidoka semantics — UNKNOWN equals DENIED.

When to use this package

Use driving_consent when a data pipeline must stop itself unless the driver has explicitly granted the exact sharing purpose.

Features

  • Jidoka gate: ConsentStatus.unknown is treated as denied. The pipeline stops itself.
  • Per-purpose consent: fleet location, weather telemetry, diagnostics — each independently controlled.
  • Multi-jurisdiction: GDPR, CCPA, APPI — design for GDPR, deploy everywhere.
  • Pluggable storage: abstract ConsentService interface. Bring your own persistent backend.
  • Pure Dart: no Flutter dependency. Works in CLI tools, servers, and Flutter apps.

Install

dependencies:
  driving_consent: ^0.1.1

Quick Start

import 'package:driving_consent/driving_consent.dart';

final service = InMemoryConsentService();

// Jidoka gate — check before any data leaves the device
final consent = await service.getConsent(ConsentPurpose.fleetLocation);
if (!consent.isEffectivelyGranted) {
  // UNKNOWN or DENIED — pipeline stops. No data sent.
  return;
}

// Driver explicitly grants consent
await service.grant(ConsentPurpose.fleetLocation, Jurisdiction.appi);

// Driver revokes — pipeline stops again
await service.revoke(ConsentPurpose.fleetLocation);

Integration Pattern

The package is designed to sit at the entrance to any data-sharing feature. Typical app wiring: query consent before enabling telemetry, render the current state, and only activate the upstream provider after the driver grants the exact purpose.

import 'package:driving_consent/driving_consent.dart';
import 'package:flutter/material.dart';

class FleetConsentGate extends StatefulWidget {
  const FleetConsentGate({super.key});

  @override
  State<FleetConsentGate> createState() => _FleetConsentGateState();
}

class _FleetConsentGateState extends State<FleetConsentGate> {
  final service = InMemoryConsentService();
  late Future<ConsentRecord> consentFuture;

  @override
  void initState() {
    super.initState();
    consentFuture = service.getConsent(ConsentPurpose.fleetLocation);
  }

  Future<void> _grant() async {
    await service.grant(ConsentPurpose.fleetLocation, Jurisdiction.appi);
    setState(() {
      consentFuture = service.getConsent(ConsentPurpose.fleetLocation);
    });
  }

  @override
  void dispose() {
    service.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<ConsentRecord>(
      future: consentFuture,
      builder: (context, snapshot) {
        final consent = snapshot.data;
        if (consent == null) {
          return const Text('Checking consent...');
        }

        if (consent.isEffectivelyGranted) {
          return const Text('Fleet telemetry enabled');
        }

        return Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Text('Fleet telemetry is blocked: ${consent.status.name}'),
            const SizedBox(height: 8),
            ElevatedButton(
              onPressed: _grant,
              child: const Text('Grant consent'),
            ),
          ],
        );
      },
    );
  }
}

This is the Jidoka posture in UI form: unknown and denied both stop the line until the human makes an explicit choice.

Implement a persistent service

class MyPersistentConsentService implements ConsentService {
  @override
  Future<ConsentRecord> getConsent(ConsentPurpose purpose) async {
    // Read from your database
  }

  @override
  Future<List<ConsentRecord>> getAllConsents() async {
    // Read all purposes from your database
  }

  @override
  Future<ConsentRecord> grant(
    ConsentPurpose purpose,
    Jurisdiction jurisdiction,
  ) async {
    // Write granted record + audit trail
  }

  @override
  Future<ConsentRecord> revoke(ConsentPurpose purpose) async {
    // Write denied record + audit trail
  }

  @override
  Future<void> dispose() async {
    // Close database
  }
}

API Overview

Type Purpose
ConsentRecord Stores consent status, purpose, jurisdiction, and audit timestamp.
ConsentService Abstract interface for reading, granting, revoking, and listing consent state.
InMemoryConsentService Ready-to-run in-memory implementation for tests, demos, and offline flows.
ConsentPurpose Enumerates independently controlled data-sharing purposes.
ConsentStatus Three-state consent gate where unknown is treated as denied.
Jurisdiction Captures the policy context for the recorded consent decision.

See Also

  • kalman_dr — Dead reckoning through GPS loss (tunnels, urban canyons)
  • routing_engine — Engine-agnostic routing (OSRM, Valhalla, local/public)
  • driving_weather — Weather condition model for driving (snow, ice, visibility)
  • fleet_hazard — Fleet telemetry hazard model and geographic clustering
  • driving_conditions — Pure Dart computation models for road surface, visibility, and safety score simulation
  • navigation_safety — Flutter navigation safety state machine and safety overlay
  • map_viewport_bloc — Flutter viewport and layer composition state machine
  • routing_bloc — Flutter route lifecycle state machine and progress UI
  • offline_tiles — Flutter offline tile manager with MBTiles fallback

Part of SNGNav

driving_consent is one of the 10 packages in SNGNav, an offline-first, driver-assisting navigation reference product for embedded Linux.

License

BSD-3-Clause — see LICENSE.

Libraries

Automotive-grade privacy consent with Jidoka semantics.