FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [View Raw Code]   [Original HTTPS Page]

AndroidUsePdd/step4-data-model.md at main · hackathonprojs/AndroidUsePdd · GitHub

Latest commit

 

History

History
83 lines (68 loc) · 13.6 KB

File metadata and controls

83 lines (68 loc) · 13.6 KB

Step 4: Data Model Design

Status: Data Model Complete

The PRD does not authorize an Android-side memory database. The authoritative durable model below is the contract the separately implemented application backend should enforce behind Mem0. In this Android repository, only the device-scoped enablement preference is persisted; retrieved text, candidates, run state, and provider prompts remain in memory for the current operation only.

Core Entities

Entity Fields Primary Key Notes
AuthenticatedPrincipal id: UUID required; subject_hash: string required; created_at: datetime required; disabled_at: datetime? optional Surrogate UUID; natural alternate key subject_hash unique Backend-only pseudonymous identity derived from the authenticated application session. Android cannot select or override it. Store a one-way/opaque subject binding rather than account details.
AssistantAgent id: string required; display_name: string required; created_at: datetime required Natural key id; recommended value android_assistant Stable product identity shared across installs/devices; not a secret and not a randomly persisted device ID.
DurableMemory id: UUID required; principal_id: UUID required; agent_id: string required; text: string required; schema_version: string required; source: string required (android_assistant); task_outcome_type: string? optional; locale: string? optional; app_package: string? optional; created_at: datetime required; updated_at: datetime required; deleted_at: datetime? optional; provider_memory_id: string? optional Surrogate UUID; provider_memory_id is an optional unique external key within the backend tenancy Authoritative durable record/index entry. text is an approved/inferred durable fact or concise outcome, never a raw transcript or observed screen text. Metadata is columnar/allowlisted rather than an arbitrary JSON map. Soft-delete is recommended until remote deletion is confirmed.
MemoryWrite id: UUID required; principal_id: UUID required; agent_id: string required; run_id: UUID required; idempotency_key: string required; status: string required; memory_id: UUID? optional; provider_write_id: string? optional; failure_code: string? optional; created_at: datetime required; updated_at: datetime required; confirmed_at: datetime? optional Surrogate UUID; natural alternate key (principal_id, agent_id, run_id, idempotency_key) unique Backend idempotency/async-confirmation ledger required by R13-R14. It stores no candidate text or backend response body. Recommended statuses are an implementation extension: PENDING, CONFIRMED, FAILED.
MemoryEnablementSetting enabled: boolean required, default false; updated_at_epoch_ms: long? optional Single Preferences DataStore key memory_enabled The only Android-persisted entity. Device-scoped, off by default; disabling stops future task search/add calls but does not delete remote memories. No user ID, token, memory content, backend response, or Mem0 credential is stored with it.
Mem0ProviderReference durable_memory_id: UUID required; provider_memory_id: string required; provider_revision: string? optional; last_synced_at: datetime? optional durable_memory_id; provider_memory_id unique within backend tenancy Optional backend adapter record if the implementation needs provider mapping separate from DurableMemory. It contains identifiers only; Mem0 credentials remain in server secret storage, outside this model.

Not persistent by design:

  • MemoryScope(userId, agentId, runId) is an operation value. userId comes from the authenticated identity provider, agentId is stable, and a fresh UUID runId is generated per task or management operation.
  • MemoryCandidate, RetrievedMemory, and MemoryContext are bounded transient domain values. They must not be written to Android storage.
  • Retrieval cache and completion guards live only for the active service/run. Backend MemoryWrite provides durable cross-retry idempotency.
  • Screenshots, bitmaps, accessibility node trees, visible/focused text, notifications, clipboard content, gesture coordinates/traces, conversationHistory, raw model reasoning, prompts, credentials, headers, and raw response bodies have no table, collection, blob, file, log, or preference representation.

Relationships

From To Cardinality Foreign Key Cascade
AuthenticatedPrincipal DurableMemory 1:N DurableMemory.principal_id -> AuthenticatedPrincipal.id Restrict hard deletion; delete-all should soft-delete only rows bound to the authenticated principal, then reconcile provider deletion. Never cascade across principals.
AssistantAgent DurableMemory 1:N DurableMemory.agent_id -> AssistantAgent.id Restrict agent deletion/update while memories exist; stable natural key should not change.
AuthenticatedPrincipal MemoryWrite 1:N MemoryWrite.principal_id -> AuthenticatedPrincipal.id Restrict principal hard deletion until writes are finalized; privacy erasure deletes/anonymizes ledger rows after provider reconciliation.
AssistantAgent MemoryWrite 1:N MemoryWrite.agent_id -> AssistantAgent.id Restrict deletion/update while write records exist.
DurableMemory MemoryWrite 1:N over time; each write references 0..1 memory MemoryWrite.memory_id -> DurableMemory.id, nullable while pending/failed Set null only if a finalized ledger must outlive a purged memory; otherwise delete ledger under the same authenticated erasure transaction.
DurableMemory Mem0ProviderReference 1:0..1 Mem0ProviderReference.durable_memory_id -> DurableMemory.id Cascade provider-reference deletion when the authoritative memory row is purged; remote provider deletion must be confirmed first or recorded for retry.

There is no N:M relationship and therefore no join table. Tenant ownership is always AuthenticatedPrincipal -> DurableMemory/MemoryWrite; agent_id is a namespace/filter, never an authorization substitute. run_id is correlation/idempotency, not ownership. Queries, unique constraints, updates, list operations, and deletes must include the session-derived principal_id; foreign identifiers returned by a provider are rejected rather than displayed or injected.

Storage Decision

  • Primary store: Backend-managed PostgreSQL — recommended for authoritative user isolation, unique idempotency constraints, transactional write confirmation, soft deletion, and auditable scoped list/delete operations. The backend may use Mem0 for inference/vector retrieval, but Mem0 is behind the backend contract and is not the Android security boundary.
  • Vector/semantic store: Mem0-managed backend storage/index — used only server-side for semantic add/search. PostgreSQL retains authoritative tenancy, idempotency, lifecycle, and opaque provider mappings if Mem0 cannot enforce all application invariants directly.
  • Android local store: Preferences DataStore — one off-by-default memory_enabled boolean. This follows the researched Android/Compose coroutine conventions. No Room/SQLite database is justified because offline memory, local memory browsing, and local durable text retention are explicitly not required and would expand privacy risk.
  • Cache layer: Process-memory immutable MemoryContext, keyed by runId, for the active run only; maximum five results, score at least 0.70, maximum 2,000 UTF-8 bytes, descending score, deduplicated by ID then normalized text. Clear it on every terminal path/service destruction. Redis is unnecessary on Android; a backend may add a short-lived cache only if it preserves tenant keys and deletion consistency.
  • File storage: None. No JSON files, blobs, screenshots, transcripts, or response dumps.

Schema/ORM Recommendation

  • Android schema access: Preferences DataStore with typed wrapper/domain mapping. Use Kotlin serialization only for network DTOs; it is not a persistence ORM. Do not add Room or another ORM for this feature.
  • Backend ORM/query builder: The backend stack is outside this repository and remains unspecified, so do not select a language-specific ORM prematurely. For the recommended PostgreSQL design, use the backend project's established typed ORM/query builder and express tenant-scoped composite indexes, foreign keys, check constraints, soft-delete filters, and the unique idempotency constraint in database migrations. If no backend stack exists yet, choose it first and then use its conventional migration-backed ORM rather than letting Mem0 DTOs become the application schema.
  • Migration tool: Use the migration system native to the chosen backend stack (for example, Prisma Migrate for TypeScript/Prisma or Alembic for Python/SQLAlchemy). Migrations must be reviewed SQL artifacts and must create the composite ownership/index constraints before traffic is enabled. DataStore needs no relational migration for the initial boolean key; future preference changes use DataStore version/default handling.
  • Schema organization: Backend: one schema model per cohesive entity plus explicit migration definitions and separate Mem0 adapter DTOs. Android: grouped pure domain values, separate transport DTOs, and a narrow settings-store schema. Domain models must not import Ktor, JSON, Compose, Android accessibility/graphics, or provider SDK types.
  • Note: Exact file paths are determined in Step 5 (Module Design), not here.

Enums (Verbatim from PRD)

Enum Name Values (ALL from PRD) Source
MemoryResult<T> variants Success<T>, Disabled, Unavailable, Rejected PRD <pdd-interface>
Successful terminal action done PRD vocabulary / R10-R11
Compose memory-management presentation states loading, disabled, empty, unavailable PRD verification

The PRD also requires an error presentation state, but does not declare it as part of a named enum; retain error verbatim when defining the UI state algebra. Likewise, transport cases offline, timed out, rate-limited, unauthorized, and malformed are required failure categories, not declared enum values. No values are renamed or collapsed.

R14 exposes a deliberate contract gap: asynchronous acceptance cannot be represented by the four declared MemoryResult<T> variants. Recommendation: extend the result algebra with Pending(writeId: String) while retaining all four declared variants exactly. Backend MemoryWrite.status should use PENDING, CONFIRMED, and FAILED; these are recommended persistence states, not substitutions for PRD enum values.

Shared Types

  • MemoryScope(userId: String, agentId: String, runId: String): shared by identity/scope construction, coordinator, gateway, management operations, and tests. It is transient; backend authorization always derives the principal from the authenticated session.
  • MemoryCandidate(userText: String, outcome: String?, explicitRequest: Boolean, metadata: Map<String, String>): shared by orchestration, policy, coordinator, gateway, and tests. Only metadata keys schema_version, source, task_outcome_type, locale, and app_package survive validation.
  • RetrievedMemory(id: String, text: String, score: Double, metadata: Map<String, String>): shared by gateway, retrieval policy, settings presentation, model-context rendering, and tests.
  • MemoryContext(memories: List<RetrievedMemory>): shared by coordinator, provider-neutral agent request, all three model adapters, and tests; immutable and run-bounded.
  • MemoryResult<T>: shared exhaustive operation result across gateway, coordinator, settings state holder, observability mapping, and tests; add Pending to reconcile R14.
  • MemoryGateway and MemoryCoordinator: shared domain ports consumed by orchestration, transport/no-op implementations, management state, and test fakes.
  • MemoryMetadata: recommended typed shared value replacing free-form maps after boundary parsing; exact keys are the five allowlisted names above, with source = android_assistant.
  • AuthenticatedIdentity / backend-session authentication abstraction: shared by scope creation, gateway composition, and management; it exposes pseudonymous identity/session material without logging or persistence.
  • MemoryPolicyConfig: shared immutable limits for count, score, byte budget, timeouts, retries, metadata schema version, and enabled default.

Module-Local Types

  • Search/add/list/delete transport request and response DTOs, pagination cursors, redacted error DTO, and DTO mappers: internal to backend transport.
  • MemoryWrite transport status DTO and polling response: internal to transport/coordinator; the persisted backend ledger is not exposed as an Android domain entity.
  • Retrieval normalization/deduplication keys, byte-budget accumulator, candidate rejection reasons, and forbidden-source markers: internal to deterministic policy implementation.
  • Per-run cache entry, begin-once/completion guard, mutex/state-machine representation, and cleanup token: internal to coordinator orchestration and never persisted.
  • DataStore preference keys and serialized preference representation: internal to the settings store.
  • Compose state algebra and confirmation-dialog state: internal to the memory-management UI; it must include Disabled, Loading, Empty, Content, Unavailable, and Error.
  • Ktor timeout/retry configuration DTOs and authentication-header injection details: internal to transport/composition.
  • Redacted metric event implementation and elapsed-time buckets: internal to observability; the public reporter accepts allowlisted scalars only.

Proceeding to Step 5: Design


Back | FazBrowse Home | New Git URL