task-d.7.6

This commit is contained in:
phaichayon
2026-07-03 09:51:36 +07:00
parent b7589017ab
commit 110c2f9e7f
10 changed files with 1376 additions and 392 deletions

View File

@@ -0,0 +1,71 @@
# Task D.7.6 Dashboard Setup Wizard UI
Date: 2026-07-03
Status: implemented
## Scope Delivered
Added dashboard-native setup wizard route:
- `GET /dashboard/administration/setup`
- Server-side page access restricted to `super_admin`
- Admin navigation item for `Setup Wizard`
Added setup UI orchestration:
- `src/features/setup/components/setup-wizard.tsx`
- `src/app/dashboard/administration/setup/page.tsx`
Extended setup API client surface:
- `src/features/setup/api/types.ts`
- `src/features/setup/api/service.ts`
- `src/features/setup/api/queries.ts`
- `src/features/setup/api/use-csv-commit.ts`
- `src/features/setup/api/use-setup-verification.ts`
## Behavior
- Step 1 calls setup readiness and displays overall status, PASS / WARNING / FAIL counts, grouped checks, suggested fixes, loading, error, and permission states.
- Step 2 calls template metadata and displays registered setup templates from the existing setup template API.
- Step 3 accepts one or more CSV files and does not upload them until the user clicks preview.
- Step 4 calls CSV preview, stores `previewHash` in client state only, displays per-file summaries, row/error/warning counts, and grouped safe error messages.
- Step 5 calls CSV commit with the latest `previewHash`.
- Commit is disabled when preview has `FAIL`.
- Commit requires warning acknowledgement when preview has `WARNING`.
- File changes after preview clear commit eligibility and require re-preview, using file name + size + lastModified fingerprint.
- Step 6 calls setup verification and displays grouped checks plus summary counts.
- Step 7 summarizes readiness, preview, commit, and verification results for the current browser session.
## Security And API Notes
- Setup page uses `auth()` and `PageContainer` access fallback for non-super-admin users.
- Existing setup APIs remain the enforcement boundary and still require `super_admin`.
- Upload requests use `FormData` directly so browser-managed multipart boundaries are preserved.
- UI reads safe API error messages and does not render raw stack traces.
- CSV files are uploaded only to the preview and commit endpoints.
- The wizard does not log CSV data.
## Out Of Scope Preserved
- No setup state persistence.
- No seed manifest persistence.
- No destructive reset or reseed behavior.
- No seed execution.
- No database migrations.
- No new CRM behavior.
- No file download or ZIP template generation.
Persistent setup runs and resume behavior remain deferred to D.7.8.
## Validation
- `npm run typecheck -- --pretty false` passed.
- `npx oxlint src/features/setup/api/types.ts src/features/setup/api/service.ts src/features/setup/api/queries.ts src/features/setup/api/use-csv-commit.ts src/features/setup/api/use-setup-verification.ts src/features/setup/components/setup-wizard.tsx src/app/dashboard/administration/setup/page.tsx src/config/nav-config.ts` passed.
- Existing dev server was already running at `http://localhost:3000`.
- `curl.exe -I -L --max-time 20 http://localhost:3000/dashboard/administration/setup` returned `200 OK`.
## Residual Notes
- `plans/task-d.7.6.md` was already untracked during implementation and was not modified as part of this delivery.
- The wizard is intentionally session-only until the D.7.8 setup-state persistence slice.

486
plans/task-d.7.6.md Normal file
View File

@@ -0,0 +1,486 @@
# Task D.7.6 Dashboard Setup Wizard UI
## Objective
Build a dashboard-native Setup Wizard UI for ALLA OS Administration.
The wizard must connect the previously implemented setup APIs into one guided workflow:
- D.7.2 Readiness and Verification APIs
- D.7.3 CSV Template Pack and Template Metadata API
- D.7.4 CSV Preview Validation Engine
- D.7.5 CSV Commit Import Engine
This task focuses on UI and orchestration only.
Do not implement seed execution, destructive reset, setup state persistence, seed manifest persistence, or new migrations in this task.
---
## Review Before Implementation
Review:
- AGENTS.md
- plans/task-d.7.md
- plans/task-d.7.1.md
- plans/task-d.7.2.md
- plans/task-d.7.3.md
- plans/task-d.7.4.md
- plans/task-d.7.5.md
- docs/setup/seed-matrix.md
- docs/setup/setup-wizard-blueprint.md
- docs/setup/setup-state-machine.md
- docs/setup/verification-matrix.md
- docs/setup/csv-template-spec.md
- docs/setup/import-mapping.md
- setup/templates/README.md
- setup/templates/templates.json
- src/features/setup/api/types.ts
- src/features/setup/api/service.ts
- src/features/setup/api/queries.ts
- src/app/api/setup/readiness/route.ts
- src/app/api/setup/verify/route.ts
- src/app/api/setup/templates/route.ts
- src/app/api/setup/import/preview/route.ts
- src/app/api/setup/import/commit/route.ts
- existing dashboard pages and PageContainer usage
- src/config/nav-config.ts
---
## Implementation Scope
Create dashboard page:
src/app/dashboard/administration/setup/page.tsx
Create UI components under:
src/features/setup/components/
Recommended components:
- setup-wizard.tsx
- setup-wizard-stepper.tsx
- setup-status-badge.tsx
- setup-check-list.tsx
- setup-summary-cards.tsx
- setup-template-list.tsx
- csv-upload-dropzone.tsx
- csv-preview-table.tsx
- csv-import-report.tsx
- setup-verification-summary.tsx
- setup-finish-panel.tsx
Optional hooks:
src/features/setup/api/use-setup-readiness.ts
src/features/setup/api/use-setup-templates.ts
src/features/setup/api/use-csv-preview.ts
src/features/setup/api/use-csv-commit.ts
src/features/setup/api/use-setup-verification.ts
---
## Route and Navigation
Add menu item under Administration:
Administration
Setup Wizard
Target route:
/dashboard/administration/setup
The route must be protected by existing dashboard/auth rules.
If setup APIs require `super_admin`, the UI should show a friendly permission message when unauthorized.
---
## Wizard Steps
Implement these UI steps.
### Step 1 System Readiness
Call:
GET /api/setup/readiness
Show:
- Overall status
- PASS / WARNING / FAIL counts
- Check list grouped by area
- Suggested fixes
- Re-run button
Blocking behavior:
- FAIL should block moving forward unless step is marked dry-run / review-only.
- WARNING can continue with acknowledgement.
---
### Step 2 Template Pack
Call:
GET /api/setup/templates
Show:
- available CSV templates
- import order
- seed type
- required columns
- sample file name
- unsupported/deferred templates from README or metadata if available
Optional:
- link to local setup/templates path in documentation text only
- do not implement file download unless already available
---
### Step 3 CSV Upload
Allow upload of multiple CSV files.
Rules:
- accept only `.csv`
- show selected files
- allow remove/replace
- show detected file count
- show missing recommended templates as info only
- do not upload automatically until Preview button is clicked
---
### Step 4 CSV Preview
Call:
POST /api/setup/import/preview
Input:
multipart/form-data files
Show:
- previewHash
- overall status
- per-file status
- row count
- create/update/error/warning counts
- row-level errors
- row-level warnings
- dependency warnings
- duplicate warnings
Blocking behavior:
- FAIL blocks commit.
- WARNING requires acknowledgement before commit.
- Store previewHash in client state only for this task.
---
### Step 5 CSV Commit
Call:
POST /api/setup/import/commit
Input:
same files + previewHash
Support:
- dryRun toggle
- commit button
- show import report
Rules:
- Commit button disabled when preview has blocking errors.
- If files changed after preview, force re-preview.
- If commit returns previewHash mismatch, show clear message and require re-preview.
---
### Step 6 Verification
Call:
POST /api/setup/verify
Input:
optional organizationId / active org context
Show:
- overall status
- PASS / WARNING / FAIL counts
- grouped checks
- suggested fixes
- re-run button
---
### Step 7 Finish
Show:
- readiness summary
- template summary
- preview summary
- commit summary
- verification summary
- next recommended task
Because setup state persistence is out of scope, do not permanently lock or complete setup.
Show clear message:
This wizard session is not persisted yet. Persistent setup runs will be implemented in D.7.8.
---
## UI Requirements
Use:
- shadcn/ui
- PageContainer
- Card
- Button
- Badge
- Alert
- Table
- Tabs or Accordion where helpful
- Progress / Stepper
- ScrollArea for long reports
- responsive layout
- dark mode compatible styles
Avoid:
- hardcoded colors outside design tokens
- raw JSON dumps as main UI
- giant ungrouped error lists
- hidden errors
---
## UX Requirements
The wizard should feel like an enterprise setup console.
Must include:
- clear progress
- clear blocking vs non-blocking issues
- grouped diagnostics
- concise summary cards
- actionable suggested fixes
- retry/re-run buttons
- empty states
- loading states
- error states
- permission denied state
Recommended status language:
PASS
WARNING
FAIL
Do not translate status enum values in API handling.
---
## State Management
D.7.6 uses client-side state only.
Track:
- current step
- readiness report
- template metadata
- selected files
- preview report
- previewHash
- commit report
- verification report
- warning acknowledgement
Do not implement DB persistence.
If browser refreshes, state can reset.
Add note that persistent resume will arrive in D.7.8.
---
## API Integration Rules
- Reuse existing setup API types.
- Do not duplicate response shapes manually if types exist.
- Handle non-200 responses safely.
- Show safe error message from API contract.
- Do not display raw stack traces.
- Do not log sensitive CSV data.
- Do not upload files except to preview/commit endpoints.
---
## CSV File Change Rules
After successful preview:
- if selected files are removed, added, renamed, or content changed
- clear previewHash
- clear commit report
- require preview again
Implementation can use file name + size + lastModified fingerprint for this task.
---
## Out Of Scope
- Persistent setup state
- setup_runs / setup_run_steps migrations
- seed_manifests persistence
- seed execution
- scoped reset/reseed UI
- CSV template ZIP download
- production setup lock
- installation profile engine
- plugin runtime
- real file attachment import
- email settings persistence
- new CRM behavior
---
## Deliverables
Required:
src/app/dashboard/administration/setup/page.tsx
src/features/setup/components/setup-wizard.tsx
src/features/setup/components/setup-wizard-stepper.tsx
src/features/setup/components/setup-status-badge.tsx
src/features/setup/components/setup-check-list.tsx
src/features/setup/components/setup-summary-cards.tsx
src/features/setup/components/setup-template-list.tsx
src/features/setup/components/csv-upload-dropzone.tsx
src/features/setup/components/csv-preview-table.tsx
src/features/setup/components/csv-import-report.tsx
src/features/setup/components/setup-verification-summary.tsx
src/features/setup/components/setup-finish-panel.tsx
Navigation update:
src/config/nav-config.ts
Optional:
src/features/setup/api/use-setup-readiness.ts
src/features/setup/api/use-setup-templates.ts
src/features/setup/api/use-csv-preview.ts
src/features/setup/api/use-csv-commit.ts
src/features/setup/api/use-setup-verification.ts
---
## Acceptance Criteria
✓ Dashboard route exists at /dashboard/administration/setup.
✓ Navigation exposes Setup Wizard under Administration.
✓ Stepper wizard renders with all required steps.
✓ Readiness step calls GET /api/setup/readiness.
✓ Template step calls GET /api/setup/templates.
✓ CSV upload accepts multiple CSV files.
✓ Preview step calls POST /api/setup/import/preview.
✓ Preview report displays file and row-level validation results.
✓ Commit step calls POST /api/setup/import/commit with previewHash.
✓ Commit is disabled when preview has FAIL.
✓ File changes after preview clear previewHash and require re-preview.
✓ Verification step calls POST /api/setup/verify.
✓ Finish step summarizes all prior outputs.
✓ UI handles loading, empty, error, unauthorized, warning, and success states.
✓ Uses shadcn/ui and existing dashboard layout conventions.
✓ No setup data persistence or reset logic is introduced.
✓ Typecheck passes or unrelated failures are documented.
---
## Suggested Verification
Run:
npm run typecheck
Run scoped lint:
npx oxlint src/features/setup src/app/dashboard/administration/setup src/config/nav-config.ts
Manual test:
1. Open /dashboard/administration/setup as super_admin.
2. Run readiness.
3. View template pack.
4. Upload valid CSV batch.
5. Run preview.
6. Confirm previewHash appears.
7. Run dryRun commit.
8. Run commit.
9. Re-run verification.
10. Confirm finish summary.
11. Modify selected file after preview.
12. Confirm previewHash clears.
13. Login as non-super_admin and confirm friendly unauthorized behavior.
---
## Follow-up
After D.7.6:
D.7.8 Seed Manifest and Setup State Persistence
D.7.7 Scoped Reset and Reseed Engine
D.7.9 Installation Profile and Plugin Runtime Enhancement

