738 lines
18 KiB
Markdown
738 lines
18 KiB
Markdown
# NuQloud Scrum Implementation Plan
|
|
|
|
Plan date: 2026-07-03
|
|
|
|
## 1. Direction
|
|
|
|
NuQloud Scrum is a Talk-first scrum layer for NuQloud deployments.
|
|
|
|
Canonical model:
|
|
|
|
| Nextcloud surface | NuQloud Scrum meaning |
|
|
|---|---|
|
|
| Talk conversation | Scrum workspace |
|
|
| Talk thread / reply chain | Task |
|
|
| Talk messages in thread | Task discussion/activity |
|
|
| Files shared in conversation | Workspace files |
|
|
| Files shared in thread/reply chain | Task files |
|
|
| Deck board | Workspace board mirror |
|
|
| Deck card | Task mirror |
|
|
| NuQloud Scrum DB | Mapping, index, sync state, audit |
|
|
|
|
Product rule for v1:
|
|
|
|
1. Talk is the primary UX, especially on mobile.
|
|
2. Threads/reply chains are tasks.
|
|
3. Files and Deck are mirrors.
|
|
4. NuQloud Scrum stores indexes and sync state only.
|
|
5. No custom mobile client is required.
|
|
|
|
## 2. App Boundary
|
|
|
|
Create a new app:
|
|
|
|
```text
|
|
nextcloud/custom_apps/nuqloud_scrum/
|
|
```
|
|
|
|
Do not merge this into:
|
|
|
|
1. `qortal_integration` - account, broker, OIDC, publishing controls.
|
|
2. `qortal_files_bridge` - QDN/files bridge.
|
|
3. `qortal_talk_bridge` - temporary Talk/Q-Chat bridge.
|
|
4. `chd_admin` - internal CHD/admin-only work.
|
|
|
|
Suggested app metadata:
|
|
|
|
```text
|
|
id: nuqloud_scrum
|
|
name: NuQloud Scrum
|
|
namespace: NuqloudScrum
|
|
category: integration
|
|
dependencies:
|
|
nextcloud min-version: 32
|
|
nextcloud max-version: 34 initially
|
|
optional apps: spreed, deck
|
|
```
|
|
|
|
Use Powered Mode language by default. Avoid crypto-native labels in this app UI.
|
|
|
|
## 3. Compatibility Baseline
|
|
|
|
Verified documentation assumptions on 2026-07-03:
|
|
|
|
1. Talk chat API base endpoint is `/ocs/v2.php/apps/spreed/api/v1`.
|
|
2. Talk chat fetch supports `lastKnownMessageId`, pagination headers, parent message data, and reaction fields.
|
|
3. Talk send-message supports `replyTo` for replies.
|
|
4. Talk file share uses Files Sharing OCS with `shareType=10` for conversation shares.
|
|
5. Talk shared item listings support `lastKnownMessageId` pagination when the relevant capability exists.
|
|
6. Deck REST API is authenticated and exposes boards, stacks, cards, assignments, labels, comments, and attachments.
|
|
7. Nextcloud app schema changes belong in `lib/Migration`.
|
|
8. Background jobs belong in the app bootstrap/job registration path.
|
|
|
|
Implementation rule:
|
|
|
|
```text
|
|
Native Talk thread metadata available?
|
|
Use Talk thread identifiers directly.
|
|
|
|
Only parent/reply chain available?
|
|
Treat root message ID + parent relationship as task identity.
|
|
|
|
No stable thread creation API available?
|
|
Bot posts an anchor task message and users reply to that message.
|
|
```
|
|
|
|
## 4. Target App Structure
|
|
|
|
```text
|
|
nextcloud/custom_apps/nuqloud_scrum/
|
|
appinfo/
|
|
info.xml
|
|
routes.php
|
|
|
|
lib/
|
|
AppInfo/
|
|
Application.php
|
|
|
|
BackgroundJob/
|
|
SyncConversationsJob.php
|
|
SyncConversationMessagesJob.php
|
|
SyncDeckJob.php
|
|
SyncFilesJob.php
|
|
SummarizeWorkspacesJob.php
|
|
|
|
Controller/
|
|
PageController.php
|
|
SettingsController.php
|
|
WorkspaceController.php
|
|
TaskController.php
|
|
|
|
Db/
|
|
Workspace.php
|
|
WorkspaceMapper.php
|
|
ThreadTask.php
|
|
ThreadTaskMapper.php
|
|
ThreadMessage.php
|
|
ThreadMessageMapper.php
|
|
MirroredFile.php
|
|
MirroredFileMapper.php
|
|
DeckSync.php
|
|
DeckSyncMapper.php
|
|
SyncCursor.php
|
|
SyncCursorMapper.php
|
|
|
|
Migration/
|
|
Version000001DateYYYYMMDDHHMMSS.php
|
|
|
|
Service/
|
|
ConfigService.php
|
|
TalkApiClient.php
|
|
TalkCapabilityService.php
|
|
WorkspaceService.php
|
|
ThreadTaskService.php
|
|
FolderMirrorService.php
|
|
FileIndexService.php
|
|
DeckApiClient.php
|
|
DeckMirrorService.php
|
|
ReactionWorkflowService.php
|
|
BotCommandService.php
|
|
SummaryService.php
|
|
SlugService.php
|
|
AuditService.php
|
|
|
|
templates/
|
|
index.php
|
|
admin.php
|
|
|
|
js/
|
|
index.js
|
|
admin.js
|
|
|
|
css/
|
|
style.css
|
|
admin.css
|
|
|
|
img/
|
|
app.svg
|
|
|
|
l10n/
|
|
.gitkeep
|
|
```
|
|
|
|
Keep the first UI thin:
|
|
|
|
1. Admin settings: enable/disable, service user config, sync intervals, workspace filters.
|
|
2. User page: workspace index, task links, sync state, Deck links, folder links.
|
|
3. No replacement scrum board in v1.
|
|
|
|
## 5. Data Model
|
|
|
|
### `nuqloud_scrum_workspaces`
|
|
|
|
```text
|
|
id bigint primary key
|
|
talk_token varchar(128) not null unique
|
|
talk_room_name varchar(255) not null
|
|
talk_room_type varchar(64) null
|
|
deck_board_id bigint null
|
|
root_folder_path varchar(1024) not null
|
|
sync_enabled smallint default 1
|
|
last_message_id bigint default 0
|
|
last_share_message_id bigint default 0
|
|
created_by varchar(128) null
|
|
created_at bigint not null
|
|
updated_at bigint not null
|
|
```
|
|
|
|
Indexes:
|
|
|
|
```text
|
|
uniq talk_token
|
|
idx sync_enabled
|
|
idx updated_at
|
|
```
|
|
|
|
### `nuqloud_scrum_threads`
|
|
|
|
```text
|
|
id bigint primary key
|
|
workspace_id bigint not null
|
|
talk_thread_id varchar(128) null
|
|
talk_root_message_id bigint not null
|
|
title varchar(255) not null
|
|
slug varchar(255) not null
|
|
folder_path varchar(1024) not null
|
|
deck_card_id bigint null
|
|
deck_stack_id bigint null
|
|
status varchar(32) default 'inbox'
|
|
priority varchar(32) default 'normal'
|
|
created_by varchar(128) null
|
|
assigned_to varchar(128) null
|
|
due_at bigint null
|
|
last_activity_message_id bigint default 0
|
|
created_at bigint not null
|
|
updated_at bigint not null
|
|
```
|
|
|
|
Indexes:
|
|
|
|
```text
|
|
uniq workspace_id + talk_root_message_id
|
|
uniq workspace_id + talk_thread_id when available
|
|
idx workspace_id + status
|
|
idx deck_card_id
|
|
```
|
|
|
|
### `nuqloud_scrum_thread_messages`
|
|
|
|
```text
|
|
id bigint primary key
|
|
thread_id bigint not null
|
|
talk_message_id bigint not null
|
|
actor_type varchar(64) not null
|
|
actor_id varchar(128) not null
|
|
actor_display_name varchar(255) null
|
|
message_text clob null
|
|
message_hash varchar(128) not null
|
|
raw_payload clob null
|
|
created_at bigint not null
|
|
updated_at bigint not null
|
|
```
|
|
|
|
Indexes:
|
|
|
|
```text
|
|
uniq thread_id + talk_message_id
|
|
idx actor_id
|
|
idx created_at
|
|
```
|
|
|
|
### `nuqloud_scrum_files`
|
|
|
|
```text
|
|
id bigint primary key
|
|
workspace_id bigint not null
|
|
thread_id bigint null
|
|
talk_message_id bigint null
|
|
nc_file_id bigint null
|
|
original_path varchar(1024) not null
|
|
workspace_path varchar(1024) not null
|
|
checksum varchar(128) null
|
|
size bigint default 0
|
|
mime_type varchar(255) null
|
|
mirror_state varchar(32) default 'pending'
|
|
sync_error clob null
|
|
created_at bigint not null
|
|
updated_at bigint not null
|
|
```
|
|
|
|
Indexes:
|
|
|
|
```text
|
|
idx workspace_id + thread_id
|
|
idx nc_file_id
|
|
idx mirror_state
|
|
```
|
|
|
|
### `nuqloud_scrum_deck_sync`
|
|
|
|
```text
|
|
id bigint primary key
|
|
workspace_id bigint not null
|
|
thread_id bigint null
|
|
deck_board_id bigint null
|
|
deck_stack_id bigint null
|
|
deck_card_id bigint null
|
|
last_sync_at bigint null
|
|
sync_state varchar(32) default 'pending'
|
|
sync_error clob null
|
|
created_at bigint not null
|
|
updated_at bigint not null
|
|
```
|
|
|
|
### `nuqloud_scrum_sync_cursors`
|
|
|
|
```text
|
|
id bigint primary key
|
|
cursor_type varchar(64) not null
|
|
scope_key varchar(255) not null
|
|
cursor_value varchar(255) not null
|
|
locked_until bigint null
|
|
updated_at bigint not null
|
|
```
|
|
|
|
Indexes:
|
|
|
|
```text
|
|
uniq cursor_type + scope_key
|
|
idx locked_until
|
|
```
|
|
|
|
## 6. Folder Layout
|
|
|
|
Root folder:
|
|
|
|
```text
|
|
/NuQloud Scrum/
|
|
```
|
|
|
|
Workspace folder:
|
|
|
|
```text
|
|
/NuQloud Scrum/{workspace-name}/
|
|
_workspace.md
|
|
_manifest.json
|
|
_open-tasks.md
|
|
_decisions.md
|
|
Files/
|
|
Threads/
|
|
Summaries/
|
|
```
|
|
|
|
Task folder:
|
|
|
|
```text
|
|
/NuQloud Scrum/{workspace-name}/Threads/
|
|
{root-message-id}-{slug}/
|
|
_task.md
|
|
_activity.jsonl
|
|
_summary.md
|
|
Files/
|
|
Decisions/
|
|
```
|
|
|
|
Rules:
|
|
|
|
1. Prefix folders with immutable IDs.
|
|
2. Slugs are display-only and may be regenerated.
|
|
3. DB identity always wins over path names.
|
|
4. Folder moves are detected and healed through `file_id` where possible.
|
|
5. Generated markdown must escape raw user text.
|
|
|
|
## 7. Sync Flow
|
|
|
|
### Conversation discovery
|
|
|
|
`SyncConversationsJob`:
|
|
|
|
1. Fetch configured Talk conversations visible to the automation/service user.
|
|
2. Apply workspace filters:
|
|
- all conversations
|
|
- named allowlist
|
|
- group/member filter
|
|
3. `ensureWorkspace(token)`.
|
|
4. Create root folder and manifest.
|
|
5. Ensure Deck board when Deck is enabled.
|
|
|
|
### Message sync
|
|
|
|
`SyncConversationMessagesJob`:
|
|
|
|
1. For each enabled workspace, fetch Talk messages after `last_message_id`.
|
|
2. Store raw payload only server-side.
|
|
3. Detect task root:
|
|
- native `threadId` root when available
|
|
- parent/reply root message ID fallback
|
|
- bot anchor message fallback
|
|
4. `ensureThreadTask`.
|
|
5. Append message record if it belongs to a task.
|
|
6. Apply reactions.
|
|
7. Queue Deck and file sync.
|
|
8. Advance cursor only after successful persistence.
|
|
|
|
### File sync
|
|
|
|
`SyncFilesJob`:
|
|
|
|
1. Fetch shared items from Talk where capability allows it.
|
|
2. Resolve target:
|
|
- thread/task folder when message has thread/root context
|
|
- workspace `Files/YYYY-MM/` otherwise
|
|
3. Copy or link according to admin setting:
|
|
- v1 default: copy into NuQloud Scrum folder
|
|
- future option: retain original and write folder link only
|
|
4. Record file ID, checksum, size, MIME type.
|
|
5. Avoid duplicate copies by `nc_file_id + target_path`.
|
|
|
|
### Deck sync
|
|
|
|
`SyncDeckJob`:
|
|
|
|
1. Ensure one Deck board per workspace.
|
|
2. Ensure default stacks:
|
|
- Inbox
|
|
- Ready
|
|
- In Progress
|
|
- Blocked
|
|
- Review
|
|
- Done
|
|
- Archived
|
|
3. Ensure one Deck card per thread task.
|
|
4. Mirror status to stack.
|
|
5. Update card description with:
|
|
- Talk room link
|
|
- thread/task folder link
|
|
- latest summary
|
|
- source IDs
|
|
6. Avoid syncing every Talk reply as a Deck comment in v1 unless explicitly enabled.
|
|
|
|
## 8. Reaction Workflow
|
|
|
|
Default mappings:
|
|
|
|
| Reaction | Status/action |
|
|
|---|---|
|
|
| check mark | Done |
|
|
| construction | Blocked |
|
|
| eyes | Review |
|
|
| fire | Priority |
|
|
| pushpin | Decision |
|
|
| folder | File/context marker |
|
|
|
|
Implementation notes:
|
|
|
|
1. Store reaction-derived status changes in DB.
|
|
2. Prefer latest trusted actor reaction if conflicts exist.
|
|
3. Allow admins to disable reaction mappings.
|
|
4. Do not rely on client-only state.
|
|
5. Reaction values must be normalized before matching.
|
|
|
|
## 9. Bot Commands
|
|
|
|
Use bot-style messages, not legacy slash commands.
|
|
|
|
Supported v1 commands:
|
|
|
|
```text
|
|
@NuQloud status blocked
|
|
@NuQloud status done
|
|
@NuQloud assign @username
|
|
@NuQloud due 2026-07-10
|
|
@NuQloud summarize
|
|
@NuQloud help
|
|
```
|
|
|
|
Rules:
|
|
|
|
1. Commands only work in authenticated Talk conversations.
|
|
2. Only room participants can affect that workspace.
|
|
3. Admin-configured moderators can override any task.
|
|
4. User input is parsed with strict allowlists.
|
|
5. Bot responses must not expose raw payloads, secrets, or stack traces.
|
|
|
|
## 10. Security Requirements
|
|
|
|
Public endpoints:
|
|
|
|
1. None in v1.
|
|
|
|
Authenticated endpoints:
|
|
|
|
1. Workspace/task index pages.
|
|
2. Per-user workspace/task JSON APIs.
|
|
|
|
Admin endpoints:
|
|
|
|
1. App enable/disable.
|
|
2. Service user/app-password settings.
|
|
3. Workspace sync filters.
|
|
4. Reaction/Deck/file mirroring settings.
|
|
5. Manual resync/repair actions.
|
|
|
|
Required controls:
|
|
|
|
1. Use Nextcloud controller auth for all routes.
|
|
2. Use CSRF checks for state-changing browser routes.
|
|
3. Validate all IDs, paths, statuses, dates, and command arguments.
|
|
4. Escape user message text in generated markdown and UI.
|
|
5. Never log app passwords, raw auth headers, invite tokens, or raw message bodies.
|
|
6. Store service credentials in app config with admin-only access.
|
|
7. Enforce participant/admin checks server-side.
|
|
8. Treat Deck and folder mirrors as derived state, not authority.
|
|
|
|
## 11. Admin Settings
|
|
|
|
Initial settings:
|
|
|
|
```text
|
|
nuqloud_scrum_enabled: 0|1
|
|
talk_service_user: string
|
|
talk_service_app_password: secret
|
|
workspace_filter_mode: all|allowlist|disabled
|
|
workspace_allowlist: JSON array of Talk tokens/names
|
|
deck_sync_enabled: 0|1
|
|
file_mirror_enabled: 0|1
|
|
file_mirror_mode: copy|link
|
|
reaction_workflow_enabled: 0|1
|
|
bot_commands_enabled: 0|1
|
|
summary_enabled: 0|1
|
|
sync_interval_minutes: integer
|
|
```
|
|
|
|
Admin UI should use theme variables, l10n strings, and existing Nextcloud settings patterns.
|
|
|
|
## 12. Implementation Phases
|
|
|
|
### Phase 0 - API validation spike
|
|
|
|
Goal: prove target Talk/Deck behavior on devcloud before committing to event semantics.
|
|
|
|
Tasks:
|
|
|
|
1. Confirm Talk capabilities for target Nextcloud/Talk version.
|
|
2. Confirm whether native thread identifiers appear in fetched message payloads.
|
|
3. Confirm reply-chain fallback using `parent` and `replyTo`.
|
|
4. Confirm reaction payload shape.
|
|
5. Confirm file share metadata includes usable thread/root context.
|
|
6. Confirm Deck card create/update/comment/attachment endpoints.
|
|
7. Decide service account pattern for background jobs.
|
|
|
|
Deliverable:
|
|
|
|
```text
|
|
docs/engineering/nuqloud-scrum-api-validation.md
|
|
```
|
|
|
|
### Phase 1 - app skeleton and settings
|
|
|
|
Tasks:
|
|
|
|
1. Add `nuqloud_scrum` app scaffold.
|
|
2. Add `info.xml`, bootstrap, routes, admin settings page.
|
|
3. Add config service.
|
|
4. Add app icon and minimal themed CSS.
|
|
5. Add l10n-ready strings.
|
|
6. Register background jobs disabled until config is valid.
|
|
|
|
Acceptance:
|
|
|
|
1. App installs/enables.
|
|
2. Admin can save settings.
|
|
3. Missing Talk/Deck apps show clear admin warnings.
|
|
4. No public routes exist.
|
|
|
|
### Phase 2 - migrations and persistence
|
|
|
|
Tasks:
|
|
|
|
1. Add migration for workspace/thread/message/file/deck/cursor tables.
|
|
2. Add entities/mappers.
|
|
3. Add repository-level unit tests where practical.
|
|
4. Add idempotent upsert methods.
|
|
5. Add sync cursor locking.
|
|
|
|
Acceptance:
|
|
|
|
1. Install creates tables.
|
|
2. Upgrade path is repeatable.
|
|
3. Duplicate Talk messages do not create duplicate tasks.
|
|
|
|
### Phase 3 - Talk workspace discovery
|
|
|
|
Tasks:
|
|
|
|
1. Implement `TalkApiClient`.
|
|
2. Implement `TalkCapabilityService`.
|
|
3. Implement `WorkspaceService`.
|
|
4. Implement `SyncConversationsJob`.
|
|
5. Create `/NuQloud Scrum/{conversation}/` folders.
|
|
6. Write `_workspace.md` and `_manifest.json`.
|
|
|
|
Acceptance:
|
|
|
|
1. Allowed Talk conversations become workspaces.
|
|
2. Re-running sync is idempotent.
|
|
3. Folder names are sanitized.
|
|
4. Immutable Talk token remains the workspace key.
|
|
|
|
### Phase 4 - thread/task indexing
|
|
|
|
Tasks:
|
|
|
|
1. Implement `ThreadTaskService`.
|
|
2. Implement task root detection.
|
|
3. Implement title extraction:
|
|
- explicit thread title when available
|
|
- first sentence/message summary fallback
|
|
- safe length cap
|
|
4. Create task folders.
|
|
5. Write `_task.md` and `_activity.jsonl`.
|
|
6. Track `last_message_id` per workspace.
|
|
|
|
Acceptance:
|
|
|
|
1. Talk replies create/update task records.
|
|
2. Existing reply chains backfill correctly.
|
|
3. Generated files escape raw Talk content.
|
|
4. Task folders use `{root-message-id}-{slug}`.
|
|
|
|
### Phase 5 - file mirroring
|
|
|
|
Tasks:
|
|
|
|
1. Implement `FileIndexService`.
|
|
2. Implement `FolderMirrorService`.
|
|
3. Resolve root conversation files vs task files.
|
|
4. Copy files into workspace/task folders.
|
|
5. Deduplicate by source file ID/checksum.
|
|
6. Record mirror errors without exposing secrets.
|
|
|
|
Acceptance:
|
|
|
|
1. Conversation file shares appear under `Files/YYYY-MM/`.
|
|
2. Task file shares appear under task `Files/`.
|
|
3. Duplicate shares do not create uncontrolled copies.
|
|
4. Failed copies remain retryable.
|
|
|
|
### Phase 6 - Deck board/card mirror
|
|
|
|
Tasks:
|
|
|
|
1. Implement `DeckApiClient`.
|
|
2. Implement `DeckMirrorService`.
|
|
3. Create workspace board.
|
|
4. Create default stacks.
|
|
5. Create/update one card per task.
|
|
6. Sync status to stack.
|
|
7. Add card links back to Talk/folder.
|
|
|
|
Acceptance:
|
|
|
|
1. One board exists per workspace.
|
|
2. One card exists per task.
|
|
3. Moving Deck card updates local task status.
|
|
4. Talk remains canonical for task identity.
|
|
|
|
### Phase 7 - mobile status controls
|
|
|
|
Tasks:
|
|
|
|
1. Implement `ReactionWorkflowService`.
|
|
2. Implement admin-configurable mappings.
|
|
3. Implement conflict resolution.
|
|
4. Implement bot command parser.
|
|
5. Add concise bot replies.
|
|
|
|
Acceptance:
|
|
|
|
1. Mobile Talk reactions update task status.
|
|
2. Bot commands update status/assignee/due date.
|
|
3. Invalid commands fail safely.
|
|
4. Status changes are mirrored to Deck.
|
|
|
|
### Phase 8 - summaries
|
|
|
|
Tasks:
|
|
|
|
1. Implement `SummaryService`.
|
|
2. Generate `_summary.md` per task.
|
|
3. Generate daily summaries under `Summaries/`.
|
|
4. Generate `_open-tasks.md` and `_decisions.md`.
|
|
5. Keep AI extraction as optional suggestions only.
|
|
|
|
Acceptance:
|
|
|
|
1. Summaries are regenerated idempotently.
|
|
2. No raw secrets or private auth data are included.
|
|
3. Summaries link back to source task folders.
|
|
|
|
### Phase 9 - hardening and release
|
|
|
|
Tasks:
|
|
|
|
1. Add repair command/job for missing folders/cards.
|
|
2. Add admin sync status dashboard.
|
|
3. Add logging with redaction.
|
|
4. Add docs for admin setup and user workflow.
|
|
5. Add compatibility notes for Nextcloud 32-34 and Talk thread differences.
|
|
6. Add rollback notes.
|
|
|
|
Acceptance:
|
|
|
|
1. Failed syncs are visible and retryable.
|
|
2. App degrades gracefully without Deck.
|
|
3. App degrades gracefully without native Talk thread metadata.
|
|
4. Operators have devcloud verification commands.
|
|
|
|
## 13. Verification Commands
|
|
|
|
Do not run or simulate Docker/Nextcloud locally. Use devcloud.
|
|
|
|
```bash
|
|
docker compose -f docker-compose.devprod.yml --env-file .env.devprod ps
|
|
docker compose -f docker-compose.devprod.yml --env-file .env.devprod exec app php occ app:list
|
|
docker compose -f docker-compose.devprod.yml --env-file .env.devprod exec app php occ app:enable nuqloud_scrum
|
|
docker compose -f docker-compose.devprod.yml --env-file .env.devprod exec app php occ migrations:status nuqloud_scrum
|
|
docker compose -f docker-compose.devprod.yml --env-file .env.devprod exec app php occ background-job:list | grep -i nuqloud
|
|
docker compose -f docker-compose.devprod.yml --env-file .env.devprod logs --tail=200 app
|
|
```
|
|
|
|
If using the no-SSL devprod stack:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod ps
|
|
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod exec app php occ app:enable nuqloud_scrum
|
|
docker compose -f docker-compose.devprod.nossl.yml --env-file .env.devprod exec app php occ migrations:status nuqloud_scrum
|
|
```
|
|
|
|
## 14. Risks
|
|
|
|
1. Talk native thread payloads may differ by Talk version.
|
|
- Mitigation: implement reply-chain fallback and API validation spike.
|
|
2. Deck API authentication from background jobs needs a clear service-account pattern.
|
|
- Mitigation: configure a dedicated automation user/app password.
|
|
3. Mirroring files can duplicate storage.
|
|
- Mitigation: admin-selectable `copy|link`, dedupe, size limits.
|
|
4. Reaction status conflicts can be ambiguous.
|
|
- Mitigation: deterministic precedence and admin-configurable mappings.
|
|
5. App-to-app internals may change.
|
|
- Mitigation: isolate Talk/Deck clients behind service interfaces.
|
|
|
|
## 15. External References
|
|
|
|
1. Nextcloud Talk chat API: https://nextcloud-talk.readthedocs.io/en/latest/chat/
|
|
2. Nextcloud Deck REST API: https://deck.readthedocs.io/en/latest/API/
|
|
3. Nextcloud migrations: https://docs.nextcloud.com/server/stable/developer_manual/basics/storage/migrations.html
|
|
4. Nextcloud developer manual: https://docs.nextcloud.com/server/stable/developer_manual/
|