Files
SRCmail/runs/2026-08-07-v1.7.8-baseline/DEVELOPMENT-PLAN.md
T
Bernd Rodler f34537adcf release: v1.7.9 — Phase 1 critical+high fixes (17/18)
Housekeeping:
- Bump VERSION to 1.7.9
- CHANGELOG entry for all Phase 1 fixes
- Mark Phase 1 as completed in development plan
2026-08-07 12:41:34 +02:00

515 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VNCmail+ v1.7.8 → v1.8.0 Development Plan
**Date:** 2026-08-07
**Target:** `brvncde-dotcom/vncmail-plus` (Next.js 16)
**Baseline:** VNCmailgraph audit (82 findings) + Bugs VNCmail+.docx (12 missing features)
---
## Phase Structure
| Phase | Focus | Features + Fixes | Autonomy |
|-------|-------|-----------------|----------|
| **P1** | Critical fixes | 8 CRITICAL + 10 HIGH audit findings | Full autonomous |
| **P2** | Missing features | 12 docx features, code reuse from Angular | Full autonomous (board decided VNCtalk/Collabora/ActionWheel) |
| **P3** | Security hardening | Auth, cookies, rate limiting, encryption | Full autonomous |
| **P4** | Polish & sync | Remaining HIGH + cross-feature substrate | Full autonomous |
---
## Phase 1 — Critical Bug Fixes (Autonomous)
### P1.1 — Error Swallowing (CRITICAL C1)
**Issue:** `getEmails`/`searchEmails` return empty on transport failure. Network-down = empty folder.
**Fix:** Sample `transportHealth().transportFailureCount()` before/after JMAP reads. If incremented, throw `TransportError` instead of returning `{ emails: [], ... }`. Store catches and shows connectivity banner.
- Files: `lib/jmap/client.ts`, `stores/email-store.ts`, `lib/jmap/transport-health.ts`
- Reuse: None
- Effort: 2h
### P1.2 — FTS5 Schema-Drop Rebuild (CRITICAL C6)
**Issue:** Schema version bump drops all tables without auto-rebuild.
**Fix:** After `DROP TABLE IF EXISTS`, trigger automatic `catchUpAll()` in the same operation. Add user-facing "Rebuilding search index..." indicator.
- Files: `lib/mail-index/store.ts`, `lib/mail-index/reindex.ts`
- Reuse: None
- Effort: 2h
### P1.3 — Auth Credentials in localStorage (CRITICAL C5)
**Issue:** `auth-storage` + `account-storage` contain server URLs and usernames in plaintext.
**Fix:** Encrypt the Zustand persist payload for these two stores using a key derived from session secret or a per-device key. Scope: `auth-store.ts` and `account-store.ts` persist middleware.
- Files: `stores/auth-store.ts`, `stores/account-store.ts`, new `lib/auth/local-storage-crypto.ts`
- Reuse: AES-256-GCM pattern from `lib/auth/crypto.ts`
- Effort: 4h
### P1.4 — Settings Lock Bypass (CRITICAL C7)
**Issue:** `updateSetting()` has no policy check. Admin locks bypassable via store.
**Fix:** Gate `updateSetting(key, value)` with `isSettingLocked(key)`. Add `{ force: true }` opt-in for legitimate bypassers (auth bootstrap, settings sync). Audit all `updateSetting` call sites.
- Files: `stores/settings-store.ts`, `stores/auth-store.ts`, `lib/settings-sync.ts`
- Reuse: None
- Effort: 3h
### P1.5 — Offline Push Detection (CRITICAL C8)
**Issue:** No `offline` event listener. Transports retry blindly, draining battery.
**Fix:** Add `window.addEventListener('offline', ...)` that pauses all push transports. Add `navigator.onLine` gate on each transport cycle. Wire `transportHealth().likelyOffline` into push lifecycle.
- Files: `lib/jmap/client.ts`
- Reuse: None
- Effort: 1h
### P1.6 — Admin Session Revocation (CRITICAL C4)
**Issue:** AES-256-GCM token has no server-side revocation.
**Fix:** Add in-memory token blacklist (Set with TTL) in admin session middleware. Logout adds token `jti` to blacklist. Cleanup expired entries on verification.
- Files: `lib/admin/session.ts`, `app/api/admin/auth/route.ts`
- Reuse: None
- Effort: 3h
### P1.7 — Calendar ID Collision (CRITICAL C2)
**Issue:** Recurrence expansion (`:` delimiter) collides with shared event prefix.
**Fix:** Change expansion delimiter from `:` to `::occurrence::`. Update `stripLocalAccountPrefix` and all ID parsing.
- Files: `lib/recurrence-expansion.ts`, `stores/calendar-store.ts`
- Reuse: None
- Effort: 1h
### P1.8 — Calendar Cross-Account Dedup (CRITICAL C3)
**Issue:** Multi-account event aggregation has no UID dedup.
**Fix:** After `Promise.all(...).flat()`, run `uniqueBy(events, e => e.uid + e.recurrenceId)` pass.
- Files: `stores/calendar-store.ts`
- Reuse: None
- Effort: 1h
### P1.9 — HIGH Fixes Batch
- **H4:** Strip `access_token` from OAuth error logs (`lib/oauth/token-exchange.ts`) — 30min
- **H9:** Fix bcrypt in `isHashed()` (`lib/admin/password.ts`) — 1h
- **H18:** Default `autoSelectReplyIdentity` to `true` (`stores/settings-store.ts`) — 30min
- **H7:** DOMPurify HTML template body on import (`lib/template-utils.ts`) — 1h
- **H13:** `calendarTasksEnabled` runtime enforcement (`stores/task-store.ts`, `components/calendar/`) — 2h
- **H14:** try/catch + toast on task mutations (`stores/task-store.ts`) — 1h
- **H8:** Derive `secure` cookie from `x-forwarded-proto` (`lib/admin/session.ts`) — 1h
- **H3:** Rate-limit user auth endpoints (`app/api/auth/*`) — 3h
- **H2:** Await state snapshot in `reconcileAfterWebSocketFallback` (`lib/jmap/client.ts`) — 2h
- **H1:** Push handler: add ContactCard/FileNode branches (`stores/email-store.ts`) — 3h
**P1 Total:** ~32h
---
## Phase 2 — Missing Features (Autonomous, Code Reuse)
### P2.1 — Extended Signatures (Multiple per Identity + HTML Editor)
**Docx:** "Add option to create various email signatures and to select standard signature for new emails and for replies"
**Reuse from Angular:**
- Models: `signature.model.ts` (Signature interface), `identity.model.ts` (zimbraPrefDefaultSignatureId)
- API: Signature CRUD endpoints, `modifySignaturePrefs()` pattern
- UI logic: Quill editor toolbar config → `react-quill-new` equivalent
**Implementation:**
1. New `stores/signature-store.ts` — Signature[] with CRUD + identity assignment
2. New `components/settings/signature-settings.tsx` — list management page
3. New `components/settings/signature-editor-modal.tsx` — Quill-based HTML editor
4. Extend `components/identity/identity-form.tsx` — default/forward-reply signature picker
5. Extend `components/email/email-composer.tsx` — signature selector dropdown in compose
6. JMAP/Sieve integration: if the server stores signatures as Sieve or Identity properties, map accordingly
**Effort:** 12h
### P2.2 — Create Appointment from Email
**Docx:** "create a calendar entry from an email with recipients as participants and email text in description"
**Reuse from Angular:**
- `Appointment` interface from `appoinment.model.ts`
- Calendar compose pre-fill logic from `calendar-compose.component.ts`
- API payload shapes for event creation
**Implementation:**
1. New `components/email/create-appointment-button.tsx` — button in email toolbar
2. Extend `components/calendar/event-modal.tsx` — accept pre-fill props (title=subject, description=body, participants=from+to+cc)
3. Wire "Create Appointment" action into email-viewer toolbar + context menu
**Effort:** 6h
### P2.3 — Folder Sharing (Mail, Calendar, Contacts, Files)
**Docx:** "Share Folder feature" + "Sharing to see all folders shared by me and with me"
**Reuse from Angular:**
- `ShareFolderComponent` (564 lines) — full sharing dialog with email autocomplete, role selection
- `PreferencesSharingComponent` (556 lines) — "shared by me" / "shared with me" views
- `AllSharingFoldersDialogComponent` — tree-based folder browser
- API: share/revoke/accept/decline endpoints and payload shapes
**Implementation:**
1. New `components/sharing/share-folder-dialog.tsx` — modal with email autocomplete, role picker (read/read-write/admin), message
2. New `components/sharing/share-folder-revoke-dialog.tsx` — revoke confirmation
3. New `components/sharing/accept-share-dialog.tsx` — accept incoming share
4. New `components/settings/sharing-settings.tsx` — "Shared by me" / "Shared with me" tabs with folder tree
5. Extend folder context menus in email sidebar, calendar sidebar, contacts sidebar, files sidebar with "Share Folder..." action
6. New `stores/sharing-store.ts` — tracking shares state
7. API routes: `app/api/sharing/*` — share/revoke/accept/decline/find
**Effort:** 18h
### P2.4 — Calendar Dashlet (Mini Calendar in Mail View)
**Docx:** "Show Calendar in a dashlet in the bottom left corner"
**Reuse from Angular:**
- `sidebar-mini-calendar.component.ts` (701 lines) — month grid, swipe navigation, tooltip
- Tooltip directive logic for fetching day events
**Implementation:**
1. New `components/calendar/mini-calendar-dashlet.tsx` — compact month grid widget
2. Integrate into mail sidebar or bottom-left overlay in the mail page layout
3. Show date dots for days with events, today highlight, click to navigate to calendar
4. Optionally: toggleable via user setting "Show calendar dashlet"
**Effort:** 8h
### P2.5 — Email Import (.eml, tgz, zip)
**Docx:** "Missing: feature to import emails"
**Reuse from Angular:**
- `ImportExportComponent` (513 lines) — import types, destination folder, resolve settings
- `preferenceService.importFromFile()` — API request shape
- CSV type auto-detection logic
**Implementation:**
1. Extend existing `.eml` import (already partial — see `lib/eml-import.ts` and `components/email/` for `.eml` preview)
2. Add ZIP/TGZ/TAR archive import — extract, iterate, import each `.eml`
3. New `components/settings/import-settings.tsx` — import UI with file picker, destination folder, conflict resolution
4. API route: extend `app/api/account/*` or new `app/api/import/*`
**Effort:** 10h
### P2.6 — Contact Import (vCard/CSV)
**Docx:** "Missing: feature to import contacts"
**Reuse from Angular:**
- `contact-file-import-dialog.component.ts` (228 lines) — CSV upload, folder selector
- `contactService.importContacts()` — API endpoint
- vCard parsing: `lib/vcard.ts` already exists in codebase
**Implementation:**
1. Extend existing `components/contacts/contact-import-dialog.tsx` to support CSV (currently vCard-only)
2. Add CSV column mapping UI (map CSV columns to contact fields)
3. Folder selection for import destination
4. Dedup handling
**Effort:** 6h
### P2.7 — Free/Busy View
**Docx:** "Missing: free/busy view"
**Reuse from Angular:**
- `scheduler.component.ts` (1303 lines) — full free/busy grid
- `scheduler-utils.ts` — free-busy status constants (`fba` values, `FBA_TO_PTST` mapping)
- `schedule-assistant.component.ts` (1081 lines) — suggestion engine algorithm
- Free/busy URL format: `{serverURL}/home/{email}?fmt=freebusy`
**Implementation:**
1. New `components/calendar/free-busy-view.tsx` — attendee-row × time-slot grid
2. Color-coded slots: free (white), busy (red), tentative (yellow), out-of-office (purple)
3. Integration into event-modal when adding participants — show availability inline
4. Also queries `resources_bookings` table (see P2.8) to show resource availability in the same grid
5. New `lib/calendar-freebusy.ts` — fetch and parse free/busy data (user calendars + resource bookings)
**Effort:** 16h (was 14h, added resource booking integration)
### P2.8 — Resources/Equipment Booking (VNCdirectory-backed PostgreSQL)
**Docx:** "Missing: resources/equipment"
**Architecture decision:** Resources managed in **separate PostgreSQL table**, mapped to **VNCdirectory** for centralized cross-application management (rooms, cars, equipment, etc.). Independent from mail client — this is a platform-level resource system.
**Reuse from Angular:**
- `calendar-equipment-dialog.component.ts` (373 lines) — equipment browser UI patterns
- `calendar-equipment-autocomplete.component.ts` (266 lines) — autocomplete UX
- GAL query: `zimbraCalResType === "Equipment"` → adapt to VNCdirectory resource type filter
**Backend (New):**
1. **PostgreSQL migration**`resources` table:
- `id` UUID PK
- `tenant_id` UUID (VNCdirectory tenant scope)
- `name` text
- `type` enum (room, vehicle, equipment, other)
- `location` text (building/floor/room)
- `capacity` integer nullable
- `description` text
- `contact_email` text (responsible person)
- `is_active` boolean
- `metadata` jsonb (extensible: photo URL, amenities, access hours, etc.)
- `created_at`, `updated_at` timestamps
2. **`resources` table → VNCdirectory sync** — VNCdirectory is the canonical source. Options:
- **Pull model:** VNCdirectory writes to this table via API/webhook
- **Push model:** This service syncs changes back to VNCdirectory
- **Read-through:** Query VNCdirectory directly for resource listings; cache in PostgreSQL for availability booking
- Decision needed: which direction is authoritative? (Assume VNCdirectory → this table for Phase 1)
3. **New API routes:** `app/api/resources/`
- `GET /api/resources` — list/search resources (type filter, location filter, tenant scoped)
- `GET /api/resources/[id]` — single resource detail
- `GET /api/resources/[id]/availability?start=&end=` — free/busy for a resource
- `POST /api/resources/[id]/book` — create booking for a resource
- `DELETE /api/resources/[id]/book/[bookingId]` — cancel booking
4. **New `lib/resources/` service layer:**
- `lib/resources/client.ts` — fetch/query resources from VNCdirectory or local DB
- `lib/resources/availability.ts` — check resource availability for time range
- `lib/resources/booking.ts` — book/cancel resource
- `lib/resources/sync.ts` — sync with VNCdirectory (if push-model needed)
5. **Conflict checking:**
- When booking, check `resources_bookings` table for overlapping time ranges
- Return conflicts + alternative slots
**Frontend:**
1. Extend `components/calendar/event-modal.tsx` — "Resources" tab with:
- Resource type filter (room, vehicle, equipment)
- Searchable autocomplete (name, location, capacity)
- Availability indicator (free/busy for event time range)
2. New `components/calendar/resource-picker.tsx` — reusable resource selection component
3. Booked resources appear in event detail, participant list, and email invitation
**Effort:** 20h (was 10h, doubled for PostgreSQL + VNCdirectory integration)
### P2.9 — VNCtalk Video Meeting Integration
**Docx:** "Missing: integration with VNCtalk -> create Videomeeting"
**Reuse from Angular:**
- `app.service.ts``createNewMeeting()` / `updateScheduledMeeting()` API calls
- Payload: `POST /api/createnewmeeting { name, start, end, invitees, password, description, invid?, rev?, ms? }`
- `createOrUpdateMeeting()` in `edit-appointment-dialog.component.ts` — builds payload from appointment
**Implementation:**
1. New `lib/vnctalk/client.ts` — VNCtalk API client (create/update meeting)
2. Extend `components/calendar/event-modal.tsx` — "Create VNCtalk Meeting" toggle/button
3. Store meeting JID on CalendarEvent for updates
4. Add meeting link to event detail popover and email invitation body
**Effort:** 8h
### P2.10 — Collabora Online Editing
**Docx:** "Add feature to collaborate with Collabora"
**Reuse from Angular:**
- `owncloud.service.ts``getDocumentUrl(fileId, useCollabora)` with RichDocuments API
- `POST ocs/v2.php/apps/richdocuments/api/v1/document?format=json`
- Config: `collaboraBaseUrl` from admin config
**Implementation:**
1. New `lib/collabora/client.ts` — fetch editing URL from Collabora server
2. New `components/files/collabora-editor.tsx` — iframe-based editor embedding
3. Extend `components/files/file-browser.tsx` — "Edit with Collabora" action for office files
4. Admin config: `collaboraBaseUrl` in policy/config
**Effort:** 10h
### P2.11 — Calendar Enhancements Batch
**Docx:** Multiple calendar improvements
**2.11a — Clickable links in emails**
- Already partially done (TipTap Link extension). Verify link rendering in calendar event descriptions.
- Effort: 2h
**2.11b — Contact details of participants**
- Add popover on participant names in event-modal showing contact card. Reuse `components/contacts/contact-detail.tsx` data.
- Effort: 4h
**2.11c — Reply / Reply to All in meetings**
- Extend event-modal with "Reply" and "Reply to All" buttons that open composer pre-filled with participant emails.
- Effort: 3h
**2.11d — Timezone support**
- Add timezone picker to event-modal. Use `date-fns-tz` (already a dependency). Display times in event timezone with user timezone conversion.
- Effort: 6h
**2.11e — Map links**
- Extract address from event location, generate Google Maps / OpenStreetMap link.
- Effort: 2h
### P2.12 — Action Wheel (Custom Radial Menu)
**Docx:** "Recreate Action Wheel or better functionality"
**Board decision:** Build custom radial menu.
**Implementation:**
1. New `components/ui/radial-menu.tsx` — SVG-based radial menu with configurable items
2. Supports: mail actions (reply, forward, delete, archive, mark read, move, tag), contact actions, file actions
3. Trigger: long-press on mobile, right-click on desktop, or dedicated button
4. Animations: CSS rotate + scale transitions
5. Keyboard accessible
**Effort:** 10h
### P2.13 — IDP Integration — VNCdirectory Admin Configuration Panel
**Docx:** "IDP integration will be towards VNCdirectory (openldap, simplesamlphp, 2fa etc.)"
**Architecture decision:** Add admin UI for configuring VNCdirectory connection settings. Reuse auth patterns from VNCmail-analysis `api/auth-proxy/`.
**Reuse from Angular (api/auth-proxy/):**
- `config/config.js.example` — full auth configuration schema (SAML, LDAP, VNCdirectory, 2FA, hybrid auth)
- `config/passport.js` — SAML strategy + JWT custom strategy setup
- `routes/index.js` — login/logout/SAML callback/LDAP search/2FA/TOTP routes
- `utils/common.js` — JWT verification, Zimbra preauth token creation
- Auth dependencies: `@node-saml/passport-saml`, `passport`, `jsonwebtoken`, `ldapjs`
**Current VNCmail+ auth stack vs Angular auth stack:**
| Feature | Angular (Zimbra) | VNCmail+ (Stalwart) |
|---------|-----------------|---------------------|
| Primary auth | SAML 2.0 via Passport | OAuth/OIDC via Stalwart |
| Identity source | Zimbra LDAP + VNCdirectory | Stalwart internal + OIDC |
| 2FA | VNCdirectory TOTP/DUO | TOTP via Stalwart admin API |
| Directory integration | Redmine API (`contactsApiUrl`) | ❌ None |
| LDAP backend | `ldapjs` → Zimbra LDAP | ❌ None |
| SSO/Federation | JWT deeplinks + SAML | Cookie-based + OAuth |
**Implementation:**
1. **New `lib/vncdirectory/` service layer:**
- `lib/vncdirectory/client.ts` — API client for VNCdirectory REST endpoints (port auth patterns from `routes/index.js`)
- `lib/vncdirectory/config.ts` — VNCdirectory connection settings (URL, API key, LDAP bind, SAML IDP metadata)
- `lib/vncdirectory/auth.ts` — SAML 2.0 SP implementation using `@node-saml/passport-saml` via Next.js API routes
- `lib/vncdirectory/ldap.ts` — LDAP client using `ldapjs` for user/group/GAL queries
- `lib/vncdirectory/2fa.ts` — TOTP enrollment + verification via VNCdirectory
2. **New API routes:** `app/api/vncdirectory/`
- `GET /api/vncdirectory/status` — connection health check
- `POST /api/vncdirectory/saml/login` — initiate SAML login flow
- `POST /api/vncdirectory/saml/callback` — SAML assertion consumer
- `POST /api/vncdirectory/saml/logout` — SAML single logout
- `GET /api/vncdirectory/users` — search users (LDAP + VNCdirectory)
- `POST /api/vncdirectory/2fa/enroll` — generate TOTP secret
- `POST /api/vncdirectory/2fa/verify` — verify TOTP code
- `GET /api/vncdirectory/2fa/status` — check 2FA enrollment status
- `GET /api/vncdirectory/tags` — directory contact tags
- `POST /api/vncdirectory/tags` — create/update directory tags
3. **New admin configuration page:**
- `app/(main)/admin/vncdirectory/page.tsx` — VNCdirectory settings panel
- Sections:
- **Connection:** VNCdirectory URL, API key, LDAP URI, bind credentials
- **SAML/IDP:** Identity Provider URL (SimpleSAMLphp), SP certificate, issuer
- **Authentication:** Toggle SAML login, toggle 2FA enforcement, OIDC settings
- **Directory sync:** LDAP type (OpenLDAP/MS-AD), search base, attribute mapping
- **Federated apps:** Configure SSO URLs for VNCtalk, VNCtask, VNCcontacts
- Add to admin navigation sidebar
4. **New `stores/vncdirectory-store.ts`** — client-side config state
5. **Extend existing auth:**
- Add SAML login as alternative to existing Basic/OAuth flows
- Add VNCdirectory as identity source alongside Stalwart
- Wire 2FA through VNCdirectory (currently uses Stalwart admin API)
**Effort:** 24h
### P2.14 — Share Files by Email as Attachment
**Docx:** "share by email as attachment"
**Implementation:**
1. Extend `components/files/file-browser.tsx` — "Send as Email Attachment" action
2. Opens composer with selected files attached (reuse existing attachment upload in composer)
3. Effort: 4h
**P2 Total:** ~127h
---
## Phase 3 — Security Hardening (Autonomous)
### P3.1 — Feature Gate Server-Side Enforcement
**Issue:** Feature gates are UI-only. Disabled features remain accessible via direct API calls.
**Fix:** Add policy checks to API routes. For each feature-gated route, add `isFeatureEnabled()` check returning 403.
- Routes: `app/api/smime/*`, `app/api/calendar-agenda/*`, `app/api/offline/*`, `app/api/plugins/*` (plugin disabled)
- Effort: 4h
### P3.2 — Unified Auth Error Interceptor
**Issue:** 401/403 errors silently swallowed in data fetches.
**Fix:** Create `lib/auth-error-handler.ts` — global fetch wrapper that detects 401 and triggers re-auth flow. Wire into JMAP client `authenticatedFetch`.
- Effort: 6h
### P3.3 — Store-Level State Isolation on Account Switch
**Issue:** Manual `clearAllStores()` misses new fields and stores.
**Fix:** Define per-store `snapshot(): Partial<S>` and `clear(): Partial<S>` contract. Auto-discover registered stores via a registry.
- Effort: 8h
### P3.4 — Push Event Bus Extraction
**Issue:** Email store is the push dispatch hub for 5+ stores.
**Fix:** Extract `lib/push-event-bus.ts` — stores subscribe to JMAP type names. Email store stops importing calendar/filter/task stores.
- Effort: 8h
**P3 Total:** ~26h
---
## Phase 4 — Polish & Remaining HIGH Items
### P4.1 — Offline Write Queue
**Issue:** No offline write capability. Cannot compose/send while offline.
**Fix:** Add `replica_pending_ops` table. Stage mutations offline, replay on connectivity return. Start with email send only, then extend.
- Effort: 16h
### P4.2 — Identity Spoofing Protection
**Issue:** From override accepts arbitrary addresses.
**Fix:** Client-side validation — restrict `fromOverrideEmail` to domains matching user's identities.
- Effort: 2h
### P4.3 — WebSocket Push for Electron
**Issue:** Browser WebSocket push permanently disabled.
**Fix:** Implement main-process WebSocket bridge in Electron via IPC. Renderer sends token, main process connects WS with auth header.
- Effort: 8h
### P4.4 — Remaining MEDIUM audit findings
- Calendar: recurrence cap warning, prefix scheme unification, read-only calendar filter, bulk delete batching
- Contacts: cross-account move race, autocomplete indexing, import dedup
- Files: folder tree cache reuse, upload parallelism
- Search: `toWildcardQuery` quote handling, `searchEmails` AbortController
- Effort: ~20h
**P4 Total:** ~46h
---
## Summary
| Phase | Hours | Description |
|-------|-------|-------------|
| P1 | 32h | Critical + HIGH bug fixes (18 items) |
| P2 | 167h | Missing features from docx (14 features) |
| P3 | 26h | Security hardening (4 items) |
| P4 | 46h | Polish + remaining fixes (4 items) |
| **Total** | **~271h** | |
### New Infrastructure Dependencies (P2)
- **PostgreSQL database** — `resources` + `resources_bookings` tables for VNCdirectory-backed resource management
- **VNCdirectory** — canonical source for resources + IDP identity provider (SAML 2.0, LDAP, 2FA/TOTP, directory tags)
- **SimpleSAMLphp** — SAML 2.0 Identity Provider (`vncidp.dev.vnc.de`) for web SSO
- **OpenLDAP** — LDAP directory for user/group queries and GAL (via `ldapjs`)
- **Collabora server** — `collaboraBaseUrl` admin config for online document editing
- **VNCtalk API** — `/api/createnewmeeting` endpoint for video meeting integration
### Autonomy Level
- **100% autonomous** — No further board decisions needed.
- **Sync direction (VNCdirectory ↔ PostgreSQL)**: Assumed VNCdirectory → PostgreSQL (pull) for Phase 1. Can be swapped if VNCdirectory expects push updates.
- **Code reuse:** 12 areas from VNCmail-analysis Angular codebase (models, API patterns, business logic). Must be adapted from Angular DI/services to plain TS functions + React hooks.
- **Repository access:** `brvncde-dotcom/vncmail-plus` (target), `brvncde-dotcom/VNCmail-analysis` (reuse).
### Deploy Flow
Per policy: P1 → deploy to `dev` → QA → fix → promote to `main`. Then P2 → dev → QA → main. Repeat for P3, P4.
### Phase 1 — COMPLETED 2026-08-07
**Shipped as v1.7.9.** 17 of 18 fixes deployed to `main`. All 2527 tests pass (161 test files). One item deferred: P1.3 (C5 auth localStorage encryption) — requires custom Zustand persist adapter, planned for Phase 3.
---
Do you want me to start Phase 1 immediately, or adjust the plan?