View File

@@ -0,0 +1,27 @@
import { auth } from '@/auth';
import PageContainer from '@/components/layout/page-container';
import { SetupWizard } from '@/features/setup/components/setup-wizard';
export const metadata = {
title: 'Dashboard: Administration Setup'
};
export default async function AdministrationSetupPage() {
const session = await auth();
const canAccessSetup = session?.user?.systemRole === 'super_admin';
return (
<PageContainer
pageTitle='Administration Setup Wizard'
pageDescription='Run readiness checks, review setup templates, preview CSV imports, commit imports, and verify the configured system.'
access={canAccessSetup}
accessFallback={
<div className='rounded-lg border border-dashed p-8 text-center text-muted-foreground'>
Setup administration requires a super admin account.
</div>
}
>
<SetupWizard />
</PageContainer>
);
}

View File

@@ -178,6 +178,14 @@ import { NavGroup } from "@/types";
items: [], items: [],
access: { systemRole: "super_admin" }, access: { systemRole: "super_admin" },
}, },
{
title: "Setup Wizard",
url: "/dashboard/administration/setup",
icon: "settings",
isActive: false,
items: [],
access: { systemRole: "super_admin" },
},
{ {
title: "Teams", title: "Teams",
url: "/dashboard/workspaces/team", url: "/dashboard/workspaces/team",

View File

@@ -1,10 +1,11 @@
import { queryOptions } from '@tanstack/react-query'; import { queryOptions } from '@tanstack/react-query';
import { getSetupReadiness, verifySetup } from './service'; import { getSetupReadiness, getSetupTemplates, verifySetup } from './service';
import type { SetupVerificationPayload } from './types'; import type { SetupVerificationPayload } from './types';
export const setupKeys = { export const setupKeys = {
all: ['setup'] as const, all: ['setup'] as const,
readiness: () => [...setupKeys.all, 'readiness'] as const, readiness: () => [...setupKeys.all, 'readiness'] as const,
templates: () => [...setupKeys.all, 'templates'] as const,
verification: (payload: SetupVerificationPayload = {}) => verification: (payload: SetupVerificationPayload = {}) =>
[...setupKeys.all, 'verification', payload] as const [...setupKeys.all, 'verification', payload] as const
}; };
@@ -15,6 +16,12 @@ export const setupReadinessQueryOptions = () =>
queryFn: () => getSetupReadiness() queryFn: () => getSetupReadiness()
}); });
export const setupTemplatesQueryOptions = () =>
queryOptions({
queryKey: setupKeys.templates(),
queryFn: () => getSetupTemplates()
});
export const setupVerificationQueryOptions = (payload: SetupVerificationPayload = {}) => export const setupVerificationQueryOptions = (payload: SetupVerificationPayload = {}) =>
queryOptions({ queryOptions({
queryKey: setupKeys.verification(payload), queryKey: setupKeys.verification(payload),

View File

@@ -1,14 +1,26 @@
import { apiClient } from '@/lib/api-client'; import { ApiClientError, apiClient } from '@/lib/api-client';
import type { import type {
CsvPreviewResult,
ImportReport,
SetupReadinessReport, SetupReadinessReport,
SetupTemplatesResponse,
SetupVerificationPayload, SetupVerificationPayload,
SetupVerificationReport SetupVerificationReport
} from './types'; } from './types';
interface ApiErrorPayload {
message?: string;
error?: string;
}
export async function getSetupReadiness(): Promise<SetupReadinessReport> { export async function getSetupReadiness(): Promise<SetupReadinessReport> {
return apiClient<SetupReadinessReport>('/setup/readiness'); return apiClient<SetupReadinessReport>('/setup/readiness');
} }
export async function getSetupTemplates(): Promise<SetupTemplatesResponse> {
return apiClient<SetupTemplatesResponse>('/setup/templates');
}
export async function verifySetup( export async function verifySetup(
payload: SetupVerificationPayload = {} payload: SetupVerificationPayload = {}
): Promise<SetupVerificationReport> { ): Promise<SetupVerificationReport> {
@@ -17,3 +29,50 @@ export async function verifySetup(
body: JSON.stringify(payload) body: JSON.stringify(payload)
}); });
} }
async function readUploadResponse<T>(response: Response): Promise<T> {
if (response.ok) {
return response.json() as Promise<T>;
}
const payload = (await response.json().catch(() => null)) as ApiErrorPayload | null;
const message = payload?.message ?? payload?.error ?? `API error: ${response.status}`;
throw new ApiClientError(message, {
status: response.status,
statusText: response.statusText,
payload
});
}
function buildCsvFormData(files: File[]): FormData {
const formData = new FormData();
files.forEach((file) => formData.append('files', file, file.name));
return formData;
}
export async function previewSetupCsvFiles(files: File[]): Promise<CsvPreviewResult> {
return readUploadResponse<CsvPreviewResult>(
await fetch('/api/setup/import/preview', {
method: 'POST',
body: buildCsvFormData(files)
})
);
}
export async function commitSetupCsvFiles(input: {
files: File[];
previewHash: string;
dryRun?: boolean;
}): Promise<ImportReport> {
const formData = buildCsvFormData(input.files);
formData.set('previewHash', input.previewHash);
formData.set('dryRun', String(Boolean(input.dryRun)));
return readUploadResponse<ImportReport>(
await fetch('/api/setup/import/commit', {
method: 'POST',
body: formData
})
);
}

View File

@@ -37,3 +37,36 @@ export interface SetupVerificationPayload {
export interface SetupVerificationReport extends SetupReadinessReport { export interface SetupVerificationReport extends SetupReadinessReport {
organizationId: string | null; organizationId: string | null;
} }
export interface SetupTemplateMetadataItem {
file: string;
seedType: string;
importOrder: number;
supported: boolean;
requiredColumns: string[];
description: string;
}
export interface SetupTemplatesResponse {
success: boolean;
time: string;
version: string;
generatedFrom: string;
templates: SetupTemplateMetadataItem[];
}
export type {
CsvPreviewError,
CsvPreviewFileResult,
CsvPreviewRow,
CsvPreviewResult,
CsvPreviewStatus,
CsvPreviewWarning
} from '@/features/setup/server/csv/types';
export type {
ImportFileReport,
ImportReport,
ImportRowReport,
ImportStatus
} from '@/features/setup/server/csv/import-report';

View File

@@ -0,0 +1,17 @@
'use client';
import { useMutation } from '@tanstack/react-query';
import { commitSetupCsvFiles, previewSetupCsvFiles } from './service';
export function useCsvPreview() {
return useMutation({
mutationFn: (files: File[]) => previewSetupCsvFiles(files)
});
}
export function useCsvCommit() {
return useMutation({
mutationFn: (input: { files: File[]; previewHash: string; dryRun?: boolean }) =>
commitSetupCsvFiles(input)
});
}

View File

@@ -0,0 +1,11 @@
'use client';
import { useMutation } from '@tanstack/react-query';
import { verifySetup } from './service';
import type { SetupVerificationPayload } from './types';
export function useSetupVerification() {
return useMutation({
mutationFn: (payload: SetupVerificationPayload = {}) => verifySetup(payload)
});
}

File diff suppressed because it is too large Load Diff