mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
feat(lasts): M1-M7 — module ship + Meilensteine-Aggregator
Mirror sibling to firsts: das *letzte* Mal, das du etwas getan hast — markiert oder rückwirkend erkannt. Plan: docs/plans/lasts-module.md. M1 Skelett — Dexie v51 lasts-Tabelle, Encryption-Registry, Per-Space- Welcome-Seed, Empty-State ListView. Kategorien aus firsts/types.ts nach \$lib/data/milestones/categories.ts extrahiert (Re-Exports halten firsts-API stabil). M2 CRUD + DetailView — StatusTabs (Vermutet/Bestätigt/Aufgehoben), Quick-Add mit Mode-Toggle, always-editable DetailView mit Lifecycle- Buttons (Bestätigen, Aufheben mit Inline-Note), 44 i18n-Keys × 5 Locales. M3 Inbox + Inferenz — Dexie v52 lastsCooldown (12-Monate-Cooldown, deterministische ID), Source-Registry-Pattern in inference/, places- Source mit Heuristik visitCount>=5 Span>=180d Silence>=365d. InboxView mit Akzeptieren/Verwerfen + manueller Scan. contacts/habits → M3.b sobald jeweilige Frequenz-Felder existieren. M4 AI-Tools — 5 Tools im AI_TOOL_CATALOG (create_last, confirm_last, reclaim_last, list_lasts, suggest_lasts), Webapp-Executor mit Vault- Locked-Handling. Server-Drift-Test 4/4, Schema-Test 6/6. M5 Reminders + Settings — Pivot zu In-App-DueBanner statt OS-Push (kein PWA-Push-System im Repo). Pure date-math (12 Vitest cases), Settings- Store mit 4 Toggles, DueBanner mit max-N rendering, Test-Banner-Knopf. M6 Visibility + Unlisted-Sharing — VisibilityPicker + SharedLinkControls in DetailView, buildLastBlob mit reflective-core whitelist (reclaimed Lasts gehärtet ausgeblockt), SharedLastView public-render, Share- Dispatcher kennt 'lasts'. M7 Meilensteine-Aggregator — Cross-modul firsts vereinigt mit lasts Timeline + Year-Recap. Pure aggregator (mergeMilestones, buildMilestonesRecap), 12 Vitest cases. /milestones und /milestones/recap/[year] Routes, Cross-Link in lasts/ListView. Validation: 0 errors / 0 warnings (svelte-check 7645 files), 24/24 tests, i18n-parity 39x5 aligned (+2 namespaces), i18n-keys baseline- equal, crypto 211 tables. LOCAL TIER PATCH: lasts ist 'guest' für Testing — vor Release auf 'beta' setzen (packages/shared-branding/src/mana-apps.ts). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ad5e04a554
commit
bf3bca268a
53 changed files with 6572 additions and 40 deletions
|
|
@ -2299,6 +2299,186 @@ export const AI_TOOL_CATALOG: readonly ToolSchema[] = [
|
|||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ── Lasts (mirror sibling to firsts) ────────────────────────
|
||||
{
|
||||
name: 'create_last',
|
||||
module: 'lasts',
|
||||
description:
|
||||
'Erstellt einen neuen "Last" — ein letztes Mal, das markiert oder vermutet werden soll. Status standardmaessig "suspected"; "confirmed" nur setzen wenn der User sicher ist.',
|
||||
defaultPolicy: 'propose',
|
||||
parameters: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'string',
|
||||
description: 'Was zum letzten Mal passiert ist (z.B. "Letzter Tag im alten Job")',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'category',
|
||||
type: 'string',
|
||||
description: 'Kategorie',
|
||||
required: false,
|
||||
enum: [
|
||||
'culinary',
|
||||
'adventure',
|
||||
'travel',
|
||||
'people',
|
||||
'career',
|
||||
'creative',
|
||||
'nature',
|
||||
'culture',
|
||||
'health',
|
||||
'tech',
|
||||
'other',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
type: 'string',
|
||||
description: 'Lifecycle-Status',
|
||||
required: false,
|
||||
enum: ['suspected', 'confirmed'],
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
type: 'string',
|
||||
description: 'Datum des letzten Mals (YYYY-MM-DD), falls bekannt',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'confidence',
|
||||
type: 'string',
|
||||
description: 'Sicherheit, dass es das letzte Mal war',
|
||||
required: false,
|
||||
enum: ['probably', 'likely', 'certain'],
|
||||
},
|
||||
{
|
||||
name: 'meaning',
|
||||
type: 'string',
|
||||
description: 'Was es bedeutet hat (optional)',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'note',
|
||||
type: 'string',
|
||||
description: 'Freie Notiz (optional)',
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'confirm_last',
|
||||
module: 'lasts',
|
||||
description:
|
||||
'Bewegt einen Last von "suspected" auf "confirmed" und ergaenzt Reflexionsfelder. Setzt Datum auf heute, falls keines uebergeben wird.',
|
||||
defaultPolicy: 'propose',
|
||||
parameters: [
|
||||
{ name: 'lastId', type: 'string', description: 'ID des Lasts', required: true },
|
||||
{
|
||||
name: 'date',
|
||||
type: 'string',
|
||||
description: 'Datum des letzten Mals (YYYY-MM-DD)',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'meaning',
|
||||
type: 'string',
|
||||
description: 'Was es bedeutet hat',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'whatIKnewThen',
|
||||
type: 'string',
|
||||
description: 'Was du damals nicht wusstest',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'whatIKnowNow',
|
||||
type: 'string',
|
||||
description: 'Was du heute siehst',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'tenderness',
|
||||
type: 'number',
|
||||
description: 'Wie sehr es dich heute beruehrt (1-5)',
|
||||
required: false,
|
||||
},
|
||||
{
|
||||
name: 'wouldReclaim',
|
||||
type: 'string',
|
||||
description: 'Wuerdest du es zurueckholen?',
|
||||
required: false,
|
||||
enum: ['no', 'maybe', 'yes'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'reclaim_last',
|
||||
module: 'lasts',
|
||||
description:
|
||||
'Markiert einen Last als "aufgehoben" — es ist wieder passiert. Optionaler Notiz-Text beschreibt, was zurueckgekommen ist.',
|
||||
defaultPolicy: 'propose',
|
||||
parameters: [
|
||||
{ name: 'lastId', type: 'string', description: 'ID des Lasts', required: true },
|
||||
{
|
||||
name: 'reclaimedNote',
|
||||
type: 'string',
|
||||
description: 'Was ist wieder passiert (optional)',
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'list_lasts',
|
||||
module: 'lasts',
|
||||
description:
|
||||
'Listet Lasts (id, title, status, category, date). Optional nach Status oder Kategorie filterbar.',
|
||||
defaultPolicy: 'auto',
|
||||
parameters: [
|
||||
{
|
||||
name: 'status',
|
||||
type: 'string',
|
||||
description: 'Nur einen Status zeigen',
|
||||
required: false,
|
||||
enum: ['suspected', 'confirmed', 'reclaimed'],
|
||||
},
|
||||
{
|
||||
name: 'category',
|
||||
type: 'string',
|
||||
description: 'Nur eine Kategorie zeigen',
|
||||
required: false,
|
||||
enum: [
|
||||
'culinary',
|
||||
'adventure',
|
||||
'travel',
|
||||
'people',
|
||||
'career',
|
||||
'creative',
|
||||
'nature',
|
||||
'culture',
|
||||
'health',
|
||||
'tech',
|
||||
'other',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
description: 'Maximale Anzahl (Standard 30)',
|
||||
required: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'suggest_lasts',
|
||||
module: 'lasts',
|
||||
description:
|
||||
'Laesst die Inferenz-Engine ueber places/habits/contacts scannen und generiert "suspected"-Lasts mit inferredFrom-Provenance fuer Eintraege, die Frequenz-Drops zeigen. Dedupliziert gegen existierende Lasts und die Cooldown-Liste. Schreibt direkt in die Inbox — kein Proposal-Workflow noetig, weil die Eintraege als suspected landen und der User sie dort akzeptieren oder verwerfen kann.',
|
||||
defaultPolicy: 'auto',
|
||||
parameters: [],
|
||||
},
|
||||
];
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
|
|
|
|||
|
|
@ -193,6 +193,12 @@ export const APP_ICONS = {
|
|||
// Warm amber→rose gradient to evoke excitement and novelty.
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><linearGradient id="fi" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#f59e0b"/><stop offset="100%" style="stop-color:#e11d48"/></linearGradient></defs><rect width="100" height="100" rx="22" fill="url(#fi)"/><path d="M50 18l5 14 14-5-10 11 10 11-14-5-5 14-5-14-14 5 10-11-10-11 14 5z" fill="white"/><circle cx="28" cy="70" r="4" fill="white" fill-opacity="0.6"/><circle cx="72" cy="68" r="3" fill="white" fill-opacity="0.5"/><circle cx="38" cy="80" r="2.5" fill="white" fill-opacity="0.4"/><circle cx="65" cy="82" r="2" fill="white" fill-opacity="0.35"/></svg>`
|
||||
),
|
||||
lasts: svgToDataUrl(
|
||||
// Hourglass with a single falling grain — the moment something
|
||||
// passes for the last time. Indigo→slate gradient for the
|
||||
// contemplative, retrospective tone (mirror to firsts' warm amber).
|
||||
`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><linearGradient id="la" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" style="stop-color:#6366f1"/><stop offset="100%" style="stop-color:#475569"/></linearGradient></defs><rect width="100" height="100" rx="22" fill="url(#la)"/><path d="M32 22h36" stroke="white" stroke-width="4" stroke-linecap="round"/><path d="M32 78h36" stroke="white" stroke-width="4" stroke-linecap="round"/><path d="M34 24c0 14 16 22 16 26s-16 12-16 26" stroke="white" stroke-width="3" fill="none" stroke-linecap="round"/><path d="M66 24c0 14-16 22-16 26s16 12 16 26" stroke="white" stroke-width="3" fill="none" stroke-linecap="round"/><path d="M40 30h20l-10 16z" fill="white" fill-opacity="0.85"/><path d="M40 70h20l-10-16z" fill="white" fill-opacity="0.35"/><circle cx="50" cy="55" r="2" fill="white"/></svg>`
|
||||
),
|
||||
drink: svgToDataUrl(
|
||||
// Water drop + glass — represents beverage tracking.
|
||||
// Blue→cyan gradient for the hydration theme.
|
||||
|
|
|
|||
|
|
@ -751,6 +751,23 @@ export const MANA_APPS: ManaApp[] = [
|
|||
status: 'development',
|
||||
requiredTier: 'guest',
|
||||
},
|
||||
{
|
||||
id: 'lasts',
|
||||
name: 'Lasts',
|
||||
description: {
|
||||
de: 'Letzte Male',
|
||||
en: 'Last Times',
|
||||
},
|
||||
longDescription: {
|
||||
de: 'Halte fest, was zum letzten Mal passiert ist — bewusst markiert oder rückwirkend erkannt. Spiegelbild zu Firsts: leise Reflexion statt Vorfreude.',
|
||||
en: 'Capture what happened for the last time — marked deliberately or recognised in hindsight. Mirror sibling to Firsts: quiet reflection instead of anticipation.',
|
||||
},
|
||||
icon: APP_ICONS.lasts,
|
||||
color: '#6366f1',
|
||||
comingSoon: false,
|
||||
status: 'development',
|
||||
requiredTier: 'guest', // LOCAL TIER PATCH — revert to 'beta' before release (see project_tier_patch_resolved memory)
|
||||
},
|
||||
{
|
||||
id: 'period',
|
||||
name: 'Periode',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue