Compare commits
12 Commits
Calendar
...
setup-wizr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18cc9bbfd0 | ||
|
|
d93f25e1ce | ||
|
|
944dbc031d | ||
|
|
15c56efc8b | ||
|
|
9c8d6a0d6d | ||
|
|
503f34e22f | ||
|
|
ccfd7c6cd7 | ||
|
|
9b05743b1e | ||
|
|
110c2f9e7f | ||
|
|
b7589017ab | ||
|
|
0b7aeea0a7 | ||
|
|
0c3d488d7d |
181
alla-theme.css
Normal file
181
alla-theme.css
Normal file
@@ -0,0 +1,181 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(0.9911 0 0);
|
||||
--foreground: oklch(0.2046 0 0);
|
||||
--card: oklch(0.9911 0 0);
|
||||
--card-foreground: oklch(0.2046 0 0);
|
||||
--popover: oklch(0.9911 0 0);
|
||||
--popover-foreground: oklch(0.4386 0 0);
|
||||
--primary: oklch(0.4799 0.0804 155.8197);
|
||||
--primary-foreground: oklch(1.0000 0 0);
|
||||
--secondary: oklch(0.9940 0 0);
|
||||
--secondary-foreground: oklch(0.2046 0 0);
|
||||
--muted: oklch(0.9461 0 0);
|
||||
--muted-foreground: oklch(0.2435 0 0);
|
||||
--accent: oklch(0.9461 0 0);
|
||||
--accent-foreground: oklch(0.2435 0 0);
|
||||
--destructive: oklch(0.5523 0.1927 32.7272);
|
||||
--destructive-foreground: oklch(0.9934 0.0032 17.2118);
|
||||
--border: oklch(0.9037 0 0);
|
||||
--input: oklch(0.9731 0 0);
|
||||
--ring: oklch(0.5568 0.1355 155.8120);
|
||||
--chart-1: oklch(0.8348 0.1302 160.9080);
|
||||
--chart-2: oklch(0.6231 0.1880 259.8145);
|
||||
--chart-3: oklch(0.6056 0.2189 292.7172);
|
||||
--chart-4: oklch(0.7686 0.1647 70.0804);
|
||||
--chart-5: oklch(0.6959 0.1491 162.4796);
|
||||
--sidebar: oklch(0.9911 0 0);
|
||||
--sidebar-foreground: oklch(0.5452 0 0);
|
||||
--sidebar-primary: oklch(0.5568 0.1355 155.8120);
|
||||
--sidebar-primary-foreground: oklch(0.2626 0.0147 166.4589);
|
||||
--sidebar-accent: oklch(0.9461 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.2435 0 0);
|
||||
--sidebar-border: oklch(0.9037 0 0);
|
||||
--sidebar-ring: oklch(0.5568 0.1355 155.8120);
|
||||
--font-sans: Anek Kannada, ui-sans-serif, sans-serif, system-ui;
|
||||
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
--font-mono: monospace;
|
||||
--radius: 0.5rem;
|
||||
--shadow-x: 0px;
|
||||
--shadow-y: 1px;
|
||||
--shadow-blur: 5.5px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-color: #000000;
|
||||
--shadow-2xs: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 2px 4px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 4px 6px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 8px 10px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.25);
|
||||
--tracking-normal: 0.025em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.1822 0 0);
|
||||
--foreground: oklch(0.9288 0.0126 255.5078);
|
||||
--card: oklch(0.2046 0 0);
|
||||
--card-foreground: oklch(0.9288 0.0126 255.5078);
|
||||
--popover: oklch(0.2603 0 0);
|
||||
--popover-foreground: oklch(0.7348 0 0);
|
||||
--primary: oklch(0.5568 0.1355 155.8120);
|
||||
--primary-foreground: oklch(0.9213 0.0135 167.1556);
|
||||
--secondary: oklch(0.2603 0 0);
|
||||
--secondary-foreground: oklch(0.9851 0 0);
|
||||
--muted: oklch(0.2393 0 0);
|
||||
--muted-foreground: oklch(0.7122 0 0);
|
||||
--accent: oklch(0.3132 0 0);
|
||||
--accent-foreground: oklch(0.9851 0 0);
|
||||
--destructive: oklch(0.3123 0.0852 29.7877);
|
||||
--destructive-foreground: oklch(0.9368 0.0045 34.3092);
|
||||
--border: oklch(0.2809 0 0);
|
||||
--input: oklch(0.2603 0 0);
|
||||
--ring: oklch(0.5568 0.1355 155.8120);
|
||||
--chart-1: oklch(0.8003 0.1821 151.7110);
|
||||
--chart-2: oklch(0.7137 0.1434 254.6240);
|
||||
--chart-3: oklch(0.7090 0.1592 293.5412);
|
||||
--chart-4: oklch(0.8369 0.1644 84.4286);
|
||||
--chart-5: oklch(0.7845 0.1325 181.9120);
|
||||
--sidebar: oklch(0.1822 0 0);
|
||||
--sidebar-foreground: oklch(0.6301 0 0);
|
||||
--sidebar-primary: oklch(0.5568 0.1355 155.8120);
|
||||
--sidebar-primary-foreground: oklch(0.9213 0.0135 167.1556);
|
||||
--sidebar-accent: oklch(0.3132 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.9851 0 0);
|
||||
--sidebar-border: oklch(0.2809 0 0);
|
||||
--sidebar-ring: oklch(0.5568 0.1355 155.8120);
|
||||
--font-sans: Anek Kannada, ui-sans-serif, sans-serif, system-ui;
|
||||
--font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
|
||||
--font-mono: monospace;
|
||||
--radius: 0.5rem;
|
||||
--shadow-x: 0px;
|
||||
--shadow-y: 1px;
|
||||
--shadow-blur: 5.5px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-color: #000000;
|
||||
--shadow-2xs: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 2px 4px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 4px 6px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.10), 0px 8px 10px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0px 1px 5.5px 0px hsl(0 0% 0% / 0.25);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
|
||||
--font-sans: var(--font-sans);
|
||||
--font-mono: var(--font-mono);
|
||||
--font-serif: var(--font-serif);
|
||||
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
|
||||
--shadow-2xs: var(--shadow-2xs);
|
||||
--shadow-xs: var(--shadow-xs);
|
||||
--shadow-sm: var(--shadow-sm);
|
||||
--shadow: var(--shadow);
|
||||
--shadow-md: var(--shadow-md);
|
||||
--shadow-lg: var(--shadow-lg);
|
||||
--shadow-xl: var(--shadow-xl);
|
||||
--shadow-2xl: var(--shadow-2xl);
|
||||
|
||||
--tracking-tighter: calc(var(--tracking-normal) - 0.05em);
|
||||
--tracking-tight: calc(var(--tracking-normal) - 0.025em);
|
||||
--tracking-normal: var(--tracking-normal);
|
||||
--tracking-wide: calc(var(--tracking-normal) + 0.025em);
|
||||
--tracking-wider: calc(var(--tracking-normal) + 0.05em);
|
||||
--tracking-widest: calc(var(--tracking-normal) + 0.1em);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
letter-spacing: var(--tracking-normal);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
# Task D.7.10 Setup Integration Test & Golden Dataset
|
||||
|
||||
Date: 2026-07-03
|
||||
Status: implemented
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
Added official setup golden dataset:
|
||||
|
||||
- `setup/golden-dataset/README.md`
|
||||
- `setup/golden-dataset/dataset.json`
|
||||
- 22 setup CSV files matching `setup/templates/templates.json`
|
||||
|
||||
Dataset coverage:
|
||||
|
||||
- Organizations: `ALLA`, `ONVALLA`
|
||||
- Users: IT/admin, marketing, sales, sales manager, CEO
|
||||
- Customers: 10
|
||||
- Contacts: 20
|
||||
- Leads: 20
|
||||
- Opportunities: 15
|
||||
- Quotations: 20
|
||||
- Multiple branches and product types
|
||||
- Quotation statuses: draft, pending approval, approved, rejected, revision
|
||||
|
||||
Added setup integration documentation:
|
||||
|
||||
- `docs/setup/integration-scenarios.md`
|
||||
- `docs/setup/setup-performance-report.md`
|
||||
|
||||
Added automated setup contract tests:
|
||||
|
||||
- `src/tests/setup/helpers.ts`
|
||||
- `src/tests/setup/golden-dataset.test.ts`
|
||||
- `src/tests/setup/setup-install.test.ts`
|
||||
- `src/tests/setup/setup-preview.test.ts`
|
||||
- `src/tests/setup/setup-commit.test.ts`
|
||||
- `src/tests/setup/setup-verification.test.ts`
|
||||
- `src/tests/setup/setup-resume.test.ts`
|
||||
- `src/tests/setup/setup-reset.test.ts`
|
||||
|
||||
Added script:
|
||||
|
||||
- `npm run test:setup`
|
||||
|
||||
## Test Coverage
|
||||
|
||||
The setup test suite validates:
|
||||
|
||||
- Golden dataset files exist.
|
||||
- Golden dataset headers match official setup templates.
|
||||
- Required row counts are present.
|
||||
- Quotation statuses cover approval and revision scenarios.
|
||||
- Golden dataset includes every supported setup template.
|
||||
- Dataset import order follows template registry ordering.
|
||||
- Preview hash semantics change when CSV content changes.
|
||||
- Commit API and seed manifest integration exist.
|
||||
- Commit engine preserves preview hash validation contract.
|
||||
- Setup readiness and verification APIs exist.
|
||||
- Setup run resume APIs exist.
|
||||
- Setup wizard persists core step outputs.
|
||||
- Reset and reseed APIs exist.
|
||||
- Reset guard source blocks production and requires preview token semantics.
|
||||
- Unsafe reset scopes are intentionally blocked.
|
||||
- Integration scenarios document operational readiness checks.
|
||||
|
||||
## Validation
|
||||
|
||||
- `npm run test:setup` passed: 17 tests.
|
||||
- `npm run typecheck -- --pretty false` passed.
|
||||
- `npx oxlint src/tests/setup` passed.
|
||||
|
||||
## Residual Notes
|
||||
|
||||
- This task adds runnable setup contract tests using Node's built-in test runner to avoid introducing a new test framework.
|
||||
- Full empty-database E2E execution is documented in `docs/setup/integration-scenarios.md` but not automated because this repository does not yet have an isolated CI test database harness.
|
||||
- Performance targets are documented in `docs/setup/setup-performance-report.md`; measured preview/commit/verification timings require the future isolated database harness.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Task D.7.12 Step-by-Step First-Run Required CSV Import
|
||||
|
||||
Date: 2026-07-03
|
||||
Status: implemented
|
||||
|
||||
## Review Completed
|
||||
|
||||
- Reviewed `AGENTS.md` task governance from the active repository instructions.
|
||||
- Reviewed `docs/standards/task-contract-template.md`.
|
||||
- Reviewed `docs/standards/task-catalog.md`.
|
||||
- Reviewed `docs/standards/project-foundations.md`.
|
||||
- Reviewed `docs/standards/architecture-rules.md`.
|
||||
- Reviewed `docs/standards/ui-ux-rules.md`.
|
||||
- Reviewed `docs/standards/task-review-checklist.md`.
|
||||
- Reviewed setup lineage notes:
|
||||
- `docs/implementation/task-d7-initial-system-setup-audit.md`
|
||||
- `docs/implementation/task-d76-dashboard-setup-wizard-ui.md`
|
||||
- `docs/implementation/task-d78-seed-manifest-setup-state-persistence.md`
|
||||
- `docs/setup/setup-wizard-blueprint.md`
|
||||
|
||||
## Decision
|
||||
|
||||
The required CSV order is:
|
||||
|
||||
1. `users.csv`
|
||||
2. `organizations.csv`
|
||||
3. `memberships.csv`
|
||||
4. `crm-role-assignments.csv`
|
||||
5. `master-options.csv`
|
||||
6. `branches.csv`
|
||||
7. `product-types.csv`
|
||||
8. `document-sequences.csv`
|
||||
9. `approval-workflows.csv`
|
||||
10. `approval-steps.csv`
|
||||
11. `approval-matrix.csv`
|
||||
|
||||
This intentionally uses `users.csv` before `organizations.csv` because `organizations.csv`
|
||||
resolves `created_by_email` against existing users. This follows the recommendation in
|
||||
`plans/task-d.7.12.md` and avoids introducing a temporary bootstrap actor into the
|
||||
organization import data path.
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
- Added server-owned bootstrap required step metadata in `setup-bootstrap.service.ts`.
|
||||
- Added `crm-role-assignments.csv` to the required bootstrap file list.
|
||||
- Changed public bootstrap preview and commit APIs to accept one expected CSV file per step.
|
||||
- Persisted each required CSV result to its own `setup_run_steps.step_key`.
|
||||
- Updated bootstrap completion to require all required step keys to be `passed` or `warning`.
|
||||
- Added bootstrap step dependency staleness rules in setup run persistence.
|
||||
- Reworked the Administration Setup Wizard UI into a left-stepper, single-step import flow.
|
||||
- Kept optional business CSV imports separate from system-required steps.
|
||||
|
||||
## Reuse
|
||||
|
||||
- Reused existing CSV preview and commit engine.
|
||||
- Reused existing `/api/setup/bootstrap/preview`, `/api/setup/bootstrap/commit`, and
|
||||
`/api/setup/bootstrap/complete` route groups.
|
||||
- Reused existing `setup_runs` and `setup_run_steps` persistence.
|
||||
- Reused setup template metadata from `setup/templates/templates.json`.
|
||||
- Reused shadcn/ui dashboard primitives and existing icon registry.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run typecheck -- --pretty false` passed.
|
||||
|
||||
67
docs/implementation/task-d73-csv-template-static-pack.md
Normal file
67
docs/implementation/task-d73-csv-template-static-pack.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Task D.7.3 CSV Template Generator Static Template Pack
|
||||
|
||||
Date: 2026-07-02
|
||||
Status: implemented
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
Created the official static setup CSV template pack under `setup/templates/`.
|
||||
|
||||
Generated supported CSV files:
|
||||
|
||||
- `organizations.csv`
|
||||
- `users.csv`
|
||||
- `memberships.csv`
|
||||
- `crm-role-assignments.csv`
|
||||
- `master-options.csv`
|
||||
- `branches.csv`
|
||||
- `product-types.csv`
|
||||
- `document-sequences.csv`
|
||||
- `approval-workflows.csv`
|
||||
- `approval-steps.csv`
|
||||
- `approval-matrix.csv`
|
||||
- `customers.csv`
|
||||
- `contacts.csv`
|
||||
- `contact-shares.csv`
|
||||
- `leads.csv`
|
||||
- `opportunities.csv`
|
||||
- `opportunity-parties.csv`
|
||||
- `quotations.csv`
|
||||
- `quotation-items.csv`
|
||||
- `quotation-parties.csv`
|
||||
- `quotation-topics.csv`
|
||||
- `quotation-topic-items.csv`
|
||||
|
||||
Supporting files:
|
||||
|
||||
- `setup/templates/README.md`
|
||||
- `setup/templates/templates.json`
|
||||
|
||||
Optional read-only metadata API:
|
||||
|
||||
- `GET /api/setup/templates`
|
||||
|
||||
## Safety Notes
|
||||
|
||||
- No CSV parser was implemented.
|
||||
- No CSV validation/preview engine was implemented.
|
||||
- No CSV commit/import logic was implemented.
|
||||
- No seed execution was implemented.
|
||||
- No reset/reseed logic was implemented.
|
||||
- No unsupported CSV files were generated.
|
||||
- Sample `users.csv` leaves `password` empty to avoid embedding secrets.
|
||||
|
||||
## Verification
|
||||
|
||||
- Template structure check: 22 CSV files; each has one header row and one sample row.
|
||||
- Column count check: every sample row has the same column count as its header row.
|
||||
- Unsupported template check: no unsupported CSV files were present.
|
||||
- `templates.json` parse check: passed; 22 templates listed.
|
||||
- `npm run typecheck`: passed.
|
||||
- `npx oxlint src/app/api/setup setup/templates`: passed.
|
||||
- `npm run lint`: failed due to pre-existing unrelated repo lint issues outside this task, including `src/features/foundation/document-template/server/management-service.ts` and skill asset scripts.
|
||||
|
||||
## Follow-up
|
||||
|
||||
- D.7.4 should use `setup/templates/templates.json` and the CSV headers as the source contract for preview validation.
|
||||
- D.7.6 can call `GET /api/setup/templates` for template metadata.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Task D.7.4 CSV Preview Validation Engine
|
||||
|
||||
Date: 2026-07-02
|
||||
Status: implemented
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
- Added reusable preview-only CSV engine:
|
||||
- `src/features/setup/server/csv-preview.service.ts`
|
||||
- `src/features/setup/server/csv/parser.ts`
|
||||
- `src/features/setup/server/csv/template-registry.ts`
|
||||
- `src/features/setup/server/csv/header-validator.ts`
|
||||
- `src/features/setup/server/csv/value-validator.ts`
|
||||
- `src/features/setup/server/csv/dependency-resolver.ts`
|
||||
- `src/features/setup/server/csv/validator.ts`
|
||||
- `src/features/setup/server/csv/preview-builder.ts`
|
||||
- `src/features/setup/server/csv/types.ts`
|
||||
- Added protected preview route:
|
||||
- `POST /api/setup/import/preview`
|
||||
|
||||
## Behavior
|
||||
|
||||
- Accepts one or more CSV files through `multipart/form-data`.
|
||||
- Detects templates by filename from `setup/templates/templates.json`.
|
||||
- Treats `templates.json` plus checked-in CSV headers as runtime template truth.
|
||||
- Rejects unknown and unsupported templates with structured row/file errors.
|
||||
- Validates exact header names, order, duplicate columns, missing columns, and extra columns.
|
||||
- Parses UTF-8 comma-delimited CSV with quoted cell support.
|
||||
- Reports invalid encoding, empty rows, duplicate rows, inconsistent column counts, required fields, emails, booleans, integers, decimals, dates, enums, JSON metadata, format rules, and amount/line-total warnings.
|
||||
- Resolves dependencies from both uploaded batch files and existing database rows without writing.
|
||||
- Detects duplicate business keys inside each uploaded file.
|
||||
- Classifies rows as `create`, `update`, or `error`.
|
||||
- Returns structured file/row report with `PASS`, `WARNING`, `FAIL` status and `previewHash` for D.7.5.
|
||||
|
||||
## Safety Notes
|
||||
|
||||
- No database insert/update/delete logic added.
|
||||
- No seed execution added.
|
||||
- No reset/reseed behavior added.
|
||||
- No document number generation, approval triggering, PDF generation, or storage writes added.
|
||||
- Relationship checks use read-only Drizzle selects.
|
||||
- `quotation-topic-items.csv` resolves `topic_key` from the uploaded batch because `topic_key` is an import-only alias and is not persisted in `crm_quotation_topics`.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run typecheck`: passed.
|
||||
- `npx oxlint src/features/setup/server/csv src/features/setup/server/csv-preview.service.ts src/app/api/setup/import/preview`: passed.
|
||||
66
docs/implementation/task-d75-csv-commit-import-engine.md
Normal file
66
docs/implementation/task-d75-csv-commit-import-engine.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Task D.7.5 CSV Commit Import Engine
|
||||
|
||||
Date: 2026-07-03
|
||||
Status: implemented
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
- Added protected commit API:
|
||||
- `POST /api/setup/import/commit`
|
||||
- Added setup CSV commit service:
|
||||
- `src/features/setup/server/csv-commit.service.ts`
|
||||
- `src/features/setup/server/csv/commit-builder.ts`
|
||||
- `src/features/setup/server/csv/upsert-executor.ts`
|
||||
- `src/features/setup/server/csv/import-report.ts`
|
||||
|
||||
## Behavior
|
||||
|
||||
- Commit requires `previewHash`.
|
||||
- Commit re-runs D.7.4 preview on the submitted files.
|
||||
- Commit rejects mismatched `previewHash`.
|
||||
- Commit rejects preview results with blocking errors.
|
||||
- Commit follows dependency order from `setup/templates/templates.json` through the D.7.4 preview ordering.
|
||||
- `dryRun=true` returns planned actions and does not start transaction writes.
|
||||
- Non-dry-run commits execute in a single database transaction.
|
||||
- Supported rows use idempotent business-key upsert behavior.
|
||||
- Password updates only run for existing users when `password` is supplied and `reset_password=true`; otherwise password input is ignored with a report warning.
|
||||
- Import reports never return password hashes.
|
||||
|
||||
## Supported Templates
|
||||
|
||||
The commit executor supports the templates registered by D.7.3/D.7.4:
|
||||
|
||||
- `users.csv`
|
||||
- `organizations.csv`
|
||||
- `memberships.csv`
|
||||
- `crm-role-assignments.csv`
|
||||
- `master-options.csv`
|
||||
- `branches.csv`
|
||||
- `product-types.csv`
|
||||
- `document-sequences.csv`
|
||||
- `approval-workflows.csv`
|
||||
- `approval-steps.csv`
|
||||
- `approval-matrix.csv`
|
||||
- `customers.csv`
|
||||
- `contacts.csv`
|
||||
- `contact-shares.csv`
|
||||
- `leads.csv`
|
||||
- `opportunities.csv`
|
||||
- `opportunity-parties.csv`
|
||||
- `quotations.csv`
|
||||
- `quotation-items.csv`
|
||||
- `quotation-parties.csv`
|
||||
- `quotation-topics.csv`
|
||||
- `quotation-topic-items.csv`
|
||||
|
||||
## Safety Notes
|
||||
|
||||
- D.7.5 reuses D.7.4 parsing, template detection, validation, dependency resolution, preview actions, and `previewHash`.
|
||||
- Setup import writes directly with Drizzle for this slice because no safe setup import service contract exists for every supported template.
|
||||
- The import report includes `AUDIT_GAP` warnings for direct Drizzle writes; a future service wrapper can add per-row audit semantics without changing the preview contract.
|
||||
- Storage, attachments, approval execution, PDFs, setup state persistence, seed manifest persistence, and destructive reset remain out of scope.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run typecheck` passed.
|
||||
- `npx oxlint src/features/setup/server/csv src/features/setup/server/csv-commit.service.ts src/app/api/setup/import/commit/route.ts` passed.
|
||||
71
docs/implementation/task-d76-dashboard-setup-wizard-ui.md
Normal file
71
docs/implementation/task-d76-dashboard-setup-wizard-ui.md
Normal 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.
|
||||
130
docs/implementation/task-d77-scoped-reset-reseed-engine.md
Normal file
130
docs/implementation/task-d77-scoped-reset-reseed-engine.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# Task D.7.7 Scoped Reset Reseed Engine
|
||||
|
||||
Date: 2026-07-03
|
||||
Status: implemented
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
Added setup reset/reseed server foundations:
|
||||
|
||||
- `src/features/setup/server/reset.service.ts`
|
||||
- `src/features/setup/server/reseed.service.ts`
|
||||
- `src/features/setup/server/reset-guards.ts`
|
||||
- `src/features/setup/server/reset-report.ts`
|
||||
- `src/features/setup/server/reset-scopes.ts`
|
||||
|
||||
Added protected setup maintenance APIs:
|
||||
|
||||
- `POST /api/setup/reset/preview`
|
||||
- `POST /api/setup/reset/execute`
|
||||
- `POST /api/setup/reseed/preview`
|
||||
- `POST /api/setup/reseed/execute`
|
||||
|
||||
## Reset Behavior
|
||||
|
||||
Reset preview is implemented for all D.7.7 scopes:
|
||||
|
||||
- `foundation_reset`
|
||||
- `organization_reset`
|
||||
- `business_reset`
|
||||
- `demo_uat_reset`
|
||||
- `full_reset`
|
||||
- `csv_import_rollback`
|
||||
- `setup_run_reset`
|
||||
|
||||
Reset execute is implemented only where ownership and safety are clear:
|
||||
|
||||
- `setup_run_reset`
|
||||
- Deletes setup metadata only.
|
||||
- Deletes `setup_runs`, `setup_run_steps`, `seed_manifests`, and `seed_manifest_items`.
|
||||
- Does not delete business, organization, foundation, or user data.
|
||||
- `business_reset`
|
||||
- Deletes organization-scoped CRM business rows only.
|
||||
- Retains organization, users, memberships, and foundation rows.
|
||||
- Marks matching seed manifests `rolled_back`.
|
||||
- Marks CSV commit and verification setup steps `stale`.
|
||||
|
||||
The following scopes intentionally block execution with safe reports:
|
||||
|
||||
- `foundation_reset`
|
||||
- `organization_reset`
|
||||
- `demo_uat_reset`
|
||||
- `full_reset`
|
||||
- `csv_import_rollback`
|
||||
|
||||
These are blocked until service-specific seed/reseed wrappers, deterministic UAT ownership markers, or reversible manifest ownership metadata are available.
|
||||
|
||||
## Reseed Behavior
|
||||
|
||||
Reseed preview exists for:
|
||||
|
||||
- `foundation`
|
||||
- `demo_uat`
|
||||
- `csv_manifest`
|
||||
|
||||
Reseed execute is blocked in D.7.7 and returns a safe report. This avoids duplicating seed scripts or pretending CSV manifests can be replayed when original CSV payloads are not persisted.
|
||||
|
||||
## Safety Guards
|
||||
|
||||
All reset/reseed APIs require:
|
||||
|
||||
- `super_admin`
|
||||
- non-production environment
|
||||
- non-production-like database host/name
|
||||
- explicit scope or target
|
||||
- preview before execute
|
||||
- valid `previewHash`
|
||||
- valid short-lived `confirmationToken`
|
||||
- exact typed confirmation phrase
|
||||
|
||||
Organization-aware scopes require `organizationId`.
|
||||
|
||||
## Report Behavior
|
||||
|
||||
Preview reports include:
|
||||
|
||||
- scope or reseed target
|
||||
- affected tables
|
||||
- estimated row counts
|
||||
- retained data
|
||||
- deleted data
|
||||
- storage cleanup plan
|
||||
- seed manifest impact
|
||||
- warnings and blocking errors
|
||||
- confirmation phrase
|
||||
- preview hash
|
||||
- confirmation token and expiry
|
||||
|
||||
Execute reports include:
|
||||
|
||||
- execution status
|
||||
- deleted row estimate
|
||||
- updated manifest count
|
||||
- best-effort storage cleanup result
|
||||
|
||||
Storage cleanup is report-only/best-effort and never silently deletes approved production artifacts.
|
||||
|
||||
## Out Of Scope Preserved
|
||||
|
||||
- Production reset workflow.
|
||||
- Silent automatic reset.
|
||||
- Arbitrary rollback without manifest ownership.
|
||||
- Deleting approved production artifacts.
|
||||
- New seed data creation.
|
||||
- Installation profile plugin runtime.
|
||||
- Backup/restore.
|
||||
- Data anonymization.
|
||||
- Cross-environment migration.
|
||||
- Email/storage secret reset.
|
||||
- CRM business behavior changes.
|
||||
|
||||
## Validation
|
||||
|
||||
- `npm run typecheck -- --pretty false` passed.
|
||||
- `npx oxlint src/features/setup/server/reset.service.ts src/features/setup/server/reseed.service.ts src/features/setup/server/reset-guards.ts src/features/setup/server/reset-report.ts src/features/setup/server/reset-scopes.ts src/app/api/setup/reset src/app/api/setup/reseed` passed.
|
||||
|
||||
## Residual Notes
|
||||
|
||||
- Full reset remains delegated to existing guarded scripts operationally; the dashboard API returns a blocking report instead of running process-level database reset commands.
|
||||
- `csv_import_rollback` remains report-only because D.7.8 seed manifest records do not persist enough row-level reversible ownership metadata for arbitrary rollback.
|
||||
- `demo_uat_reset` remains blocked until UAT rows have deterministic persisted ownership markers beyond seed conventions.
|
||||
@@ -0,0 +1,86 @@
|
||||
# Task D.7.8 Seed Manifest Setup State Persistence
|
||||
|
||||
Date: 2026-07-03
|
||||
Status: implemented
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
Added setup persistence schema and migration:
|
||||
|
||||
- `setup_runs`
|
||||
- `setup_run_steps`
|
||||
- `seed_manifests`
|
||||
- `seed_manifest_items`
|
||||
- `drizzle/0004_setup_state_seed_manifest.sql`
|
||||
|
||||
Added setup state services:
|
||||
|
||||
- `src/features/setup/server/setup-state.service.ts`
|
||||
- `src/features/setup/server/seed-manifest.service.ts`
|
||||
|
||||
Added protected setup run APIs:
|
||||
|
||||
- `GET /api/setup/run/current`
|
||||
- `POST /api/setup/run/start`
|
||||
- `POST /api/setup/run/steps`
|
||||
- `POST /api/setup/run/complete`
|
||||
- `GET /api/setup/run/report`
|
||||
|
||||
Updated CSV commit integration:
|
||||
|
||||
- Successful non-dry-run CSV commits create seed manifest records.
|
||||
- Dry-run commits do not write seed manifest records.
|
||||
- Failed commits do not write seed manifest records.
|
||||
|
||||
Updated Setup Wizard UI:
|
||||
|
||||
- Loads current setup run on mount.
|
||||
- Shows resumable/completed setup run banner.
|
||||
- Shows persisted step statuses.
|
||||
- Saves readiness, CSV preview, CSV commit, and verification step outputs.
|
||||
- Marks dependent later steps stale when step input hash changes.
|
||||
- Shows persisted seed manifest summaries.
|
||||
- Adds complete setup action.
|
||||
- Wizard remains usable if persistence APIs fail, with a warning.
|
||||
|
||||
## Persistence Behavior
|
||||
|
||||
- Step re-runs update the same `setup_run_steps` row.
|
||||
- Latest step report replaces prior step report.
|
||||
- CSV preview persistence strips raw row values before saving.
|
||||
- CSV commit persistence strips row-level raw details before saving.
|
||||
- Seed manifest item records store filenames, checksums, counts, status, and safe reports.
|
||||
- No raw CSV contents, passwords, password hashes, SQL errors, storage credentials, or secrets are persisted.
|
||||
|
||||
## Staleness Rules Implemented
|
||||
|
||||
- `readiness` changes mark later setup steps stale.
|
||||
- `organization` changes mark administrator, scope, sequence, approval, CSV, and verification steps stale.
|
||||
- `scope` changes mark sequence, approval, CSV, and verification steps stale.
|
||||
- `sequences` changes mark verification stale.
|
||||
- `approval` changes mark CSV and verification stale.
|
||||
- `csv_preview` changes mark `csv_commit` stale.
|
||||
- `csv_commit` changes mark verification stale.
|
||||
|
||||
## Out Of Scope Preserved
|
||||
|
||||
- No destructive reset/reseed behavior.
|
||||
- No `RESET_STEP` implementation.
|
||||
- No installation profile plugin runtime.
|
||||
- No CSV parser changes.
|
||||
- No setup template changes.
|
||||
- No storage or attachment import.
|
||||
- No new CRM behavior.
|
||||
- No production setup lock enforcement beyond completed status display.
|
||||
|
||||
## Validation
|
||||
|
||||
- `npm run typecheck -- --pretty false` passed.
|
||||
- `npx oxlint src/features/setup src/app/api/setup src/app/dashboard/administration/setup src/db/schema.ts` passed.
|
||||
- `npm run db:migrate` passed and applied migrations successfully.
|
||||
|
||||
## Residual Notes
|
||||
|
||||
- `plans/task-d.7.8.md` was untracked during implementation and was not modified as part of this delivery.
|
||||
- The Drizzle migration was added manually to match the current repository migration style and journal.
|
||||
- D.7.7 remains responsible for scoped reset/reseed behavior.
|
||||
@@ -0,0 +1,80 @@
|
||||
# Task D.7.9 Installation Profiles & Setup Plugin Registry
|
||||
|
||||
Date: 2026-07-03
|
||||
Status: implemented
|
||||
|
||||
## Scope Delivered
|
||||
|
||||
Added setup plugin platform layer:
|
||||
|
||||
- `src/features/setup/plugins/plugin-types.ts`
|
||||
- `src/features/setup/plugins/plugin-registry.ts`
|
||||
- `src/features/setup/plugins/installation-profile.ts`
|
||||
- `src/features/setup/plugins/foundation/foundation-plugin.ts`
|
||||
- `src/features/setup/plugins/crm/crm-setup-plugin.ts`
|
||||
- `src/features/setup/plugins/crm/crm-installation-profile.ts`
|
||||
|
||||
Added installation profile API:
|
||||
|
||||
- `GET /api/setup/profiles`
|
||||
|
||||
Updated existing setup APIs:
|
||||
|
||||
- `GET /api/setup/templates?profile=<profileId>` now returns plugin-aware metadata while preserving legacy template fields.
|
||||
- `GET /api/setup/readiness?profile=<profileId>` includes plugin registry readiness checks.
|
||||
- `POST /api/setup/verify` accepts optional `profileId` and includes plugin registry verification checks.
|
||||
|
||||
Updated Setup Wizard:
|
||||
|
||||
- Loads installation profiles from the setup plugin registry.
|
||||
- Allows profile selection.
|
||||
- Builds wizard stepper from profile-resolved wizard steps with fallback to existing steps.
|
||||
- Displays installed setup modules/plugins.
|
||||
|
||||
Added plugin documentation:
|
||||
|
||||
- `docs/setup/installation-profiles.md`
|
||||
- `docs/setup/setup-plugin-development.md`
|
||||
|
||||
Added setup tests:
|
||||
|
||||
- `src/tests/setup/setup-plugin-registry.test.ts`
|
||||
|
||||
## Profiles
|
||||
|
||||
Implemented profiles:
|
||||
|
||||
- `crm_starter`
|
||||
- `crm_demo`
|
||||
- `production`
|
||||
- `restore_backup`
|
||||
- `custom`
|
||||
|
||||
## Plugins
|
||||
|
||||
Implemented built-in plugins:
|
||||
|
||||
- `foundation`
|
||||
- owns setup platform foundations, setup state, seed manifests, reset framework, CSV framework, and foundation golden dataset registration
|
||||
- `crm`
|
||||
- owns CRM templates, CRM verification registration, CRM reset scopes, CRM reseed target registration, and CRM golden dataset registration
|
||||
|
||||
## Compatibility Notes
|
||||
|
||||
- No breaking API field removals were introduced.
|
||||
- Existing template metadata fields remain: `file`, `seedType`, `importOrder`, `supported`, `requiredColumns`, `description`.
|
||||
- New template metadata fields are additive: `plugin`, `profiles`, `visible`.
|
||||
- Existing CSV preview/commit behavior is unchanged.
|
||||
- Existing reset/reseed behavior is unchanged.
|
||||
- External plugin loading, marketplace behavior, and new business modules remain out of scope.
|
||||
|
||||
## Validation
|
||||
|
||||
- `npm run typecheck -- --pretty false` passed.
|
||||
- `npm run test:setup` passed: 20 tests.
|
||||
- `npx oxlint src/features/setup/plugins src/app/api/setup/profiles src/app/api/setup/templates src/app/api/setup/readiness src/app/api/setup/verify src/features/setup/components/setup-wizard.tsx src/features/setup/api src/tests/setup` passed.
|
||||
|
||||
## Residual Notes
|
||||
|
||||
- Readiness and verification services now aggregate plugin registry checks additively. Existing concrete CRM checks remain in place to avoid regression.
|
||||
- Future module plugins should register through `plugin-registry.ts` rather than editing the setup wizard directly.
|
||||
167
docs/implementation/task-p.7.2-implementation.md
Normal file
167
docs/implementation/task-p.7.2-implementation.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# Task P.7.2 Implementation Report
|
||||
|
||||
## Scope
|
||||
|
||||
This round implements the first working slice of the SMTP / Email Configuration Platform for ALLA OS.
|
||||
|
||||
Delivered scope:
|
||||
|
||||
- organization-scoped email configuration persistence
|
||||
- encrypted SMTP password storage
|
||||
- CRUD APIs for email configurations
|
||||
- SMTP connection test
|
||||
- send test email action
|
||||
- setup readiness / verification integration
|
||||
- setup wizard optional email status card
|
||||
- dashboard-native email administration page
|
||||
- notification runtime integration so email sending uses the stored organization configuration
|
||||
|
||||
## Review Summary
|
||||
|
||||
Reviewed before implementation:
|
||||
|
||||
- [AGENTS.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/AGENTS.md)
|
||||
- [docs/standards/project-foundations.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/standards/project-foundations.md)
|
||||
- [docs/standards/architecture-rules.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/standards/architecture-rules.md)
|
||||
- [docs/standards/ui-ux-rules.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/standards/ui-ux-rules.md)
|
||||
- [docs/standards/task-review-checklist.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/standards/task-review-checklist.md)
|
||||
- [docs/setup/verification-matrix.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/setup/verification-matrix.md)
|
||||
- [docs/setup/setup-wizard-blueprint.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/setup/setup-wizard-blueprint.md)
|
||||
- [docs/setup/installation-profiles.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/setup/installation-profiles.md)
|
||||
- [docs/implementation/task-d72-setup-readiness-verification-apis.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/implementation/task-d72-setup-readiness-verification-apis.md)
|
||||
- [docs/implementation/task-d76-dashboard-setup-wizard-ui.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/implementation/task-d76-dashboard-setup-wizard-ui.md)
|
||||
- [docs/implementation/task-f4-notification-framework-foundation.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/implementation/task-f4-notification-framework-foundation.md)
|
||||
- [docs/implementation/task-p.7.1-implementation.md](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/docs/implementation/task-p.7.1-implementation.md)
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
The implementation intentionally extends the existing notification foundation instead of creating a second outbound-email stack.
|
||||
|
||||
Key decisions:
|
||||
|
||||
- persisted email configuration is organization-scoped in a new `email_configurations` table
|
||||
- secret encryption is isolated in a reusable helper at [src/features/foundation/secrets/server/crypto.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/secrets/server/crypto.ts)
|
||||
- the notification runtime keeps using the existing provider factory, but the email provider now resolves organization SMTP config from the new foundation
|
||||
- setup readiness and setup verification both read from the same persisted source of truth instead of environment-only `SMTP_*` variables
|
||||
- the setup wizard keeps email as an optional operator step, matching the task requirement that email must not block first-run setup by default
|
||||
|
||||
## Main Changes
|
||||
|
||||
### 1. Data Model And Secret Handling
|
||||
|
||||
Added:
|
||||
|
||||
- [src/db/schema.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/db/schema.ts)
|
||||
- [drizzle/0001_yellow_wasp.sql](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/drizzle/0001_yellow_wasp.sql)
|
||||
- [src/features/foundation/secrets/server/crypto.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/secrets/server/crypto.ts)
|
||||
|
||||
Behavior:
|
||||
|
||||
- SMTP passwords are stored only as encrypted ciphertext
|
||||
- API responses never return decrypted or raw password values
|
||||
- UI only receives `hasPassword`
|
||||
- missing or weak `EMAIL_CONFIG_ENCRYPTION_KEY` blocks encryption-dependent save paths
|
||||
|
||||
### 2. Email Foundation Services
|
||||
|
||||
Added:
|
||||
|
||||
- [src/features/foundation/email/server/email-provider.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/server/email-provider.ts)
|
||||
- [src/features/foundation/email/server/smtp-provider.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/server/smtp-provider.ts)
|
||||
- [src/features/foundation/email/server/email-config.service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/server/email-config.service.ts)
|
||||
- [src/features/foundation/email/server/email-test.service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/server/email-test.service.ts)
|
||||
|
||||
Behavior:
|
||||
|
||||
- create, update, list, fetch, and delete email configs
|
||||
- track default / active config
|
||||
- test connection and test send update `last_test_status`, `last_tested_at`, and safe `last_test_error`
|
||||
- audit events are written for create, update, delete, and test outcomes
|
||||
|
||||
### 3. Notification Runtime Integration
|
||||
|
||||
Updated:
|
||||
|
||||
- [src/features/foundation/notifications/server/email-provider.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/notifications/server/email-provider.ts)
|
||||
- [src/features/foundation/notifications/server/provider-factory.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/notifications/server/provider-factory.ts)
|
||||
- [src/features/foundation/notifications/server/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/notifications/server/service.ts)
|
||||
|
||||
Behavior:
|
||||
|
||||
- email dispatches now resolve SMTP settings from the active organization configuration
|
||||
- the provider factory now receives `organizationId`
|
||||
- existing notification send / resend flows continue using the established foundation contract
|
||||
|
||||
### 4. Setup Integration
|
||||
|
||||
Updated:
|
||||
|
||||
- [src/features/setup/server/readiness.service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/setup/server/readiness.service.ts)
|
||||
- [src/features/setup/server/verification.service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/setup/server/verification.service.ts)
|
||||
- [src/features/setup/components/setup-wizard.tsx](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/setup/components/setup-wizard.tsx)
|
||||
- [src/features/foundation/email/components/setup-email-card.tsx](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/components/setup-email-card.tsx)
|
||||
|
||||
Behavior:
|
||||
|
||||
- readiness and verification now check persisted organization email config
|
||||
- no configuration returns `WARNING`, not `FAIL`, so setup remains non-blocking by default
|
||||
- a lightweight email status card is shown inside the setup wizard and links to the email admin page
|
||||
|
||||
### 5. Admin APIs And UI
|
||||
|
||||
Added APIs:
|
||||
|
||||
- [src/app/api/notifications/email-configurations/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/notifications/email-configurations/route.ts)
|
||||
- [src/app/api/notifications/email-configurations/[id]/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/notifications/email-configurations/[id]/route.ts)
|
||||
- [src/app/api/notifications/email-configurations/[id]/test/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/notifications/email-configurations/[id]/test/route.ts)
|
||||
- [src/app/api/notifications/email-configurations/[id]/send-test/route.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/api/notifications/email-configurations/[id]/send-test/route.ts)
|
||||
|
||||
Added client layer:
|
||||
|
||||
- [src/features/foundation/email/api/types.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/api/types.ts)
|
||||
- [src/features/foundation/email/api/service.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/api/service.ts)
|
||||
- [src/features/foundation/email/api/queries.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/api/queries.ts)
|
||||
- [src/features/foundation/email/api/mutations.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/api/mutations.ts)
|
||||
|
||||
Added page:
|
||||
|
||||
- [src/app/dashboard/administration/email/page.tsx](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/app/dashboard/administration/email/page.tsx)
|
||||
- [src/features/foundation/email/components/email-configuration-page.tsx](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/features/foundation/email/components/email-configuration-page.tsx)
|
||||
- [src/config/nav-config.ts](/C:/Users/mtpphtaps/Documents/gitea/alla-allaos-fullstack/src/config/nav-config.ts)
|
||||
|
||||
UI notes:
|
||||
|
||||
- layout follows dashboard-native card rhythm rather than a separate visual system
|
||||
- top summary area keeps status scannable
|
||||
- quick verification panel gives one stable place for test-recipient entry
|
||||
- config cards separate transport, sender identity, secret state, and test state clearly
|
||||
- operator notes are intentionally calm and low-noise per task request
|
||||
|
||||
## Validation
|
||||
|
||||
Executed:
|
||||
|
||||
- `npm run typecheck -- --pretty false`
|
||||
- `npm run db:generate`
|
||||
- `npm run test:setup`
|
||||
- `npx oxlint src/features/foundation/email src/features/foundation/secrets src/features/foundation/notifications/server/email-provider.ts src/features/foundation/notifications/server/provider-factory.ts src/features/setup/server/readiness.service.ts src/features/setup/server/verification.service.ts src/features/setup/components/setup-wizard.tsx src/app/api/notifications/email-configurations src/app/dashboard/administration/email/page.tsx src/config/nav-config.ts`
|
||||
|
||||
Results:
|
||||
|
||||
- TypeScript passed
|
||||
- Drizzle migration generated successfully
|
||||
- setup test suite passed
|
||||
- targeted lint passed
|
||||
|
||||
## Known Gaps After This Round
|
||||
|
||||
- no dedicated profile-level rule yet to force email as a blocking setup requirement for selected installation profiles
|
||||
- no password reset or invitation flow integration yet; this round only builds the platform and runtime foundation
|
||||
- no seeded email templates or notification-template management UI specific to outbound email yet
|
||||
- no per-configuration preview panel for rendered notification payloads yet
|
||||
- no explicit soft-delete or archived state; delete currently removes the configuration row
|
||||
|
||||
## Notes
|
||||
|
||||
- This implementation assumes `EMAIL_CONFIG_ENCRYPTION_KEY` will be added to runtime environments before operators save SMTP passwords.
|
||||
- Existing unrelated dirty files in the worktree were left untouched.
|
||||
20
docs/setup/installation-profiles.md
Normal file
20
docs/setup/installation-profiles.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Installation Profiles
|
||||
|
||||
Installation profiles select setup plugins, wizard steps, required templates, verification checks, reset scopes, and reseed targets.
|
||||
|
||||
Current profiles:
|
||||
|
||||
- `crm_starter`: foundation plus CRM structure.
|
||||
- `crm_demo`: foundation plus CRM golden/demo dataset.
|
||||
- `production`: foundation plus CRM production setup, with destructive maintenance disabled by default.
|
||||
- `restore_backup`: minimal readiness and verification for restored environments.
|
||||
- `custom`: operator-selected setup modules and templates.
|
||||
|
||||
Profiles are resolved by `src/features/setup/plugins/plugin-registry.ts` and exposed by:
|
||||
|
||||
- `GET /api/setup/profiles`
|
||||
- `GET /api/setup/templates?profile=<profileId>`
|
||||
- `GET /api/setup/readiness?profile=<profileId>`
|
||||
- `POST /api/setup/verify` with optional `profileId`
|
||||
|
||||
The setup wizard uses the selected profile to render profile-aware plugin metadata and wizard steps.
|
||||
81
docs/setup/integration-scenarios.md
Normal file
81
docs/setup/integration-scenarios.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Setup Integration Scenarios
|
||||
|
||||
This document defines the D.7.10 setup integration workflow and the golden dataset validation contract.
|
||||
|
||||
## Golden Dataset
|
||||
|
||||
Source: `setup/golden-dataset/`
|
||||
|
||||
The dataset must remain compatible with `setup/templates/templates.json` and must not introduce business behavior beyond existing setup/import contracts.
|
||||
|
||||
## Scenario 1: Fresh Install Smoke
|
||||
|
||||
1. Start from an empty local or CI database.
|
||||
2. Run migrations.
|
||||
3. Run setup readiness.
|
||||
4. Start a setup run.
|
||||
5. Preview every CSV in `setup/golden-dataset/`.
|
||||
6. Commit with the returned `previewHash`.
|
||||
7. Run verification.
|
||||
8. Complete setup.
|
||||
9. Confirm seed manifests and setup run report exist.
|
||||
|
||||
Expected result: setup completes without manual SQL.
|
||||
|
||||
## Scenario 2: Idempotent Import
|
||||
|
||||
1. Preview and commit the full golden dataset.
|
||||
2. Preview and commit the same files again.
|
||||
3. Preview and commit the same files a third time.
|
||||
|
||||
Expected result: repeated imports produce update/skip behavior and do not create duplicate business-key records.
|
||||
|
||||
## Scenario 3: Preview Hash Rejection
|
||||
|
||||
1. Preview the golden dataset.
|
||||
2. Modify one CSV row.
|
||||
3. Attempt commit using the old `previewHash`.
|
||||
|
||||
Expected result: commit is rejected and requires re-preview.
|
||||
|
||||
## Scenario 4: Resume
|
||||
|
||||
1. Start setup run.
|
||||
2. Save readiness and CSV preview steps.
|
||||
3. Refresh browser or call `GET /api/setup/run/current`.
|
||||
|
||||
Expected result: persisted setup run and step statuses are returned without raw CSV contents.
|
||||
|
||||
## Scenario 5: Reset Safety
|
||||
|
||||
1. Preview `business_reset` with a target organization.
|
||||
2. Execute only after matching preview hash, token, and typed phrase.
|
||||
3. Preview `setup_run_reset`.
|
||||
4. Confirm blocked reports for `foundation_reset`, `organization_reset`, `demo_uat_reset`, `full_reset`, and `csv_import_rollback`.
|
||||
|
||||
Expected result: only explicitly supported safe reset paths execute; unsupported reset paths return blocking reports.
|
||||
|
||||
## Scenario 6: Operational Readiness
|
||||
|
||||
After setup completes, verify these domains are ready:
|
||||
|
||||
- login
|
||||
- CRM dashboard
|
||||
- customer list and detail
|
||||
- lead list and detail
|
||||
- opportunity list and detail
|
||||
- quotation list and detail
|
||||
- quotation approval routing
|
||||
- document sequence previews
|
||||
- PDF/document template readiness
|
||||
- setup report and seed manifest report
|
||||
|
||||
## Automated Contract Tests
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
npm run test:setup
|
||||
```
|
||||
|
||||
These tests validate golden dataset headers, counts, import ordering, reset/reseed API surfaces, setup state surfaces, and non-destructive reset policy contracts.
|
||||
27
docs/setup/setup-performance-report.md
Normal file
27
docs/setup/setup-performance-report.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Setup Performance Report
|
||||
|
||||
Date: 2026-07-03
|
||||
|
||||
## Targets
|
||||
|
||||
- Preview 1000 rows: under 5 seconds.
|
||||
- Commit 1000 rows: under 10 seconds.
|
||||
- Verification: under 3 seconds.
|
||||
- Setup Wizard load: under 2 seconds.
|
||||
|
||||
## D.7.10 Status
|
||||
|
||||
D.7.10 adds the golden dataset and runnable setup contract tests. A dedicated isolated performance database harness is not yet present in this repository, so this report records targets and the contract coverage that protects future performance testing.
|
||||
|
||||
## Current Automated Coverage
|
||||
|
||||
- Golden dataset row counts and CSV headers.
|
||||
- Template registry compatibility.
|
||||
- Import order compatibility.
|
||||
- Preview hash mutation semantics.
|
||||
- Seed manifest and resume API surface existence.
|
||||
- Reset/reseed safety API surface existence.
|
||||
|
||||
## Follow-Up
|
||||
|
||||
Add a CI-only isolated database harness that can safely run the full fresh database workflow and record elapsed times for preview, commit, verification, and wizard load.
|
||||
37
docs/setup/setup-plugin-development.md
Normal file
37
docs/setup/setup-plugin-development.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Setup Plugin Development
|
||||
|
||||
Setup plugins let modules extend setup without editing the setup wizard directly.
|
||||
|
||||
Plugin source lives under:
|
||||
|
||||
```text
|
||||
src/features/setup/plugins/
|
||||
```
|
||||
|
||||
Required plugin contract:
|
||||
|
||||
- plugin id and version
|
||||
- installation profiles
|
||||
- setup templates
|
||||
- wizard steps
|
||||
- readiness checks
|
||||
- verification checks
|
||||
- CSV preview validators
|
||||
- import handlers
|
||||
- reset scopes
|
||||
- reseed targets
|
||||
- golden dataset registration
|
||||
|
||||
Core plugins:
|
||||
|
||||
- `foundation`: setup platform foundations, state, seed manifests, reset framework, CSV framework
|
||||
- `crm`: CRM templates, CRM verification, CRM reset scopes, and CRM golden dataset
|
||||
|
||||
Future modules should add a plugin class and register it in `plugin-registry.ts`. They should not add one-off setup logic directly to the wizard.
|
||||
|
||||
Safety rules:
|
||||
|
||||
- Plugins cannot bypass Auth.js setup route protection.
|
||||
- Reset scopes must declare destructive behavior and affected tables.
|
||||
- CSV templates must declare ownership to avoid duplicate file contracts.
|
||||
- Seed tasks must be idempotent before execution is exposed.
|
||||
@@ -446,11 +446,12 @@ CREATE TABLE "crm_leads" (
|
||||
"description" text,
|
||||
"project_name" text,
|
||||
"project_location" text,
|
||||
"lead_channel" text,
|
||||
"product_type" text,
|
||||
"priority" text,
|
||||
"estimated_value" double precision,
|
||||
"awareness_id" text,
|
||||
"status" text DEFAULT 'new_job' NOT NULL,
|
||||
"status" text NOT NULL,
|
||||
"followup_status" text,
|
||||
"lost_reason" text,
|
||||
"outcome" text DEFAULT 'open' NOT NULL,
|
||||
@@ -486,10 +487,14 @@ CREATE TABLE "crm_opportunities" (
|
||||
"estimated_value" double precision,
|
||||
"chance_percent" integer,
|
||||
"expected_close_date" timestamp with time zone,
|
||||
"project_close_date" timestamp with time zone,
|
||||
"delivery_date" timestamp with time zone,
|
||||
"competitor" text,
|
||||
"source" text,
|
||||
"notes" text,
|
||||
"is_hot_project" boolean DEFAULT false NOT NULL,
|
||||
"hot_project_auto_suggested" boolean DEFAULT false NOT NULL,
|
||||
"hot_project_manually_overridden" boolean DEFAULT false NOT NULL,
|
||||
"is_active" boolean DEFAULT true NOT NULL,
|
||||
"pipeline_stage" text DEFAULT 'lead' NOT NULL,
|
||||
"closed_at" timestamp with time zone,
|
||||
@@ -687,7 +692,11 @@ CREATE TABLE "crm_quotations" (
|
||||
"tax_amount" double precision DEFAULT 0 NOT NULL,
|
||||
"total_amount" double precision DEFAULT 0 NOT NULL,
|
||||
"chance_percent" integer,
|
||||
"project_close_date" timestamp with time zone,
|
||||
"delivery_date" timestamp with time zone,
|
||||
"is_hot_project" boolean DEFAULT false NOT NULL,
|
||||
"hot_project_auto_suggested" boolean DEFAULT false NOT NULL,
|
||||
"hot_project_manually_overridden" boolean DEFAULT false NOT NULL,
|
||||
"competitor" text,
|
||||
"salesman_id" text,
|
||||
"is_sent" boolean DEFAULT false NOT NULL,
|
||||
@@ -829,6 +838,70 @@ CREATE TABLE "products" (
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "seed_manifest_items" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"seed_manifest_id" text NOT NULL,
|
||||
"item_key" text NOT NULL,
|
||||
"source_file" text NOT NULL,
|
||||
"checksum" text NOT NULL,
|
||||
"status" text DEFAULT 'pending' NOT NULL,
|
||||
"imported_count" integer DEFAULT 0 NOT NULL,
|
||||
"updated_count" integer DEFAULT 0 NOT NULL,
|
||||
"skipped_count" integer DEFAULT 0 NOT NULL,
|
||||
"error_count" integer DEFAULT 0 NOT NULL,
|
||||
"warning_count" integer DEFAULT 0 NOT NULL,
|
||||
"report_json" jsonb,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "seed_manifests" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"setup_run_id" text,
|
||||
"organization_id" text,
|
||||
"name" text NOT NULL,
|
||||
"version" text NOT NULL,
|
||||
"type" text NOT NULL,
|
||||
"checksum" text NOT NULL,
|
||||
"status" text DEFAULT 'pending' NOT NULL,
|
||||
"source" text NOT NULL,
|
||||
"applied_by" text,
|
||||
"applied_at" timestamp with time zone,
|
||||
"report_json" jsonb,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "setup_run_steps" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"setup_run_id" text NOT NULL,
|
||||
"step_key" text NOT NULL,
|
||||
"status" text DEFAULT 'not_started' NOT NULL,
|
||||
"input_hash" text,
|
||||
"output_json" jsonb,
|
||||
"errors_json" jsonb,
|
||||
"warnings_json" jsonb,
|
||||
"started_at" timestamp with time zone,
|
||||
"completed_at" timestamp with time zone,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "setup_runs" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"status" text DEFAULT 'not_started' NOT NULL,
|
||||
"mode" text DEFAULT 'production' NOT NULL,
|
||||
"target_organization_id" text,
|
||||
"started_by" text NOT NULL,
|
||||
"completed_by" text,
|
||||
"started_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"completed_at" timestamp with time zone,
|
||||
"last_error" text,
|
||||
"metadata" jsonb,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "tr_audit_logs" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"organization_id" text NOT NULL,
|
||||
@@ -879,4 +952,6 @@ CREATE UNIQUE INDEX "crm_user_role_assignments_org_user_role_idx" ON "crm_user_r
|
||||
CREATE UNIQUE INDEX "document_sequences_org_branch_product_doc_period_idx" ON "document_sequences" USING btree ("organization_id","branch_id","product_type","document_type","period");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "ms_options_org_category_code_idx" ON "ms_options" USING btree ("organization_id","category","code");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "organizations_slug_idx" ON "organizations" USING btree ("slug");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "seed_manifest_items_manifest_item_idx" ON "seed_manifest_items" USING btree ("seed_manifest_id","item_key");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "setup_run_steps_run_step_idx" ON "setup_run_steps" USING btree ("setup_run_id","step_key");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "users_email_idx" ON "users" USING btree ("email");
|
||||
@@ -1,5 +0,0 @@
|
||||
ALTER TABLE "crm_leads"
|
||||
ADD COLUMN IF NOT EXISTS "lead_channel" text;
|
||||
|
||||
ALTER TABLE "crm_leads"
|
||||
ALTER COLUMN "status" DROP DEFAULT;
|
||||
25
drizzle/0001_yellow_wasp.sql
Normal file
25
drizzle/0001_yellow_wasp.sql
Normal file
@@ -0,0 +1,25 @@
|
||||
CREATE TABLE "email_configurations" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"organization_id" text NOT NULL,
|
||||
"provider_type" text DEFAULT 'smtp' NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"host" text NOT NULL,
|
||||
"port" integer DEFAULT 587 NOT NULL,
|
||||
"secure" boolean DEFAULT false NOT NULL,
|
||||
"username" text,
|
||||
"password_encrypted" text,
|
||||
"from_email" text NOT NULL,
|
||||
"from_name" text,
|
||||
"reply_to_email" text,
|
||||
"is_default" boolean DEFAULT false NOT NULL,
|
||||
"is_active" boolean DEFAULT true NOT NULL,
|
||||
"last_test_status" text DEFAULT 'not_tested' NOT NULL,
|
||||
"last_tested_at" timestamp with time zone,
|
||||
"last_test_error" text,
|
||||
"created_by" text NOT NULL,
|
||||
"updated_by" text NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "email_configurations_org_name_idx" ON "email_configurations" USING btree ("organization_id","name");
|
||||
@@ -1,11 +0,0 @@
|
||||
ALTER TABLE "crm_opportunities"
|
||||
ADD COLUMN "project_close_date" timestamp with time zone,
|
||||
ADD COLUMN "delivery_date" timestamp with time zone,
|
||||
ADD COLUMN "hot_project_auto_suggested" boolean DEFAULT false NOT NULL,
|
||||
ADD COLUMN "hot_project_manually_overridden" boolean DEFAULT false NOT NULL;
|
||||
|
||||
ALTER TABLE "crm_quotations"
|
||||
ADD COLUMN "project_close_date" timestamp with time zone,
|
||||
ADD COLUMN "delivery_date" timestamp with time zone,
|
||||
ADD COLUMN "hot_project_auto_suggested" boolean DEFAULT false NOT NULL,
|
||||
ADD COLUMN "hot_project_manually_overridden" boolean DEFAULT false NOT NULL;
|
||||
@@ -1,10 +0,0 @@
|
||||
ALTER TABLE "crm_leads" ALTER COLUMN "status" DROP DEFAULT;--> statement-breakpoint
|
||||
ALTER TABLE "crm_leads" ADD COLUMN "lead_channel" text;--> statement-breakpoint
|
||||
ALTER TABLE "crm_opportunities" ADD COLUMN "project_close_date" timestamp with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "crm_opportunities" ADD COLUMN "delivery_date" timestamp with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "crm_opportunities" ADD COLUMN "hot_project_auto_suggested" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "crm_opportunities" ADD COLUMN "hot_project_manually_overridden" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "crm_quotations" ADD COLUMN "project_close_date" timestamp with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "crm_quotations" ADD COLUMN "delivery_date" timestamp with time zone;--> statement-breakpoint
|
||||
ALTER TABLE "crm_quotations" ADD COLUMN "hot_project_auto_suggested" boolean DEFAULT false NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "crm_quotations" ADD COLUMN "hot_project_manually_overridden" boolean DEFAULT false NOT NULL;
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"id": "6eb8d614-2b85-48c3-919e-af8fa13f0fb6",
|
||||
"id": "6c217ceb-57e5-410e-9132-610c819272f2",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
@@ -3045,6 +3045,12 @@
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"lead_channel": {
|
||||
"name": "lead_channel",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"product_type": {
|
||||
"name": "product_type",
|
||||
"type": "text",
|
||||
@@ -3073,8 +3079,7 @@
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'new_job'"
|
||||
"notNull": true
|
||||
},
|
||||
"followup_status": {
|
||||
"name": "followup_status",
|
||||
@@ -3307,6 +3312,18 @@
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"project_close_date": {
|
||||
"name": "project_close_date",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"delivery_date": {
|
||||
"name": "delivery_date",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"competitor": {
|
||||
"name": "competitor",
|
||||
"type": "text",
|
||||
@@ -3332,6 +3349,20 @@
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"hot_project_auto_suggested": {
|
||||
"name": "hot_project_auto_suggested",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"hot_project_manually_overridden": {
|
||||
"name": "hot_project_manually_overridden",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"is_active": {
|
||||
"name": "is_active",
|
||||
"type": "boolean",
|
||||
@@ -4526,6 +4557,18 @@
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"project_close_date": {
|
||||
"name": "project_close_date",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"delivery_date": {
|
||||
"name": "delivery_date",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"is_hot_project": {
|
||||
"name": "is_hot_project",
|
||||
"type": "boolean",
|
||||
@@ -4533,6 +4576,20 @@
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"hot_project_auto_suggested": {
|
||||
"name": "hot_project_auto_suggested",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"hot_project_manually_overridden": {
|
||||
"name": "hot_project_manually_overridden",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"competitor": {
|
||||
"name": "competitor",
|
||||
"type": "text",
|
||||
@@ -5576,6 +5633,433 @@
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.seed_manifest_items": {
|
||||
"name": "seed_manifest_items",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"seed_manifest_id": {
|
||||
"name": "seed_manifest_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"item_key": {
|
||||
"name": "item_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"source_file": {
|
||||
"name": "source_file",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"checksum": {
|
||||
"name": "checksum",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'pending'"
|
||||
},
|
||||
"imported_count": {
|
||||
"name": "imported_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"updated_count": {
|
||||
"name": "updated_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"skipped_count": {
|
||||
"name": "skipped_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"error_count": {
|
||||
"name": "error_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"warning_count": {
|
||||
"name": "warning_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"report_json": {
|
||||
"name": "report_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"seed_manifest_items_manifest_item_idx": {
|
||||
"name": "seed_manifest_items_manifest_item_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "seed_manifest_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
},
|
||||
{
|
||||
"expression": "item_key",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": true,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.seed_manifests": {
|
||||
"name": "seed_manifests",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"setup_run_id": {
|
||||
"name": "setup_run_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"organization_id": {
|
||||
"name": "organization_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"version": {
|
||||
"name": "version",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"checksum": {
|
||||
"name": "checksum",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'pending'"
|
||||
},
|
||||
"source": {
|
||||
"name": "source",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"applied_by": {
|
||||
"name": "applied_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"applied_at": {
|
||||
"name": "applied_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"report_json": {
|
||||
"name": "report_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.setup_run_steps": {
|
||||
"name": "setup_run_steps",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"setup_run_id": {
|
||||
"name": "setup_run_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"step_key": {
|
||||
"name": "step_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not_started'"
|
||||
},
|
||||
"input_hash": {
|
||||
"name": "input_hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"output_json": {
|
||||
"name": "output_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"errors_json": {
|
||||
"name": "errors_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"warnings_json": {
|
||||
"name": "warnings_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "completed_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"setup_run_steps_run_step_idx": {
|
||||
"name": "setup_run_steps_run_step_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "setup_run_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
},
|
||||
{
|
||||
"expression": "step_key",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": true,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.setup_runs": {
|
||||
"name": "setup_runs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not_started'"
|
||||
},
|
||||
"mode": {
|
||||
"name": "mode",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'production'"
|
||||
},
|
||||
"target_organization_id": {
|
||||
"name": "target_organization_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"started_by": {
|
||||
"name": "started_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "completed_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "completed_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_error": {
|
||||
"name": "last_error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"metadata": {
|
||||
"name": "metadata",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.tr_audit_logs": {
|
||||
"name": "tr_audit_logs",
|
||||
"schema": "",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "be860157-9371-469d-84ec-aefc991ebddc",
|
||||
"prevId": "6eb8d614-2b85-48c3-919e-af8fa13f0fb6",
|
||||
"id": "3dc70e0a-e0ce-433d-9d4b-cb2ae6455ce7",
|
||||
"prevId": "6c217ceb-57e5-410e-9132-610c819272f2",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
@@ -5270,6 +5270,175 @@
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.email_configurations": {
|
||||
"name": "email_configurations",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"organization_id": {
|
||||
"name": "organization_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"provider_type": {
|
||||
"name": "provider_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'smtp'"
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"host": {
|
||||
"name": "host",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"port": {
|
||||
"name": "port",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 587
|
||||
},
|
||||
"secure": {
|
||||
"name": "secure",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"password_encrypted": {
|
||||
"name": "password_encrypted",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"from_email": {
|
||||
"name": "from_email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"from_name": {
|
||||
"name": "from_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"reply_to_email": {
|
||||
"name": "reply_to_email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"is_default": {
|
||||
"name": "is_default",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"is_active": {
|
||||
"name": "is_active",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": true
|
||||
},
|
||||
"last_test_status": {
|
||||
"name": "last_test_status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not_tested'"
|
||||
},
|
||||
"last_tested_at": {
|
||||
"name": "last_tested_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_test_error": {
|
||||
"name": "last_test_error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_by": {
|
||||
"name": "created_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"updated_by": {
|
||||
"name": "updated_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"email_configurations_org_name_idx": {
|
||||
"name": "email_configurations_org_name_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "organization_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
},
|
||||
{
|
||||
"expression": "name",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": true,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.memberships": {
|
||||
"name": "memberships",
|
||||
"schema": "",
|
||||
@@ -5633,6 +5802,433 @@
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.seed_manifest_items": {
|
||||
"name": "seed_manifest_items",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"seed_manifest_id": {
|
||||
"name": "seed_manifest_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"item_key": {
|
||||
"name": "item_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"source_file": {
|
||||
"name": "source_file",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"checksum": {
|
||||
"name": "checksum",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'pending'"
|
||||
},
|
||||
"imported_count": {
|
||||
"name": "imported_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"updated_count": {
|
||||
"name": "updated_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"skipped_count": {
|
||||
"name": "skipped_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"error_count": {
|
||||
"name": "error_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"warning_count": {
|
||||
"name": "warning_count",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"report_json": {
|
||||
"name": "report_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"seed_manifest_items_manifest_item_idx": {
|
||||
"name": "seed_manifest_items_manifest_item_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "seed_manifest_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
},
|
||||
{
|
||||
"expression": "item_key",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": true,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.seed_manifests": {
|
||||
"name": "seed_manifests",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"setup_run_id": {
|
||||
"name": "setup_run_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"organization_id": {
|
||||
"name": "organization_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"version": {
|
||||
"name": "version",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"type": {
|
||||
"name": "type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"checksum": {
|
||||
"name": "checksum",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'pending'"
|
||||
},
|
||||
"source": {
|
||||
"name": "source",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"applied_by": {
|
||||
"name": "applied_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"applied_at": {
|
||||
"name": "applied_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"report_json": {
|
||||
"name": "report_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.setup_run_steps": {
|
||||
"name": "setup_run_steps",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"setup_run_id": {
|
||||
"name": "setup_run_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"step_key": {
|
||||
"name": "step_key",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not_started'"
|
||||
},
|
||||
"input_hash": {
|
||||
"name": "input_hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"output_json": {
|
||||
"name": "output_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"errors_json": {
|
||||
"name": "errors_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"warnings_json": {
|
||||
"name": "warnings_json",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "completed_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"setup_run_steps_run_step_idx": {
|
||||
"name": "setup_run_steps_run_step_idx",
|
||||
"columns": [
|
||||
{
|
||||
"expression": "setup_run_id",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
},
|
||||
{
|
||||
"expression": "step_key",
|
||||
"isExpression": false,
|
||||
"asc": true,
|
||||
"nulls": "last"
|
||||
}
|
||||
],
|
||||
"isUnique": true,
|
||||
"concurrently": false,
|
||||
"method": "btree",
|
||||
"with": {}
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.setup_runs": {
|
||||
"name": "setup_runs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'not_started'"
|
||||
},
|
||||
"mode": {
|
||||
"name": "mode",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'production'"
|
||||
},
|
||||
"target_organization_id": {
|
||||
"name": "target_organization_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"started_by": {
|
||||
"name": "started_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"completed_by": {
|
||||
"name": "completed_by",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "completed_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"last_error": {
|
||||
"name": "last_error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"metadata": {
|
||||
"name": "metadata",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp with time zone",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.tr_audit_logs": {
|
||||
"name": "tr_audit_logs",
|
||||
"schema": "",
|
||||
@@ -5,29 +5,15 @@
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1782833951256,
|
||||
"tag": "0000_short_the_executioner",
|
||||
"when": 1783326039269,
|
||||
"tag": "0000_classy_unicorn",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1782896400000,
|
||||
"tag": "0001_lead_channel_and_status_default",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1782896500000,
|
||||
"tag": "0002_opportunity_quotation_timeline_hot_project",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 3,
|
||||
"version": "7",
|
||||
"when": 1782881325779,
|
||||
"tag": "0003_curious_wild_child",
|
||||
"when": 1783350585715,
|
||||
"tag": "0001_yellow_wasp",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
||||
173
onvalla-theme.css
Normal file
173
onvalla-theme.css
Normal file
@@ -0,0 +1,173 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
:root {
|
||||
--background: oklch(0.9816 0.0017 247.8390);
|
||||
--foreground: oklch(0.2277 0.0534 259.0168);
|
||||
--card: oklch(1.0000 0 0);
|
||||
--card-foreground: oklch(0.2277 0.0534 259.0168);
|
||||
--popover: oklch(1.0000 0 0);
|
||||
--popover-foreground: oklch(0.2277 0.0534 259.0168);
|
||||
--primary: oklch(0.3863 0.0858 321.9713);
|
||||
--primary-foreground: oklch(1.0000 0 0);
|
||||
--secondary: oklch(0.6340 0.2116 31.7828);
|
||||
--secondary-foreground: oklch(1.0000 0 0);
|
||||
--muted: oklch(0.9275 0.0017 247.8404);
|
||||
--muted-foreground: oklch(0.5751 0.0259 285.5573);
|
||||
--accent: oklch(0.6340 0.2116 31.7828);
|
||||
--accent-foreground: oklch(1.0000 0 0);
|
||||
--destructive: oklch(0.6340 0.2116 31.7828);
|
||||
--destructive-foreground: oklch(1.0000 0 0);
|
||||
--border: oklch(0.5751 0.0259 285.5573);
|
||||
--input: oklch(0.9275 0.0017 247.8404);
|
||||
--ring: oklch(0.3863 0.0858 321.9713);
|
||||
--chart-1: oklch(0.3863 0.0858 321.9713);
|
||||
--chart-2: oklch(0.6340 0.2116 31.7828);
|
||||
--chart-3: oklch(0.2277 0.0534 259.0168);
|
||||
--chart-4: oklch(0.5751 0.0259 285.5573);
|
||||
--chart-5: oklch(0.2185 0.0702 317.5316);
|
||||
--sidebar: oklch(1.0000 0 0);
|
||||
--sidebar-foreground: oklch(0.2277 0.0534 259.0168);
|
||||
--sidebar-primary: oklch(0.3863 0.0858 321.9713);
|
||||
--sidebar-primary-foreground: oklch(1.0000 0 0);
|
||||
--sidebar-accent: oklch(0.9275 0.0017 247.8404);
|
||||
--sidebar-accent-foreground: oklch(0.2277 0.0534 259.0168);
|
||||
--sidebar-border: oklch(0.9275 0.0017 247.8404);
|
||||
--sidebar-ring: oklch(0.3863 0.0858 321.9713);
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Georgia, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--radius: 0.5rem;
|
||||
--shadow-x: 0px;
|
||||
--shadow-y: 2px;
|
||||
--shadow-blur: 10px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-opacity: 0.1;
|
||||
--shadow-color: #000000;
|
||||
--shadow-2xs: 0px 2px 10px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-xs: 0px 2px 10px 0px hsl(0 0% 0% / 0.05);
|
||||
--shadow-sm: 0px 2px 10px 0px hsl(0 0% 0% / 0.10), 0px 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow: 0px 2px 10px 0px hsl(0 0% 0% / 0.10), 0px 1px 2px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-md: 0px 2px 10px 0px hsl(0 0% 0% / 0.10), 0px 2px 4px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-lg: 0px 2px 10px 0px hsl(0 0% 0% / 0.10), 0px 4px 6px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-xl: 0px 2px 10px 0px hsl(0 0% 0% / 0.10), 0px 8px 10px -1px hsl(0 0% 0% / 0.10);
|
||||
--shadow-2xl: 0px 2px 10px 0px hsl(0 0% 0% / 0.25);
|
||||
--tracking-normal: 0em;
|
||||
--spacing: 0.25rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.2277 0.0534 259.0168);
|
||||
--foreground: oklch(0.9275 0.0017 247.8404);
|
||||
--card: oklch(0.2185 0.0702 317.5316);
|
||||
--card-foreground: oklch(1.0000 0 0);
|
||||
--popover: oklch(0.2185 0.0702 317.5316);
|
||||
--popover-foreground: oklch(1.0000 0 0);
|
||||
--primary: oklch(0.3863 0.0858 321.9713);
|
||||
--primary-foreground: oklch(1.0000 0 0);
|
||||
--secondary: oklch(0.6340 0.2116 31.7828);
|
||||
--secondary-foreground: oklch(1.0000 0 0);
|
||||
--muted: oklch(0.5751 0.0259 285.5573);
|
||||
--muted-foreground: oklch(0.9275 0.0017 247.8404);
|
||||
--accent: oklch(0.6340 0.2116 31.7828);
|
||||
--accent-foreground: oklch(1.0000 0 0);
|
||||
--destructive: oklch(0.6340 0.2116 31.7828);
|
||||
--destructive-foreground: oklch(1.0000 0 0);
|
||||
--border: oklch(0.3863 0.0858 321.9713);
|
||||
--input: oklch(0.2277 0.0534 259.0168);
|
||||
--ring: oklch(0.6340 0.2116 31.7828);
|
||||
--chart-1: oklch(0.3863 0.0858 321.9713);
|
||||
--chart-2: oklch(0.6340 0.2116 31.7828);
|
||||
--chart-3: oklch(0.5751 0.0259 285.5573);
|
||||
--chart-4: oklch(0.2185 0.0702 317.5316);
|
||||
--chart-5: oklch(1.0000 0 0);
|
||||
--sidebar: oklch(0.2185 0.0702 317.5316);
|
||||
--sidebar-foreground: oklch(0.9275 0.0017 247.8404);
|
||||
--sidebar-primary: oklch(0.6340 0.2116 31.7828);
|
||||
--sidebar-primary-foreground: oklch(1.0000 0 0);
|
||||
--sidebar-accent: oklch(0.3863 0.0858 321.9713);
|
||||
--sidebar-accent-foreground: oklch(1.0000 0 0);
|
||||
--sidebar-border: oklch(0.3863 0.0858 321.9713);
|
||||
--sidebar-ring: oklch(0.6340 0.2116 31.7828);
|
||||
--font-sans: Inter, sans-serif;
|
||||
--font-serif: Georgia, serif;
|
||||
--font-mono: JetBrains Mono, monospace;
|
||||
--radius: 0.5rem;
|
||||
--shadow-x: 0px;
|
||||
--shadow-y: 4px;
|
||||
--shadow-blur: 12px;
|
||||
--shadow-spread: 0px;
|
||||
--shadow-opacity: 0.3;
|
||||
--shadow-color: #000000;
|
||||
--shadow-2xs: 0px 4px 12px 0px hsl(0 0% 0% / 0.15);
|
||||
--shadow-xs: 0px 4px 12px 0px hsl(0 0% 0% / 0.15);
|
||||
--shadow-sm: 0px 4px 12px 0px hsl(0 0% 0% / 0.30), 0px 1px 2px -1px hsl(0 0% 0% / 0.30);
|
||||
--shadow: 0px 4px 12px 0px hsl(0 0% 0% / 0.30), 0px 1px 2px -1px hsl(0 0% 0% / 0.30);
|
||||
--shadow-md: 0px 4px 12px 0px hsl(0 0% 0% / 0.30), 0px 2px 4px -1px hsl(0 0% 0% / 0.30);
|
||||
--shadow-lg: 0px 4px 12px 0px hsl(0 0% 0% / 0.30), 0px 4px 6px -1px hsl(0 0% 0% / 0.30);
|
||||
--shadow-xl: 0px 4px 12px 0px hsl(0 0% 0% / 0.30), 0px 8px 10px -1px hsl(0 0% 0% / 0.30);
|
||||
--shadow-2xl: 0px 4px 12px 0px hsl(0 0% 0% / 0.75);
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-destructive-foreground: var(--destructive-foreground);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
|
||||
--font-sans: var(--font-sans);
|
||||
--font-mono: var(--font-mono);
|
||||
--font-serif: var(--font-serif);
|
||||
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
|
||||
--shadow-2xs: var(--shadow-2xs);
|
||||
--shadow-xs: var(--shadow-xs);
|
||||
--shadow-sm: var(--shadow-sm);
|
||||
--shadow: var(--shadow);
|
||||
--shadow-md: var(--shadow-md);
|
||||
--shadow-lg: var(--shadow-lg);
|
||||
--shadow-xl: var(--shadow-xl);
|
||||
--shadow-2xl: var(--shadow-2xl);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
"lint": "oxlint",
|
||||
"lint:fix": "oxlint --fix && bun format",
|
||||
"lint:strict": "oxlint --deny-warnings",
|
||||
"test:setup": "node --disable-warning=ExperimentalWarning --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --experimental-strip-types --test src/tests/setup/*.test.ts",
|
||||
"format": "oxfmt --write .",
|
||||
"format:check": "oxfmt --check .",
|
||||
"prepare": "husky",
|
||||
|
||||
743
plans/task-d.7.10.md
Normal file
743
plans/task-d.7.10.md
Normal file
@@ -0,0 +1,743 @@
|
||||
# Task D.7.10 – Setup Integration Test & Golden Dataset
|
||||
|
||||
## Objective
|
||||
|
||||
Build a complete end-to-end integration test suite and Golden Dataset for the ALLA OS Setup Platform.
|
||||
|
||||
This task validates that a brand-new database can be transformed into a fully operational CRM system using only the Setup Platform.
|
||||
|
||||
The Golden Dataset becomes the canonical dataset for:
|
||||
|
||||
- Development
|
||||
- CI/CD
|
||||
- QA
|
||||
- UAT
|
||||
- Customer Demo
|
||||
- Regression Testing
|
||||
|
||||
This task must not introduce new business behavior. It verifies the implementation completed in D.7.1–D.7.8.
|
||||
|
||||
---
|
||||
|
||||
# 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
|
||||
- plans/task-d.7.6.md
|
||||
- plans/task-d.7.7.md
|
||||
- plans/task-d.7.8.md
|
||||
|
||||
Review
|
||||
|
||||
docs/setup/*
|
||||
|
||||
Review
|
||||
|
||||
setup/templates/*
|
||||
|
||||
Review
|
||||
|
||||
src/features/setup/**
|
||||
|
||||
Review
|
||||
|
||||
src/db/seeds/**
|
||||
|
||||
Review
|
||||
|
||||
CRM business modules
|
||||
|
||||
Customer
|
||||
|
||||
Lead
|
||||
|
||||
Opportunity
|
||||
|
||||
Quotation
|
||||
|
||||
Approval
|
||||
|
||||
PDF
|
||||
|
||||
Document Sequence
|
||||
|
||||
Storage
|
||||
|
||||
---
|
||||
|
||||
# Objective Validation
|
||||
|
||||
The following workflow must succeed without manual SQL.
|
||||
|
||||
Empty Database
|
||||
|
||||
↓
|
||||
|
||||
Migration
|
||||
|
||||
↓
|
||||
|
||||
Foundation Setup
|
||||
|
||||
↓
|
||||
|
||||
Organization Setup
|
||||
|
||||
↓
|
||||
|
||||
CSV Import
|
||||
|
||||
↓
|
||||
|
||||
Verification
|
||||
|
||||
↓
|
||||
|
||||
Login
|
||||
|
||||
↓
|
||||
|
||||
CRM Ready
|
||||
|
||||
↓
|
||||
|
||||
Quotation Ready
|
||||
|
||||
↓
|
||||
|
||||
Approval Ready
|
||||
|
||||
↓
|
||||
|
||||
PDF Ready
|
||||
|
||||
---
|
||||
|
||||
# Golden Dataset
|
||||
|
||||
Create
|
||||
|
||||
setup/golden-dataset/
|
||||
|
||||
Contents
|
||||
|
||||
README.md
|
||||
|
||||
dataset.json
|
||||
|
||||
organizations.csv
|
||||
|
||||
users.csv
|
||||
|
||||
memberships.csv
|
||||
|
||||
crm-role-assignments.csv
|
||||
|
||||
master-options.csv
|
||||
|
||||
branches.csv
|
||||
|
||||
product-types.csv
|
||||
|
||||
document-sequences.csv
|
||||
|
||||
approval-workflows.csv
|
||||
|
||||
approval-steps.csv
|
||||
|
||||
approval-matrix.csv
|
||||
|
||||
customers.csv
|
||||
|
||||
contacts.csv
|
||||
|
||||
contact-shares.csv
|
||||
|
||||
leads.csv
|
||||
|
||||
opportunities.csv
|
||||
|
||||
opportunity-parties.csv
|
||||
|
||||
quotations.csv
|
||||
|
||||
quotation-items.csv
|
||||
|
||||
quotation-parties.csv
|
||||
|
||||
quotation-topics.csv
|
||||
|
||||
quotation-topic-items.csv
|
||||
|
||||
This dataset becomes the official reference dataset.
|
||||
|
||||
---
|
||||
|
||||
# Dataset Rules
|
||||
|
||||
Organizations
|
||||
|
||||
ALLA
|
||||
|
||||
ONVALLA
|
||||
|
||||
Users
|
||||
|
||||
IT
|
||||
|
||||
Marketing
|
||||
|
||||
Sales
|
||||
|
||||
Sales Manager
|
||||
|
||||
CEO
|
||||
|
||||
Customers
|
||||
|
||||
At least
|
||||
|
||||
10
|
||||
|
||||
Contacts
|
||||
|
||||
At least
|
||||
|
||||
20
|
||||
|
||||
Leads
|
||||
|
||||
At least
|
||||
|
||||
20
|
||||
|
||||
Opportunities
|
||||
|
||||
At least
|
||||
|
||||
15
|
||||
|
||||
Quotations
|
||||
|
||||
At least
|
||||
|
||||
20
|
||||
|
||||
Include
|
||||
|
||||
Draft
|
||||
|
||||
Pending Approval
|
||||
|
||||
Approved
|
||||
|
||||
Rejected
|
||||
|
||||
Revision
|
||||
|
||||
Include
|
||||
|
||||
Multiple Branches
|
||||
|
||||
Multiple Product Types
|
||||
|
||||
Multiple Approval Levels
|
||||
|
||||
Multiple Currencies
|
||||
|
||||
Discount
|
||||
|
||||
Tax
|
||||
|
||||
Project Parties
|
||||
|
||||
Attachments metadata only
|
||||
|
||||
---
|
||||
|
||||
# Scenario Matrix
|
||||
|
||||
Create
|
||||
|
||||
docs/setup/integration-scenarios.md
|
||||
|
||||
Document
|
||||
|
||||
Scenario
|
||||
|
||||
Purpose
|
||||
|
||||
Expected Result
|
||||
|
||||
Required Dataset
|
||||
|
||||
Verification
|
||||
|
||||
Example
|
||||
|
||||
Scenario
|
||||
|
||||
Fresh Installation
|
||||
|
||||
↓
|
||||
|
||||
PASS
|
||||
|
||||
Scenario
|
||||
|
||||
Resume Setup
|
||||
|
||||
↓
|
||||
|
||||
PASS
|
||||
|
||||
Scenario
|
||||
|
||||
CSV Re-import
|
||||
|
||||
↓
|
||||
|
||||
Idempotent
|
||||
|
||||
Scenario
|
||||
|
||||
Duplicate Import
|
||||
|
||||
↓
|
||||
|
||||
No Duplicate
|
||||
|
||||
Scenario
|
||||
|
||||
Business Reset
|
||||
|
||||
↓
|
||||
|
||||
Foundation Retained
|
||||
|
||||
Scenario
|
||||
|
||||
Setup Run Reset
|
||||
|
||||
↓
|
||||
|
||||
Business Retained
|
||||
|
||||
Scenario
|
||||
|
||||
Preview Hash Changed
|
||||
|
||||
↓
|
||||
|
||||
Commit Blocked
|
||||
|
||||
Scenario
|
||||
|
||||
Verification After Import
|
||||
|
||||
↓
|
||||
|
||||
PASS
|
||||
|
||||
Scenario
|
||||
|
||||
Manifest Version Check
|
||||
|
||||
↓
|
||||
|
||||
PASS
|
||||
|
||||
---
|
||||
|
||||
# Automated Integration Tests
|
||||
|
||||
Create
|
||||
|
||||
src/tests/setup/
|
||||
|
||||
Recommended
|
||||
|
||||
setup-install.test.ts
|
||||
|
||||
setup-preview.test.ts
|
||||
|
||||
setup-commit.test.ts
|
||||
|
||||
setup-verification.test.ts
|
||||
|
||||
setup-resume.test.ts
|
||||
|
||||
setup-reset.test.ts
|
||||
|
||||
golden-dataset.test.ts
|
||||
|
||||
Tests must cover
|
||||
|
||||
Migration
|
||||
|
||||
↓
|
||||
|
||||
Readiness
|
||||
|
||||
↓
|
||||
|
||||
Template Registry
|
||||
|
||||
↓
|
||||
|
||||
Preview
|
||||
|
||||
↓
|
||||
|
||||
Commit
|
||||
|
||||
↓
|
||||
|
||||
Verification
|
||||
|
||||
↓
|
||||
|
||||
Manifest
|
||||
|
||||
↓
|
||||
|
||||
Resume
|
||||
|
||||
↓
|
||||
|
||||
Reset
|
||||
|
||||
---
|
||||
|
||||
# End-to-End Workflow Test
|
||||
|
||||
Automate
|
||||
|
||||
Fresh Database
|
||||
|
||||
↓
|
||||
|
||||
Run Migration
|
||||
|
||||
↓
|
||||
|
||||
Foundation Ready
|
||||
|
||||
↓
|
||||
|
||||
Create Organization
|
||||
|
||||
↓
|
||||
|
||||
Preview CSV
|
||||
|
||||
↓
|
||||
|
||||
Commit CSV
|
||||
|
||||
↓
|
||||
|
||||
Verification PASS
|
||||
|
||||
↓
|
||||
|
||||
Login
|
||||
|
||||
↓
|
||||
|
||||
Create Customer
|
||||
|
||||
↓
|
||||
|
||||
Create Lead
|
||||
|
||||
↓
|
||||
|
||||
Assign Opportunity
|
||||
|
||||
↓
|
||||
|
||||
Create Quotation
|
||||
|
||||
↓
|
||||
|
||||
Approval
|
||||
|
||||
↓
|
||||
|
||||
Generate PDF
|
||||
|
||||
↓
|
||||
|
||||
Completed
|
||||
|
||||
Every step must assert expected results.
|
||||
|
||||
---
|
||||
|
||||
# Idempotency Tests
|
||||
|
||||
Run
|
||||
|
||||
Import
|
||||
|
||||
↓
|
||||
|
||||
Import Again
|
||||
|
||||
↓
|
||||
|
||||
Import Again
|
||||
|
||||
Verify
|
||||
|
||||
No Duplicate
|
||||
|
||||
Only
|
||||
|
||||
Create
|
||||
|
||||
↓
|
||||
|
||||
Update
|
||||
|
||||
↓
|
||||
|
||||
Skip
|
||||
|
||||
Allowed.
|
||||
|
||||
---
|
||||
|
||||
# Preview Hash Tests
|
||||
|
||||
Verify
|
||||
|
||||
Preview
|
||||
|
||||
↓
|
||||
|
||||
Commit
|
||||
|
||||
↓
|
||||
|
||||
Modify CSV
|
||||
|
||||
↓
|
||||
|
||||
Commit
|
||||
|
||||
↓
|
||||
|
||||
Rejected
|
||||
|
||||
---
|
||||
|
||||
# Seed Manifest Tests
|
||||
|
||||
Verify
|
||||
|
||||
Manifest Created
|
||||
|
||||
↓
|
||||
|
||||
Manifest Item Created
|
||||
|
||||
↓
|
||||
|
||||
Checksum
|
||||
|
||||
↓
|
||||
|
||||
Version
|
||||
|
||||
↓
|
||||
|
||||
Status
|
||||
|
||||
↓
|
||||
|
||||
Resume
|
||||
|
||||
---
|
||||
|
||||
# Reset Tests
|
||||
|
||||
Verify
|
||||
|
||||
Business Reset
|
||||
|
||||
Deletes CRM
|
||||
|
||||
Keeps Foundation
|
||||
|
||||
Setup Run Reset
|
||||
|
||||
Deletes Setup Metadata
|
||||
|
||||
Keeps Business
|
||||
|
||||
Foundation Reset
|
||||
|
||||
Blocked
|
||||
|
||||
Organization Reset
|
||||
|
||||
Blocked
|
||||
|
||||
Production Reset
|
||||
|
||||
Blocked
|
||||
|
||||
CSV Rollback
|
||||
|
||||
Blocked
|
||||
|
||||
---
|
||||
|
||||
# Verification Tests
|
||||
|
||||
Verify
|
||||
|
||||
PASS
|
||||
|
||||
Environment
|
||||
|
||||
Database
|
||||
|
||||
Storage
|
||||
|
||||
Template
|
||||
|
||||
Approval
|
||||
|
||||
Document Sequence
|
||||
|
||||
Report Definitions
|
||||
|
||||
Notification Templates
|
||||
|
||||
Organization
|
||||
|
||||
Branch
|
||||
|
||||
Product Type
|
||||
|
||||
CRM Assignment
|
||||
|
||||
---
|
||||
|
||||
# Performance Targets
|
||||
|
||||
Preview
|
||||
|
||||
1000 rows
|
||||
|
||||
<5 seconds
|
||||
|
||||
Commit
|
||||
|
||||
1000 rows
|
||||
|
||||
<10 seconds
|
||||
|
||||
Verification
|
||||
|
||||
<3 seconds
|
||||
|
||||
Setup Wizard Load
|
||||
|
||||
<2 seconds
|
||||
|
||||
---
|
||||
|
||||
# Deliverables
|
||||
|
||||
setup/golden-dataset/
|
||||
|
||||
README.md
|
||||
|
||||
dataset.json
|
||||
|
||||
Official CSV Pack
|
||||
|
||||
docs/setup/integration-scenarios.md
|
||||
|
||||
Automated integration tests
|
||||
|
||||
Setup smoke test
|
||||
|
||||
Golden dataset validation
|
||||
|
||||
Performance report
|
||||
|
||||
---
|
||||
|
||||
# Acceptance Criteria
|
||||
|
||||
✓ Empty database can be fully initialized.
|
||||
|
||||
✓ Migration succeeds.
|
||||
|
||||
✓ Setup Wizard completes.
|
||||
|
||||
✓ Golden Dataset imports successfully.
|
||||
|
||||
✓ Verification returns PASS.
|
||||
|
||||
✓ Login works.
|
||||
|
||||
✓ Customer creation works.
|
||||
|
||||
✓ Lead workflow works.
|
||||
|
||||
✓ Opportunity workflow works.
|
||||
|
||||
✓ Quotation workflow works.
|
||||
|
||||
✓ Approval workflow works.
|
||||
|
||||
✓ PDF generation works.
|
||||
|
||||
✓ Document sequence works.
|
||||
|
||||
✓ Import is idempotent.
|
||||
|
||||
✓ Preview hash validation works.
|
||||
|
||||
✓ Seed manifests created.
|
||||
|
||||
✓ Resume works.
|
||||
|
||||
✓ Business reset works.
|
||||
|
||||
✓ Setup metadata reset works.
|
||||
|
||||
✓ Blocked reset scopes remain blocked.
|
||||
|
||||
✓ All automated integration tests pass.
|
||||
|
||||
✓ Golden Dataset becomes official regression dataset.
|
||||
|
||||
---
|
||||
|
||||
# Future
|
||||
|
||||
After D.7.10
|
||||
|
||||
Freeze the Setup Platform.
|
||||
|
||||
All future modules
|
||||
|
||||
(HR, Asset, Purchase, Inventory, Service, etc.)
|
||||
|
||||
must integrate with the existing Setup Platform rather than creating new setup or import mechanisms.
|
||||
|
||||
The Setup Platform becomes the single supported installation, onboarding, import, verification, and maintenance foundation for ALLA OS.
|
||||
340
plans/task-d.7.11.md
Normal file
340
plans/task-d.7.11.md
Normal file
@@ -0,0 +1,340 @@
|
||||
# Task D.7.11 – First-Run Bootstrap Setup Mode
|
||||
|
||||
## Objective
|
||||
|
||||
Implement first-run setup mode for ALLA OS.
|
||||
|
||||
When the database is newly migrated and the system has not been initialized, the app must automatically redirect users to a public bootstrap setup page without requiring login.
|
||||
|
||||
The bootstrap setup page allows uploading required CSV files, validates them, commits setup data, creates the first organization and administrator, marks setup as completed, and then redirects the user to login.
|
||||
|
||||
---
|
||||
|
||||
## Desired Flow
|
||||
|
||||
npm install
|
||||
npm run db:generate
|
||||
npm run db:migrate
|
||||
npm run dev
|
||||
|
||||
Open browser
|
||||
|
||||
If setup is not completed:
|
||||
|
||||
redirect to
|
||||
|
||||
/administration/setup
|
||||
|
||||
No login required.
|
||||
|
||||
User uploads CSV files:
|
||||
|
||||
- users.csv
|
||||
- organizations.csv
|
||||
- memberships.csv
|
||||
- master-options.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
- document-sequences.csv
|
||||
- approval-workflows.csv
|
||||
- approval-steps.csv
|
||||
- approval-matrix.csv
|
||||
- customers.csv
|
||||
- contacts.csv
|
||||
- leads.csv
|
||||
- opportunities.csv
|
||||
- quotations.csv
|
||||
- quotation-items.csv
|
||||
- quotation-parties.csv
|
||||
- quotation-topics.csv
|
||||
- quotation-topic-items.csv
|
||||
|
||||
Click Setup
|
||||
|
||||
System validates CSV
|
||||
|
||||
System commits data
|
||||
|
||||
System creates first admin
|
||||
|
||||
System marks setup completed
|
||||
|
||||
Redirect to login
|
||||
|
||||
User logs in and starts using the system
|
||||
|
||||
---
|
||||
|
||||
## Key Concept
|
||||
|
||||
There are now two setup modes:
|
||||
|
||||
1. Bootstrap Setup
|
||||
|
||||
Used before first login.
|
||||
|
||||
Route:
|
||||
|
||||
/administration/setup
|
||||
|
||||
No login required only when setup is not completed.
|
||||
|
||||
2. Admin Setup / Maintenance Setup
|
||||
|
||||
Used after login.
|
||||
|
||||
Route:
|
||||
|
||||
/dashboard/administration/setup
|
||||
|
||||
Requires super_admin.
|
||||
|
||||
---
|
||||
|
||||
## Required Behavior
|
||||
|
||||
## First Run Detection
|
||||
|
||||
Create setup status check:
|
||||
|
||||
System is not initialized when:
|
||||
|
||||
- no completed setup_run exists
|
||||
or
|
||||
- no super_admin user exists
|
||||
or
|
||||
- no organization exists
|
||||
or
|
||||
- no admin membership exists
|
||||
|
||||
System is initialized when:
|
||||
|
||||
- setup_run status = completed
|
||||
- at least one super_admin exists
|
||||
- at least one organization exists
|
||||
- admin membership exists
|
||||
|
||||
---
|
||||
|
||||
## Middleware Redirect
|
||||
|
||||
Update middleware behavior:
|
||||
|
||||
If setup is not completed:
|
||||
|
||||
allow only:
|
||||
|
||||
/administration/setup
|
||||
/api/setup/bootstrap/*
|
||||
/api/setup/templates
|
||||
/_next/*
|
||||
static assets
|
||||
|
||||
redirect all other routes to:
|
||||
|
||||
/administration/setup
|
||||
|
||||
If setup is completed:
|
||||
|
||||
/administration/setup redirects to:
|
||||
|
||||
/auth/sign-in
|
||||
|
||||
or
|
||||
|
||||
/dashboard
|
||||
|
||||
---
|
||||
|
||||
## Bootstrap Setup Page
|
||||
|
||||
Create:
|
||||
|
||||
src/app/administration/setup/page.tsx
|
||||
|
||||
This page must not use dashboard layout.
|
||||
|
||||
It should be a clean public setup page.
|
||||
|
||||
Show:
|
||||
|
||||
- System status
|
||||
- Required CSV upload
|
||||
- Template checklist
|
||||
- Preview result
|
||||
- Setup button
|
||||
- Completion screen
|
||||
|
||||
---
|
||||
|
||||
## Bootstrap APIs
|
||||
|
||||
Create public-but-guarded bootstrap APIs:
|
||||
|
||||
GET /api/setup/bootstrap/status
|
||||
|
||||
POST /api/setup/bootstrap/preview
|
||||
|
||||
POST /api/setup/bootstrap/commit
|
||||
|
||||
POST /api/setup/bootstrap/complete
|
||||
|
||||
These APIs do not require login only while setup is incomplete.
|
||||
|
||||
After setup is completed, these APIs must reject public access.
|
||||
|
||||
---
|
||||
|
||||
## Bootstrap Security
|
||||
|
||||
Even though no login is required, it must be protected by first-run rules.
|
||||
|
||||
Rules:
|
||||
|
||||
- Bootstrap APIs are enabled only when setup is incomplete.
|
||||
- Once completed, bootstrap APIs return 403.
|
||||
- Commit requires previewHash.
|
||||
- Commit re-runs preview.
|
||||
- Commit rejects hash mismatch.
|
||||
- Setup complete requires successful commit.
|
||||
- Never expose secrets.
|
||||
- Passwords from users.csv must be hashed.
|
||||
- No raw CSV contents are persisted.
|
||||
|
||||
Optional safety:
|
||||
|
||||
Require BOOTSTRAP_SETUP_TOKEN from .env if present.
|
||||
|
||||
If env exists:
|
||||
|
||||
User must enter token before setup.
|
||||
|
||||
---
|
||||
|
||||
## CSV Upload UX
|
||||
|
||||
The page should show required groups:
|
||||
|
||||
Foundation:
|
||||
|
||||
- users.csv
|
||||
- organizations.csv
|
||||
- memberships.csv
|
||||
- master-options.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
|
||||
Document / Approval:
|
||||
|
||||
- document-sequences.csv
|
||||
- approval-workflows.csv
|
||||
- approval-steps.csv
|
||||
- approval-matrix.csv
|
||||
|
||||
Business optional:
|
||||
|
||||
- customers.csv
|
||||
- contacts.csv
|
||||
- leads.csv
|
||||
- opportunities.csv
|
||||
- quotations.csv
|
||||
- quotation-items.csv
|
||||
- quotation-parties.csv
|
||||
- quotation-topics.csv
|
||||
- quotation-topic-items.csv
|
||||
|
||||
Allow partial setup:
|
||||
|
||||
Required minimum:
|
||||
|
||||
- users.csv
|
||||
- organizations.csv
|
||||
- memberships.csv
|
||||
- master-options.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
- document-sequences.csv
|
||||
- approval-workflows.csv
|
||||
- approval-steps.csv
|
||||
- approval-matrix.csv
|
||||
|
||||
Business CSV can be optional.
|
||||
|
||||
---
|
||||
|
||||
## Setup Completion
|
||||
|
||||
After successful commit:
|
||||
|
||||
- create setup_run completed
|
||||
- create seed_manifests
|
||||
- mark setup status completed
|
||||
- redirect to /auth/sign-in
|
||||
|
||||
Show message:
|
||||
|
||||
Setup completed. Please login with the administrator account from users.csv.
|
||||
|
||||
---
|
||||
|
||||
## Reuse Existing D.7 Work
|
||||
|
||||
Reuse:
|
||||
|
||||
- CSV templates from D.7.3
|
||||
- CSV preview engine from D.7.4
|
||||
- CSV commit engine from D.7.5
|
||||
- setup state from D.7.8
|
||||
- seed manifest from D.7.8
|
||||
- plugin profiles from D.7.9
|
||||
|
||||
Do not rewrite import engine.
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Dashboard setup redesign
|
||||
- New CSV format
|
||||
- Reset/reseed
|
||||
- Plugin marketplace
|
||||
- Production public setup after completed
|
||||
- Anonymous setup after system is initialized
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- Fresh database redirects to /administration/setup without login.
|
||||
- /administration/setup works before first login.
|
||||
- Bootstrap setup page can upload CSV files.
|
||||
- Preview validates CSV files.
|
||||
- Setup commit imports required setup data.
|
||||
- First admin user is created.
|
||||
- Organization is created.
|
||||
- Setup run is marked completed.
|
||||
- User is redirected to login.
|
||||
- After completion, /administration/setup no longer allows public setup.
|
||||
- After completion, dashboard setup requires super_admin.
|
||||
- Existing /dashboard/administration/setup remains available for maintenance.
|
||||
- No duplicate CSV validation/import logic is created.
|
||||
- Typecheck passes.
|
||||
|
||||
---
|
||||
|
||||
## Suggested Test
|
||||
|
||||
1. Drop/reset database.
|
||||
2. Run migration.
|
||||
3. Run dev server.
|
||||
4. Open `/`.
|
||||
5. Confirm redirect to `/administration/setup`.
|
||||
6. Upload required CSV files.
|
||||
7. Preview.
|
||||
8. Commit setup.
|
||||
9. Confirm redirect to login.
|
||||
10. Login with admin from CSV.
|
||||
11. Open dashboard.
|
||||
12. Confirm CRM works.
|
||||
13. Try opening `/administration/setup` again.
|
||||
14. Confirm public setup is blocked.
|
||||
355
plans/task-d.7.12.md
Normal file
355
plans/task-d.7.12.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# Task D.7.12 – Step-by-Step First-Run Required CSV Import
|
||||
|
||||
## Objective
|
||||
|
||||
Improve First-run Bootstrap Setup so required system CSV files are imported step-by-step instead of uploading all files at once.
|
||||
|
||||
The goal is to guide the user through each required setup dependency in the correct order:
|
||||
|
||||
Step 1 organizations.csv
|
||||
Step 2 users.csv
|
||||
Step 3 memberships.csv
|
||||
Step 4 crm-role-assignments.csv
|
||||
Step 5 master-options.csv
|
||||
Step 6 branches.csv
|
||||
Step 7 product-types.csv
|
||||
Step 8 document-sequences.csv
|
||||
Step 9 approval-workflows.csv
|
||||
Step 10 approval-steps.csv
|
||||
Step 11 approval-matrix.csv
|
||||
|
||||
After all required steps pass, optional business CSV import can be shown separately.
|
||||
|
||||
---
|
||||
|
||||
## Desired UX
|
||||
|
||||
Route:
|
||||
|
||||
/administration/setup
|
||||
|
||||
Show First-run Bootstrap Wizard.
|
||||
|
||||
Each step has:
|
||||
|
||||
- CSV file name
|
||||
- purpose
|
||||
- required columns
|
||||
- upload area
|
||||
- preview button
|
||||
- run/import button
|
||||
- result summary
|
||||
- PASS / WARNING / FAIL status
|
||||
- next button
|
||||
|
||||
User flow:
|
||||
|
||||
1. Upload organizations.csv
|
||||
2. Preview
|
||||
3. Run Import
|
||||
4. Step marked PASS
|
||||
5. Move to users.csv
|
||||
6. Repeat until all system-required CSV files are complete
|
||||
7. Show final verification
|
||||
8. Mark setup completed
|
||||
9. Redirect to login
|
||||
|
||||
---
|
||||
|
||||
## Required Import Steps
|
||||
|
||||
Use exact dependency order:
|
||||
|
||||
1. organizations.csv
|
||||
2. users.csv
|
||||
3. memberships.csv
|
||||
4. crm-role-assignments.csv
|
||||
5. master-options.csv
|
||||
6. branches.csv
|
||||
7. product-types.csv
|
||||
8. document-sequences.csv
|
||||
9. approval-workflows.csv
|
||||
10. approval-steps.csv
|
||||
11. approval-matrix.csv
|
||||
|
||||
Important:
|
||||
|
||||
If current import engine requires users before organizations because organizations.created_by_email resolves to users, support one of these approaches:
|
||||
|
||||
Option A:
|
||||
Use temporary bootstrap actor for organizations.csv.
|
||||
|
||||
Option B:
|
||||
Change order to users.csv first.
|
||||
|
||||
Decision must be documented before implementation.
|
||||
|
||||
Recommended decision:
|
||||
|
||||
Step 1 users.csv
|
||||
Step 2 organizations.csv
|
||||
Step 3 memberships.csv
|
||||
|
||||
because organizations.csv currently requires created_by_email.
|
||||
|
||||
---
|
||||
|
||||
## System Required Group
|
||||
|
||||
Define a bootstrap required group:
|
||||
|
||||
system_required
|
||||
|
||||
Files:
|
||||
|
||||
- users.csv
|
||||
- organizations.csv
|
||||
- memberships.csv
|
||||
- crm-role-assignments.csv
|
||||
- master-options.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
- document-sequences.csv
|
||||
- approval-workflows.csv
|
||||
- approval-steps.csv
|
||||
- approval-matrix.csv
|
||||
|
||||
Business optional group:
|
||||
|
||||
business_optional
|
||||
|
||||
Files:
|
||||
|
||||
- customers.csv
|
||||
- contacts.csv
|
||||
- contact-shares.csv
|
||||
- leads.csv
|
||||
- opportunities.csv
|
||||
- opportunity-parties.csv
|
||||
- quotations.csv
|
||||
- quotation-items.csv
|
||||
- quotation-parties.csv
|
||||
- quotation-topics.csv
|
||||
- quotation-topic-items.csv
|
||||
|
||||
---
|
||||
|
||||
## Implementation Scope
|
||||
|
||||
Update First-run Bootstrap UI:
|
||||
|
||||
src/app/administration/setup/page.tsx
|
||||
|
||||
or bootstrap setup component under:
|
||||
|
||||
src/features/setup/components/bootstrap-setup-wizard.tsx
|
||||
|
||||
Add step configuration:
|
||||
|
||||
src/features/setup/bootstrap/bootstrap-required-steps.ts
|
||||
|
||||
Each step defines:
|
||||
|
||||
- stepKey
|
||||
- fileName
|
||||
- title
|
||||
- description
|
||||
- required
|
||||
- dependsOn
|
||||
- template metadata
|
||||
- status
|
||||
- previewHash
|
||||
- import report
|
||||
|
||||
---
|
||||
|
||||
## API Reuse
|
||||
|
||||
Reuse existing APIs:
|
||||
|
||||
POST /api/setup/bootstrap/preview
|
||||
POST /api/setup/bootstrap/commit
|
||||
|
||||
Each step submits one CSV file at a time.
|
||||
|
||||
Do not create new import logic.
|
||||
|
||||
Commit flow per step:
|
||||
|
||||
1. Upload one file
|
||||
2. Preview
|
||||
3. Store previewHash for that step
|
||||
4. Commit same file with previewHash
|
||||
5. Persist step result
|
||||
6. Move to next step
|
||||
|
||||
---
|
||||
|
||||
## Persistence
|
||||
|
||||
Persist step status in setup_run_steps.
|
||||
|
||||
Step keys:
|
||||
|
||||
bootstrap_users
|
||||
bootstrap_organizations
|
||||
bootstrap_memberships
|
||||
bootstrap_crm_role_assignments
|
||||
bootstrap_master_options
|
||||
bootstrap_branches
|
||||
bootstrap_product_types
|
||||
bootstrap_document_sequences
|
||||
bootstrap_approval_workflows
|
||||
bootstrap_approval_steps
|
||||
bootstrap_approval_matrix
|
||||
|
||||
Each step stores safe output only.
|
||||
|
||||
No raw CSV contents.
|
||||
|
||||
---
|
||||
|
||||
## Dependency Rules
|
||||
|
||||
A step is locked until all dependsOn steps pass.
|
||||
|
||||
Example:
|
||||
|
||||
memberships.csv depends on:
|
||||
|
||||
- users.csv
|
||||
- organizations.csv
|
||||
|
||||
crm-role-assignments.csv depends on:
|
||||
|
||||
- users.csv
|
||||
- organizations.csv
|
||||
- memberships.csv
|
||||
- master-options.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
|
||||
document-sequences.csv depends on:
|
||||
|
||||
- organizations.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
|
||||
approval-steps.csv depends on:
|
||||
|
||||
- approval-workflows.csv
|
||||
|
||||
approval-matrix.csv depends on:
|
||||
|
||||
- approval-workflows.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
|
||||
---
|
||||
|
||||
## UI Requirements
|
||||
|
||||
Show left stepper:
|
||||
|
||||
System Required
|
||||
|
||||
- Users
|
||||
- Organizations
|
||||
- Memberships
|
||||
- CRM Roles
|
||||
- Master Options
|
||||
- Branches
|
||||
- Product Types
|
||||
- Document Sequences
|
||||
- Approval Workflows
|
||||
- Approval Steps
|
||||
- Approval Matrix
|
||||
|
||||
Optional Business Data
|
||||
|
||||
- Customers
|
||||
- Contacts
|
||||
- Leads
|
||||
- Opportunities
|
||||
- Quotations
|
||||
|
||||
Each step panel shows:
|
||||
|
||||
- What this file does
|
||||
- Required filename
|
||||
- Required headers
|
||||
- Sample template reference
|
||||
- Upload control
|
||||
- Preview result
|
||||
- Import result
|
||||
- Errors and suggested fixes
|
||||
|
||||
---
|
||||
|
||||
## Completion Rule
|
||||
|
||||
Setup can complete only when all system_required steps are PASS or WARNING acknowledged.
|
||||
|
||||
Then run:
|
||||
|
||||
POST /api/setup/bootstrap/complete
|
||||
|
||||
Completion must verify:
|
||||
|
||||
- super_admin exists
|
||||
- organization exists
|
||||
- membership exists
|
||||
- CRM role assignment exists
|
||||
- branch exists
|
||||
- product type exists
|
||||
- document sequence exists
|
||||
- approval workflow/matrix exists
|
||||
|
||||
After success:
|
||||
|
||||
redirect to /auth/sign-in
|
||||
|
||||
---
|
||||
|
||||
## Optional Business Import
|
||||
|
||||
After system_required completion, show optional step:
|
||||
|
||||
Import Business Data
|
||||
|
||||
Allow either:
|
||||
|
||||
- step-by-step business import
|
||||
or
|
||||
- batch upload all business CSV
|
||||
|
||||
This can be deferred if needed.
|
||||
|
||||
---
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- Changing CSV template format
|
||||
- Rewriting import engine
|
||||
- Dashboard setup wizard redesign
|
||||
- Reset/reseed
|
||||
- Plugin runtime changes
|
||||
- Business import advanced UI
|
||||
- Production public setup after completion
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- First-run setup imports required CSV files step-by-step.
|
||||
- Each step accepts only the expected CSV filename.
|
||||
- Each step has Preview and Run buttons.
|
||||
- Import cannot run without successful previewHash.
|
||||
- Next step is locked until dependencies pass.
|
||||
- Step status persists across refresh.
|
||||
- System cannot complete until all required steps pass.
|
||||
- Existing batch import engine remains unchanged.
|
||||
- No raw CSV contents are persisted.
|
||||
- Setup completion redirects to login.
|
||||
- After completion, public bootstrap setup is blocked.
|
||||
- Typecheck passes.
|
||||
528
plans/task-d.7.3.md
Normal file
528
plans/task-d.7.3.md
Normal file
@@ -0,0 +1,528 @@
|
||||
# Task D.7.3 – CSV Template Generator Static Template Pack
|
||||
|
||||
## Objective
|
||||
|
||||
Generate a complete static CSV template pack for ALLA OS Initial Setup.
|
||||
|
||||
The templates will become the official data contract for future CSV Preview (D.7.4) and CSV Import (D.7.5).
|
||||
|
||||
This task only creates template files and supporting metadata.
|
||||
|
||||
Do NOT implement CSV parsing, validation, import logic, seed execution, reset logic, or setup persistence.
|
||||
|
||||
---
|
||||
|
||||
## Review Before Implementation
|
||||
|
||||
Read and follow:
|
||||
|
||||
- AGENTS.md
|
||||
- plans/task-d.7.md
|
||||
- plans/task-d.7.1.md
|
||||
- plans/task-d.7.2.md
|
||||
- docs/setup/seed-matrix.md
|
||||
- docs/setup/csv-template-spec.md
|
||||
- docs/setup/import-mapping.md
|
||||
- docs/setup/setup-wizard-blueprint.md
|
||||
|
||||
Do not invent new columns.
|
||||
|
||||
CSV headers must exactly match csv-template-spec.md.
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
Create folder
|
||||
|
||||
setup/templates/
|
||||
|
||||
Generate the following files
|
||||
|
||||
organizations.csv
|
||||
|
||||
users.csv
|
||||
|
||||
memberships.csv
|
||||
|
||||
crm-role-assignments.csv
|
||||
|
||||
master-options.csv
|
||||
|
||||
branches.csv
|
||||
|
||||
product-types.csv
|
||||
|
||||
document-sequences.csv
|
||||
|
||||
approval-workflows.csv
|
||||
|
||||
approval-steps.csv
|
||||
|
||||
approval-matrix.csv
|
||||
|
||||
customers.csv
|
||||
|
||||
contacts.csv
|
||||
|
||||
contact-shares.csv
|
||||
|
||||
leads.csv
|
||||
|
||||
opportunities.csv
|
||||
|
||||
opportunity-parties.csv
|
||||
|
||||
quotations.csv
|
||||
|
||||
quotation-items.csv
|
||||
|
||||
quotation-parties.csv
|
||||
|
||||
quotation-topics.csv
|
||||
|
||||
quotation-topic-items.csv
|
||||
|
||||
---
|
||||
|
||||
## CSV Rules
|
||||
|
||||
Every CSV must contain
|
||||
|
||||
1 Header row
|
||||
|
||||
1 Safe sample row
|
||||
|
||||
UTF-8 encoding
|
||||
|
||||
Comma delimiter
|
||||
|
||||
LF line ending
|
||||
|
||||
No BOM if current repository standard already avoids BOM
|
||||
|
||||
No blank columns
|
||||
|
||||
No undocumented columns
|
||||
|
||||
No formulas
|
||||
|
||||
No secrets
|
||||
|
||||
No production data
|
||||
|
||||
No binary references
|
||||
|
||||
---
|
||||
|
||||
## Sample Data Convention
|
||||
|
||||
Use one consistent sample dataset.
|
||||
|
||||
Organization
|
||||
|
||||
ALLA
|
||||
|
||||
Branch
|
||||
|
||||
head_office
|
||||
|
||||
Product Type
|
||||
|
||||
crane
|
||||
|
||||
Currency
|
||||
|
||||
THB
|
||||
|
||||
Administrator
|
||||
|
||||
admin@example.com
|
||||
|
||||
Marketing
|
||||
|
||||
mk.uat@example.com
|
||||
|
||||
Sales
|
||||
|
||||
sales.uat@example.com
|
||||
|
||||
Manager
|
||||
|
||||
manager.uat@example.com
|
||||
|
||||
CEO
|
||||
|
||||
ceo.uat@example.com
|
||||
|
||||
Customer
|
||||
|
||||
CUS-001
|
||||
|
||||
Lead
|
||||
|
||||
LD-001
|
||||
|
||||
Opportunity
|
||||
|
||||
OP-001
|
||||
|
||||
Quotation
|
||||
|
||||
QT-HO-CR-2607-001
|
||||
|
||||
---
|
||||
|
||||
## Header Rules
|
||||
|
||||
Headers must exactly match
|
||||
|
||||
docs/setup/csv-template-spec.md
|
||||
|
||||
Do not
|
||||
|
||||
rename
|
||||
|
||||
reorder
|
||||
|
||||
remove
|
||||
|
||||
or add columns.
|
||||
|
||||
---
|
||||
|
||||
## CSV Safety
|
||||
|
||||
Passwords
|
||||
|
||||
Use placeholder only.
|
||||
|
||||
Example
|
||||
|
||||
ChangeMe123!
|
||||
|
||||
Never include
|
||||
|
||||
real password
|
||||
|
||||
API key
|
||||
|
||||
secret
|
||||
|
||||
JWT
|
||||
|
||||
SMTP credential
|
||||
|
||||
storage credential
|
||||
|
||||
real customer
|
||||
|
||||
real phone
|
||||
|
||||
real tax id
|
||||
|
||||
---
|
||||
|
||||
## Unsupported Templates
|
||||
|
||||
Do NOT create
|
||||
|
||||
departments.csv
|
||||
|
||||
teams.csv
|
||||
|
||||
warehouses.csv
|
||||
|
||||
sites.csv
|
||||
|
||||
services.csv
|
||||
|
||||
price-books.csv
|
||||
|
||||
tax-rates.csv
|
||||
|
||||
attachments.csv
|
||||
|
||||
email-settings.csv
|
||||
|
||||
Keep these documented only.
|
||||
|
||||
---
|
||||
|
||||
## README
|
||||
|
||||
Create
|
||||
|
||||
setup/templates/README.md
|
||||
|
||||
Document
|
||||
|
||||
Purpose
|
||||
|
||||
Supported Templates
|
||||
|
||||
Unsupported Templates
|
||||
|
||||
Import Order
|
||||
|
||||
Relationship Rules
|
||||
|
||||
Sample Dataset
|
||||
|
||||
Placeholder Rules
|
||||
|
||||
Future D.7.4 Preview Flow
|
||||
|
||||
---
|
||||
|
||||
## Import Order
|
||||
|
||||
Document import order.
|
||||
|
||||
Example
|
||||
|
||||
01 users.csv
|
||||
|
||||
02 organizations.csv
|
||||
|
||||
03 memberships.csv
|
||||
|
||||
04 crm-role-assignments.csv
|
||||
|
||||
05 master-options.csv
|
||||
|
||||
06 branches.csv
|
||||
|
||||
07 product-types.csv
|
||||
|
||||
08 document-sequences.csv
|
||||
|
||||
09 approval-workflows.csv
|
||||
|
||||
10 approval-steps.csv
|
||||
|
||||
11 approval-matrix.csv
|
||||
|
||||
12 customers.csv
|
||||
|
||||
13 contacts.csv
|
||||
|
||||
14 contact-shares.csv
|
||||
|
||||
15 leads.csv
|
||||
|
||||
16 opportunities.csv
|
||||
|
||||
17 opportunity-parties.csv
|
||||
|
||||
18 quotations.csv
|
||||
|
||||
19 quotation-items.csv
|
||||
|
||||
20 quotation-parties.csv
|
||||
|
||||
21 quotation-topics.csv
|
||||
|
||||
22 quotation-topic-items.csv
|
||||
|
||||
Import order must match
|
||||
|
||||
docs/setup/seed-matrix.md
|
||||
|
||||
---
|
||||
|
||||
## Optional Metadata
|
||||
|
||||
Create
|
||||
|
||||
setup/templates/templates.json
|
||||
|
||||
Structure
|
||||
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"generatedFrom": "docs/setup/csv-template-spec.md",
|
||||
"templates": [
|
||||
{
|
||||
"file": "customers.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 12,
|
||||
"supported": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
This metadata will be reused by D.7.6 Setup Wizard.
|
||||
|
||||
---
|
||||
|
||||
## Optional API
|
||||
|
||||
If simple and reusable
|
||||
|
||||
Create
|
||||
|
||||
GET /api/setup/templates
|
||||
|
||||
Return
|
||||
|
||||
Template Name
|
||||
|
||||
Seed Type
|
||||
|
||||
Import Order
|
||||
|
||||
Supported
|
||||
|
||||
Required Columns
|
||||
|
||||
Description
|
||||
|
||||
This API must be read-only.
|
||||
|
||||
Do NOT implement download or ZIP generation.
|
||||
|
||||
---
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
CSV Parser
|
||||
|
||||
CSV Validation
|
||||
|
||||
CSV Preview
|
||||
|
||||
CSV Commit
|
||||
|
||||
Seed Execution
|
||||
|
||||
Reset
|
||||
|
||||
Setup Wizard
|
||||
|
||||
Manifest
|
||||
|
||||
State Machine
|
||||
|
||||
Migrations
|
||||
|
||||
Business Logic Changes
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
setup/templates/
|
||||
|
||||
organizations.csv
|
||||
|
||||
users.csv
|
||||
|
||||
memberships.csv
|
||||
|
||||
crm-role-assignments.csv
|
||||
|
||||
master-options.csv
|
||||
|
||||
branches.csv
|
||||
|
||||
product-types.csv
|
||||
|
||||
document-sequences.csv
|
||||
|
||||
approval-workflows.csv
|
||||
|
||||
approval-steps.csv
|
||||
|
||||
approval-matrix.csv
|
||||
|
||||
customers.csv
|
||||
|
||||
contacts.csv
|
||||
|
||||
contact-shares.csv
|
||||
|
||||
leads.csv
|
||||
|
||||
opportunities.csv
|
||||
|
||||
opportunity-parties.csv
|
||||
|
||||
quotations.csv
|
||||
|
||||
quotation-items.csv
|
||||
|
||||
quotation-parties.csv
|
||||
|
||||
quotation-topics.csv
|
||||
|
||||
quotation-topic-items.csv
|
||||
|
||||
README.md
|
||||
|
||||
Optional
|
||||
|
||||
templates.json
|
||||
|
||||
Optional
|
||||
|
||||
GET /api/setup/templates
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
✓ Every supported CSV exists.
|
||||
|
||||
✓ Every CSV contains exactly
|
||||
|
||||
- one header row
|
||||
- one sample row
|
||||
|
||||
✓ Header names exactly match
|
||||
|
||||
docs/setup/csv-template-spec.md
|
||||
|
||||
✓ Sample data follows one consistent demo dataset.
|
||||
|
||||
✓ No unsupported CSV files are generated.
|
||||
|
||||
✓ No secrets or production data exist.
|
||||
|
||||
✓ README documents
|
||||
|
||||
- import order
|
||||
- relationship rules
|
||||
- placeholders
|
||||
- supported templates
|
||||
- unsupported templates
|
||||
|
||||
✓ templates.json (if implemented) matches generated CSV files.
|
||||
|
||||
✓ Optional API (if implemented) is read-only.
|
||||
|
||||
✓ No import logic or seed logic is implemented.
|
||||
|
||||
✓ Typecheck passes or unrelated failures are documented.
|
||||
|
||||
---
|
||||
|
||||
## Future Tasks
|
||||
|
||||
D.7.4
|
||||
|
||||
CSV Preview Validation Engine
|
||||
|
||||
D.7.5
|
||||
|
||||
CSV Commit Import Engine
|
||||
|
||||
D.7.6
|
||||
|
||||
Setup Wizard UI
|
||||
|
||||
The generated CSV files become the official template pack for all future setup and onboarding workflows.
|
||||
> Implementation log 2026-07-02: Static CSV template pack completed under
|
||||
> `setup/templates/`, optional metadata API added at `GET /api/setup/templates`,
|
||||
> and implementation note saved to
|
||||
> `docs/implementation/task-d73-csv-template-static-pack.md`.
|
||||
437
plans/task-d.7.4.md
Normal file
437
plans/task-d.7.4.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# Task D.7.4 – CSV Preview Validation Engine
|
||||
|
||||
## Objective
|
||||
|
||||
Implement a reusable, non-destructive CSV Preview Validation Engine for ALLA OS.
|
||||
|
||||
This engine must validate uploaded CSV files against the official template pack and return a complete preview report without modifying any database records.
|
||||
|
||||
The preview engine becomes the shared foundation for D.7.5 (CSV Commit Import Engine), Setup Wizard, and future bulk import features.
|
||||
|
||||
No database writes, seed execution, or reset operations are allowed 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
|
||||
- docs/setup/seed-matrix.md
|
||||
- docs/setup/csv-template-spec.md
|
||||
- docs/setup/import-mapping.md
|
||||
- docs/setup/setup-wizard-blueprint.md
|
||||
- docs/setup/verification-matrix.md
|
||||
- setup/templates/*
|
||||
- setup/templates/templates.json
|
||||
|
||||
Treat templates.json as the runtime source of truth.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Scope
|
||||
|
||||
Create:
|
||||
|
||||
src/features/setup/server/csv-preview.service.ts
|
||||
|
||||
Supporting modules
|
||||
|
||||
src/features/setup/server/csv/
|
||||
parser.ts
|
||||
validator.ts
|
||||
dependency-resolver.ts
|
||||
header-validator.ts
|
||||
value-validator.ts
|
||||
preview-builder.ts
|
||||
template-registry.ts
|
||||
|
||||
Create API
|
||||
|
||||
POST /api/setup/import/preview
|
||||
|
||||
---
|
||||
|
||||
## Input
|
||||
|
||||
Accept one or more CSV files.
|
||||
|
||||
Each file must match one registered template.
|
||||
|
||||
Files may be uploaded in any order.
|
||||
|
||||
Engine must automatically resolve dependency order.
|
||||
|
||||
---
|
||||
|
||||
## Validation Stages
|
||||
|
||||
Stage 1
|
||||
|
||||
Template Detection
|
||||
|
||||
- Match filename
|
||||
- Match template registry
|
||||
- Match supported template
|
||||
|
||||
Reject unknown templates.
|
||||
|
||||
---
|
||||
|
||||
Stage 2
|
||||
|
||||
Schema Validation
|
||||
|
||||
Validate
|
||||
|
||||
- header names
|
||||
- header order
|
||||
- duplicated columns
|
||||
- missing columns
|
||||
- extra columns
|
||||
- template version (if available)
|
||||
|
||||
---
|
||||
|
||||
Stage 3
|
||||
|
||||
CSV Validation
|
||||
|
||||
Validate
|
||||
|
||||
- encoding
|
||||
- delimiter
|
||||
- empty rows
|
||||
- duplicated rows
|
||||
- inconsistent column counts
|
||||
|
||||
---
|
||||
|
||||
Stage 4
|
||||
|
||||
Value Validation
|
||||
|
||||
Validate
|
||||
|
||||
Required fields
|
||||
|
||||
Email
|
||||
|
||||
Boolean
|
||||
|
||||
Integer
|
||||
|
||||
Decimal
|
||||
|
||||
Date (YYYY-MM-DD)
|
||||
|
||||
Enum
|
||||
|
||||
Length
|
||||
|
||||
Regex
|
||||
|
||||
Custom validators
|
||||
|
||||
---
|
||||
|
||||
Stage 5
|
||||
|
||||
Relationship Resolution
|
||||
|
||||
Resolve
|
||||
|
||||
organization
|
||||
|
||||
branch
|
||||
|
||||
product type
|
||||
|
||||
users
|
||||
|
||||
memberships
|
||||
|
||||
CRM role
|
||||
|
||||
customer
|
||||
|
||||
contact
|
||||
|
||||
lead
|
||||
|
||||
opportunity
|
||||
|
||||
quotation
|
||||
|
||||
master options
|
||||
|
||||
Return
|
||||
|
||||
Resolved
|
||||
|
||||
Missing
|
||||
|
||||
Ambiguous
|
||||
|
||||
---
|
||||
|
||||
Stage 6
|
||||
|
||||
Dependency Validation
|
||||
|
||||
Read
|
||||
|
||||
templates.json
|
||||
|
||||
Validate
|
||||
|
||||
dependsOn
|
||||
|
||||
Detect
|
||||
|
||||
Missing parent files
|
||||
|
||||
Circular dependency
|
||||
|
||||
Invalid import order
|
||||
|
||||
---
|
||||
|
||||
Stage 7
|
||||
|
||||
Duplicate Detection
|
||||
|
||||
Classify
|
||||
|
||||
New
|
||||
|
||||
Existing
|
||||
|
||||
Update
|
||||
|
||||
Conflict
|
||||
|
||||
Duplicate inside CSV
|
||||
|
||||
---
|
||||
|
||||
Stage 8
|
||||
|
||||
Preview Report
|
||||
|
||||
Return
|
||||
|
||||
Imported
|
||||
|
||||
Updated
|
||||
|
||||
Skipped
|
||||
|
||||
Warnings
|
||||
|
||||
Errors
|
||||
|
||||
Grouped by file.
|
||||
|
||||
---
|
||||
|
||||
## Report Contract
|
||||
|
||||
```ts
|
||||
type PreviewResult = {
|
||||
fileName: string;
|
||||
|
||||
template: string;
|
||||
|
||||
status:
|
||||
| "PASS"
|
||||
| "WARNING"
|
||||
| "FAIL";
|
||||
|
||||
summary: {
|
||||
|
||||
rows:number;
|
||||
|
||||
valid:number;
|
||||
|
||||
warning:number;
|
||||
|
||||
error:number;
|
||||
|
||||
};
|
||||
|
||||
rows:[];
|
||||
}
|
||||
```
|
||||
|
||||
Overall response
|
||||
|
||||
```ts
|
||||
{
|
||||
summary,
|
||||
|
||||
files:[],
|
||||
|
||||
generatedAt,
|
||||
|
||||
previewHash
|
||||
}
|
||||
```
|
||||
|
||||
previewHash will be required by D.7.5.
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
Do not
|
||||
|
||||
Insert
|
||||
|
||||
Update
|
||||
|
||||
Delete
|
||||
|
||||
Commit
|
||||
|
||||
Seed
|
||||
|
||||
Generate IDs
|
||||
|
||||
Generate document numbers
|
||||
|
||||
Trigger approval
|
||||
|
||||
Generate PDFs
|
||||
|
||||
Only preview.
|
||||
|
||||
---
|
||||
|
||||
## Error Contract
|
||||
|
||||
Every error
|
||||
|
||||
Must contain
|
||||
|
||||
File
|
||||
|
||||
Row
|
||||
|
||||
Column
|
||||
|
||||
Code
|
||||
|
||||
Message
|
||||
|
||||
Suggested Fix
|
||||
|
||||
Example
|
||||
|
||||
```json
|
||||
{
|
||||
"file":"customers.csv",
|
||||
|
||||
"row":12,
|
||||
|
||||
"column":"customer_type",
|
||||
|
||||
"code":"UNKNOWN_OPTION",
|
||||
|
||||
"message":"Customer type not found.",
|
||||
|
||||
"suggestedFix":"Import master-options.csv first."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Reuse Rules
|
||||
|
||||
Reuse existing
|
||||
|
||||
Master Option services
|
||||
|
||||
Organization services
|
||||
|
||||
CRM services
|
||||
|
||||
Validation helpers
|
||||
|
||||
Document sequence helpers
|
||||
|
||||
Do not duplicate logic.
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
src/features/setup/server/csv-preview.service.ts
|
||||
|
||||
src/features/setup/server/csv/
|
||||
|
||||
POST /api/setup/import/preview
|
||||
|
||||
Shared validation utilities
|
||||
|
||||
Structured preview response
|
||||
|
||||
previewHash generator
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
✓ Preview never writes database.
|
||||
|
||||
✓ Multiple CSVs supported.
|
||||
|
||||
✓ Dependency order resolved automatically.
|
||||
|
||||
✓ Unknown templates rejected.
|
||||
|
||||
✓ Header validation implemented.
|
||||
|
||||
✓ Data validation implemented.
|
||||
|
||||
✓ Relationship resolution implemented.
|
||||
|
||||
✓ Duplicate detection implemented.
|
||||
|
||||
✓ Structured report returned.
|
||||
|
||||
✓ previewHash generated.
|
||||
|
||||
✓ Uses templates.json as runtime registry.
|
||||
|
||||
✓ Typecheck passes.
|
||||
|
||||
---
|
||||
|
||||
## Future
|
||||
|
||||
D.7.5
|
||||
|
||||
Commit Import Engine
|
||||
|
||||
Uses
|
||||
|
||||
previewHash
|
||||
|
||||
↓
|
||||
|
||||
Transaction
|
||||
|
||||
↓
|
||||
|
||||
Upsert
|
||||
|
||||
↓
|
||||
|
||||
Import Report
|
||||
|
||||
No validation logic should be duplicated between D.7.4 and D.7.5.
|
||||
493
plans/task-d.7.5.md
Normal file
493
plans/task-d.7.5.md
Normal file
@@ -0,0 +1,493 @@
|
||||
# Task D.7.5 – CSV Commit Import Engine
|
||||
|
||||
## Objective
|
||||
|
||||
Implement the CSV Commit Import Engine for ALLA OS Initial Setup.
|
||||
|
||||
This task must take a previously validated CSV preview result from D.7.4, verify its `previewHash`, and commit supported CSV imports safely using transactions and idempotent upsert behavior.
|
||||
|
||||
D.7.5 must reuse the D.7.4 preview/validation engine and must not duplicate validation logic.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
- docs/setup/seed-matrix.md
|
||||
- docs/setup/csv-template-spec.md
|
||||
- docs/setup/import-mapping.md
|
||||
- docs/setup/setup-wizard-blueprint.md
|
||||
- docs/setup/verification-matrix.md
|
||||
- setup/templates/*
|
||||
- setup/templates/templates.json
|
||||
- src/features/setup/server/csv-preview.service.ts
|
||||
- src/features/setup/server/csv/**
|
||||
- src/app/api/setup/import/preview/route.ts
|
||||
- src/db/schema.ts
|
||||
- src/db/seeds/**/*
|
||||
- Existing CRM/foundation services for organizations, users, master options, document sequences, approval, customers, contacts, leads, opportunities, and quotations.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Scope
|
||||
|
||||
Create:
|
||||
|
||||
src/features/setup/server/csv-commit.service.ts
|
||||
|
||||
Supporting modules if needed:
|
||||
|
||||
src/features/setup/server/csv/commit-builder.ts
|
||||
src/features/setup/server/csv/upsert-executor.ts
|
||||
src/features/setup/server/csv/import-report.ts
|
||||
|
||||
Create API:
|
||||
|
||||
POST /api/setup/import/commit
|
||||
|
||||
---
|
||||
|
||||
## Core Rule
|
||||
|
||||
D.7.5 must use the exact same parsing, template detection, validation, dependency resolution, and preview report behavior from D.7.4.
|
||||
|
||||
Do not create a second validation engine.
|
||||
|
||||
Commit flow:
|
||||
|
||||
1. Receive CSV files and `previewHash`.
|
||||
2. Re-run preview validation using D.7.4 engine.
|
||||
3. Compare new preview hash with submitted `previewHash`.
|
||||
4. Reject commit if hashes do not match.
|
||||
5. Reject commit if preview contains blocking errors.
|
||||
6. Commit valid files in dependency/import order.
|
||||
7. Return structured import report.
|
||||
|
||||
---
|
||||
|
||||
## Input
|
||||
|
||||
Accept `multipart/form-data`.
|
||||
|
||||
Required:
|
||||
|
||||
- CSV files
|
||||
- `previewHash`
|
||||
|
||||
Optional:
|
||||
|
||||
- `mode`: `strict | permissive`
|
||||
- `organizationId`
|
||||
- `organizationCode`
|
||||
- `dryRun`
|
||||
- `allowOptionCreate`
|
||||
- `skipWarnings`
|
||||
- `replaceExisting`
|
||||
|
||||
Default behavior:
|
||||
|
||||
- `mode = strict`
|
||||
- `dryRun = false`
|
||||
- `allowOptionCreate = false`
|
||||
- `skipWarnings = false`
|
||||
- `replaceExisting = false`
|
||||
|
||||
---
|
||||
|
||||
## Commit Rules
|
||||
|
||||
### General
|
||||
|
||||
- Commit only rows classified as `create` or `update`.
|
||||
- Do not commit rows classified as `error`.
|
||||
- In strict mode, any blocking error prevents the whole commit.
|
||||
- Warnings do not block commit unless `skipWarnings = false` and the warning is configured as blocking.
|
||||
- Unsupported templates must never commit.
|
||||
- Unknown templates must never commit.
|
||||
|
||||
### Transaction
|
||||
|
||||
- Use one database transaction for all DB-only writes in the import batch.
|
||||
- If any DB write fails, rollback the whole batch.
|
||||
- Storage writes are out of scope for D.7.5.
|
||||
- Attachments are still unsupported/deferred.
|
||||
|
||||
### Upsert
|
||||
|
||||
Every importer must be idempotent.
|
||||
|
||||
Re-running the same CSV should produce either:
|
||||
|
||||
- `updated`
|
||||
- `skipped`
|
||||
- or no-op
|
||||
|
||||
Never create duplicate records.
|
||||
|
||||
---
|
||||
|
||||
## Supported Commit Templates
|
||||
|
||||
Implement commit for templates currently supported by D.7.3/D.7.4:
|
||||
|
||||
Foundation / Organization:
|
||||
|
||||
- users.csv
|
||||
- organizations.csv
|
||||
- memberships.csv
|
||||
- crm-role-assignments.csv
|
||||
- master-options.csv
|
||||
- branches.csv
|
||||
- product-types.csv
|
||||
- document-sequences.csv
|
||||
- approval-workflows.csv
|
||||
- approval-steps.csv
|
||||
- approval-matrix.csv
|
||||
|
||||
Business:
|
||||
|
||||
- customers.csv
|
||||
- contacts.csv
|
||||
- contact-shares.csv
|
||||
- leads.csv
|
||||
- opportunities.csv
|
||||
- opportunity-parties.csv
|
||||
- quotations.csv
|
||||
- quotation-items.csv
|
||||
- quotation-parties.csv
|
||||
- quotation-topics.csv
|
||||
- quotation-topic-items.csv
|
||||
|
||||
If a template cannot yet be safely committed because the service contract is unclear, mark it as blocked with a clear reason. Do not fake success.
|
||||
|
||||
---
|
||||
|
||||
## Required Import Order
|
||||
|
||||
Use import order from `setup/templates/templates.json`.
|
||||
|
||||
Commit order must follow resolved dependency order, not upload order.
|
||||
|
||||
---
|
||||
|
||||
## Importer Responsibilities
|
||||
|
||||
Each importer must define:
|
||||
|
||||
- template name
|
||||
- target table or feature service
|
||||
- business key
|
||||
- create behavior
|
||||
- update behavior
|
||||
- skip behavior
|
||||
- conflict behavior
|
||||
- reference resolution
|
||||
- audit behavior if existing service supports it
|
||||
|
||||
---
|
||||
|
||||
## Data Mapping
|
||||
|
||||
Follow:
|
||||
|
||||
docs/setup/import-mapping.md
|
||||
|
||||
Important examples:
|
||||
|
||||
branches.csv
|
||||
|
||||
maps to:
|
||||
|
||||
ms_options
|
||||
category = crm_branch
|
||||
|
||||
product-types.csv
|
||||
|
||||
maps to:
|
||||
|
||||
ms_options
|
||||
category = crm_product_type
|
||||
|
||||
document-sequences.csv
|
||||
|
||||
resolves:
|
||||
|
||||
organization_code
|
||||
branch_code
|
||||
product_type_code
|
||||
document_type
|
||||
period
|
||||
prefix
|
||||
|
||||
quotation-topic-items.csv
|
||||
|
||||
uses `topic_key` from uploaded batch to resolve committed quotation topic ids.
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
- API must be protected.
|
||||
- Require `super_admin` for setup-wide import.
|
||||
- Organization admin may be supported later, but D.7.5 can restrict to `super_admin`.
|
||||
- Do not return raw SQL, stack traces, password hashes, or secrets.
|
||||
- Raw `password` from users.csv must be hashed before storage.
|
||||
- Never log raw passwords.
|
||||
- Empty password must not overwrite existing password.
|
||||
- Existing user password can be reset only when explicit reset flag exists.
|
||||
|
||||
---
|
||||
|
||||
## Password Rules
|
||||
|
||||
For `users.csv`:
|
||||
|
||||
- New credential user requires either:
|
||||
- `password`, or
|
||||
- future invitation flow support.
|
||||
- Existing user:
|
||||
- empty password = keep existing password
|
||||
- password + reset_password=true = update password hash
|
||||
- password + reset_password=false = ignore password with warning
|
||||
- Never return password or hash in report.
|
||||
|
||||
---
|
||||
|
||||
## Report Contract
|
||||
|
||||
Return:
|
||||
|
||||
ImportReport
|
||||
|
||||
Fields:
|
||||
|
||||
- status: PASS | WARNING | FAIL
|
||||
- generatedAt
|
||||
- previewHash
|
||||
- committedHash
|
||||
- dryRun
|
||||
- summary
|
||||
- files
|
||||
- errors
|
||||
- warnings
|
||||
|
||||
File report:
|
||||
|
||||
- fileName
|
||||
- template
|
||||
- status
|
||||
- imported
|
||||
- updated
|
||||
- skipped
|
||||
- errors
|
||||
- warnings
|
||||
|
||||
Row report:
|
||||
|
||||
- row
|
||||
- action: create | update | skip | error
|
||||
- businessKey
|
||||
- entityId if safe
|
||||
- message
|
||||
- warnings
|
||||
- errors
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"status": "PASS",
|
||||
"previewHash": "...",
|
||||
"committedHash": "...",
|
||||
"summary": {
|
||||
"imported": 10,
|
||||
"updated": 4,
|
||||
"skipped": 2,
|
||||
"errors": 0,
|
||||
"warnings": 1
|
||||
},
|
||||
"files": []
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
## Error Contract
|
||||
|
||||
Every error must include:
|
||||
|
||||
- file
|
||||
- row
|
||||
- column
|
||||
- code
|
||||
- message
|
||||
- suggestedFix
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"file": "customers.csv",
|
||||
"row": 12,
|
||||
"column": "customer_code",
|
||||
"code": "UPSERT_FAILED",
|
||||
"message": "Customer could not be imported.",
|
||||
"suggestedFix": "Review the customer row and retry after fixing related references."
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
## Dry Run
|
||||
|
||||
Support `dryRun=true`.
|
||||
|
||||
Dry run must:
|
||||
|
||||
- re-run preview
|
||||
- build commit plan
|
||||
- return planned actions
|
||||
- not write database
|
||||
- not run transaction writes
|
||||
|
||||
---
|
||||
|
||||
## Audit
|
||||
|
||||
If existing feature services automatically write audit logs, allow them.
|
||||
|
||||
If importing directly with Drizzle because no safe service exists, do not invent audit semantics in D.7.5.
|
||||
|
||||
Instead:
|
||||
|
||||
- include audit gap warning in report
|
||||
- document follow-up
|
||||
|
||||
---
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- CSV preview validation logic duplication
|
||||
- CSV template creation
|
||||
- Setup Wizard UI
|
||||
- Seed manifest persistence
|
||||
- Setup state persistence
|
||||
- Rollback after successful commit
|
||||
- Storage import
|
||||
- Attachment import
|
||||
- Email settings import
|
||||
- Unsupported templates
|
||||
- Destructive reset
|
||||
- PDF generation
|
||||
- Approval workflow execution
|
||||
- Document artifact creation
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
Required:
|
||||
|
||||
src/features/setup/server/csv-commit.service.ts
|
||||
src/features/setup/server/csv/commit-builder.ts
|
||||
src/features/setup/server/csv/upsert-executor.ts
|
||||
src/features/setup/server/csv/import-report.ts
|
||||
src/app/api/setup/import/commit/route.ts
|
||||
|
||||
Optional:
|
||||
|
||||
src/features/setup/server/csv/importers/*.ts
|
||||
|
||||
Recommended importer organization:
|
||||
|
||||
src/features/setup/server/csv/importers/
|
||||
users.importer.ts
|
||||
organizations.importer.ts
|
||||
memberships.importer.ts
|
||||
crm-role-assignments.importer.ts
|
||||
master-options.importer.ts
|
||||
document-sequences.importer.ts
|
||||
approval.importer.ts
|
||||
customers.importer.ts
|
||||
contacts.importer.ts
|
||||
leads.importer.ts
|
||||
opportunities.importer.ts
|
||||
quotations.importer.ts
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
✓ POST /api/setup/import/commit exists.
|
||||
|
||||
✓ Commit requires `previewHash`.
|
||||
|
||||
✓ Commit re-runs D.7.4 preview engine.
|
||||
|
||||
✓ Commit rejects mismatched preview hash.
|
||||
|
||||
✓ Commit rejects preview with blocking errors.
|
||||
|
||||
✓ Commit follows dependency/import order from templates.json.
|
||||
|
||||
✓ Commit is transaction-safe for DB writes.
|
||||
|
||||
✓ Re-running the same valid CSV does not duplicate records.
|
||||
|
||||
✓ users.csv password handling is safe.
|
||||
|
||||
✓ branches.csv imports into ms_options category crm_branch.
|
||||
|
||||
✓ product-types.csv imports into ms_options category crm_product_type.
|
||||
|
||||
✓ quotation-topic-items.csv resolves topic_key from committed/imported quotation topics.
|
||||
|
||||
✓ Unsupported templates do not commit.
|
||||
|
||||
✓ dryRun returns planned actions without writing DB.
|
||||
|
||||
✓ Structured import report is returned.
|
||||
|
||||
✓ No storage/binary attachment import is implemented.
|
||||
|
||||
✓ Typecheck passes or unrelated failures are documented.
|
||||
|
||||
---
|
||||
|
||||
## Suggested Verification
|
||||
|
||||
Run:
|
||||
|
||||
npm run typecheck
|
||||
|
||||
Run scoped lint:
|
||||
|
||||
npx oxlint src/features/setup/server/csv src/features/setup/server/csv-commit.service.ts src/app/api/setup/import/commit
|
||||
|
||||
Manual test flow:
|
||||
|
||||
1. Call POST /api/setup/import/preview with valid CSV batch.
|
||||
2. Copy previewHash.
|
||||
3. Call POST /api/setup/import/commit with same files and previewHash.
|
||||
4. Confirm rows are created/updated.
|
||||
5. Re-run same commit.
|
||||
6. Confirm no duplicates.
|
||||
7. Modify CSV after preview.
|
||||
8. Confirm commit rejects previewHash mismatch.
|
||||
9. Submit CSV with blocking errors.
|
||||
10. Confirm commit fails without partial writes.
|
||||
|
||||
---
|
||||
|
||||
## Follow-up
|
||||
|
||||
After this task:
|
||||
|
||||
D.7.6 – Dashboard Setup Wizard UI
|
||||
|
||||
D.7.8 – Seed Manifest and Setup State Persistence
|
||||
|
||||
D.7.7 – Scoped Reset and Reseed Engine
|
||||
486
plans/task-d.7.6.md
Normal file
486
plans/task-d.7.6.md
Normal 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
|
||||
611
plans/task-d.7.7.md
Normal file
611
plans/task-d.7.7.md
Normal file
@@ -0,0 +1,611 @@
|
||||
# Task D.7.7 – Scoped Reset and Reseed Engine
|
||||
|
||||
## Objective
|
||||
|
||||
Implement a safe, non-production Scoped Reset and Reseed Engine for ALLA OS Initial Setup.
|
||||
|
||||
This task must allow controlled reset/reseed operations for setup, foundation, organization, business, demo/UAT, and CSV-imported data while preserving production safety guards.
|
||||
|
||||
D.7.7 must use the Setup State and Seed Manifest foundations from D.7.8 where possible.
|
||||
|
||||
This task must not introduce any destructive reset path for production.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
- plans/task-d.7.6.md
|
||||
- plans/task-d.7.8.md
|
||||
- docs/setup/reset-reseed-matrix.md
|
||||
- docs/setup/seed-version-manifest.md
|
||||
- docs/setup/setup-state-machine.md
|
||||
- docs/setup/seed-matrix.md
|
||||
- docs/setup/import-mapping.md
|
||||
- src/db/schema.ts
|
||||
- src/features/setup/**
|
||||
- src/app/api/setup/**
|
||||
- scripts/seed-reset.ts
|
||||
- scripts/db/reset-database.ts
|
||||
- scripts/seed-system.ts
|
||||
- scripts/seed-uat.ts
|
||||
- src/db/seeds/**/*
|
||||
- existing storage provider implementation
|
||||
|
||||
---
|
||||
|
||||
## Implementation Scope
|
||||
|
||||
Create reset/reseed services:
|
||||
|
||||
src/features/setup/server/reset.service.ts
|
||||
src/features/setup/server/reseed.service.ts
|
||||
|
||||
Optional helpers:
|
||||
|
||||
src/features/setup/server/reset-guards.ts
|
||||
src/features/setup/server/reset-report.ts
|
||||
src/features/setup/server/reset-scopes.ts
|
||||
|
||||
Create API routes:
|
||||
|
||||
POST /api/setup/reset/preview
|
||||
POST /api/setup/reset/execute
|
||||
POST /api/setup/reseed/preview
|
||||
POST /api/setup/reseed/execute
|
||||
|
||||
Optional UI integration:
|
||||
|
||||
Add a Maintenance panel in Setup Wizard or Administration Setup page.
|
||||
|
||||
---
|
||||
|
||||
## Reset Scopes
|
||||
|
||||
Implement scopes from docs/setup/reset-reseed-matrix.md:
|
||||
|
||||
foundation_reset
|
||||
|
||||
organization_reset
|
||||
|
||||
business_reset
|
||||
|
||||
demo_uat_reset
|
||||
|
||||
csv_import_rollback
|
||||
|
||||
setup_run_reset
|
||||
|
||||
full_reset
|
||||
|
||||
---
|
||||
|
||||
## Scope Rules
|
||||
|
||||
### foundation_reset
|
||||
|
||||
Deletes and optionally reseeds organization-scoped foundation rows.
|
||||
|
||||
May affect:
|
||||
|
||||
- ms_options
|
||||
- document_sequences
|
||||
- approval workflows
|
||||
- approval steps
|
||||
- approval matrices
|
||||
- document template foundation rows
|
||||
- document library foundation rows
|
||||
- notification templates
|
||||
- report definitions
|
||||
|
||||
Must retain:
|
||||
|
||||
- users
|
||||
- organizations
|
||||
- memberships
|
||||
- business CRM data unless explicitly selected
|
||||
|
||||
---
|
||||
|
||||
### organization_reset
|
||||
|
||||
Deletes target organization and tenant-scoped rows.
|
||||
|
||||
Must require exact organization code/name confirmation.
|
||||
|
||||
Must retain:
|
||||
|
||||
- global users unless explicitly selected
|
||||
|
||||
Must delete:
|
||||
|
||||
- memberships for target organization
|
||||
- CRM role assignments/profiles for target organization
|
||||
- organization-scoped foundation rows
|
||||
- business rows for target organization
|
||||
|
||||
---
|
||||
|
||||
### business_reset
|
||||
|
||||
Deletes CRM business records for target organization.
|
||||
|
||||
May affect:
|
||||
|
||||
- customers
|
||||
- contacts
|
||||
- contact shares
|
||||
- leads
|
||||
- opportunities
|
||||
- quotations
|
||||
- quotation items
|
||||
- quotation parties
|
||||
- quotation topics
|
||||
- quotation topic items
|
||||
- followups
|
||||
- business attachment metadata
|
||||
|
||||
Must retain:
|
||||
|
||||
- organization
|
||||
- users
|
||||
- memberships
|
||||
- foundation rows
|
||||
- setup run history unless explicitly selected
|
||||
|
||||
---
|
||||
|
||||
### demo_uat_reset
|
||||
|
||||
Deletes deterministic Demo/UAT rows only.
|
||||
|
||||
Must rely on:
|
||||
|
||||
- UAT seed markers
|
||||
- deterministic emails/codes
|
||||
- seed manifest records
|
||||
- known UAT seed package names
|
||||
|
||||
Must retain:
|
||||
|
||||
- production foundation
|
||||
- non-UAT business data
|
||||
|
||||
---
|
||||
|
||||
### csv_import_rollback
|
||||
|
||||
Rolls back rows associated with a seed manifest/import package when safely reversible.
|
||||
|
||||
Rules:
|
||||
|
||||
- only rollback manifest-owned rows
|
||||
- block rollback if rows were changed after import and no safe conflict policy exists
|
||||
- if rollback is not fully safe, return warning and require manual review
|
||||
- do not pretend arbitrary rollback is safe
|
||||
|
||||
---
|
||||
|
||||
### setup_run_reset
|
||||
|
||||
Deletes setup run metadata only.
|
||||
|
||||
May affect:
|
||||
|
||||
- setup_runs
|
||||
- setup_run_steps
|
||||
- seed_manifests
|
||||
- seed_manifest_items
|
||||
|
||||
Must not delete:
|
||||
|
||||
- business data
|
||||
- foundation data
|
||||
- organizations
|
||||
- users
|
||||
|
||||
---
|
||||
|
||||
### full_reset
|
||||
|
||||
Must use existing guarded reset script behavior.
|
||||
|
||||
Rules:
|
||||
|
||||
- block in production
|
||||
- require explicit allow flag
|
||||
- require typed confirmation
|
||||
- local/test only by default
|
||||
- do not expose casually in UI
|
||||
|
||||
---
|
||||
|
||||
## Safety Guards
|
||||
|
||||
All destructive actions require:
|
||||
|
||||
- super_admin
|
||||
- non-production environment
|
||||
- explicit scope
|
||||
- target organization when scope is organization-aware
|
||||
- typed confirmation
|
||||
- preview before execute
|
||||
- confirmation token generated from preview
|
||||
- token expires after short duration
|
||||
- execute must match preview hash/token
|
||||
|
||||
Block when:
|
||||
|
||||
- NODE_ENV=production
|
||||
- production-like database host/name is detected
|
||||
- missing target organization
|
||||
- missing typed confirmation
|
||||
- preview was not run
|
||||
- preview token expired
|
||||
- preview hash mismatch
|
||||
- affected row count exceeds safe threshold unless force flag is provided
|
||||
|
||||
---
|
||||
|
||||
## Preview Behavior
|
||||
|
||||
Reset preview must not delete anything.
|
||||
|
||||
Preview returns:
|
||||
|
||||
- scope
|
||||
- target organization
|
||||
- affected tables
|
||||
- estimated row counts
|
||||
- retained data
|
||||
- deleted data
|
||||
- storage cleanup plan
|
||||
- manifest impact
|
||||
- warnings
|
||||
- blocking errors
|
||||
- confirmation phrase
|
||||
- previewHash
|
||||
- confirmationToken
|
||||
|
||||
Example:
|
||||
|
||||
{
|
||||
"scope": "business_reset",
|
||||
"targetOrganization": "ALLA",
|
||||
"summary": {
|
||||
"tables": 12,
|
||||
"rows": 520,
|
||||
"warnings": 2,
|
||||
"errors": 0
|
||||
},
|
||||
"affectedTables": [],
|
||||
"confirmationPhrase": "RESET BUSINESS ALLA",
|
||||
"previewHash": "...",
|
||||
"confirmationToken": "..."
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
## Execute Behavior
|
||||
|
||||
Execute requires:
|
||||
|
||||
- scope
|
||||
- previewHash
|
||||
- confirmationToken
|
||||
- typed confirmation phrase
|
||||
|
||||
Execution must:
|
||||
|
||||
1. Rebuild preview.
|
||||
2. Compare previewHash.
|
||||
3. Validate token.
|
||||
4. Validate typed confirmation.
|
||||
5. Run reset inside transaction where DB-only.
|
||||
6. Handle storage cleanup best-effort.
|
||||
7. Persist reset report to setup run if available.
|
||||
8. Return final report.
|
||||
|
||||
---
|
||||
|
||||
## Reseed Behavior
|
||||
|
||||
Reseed is optional but recommended for:
|
||||
|
||||
- foundation_reset
|
||||
- demo_uat_reset
|
||||
- csv_import_rollback after cleanup
|
||||
|
||||
Reseed must call existing seed services/scripts through safe wrappers.
|
||||
|
||||
Do not duplicate seed data.
|
||||
|
||||
Supported reseed targets:
|
||||
|
||||
foundation
|
||||
|
||||
demo_uat
|
||||
|
||||
csv_manifest
|
||||
|
||||
Rules:
|
||||
|
||||
- foundation reseed is idempotent
|
||||
- demo/UAT reseed is deterministic
|
||||
- csv_manifest reseed requires original manifest/files available or block with clear reason
|
||||
|
||||
---
|
||||
|
||||
## Storage Cleanup
|
||||
|
||||
Storage cleanup must be:
|
||||
|
||||
- best-effort
|
||||
- scoped
|
||||
- reported
|
||||
- never silent
|
||||
|
||||
Rules:
|
||||
|
||||
- delete setup-owned temp objects only when safe
|
||||
- delete demo-generated objects only under demo prefix
|
||||
- do not delete approved immutable artifacts unless explicit full reset/demo reset and policy allows
|
||||
- if cleanup fails, DB transaction should not necessarily rollback unless storage cleanup is required by scope
|
||||
- report leftover keys
|
||||
|
||||
---
|
||||
|
||||
## Seed Manifest Integration
|
||||
|
||||
Use D.7.8 seed manifest tables.
|
||||
|
||||
Reset preview should show:
|
||||
|
||||
- affected seed manifests
|
||||
- affected seed manifest items
|
||||
- whether import rollback is safe
|
||||
- checksum/package info
|
||||
|
||||
Reset execute should update manifest status when applicable:
|
||||
|
||||
- rolled_back
|
||||
- warning
|
||||
- failed
|
||||
|
||||
Do not delete manifest rows unless scope is setup_run_reset.
|
||||
|
||||
---
|
||||
|
||||
## Setup State Integration
|
||||
|
||||
Reset should update setup run state when applicable.
|
||||
|
||||
Examples:
|
||||
|
||||
- business_reset marks csv_commit and verification stale
|
||||
- foundation_reset marks readiness, scope, sequence, approval, CSV, and verification stale
|
||||
- setup_run_reset clears setup state only
|
||||
- organization_reset cancels or invalidates active setup runs for that organization
|
||||
|
||||
Do not implement destructive RESET_STEP from UI unless explicitly scoped.
|
||||
|
||||
---
|
||||
|
||||
## API Contracts
|
||||
|
||||
### POST /api/setup/reset/preview
|
||||
|
||||
Input:
|
||||
|
||||
scope
|
||||
organizationId?
|
||||
organizationCode?
|
||||
manifestId?
|
||||
options?
|
||||
|
||||
Output:
|
||||
|
||||
ResetPreviewReport
|
||||
|
||||
---
|
||||
|
||||
### POST /api/setup/reset/execute
|
||||
|
||||
Input:
|
||||
|
||||
scope
|
||||
previewHash
|
||||
confirmationToken
|
||||
confirmationPhrase
|
||||
organizationId?
|
||||
organizationCode?
|
||||
manifestId?
|
||||
options?
|
||||
|
||||
Output:
|
||||
|
||||
ResetExecuteReport
|
||||
|
||||
---
|
||||
|
||||
### POST /api/setup/reseed/preview
|
||||
|
||||
Input:
|
||||
|
||||
target
|
||||
organizationId?
|
||||
organizationCode?
|
||||
manifestId?
|
||||
options?
|
||||
|
||||
Output:
|
||||
|
||||
ReseedPreviewReport
|
||||
|
||||
---
|
||||
|
||||
### POST /api/setup/reseed/execute
|
||||
|
||||
Input:
|
||||
|
||||
target
|
||||
previewHash
|
||||
confirmationToken
|
||||
confirmationPhrase
|
||||
organizationId?
|
||||
organizationCode?
|
||||
manifestId?
|
||||
options?
|
||||
|
||||
Output:
|
||||
|
||||
ReseedExecuteReport
|
||||
|
||||
---
|
||||
|
||||
## UI Requirements If Implemented
|
||||
|
||||
Add Maintenance panel:
|
||||
|
||||
- Reset scope selector
|
||||
- Target organization selector
|
||||
- Preview button
|
||||
- Affected tables/counts
|
||||
- Warnings/errors
|
||||
- Typed confirmation input
|
||||
- Execute button
|
||||
- Final report
|
||||
|
||||
UI must hide or disable destructive actions when environment is production.
|
||||
|
||||
---
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- Production reset workflow
|
||||
- Silent automatic reset
|
||||
- Arbitrary rollback without manifest ownership
|
||||
- Deleting approved production artifacts
|
||||
- New seed data creation
|
||||
- Installation profile engine
|
||||
- Plugin runtime
|
||||
- Backup/restore
|
||||
- Data anonymization
|
||||
- Cross-environment migration
|
||||
- Email/storage secret reset
|
||||
- Changing CRM business behavior
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
Required:
|
||||
|
||||
src/features/setup/server/reset.service.ts
|
||||
src/features/setup/server/reseed.service.ts
|
||||
src/features/setup/server/reset-guards.ts
|
||||
src/features/setup/server/reset-report.ts
|
||||
|
||||
API routes:
|
||||
|
||||
src/app/api/setup/reset/preview/route.ts
|
||||
src/app/api/setup/reset/execute/route.ts
|
||||
src/app/api/setup/reseed/preview/route.ts
|
||||
src/app/api/setup/reseed/execute/route.ts
|
||||
|
||||
Optional:
|
||||
|
||||
src/features/setup/components/setup-maintenance-panel.tsx
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
✓ Reset preview API exists.
|
||||
|
||||
✓ Reset execute API exists.
|
||||
|
||||
✓ Reseed preview API exists.
|
||||
|
||||
✓ Reseed execute API exists.
|
||||
|
||||
✓ All APIs require super_admin.
|
||||
|
||||
✓ Production destructive reset is blocked.
|
||||
|
||||
✓ Preview is required before execute.
|
||||
|
||||
✓ Execute requires valid previewHash.
|
||||
|
||||
✓ Execute requires valid confirmationToken.
|
||||
|
||||
✓ Execute requires typed confirmation phrase.
|
||||
|
||||
✓ Organization-aware scopes require target organization.
|
||||
|
||||
✓ Preview returns affected tables and estimated rows.
|
||||
|
||||
✓ Execute uses transaction for DB-only deletes.
|
||||
|
||||
✓ Storage cleanup is best-effort and reported.
|
||||
|
||||
✓ Seed manifest status updates for rollback/reset where applicable.
|
||||
|
||||
✓ Setup run steps are marked stale after reset.
|
||||
|
||||
✓ full_reset delegates to existing guarded reset behavior or blocks with clear instructions.
|
||||
|
||||
✓ No reset deletes approved immutable artifacts unless explicitly allowed by scope policy.
|
||||
|
||||
✓ No seed logic is duplicated.
|
||||
|
||||
✓ Typecheck passes or unrelated failures are documented.
|
||||
|
||||
---
|
||||
|
||||
## Suggested Verification
|
||||
|
||||
Run:
|
||||
|
||||
npm run typecheck
|
||||
|
||||
Run scoped lint:
|
||||
|
||||
npx oxlint src/features/setup src/app/api/setup
|
||||
|
||||
Manual test:
|
||||
|
||||
1. Run business_reset preview for ALLA.
|
||||
2. Confirm affected table counts are shown.
|
||||
3. Execute without preview token.
|
||||
4. Confirm blocked.
|
||||
5. Execute with wrong confirmation phrase.
|
||||
6. Confirm blocked.
|
||||
7. Execute with valid token and phrase in local environment.
|
||||
8. Confirm rows deleted and foundation retained.
|
||||
9. Run setup verification.
|
||||
10. Confirm CSV/verification steps stale.
|
||||
11. Try in NODE_ENV=production.
|
||||
12. Confirm destructive reset is blocked.
|
||||
13. Run setup_run_reset.
|
||||
14. Confirm setup metadata deleted but business rows remain.
|
||||
15. Run csv_import_rollback for manifest.
|
||||
16. Confirm only manifest-owned rows are affected or rollback is blocked with manual review warning.
|
||||
|
||||
---
|
||||
|
||||
## Follow-up
|
||||
|
||||
After D.7.7:
|
||||
|
||||
D.7.9 – Installation Profile and Plugin Runtime Enhancement
|
||||
|
||||
D.7.10 – Setup Integration Test and Golden Dataset
|
||||
681
plans/task-d.7.8.md
Normal file
681
plans/task-d.7.8.md
Normal file
@@ -0,0 +1,681 @@
|
||||
# Task D.7.8 – Seed Manifest and Setup State Persistence
|
||||
|
||||
## Objective
|
||||
|
||||
Add persistent setup run tracking and seed manifest lifecycle tracking for ALLA OS Initial Setup.
|
||||
|
||||
This task must make the Setup Wizard resumable, auditable, and able to persist setup reports across browser refreshes and future setup sessions.
|
||||
|
||||
D.7.8 should build on:
|
||||
|
||||
- D.7.2 Readiness and Verification APIs
|
||||
- D.7.3 CSV Template Pack
|
||||
- D.7.4 CSV Preview Validation Engine
|
||||
- D.7.5 CSV Commit Import Engine
|
||||
- D.7.6 Dashboard Setup Wizard UI
|
||||
|
||||
This task must not implement destructive reset/reseed behavior. Reset remains D.7.7.
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
- plans/task-d.7.6.md
|
||||
- docs/setup/setup-state-machine.md
|
||||
- docs/setup/seed-version-manifest.md
|
||||
- docs/setup/setup-wizard-blueprint.md
|
||||
- docs/setup/verification-matrix.md
|
||||
- docs/setup/reset-reseed-matrix.md
|
||||
- docs/setup/setup-plugin-architecture.md
|
||||
- src/db/schema.ts
|
||||
- src/features/setup/**
|
||||
- src/app/dashboard/administration/setup/page.tsx
|
||||
- src/app/api/setup/**
|
||||
- existing migration conventions under drizzle/
|
||||
|
||||
---
|
||||
|
||||
## Implementation Scope
|
||||
|
||||
Add setup persistence tables:
|
||||
|
||||
- setup_runs
|
||||
- setup_run_steps
|
||||
- seed_manifests
|
||||
- seed_manifest_items
|
||||
|
||||
Add migration through existing Drizzle workflow.
|
||||
|
||||
Add schema definitions to:
|
||||
|
||||
src/db/schema.ts
|
||||
|
||||
or appropriate split schema location if the repo already uses modular schema files.
|
||||
|
||||
Add setup persistence services:
|
||||
|
||||
src/features/setup/server/setup-state.service.ts
|
||||
src/features/setup/server/seed-manifest.service.ts
|
||||
|
||||
Add API routes:
|
||||
|
||||
GET /api/setup/run/current
|
||||
POST /api/setup/run/start
|
||||
POST /api/setup/run/step
|
||||
POST /api/setup/run/complete
|
||||
GET /api/setup/run/report
|
||||
|
||||
Update setup wizard UI to:
|
||||
|
||||
- load current setup run
|
||||
- resume prior step status
|
||||
- persist step outputs
|
||||
- show completed/pending/stale step status
|
||||
- persist finish report
|
||||
- show setup completed state
|
||||
|
||||
Update CSV commit flow to optionally record seed manifest and manifest items.
|
||||
|
||||
---
|
||||
|
||||
## Database Tables
|
||||
|
||||
### setup_runs
|
||||
|
||||
Purpose:
|
||||
|
||||
One row per setup attempt/session.
|
||||
|
||||
Suggested fields:
|
||||
|
||||
id
|
||||
|
||||
status
|
||||
|
||||
mode
|
||||
|
||||
target_organization_id
|
||||
|
||||
started_by
|
||||
|
||||
completed_by
|
||||
|
||||
started_at
|
||||
|
||||
completed_at
|
||||
|
||||
last_error
|
||||
|
||||
metadata
|
||||
|
||||
created_at
|
||||
|
||||
updated_at
|
||||
|
||||
Status values:
|
||||
|
||||
not_started
|
||||
|
||||
readiness_checked
|
||||
|
||||
foundation_installed
|
||||
|
||||
organization_created
|
||||
|
||||
administrator_created
|
||||
|
||||
scope_configured
|
||||
|
||||
sequences_configured
|
||||
|
||||
approval_configured
|
||||
|
||||
csv_validated
|
||||
|
||||
csv_imported
|
||||
|
||||
verified
|
||||
|
||||
completed
|
||||
|
||||
failed
|
||||
|
||||
cancelled
|
||||
|
||||
Mode values:
|
||||
|
||||
production
|
||||
|
||||
demo_uat
|
||||
|
||||
dry_run
|
||||
|
||||
---
|
||||
|
||||
### setup_run_steps
|
||||
|
||||
Purpose:
|
||||
|
||||
Step-level state, input hash, output report, warning/error history.
|
||||
|
||||
Suggested fields:
|
||||
|
||||
id
|
||||
|
||||
setup_run_id
|
||||
|
||||
step_key
|
||||
|
||||
status
|
||||
|
||||
input_hash
|
||||
|
||||
output_json
|
||||
|
||||
errors_json
|
||||
|
||||
warnings_json
|
||||
|
||||
started_at
|
||||
|
||||
completed_at
|
||||
|
||||
created_at
|
||||
|
||||
updated_at
|
||||
|
||||
Step status values:
|
||||
|
||||
not_started
|
||||
|
||||
running
|
||||
|
||||
passed
|
||||
|
||||
warning
|
||||
|
||||
failed
|
||||
|
||||
skipped
|
||||
|
||||
stale
|
||||
|
||||
---
|
||||
|
||||
### seed_manifests
|
||||
|
||||
Purpose:
|
||||
|
||||
Track seed/import package lifecycle.
|
||||
|
||||
Suggested fields:
|
||||
|
||||
id
|
||||
|
||||
setup_run_id
|
||||
|
||||
organization_id
|
||||
|
||||
name
|
||||
|
||||
version
|
||||
|
||||
type
|
||||
|
||||
checksum
|
||||
|
||||
status
|
||||
|
||||
source
|
||||
|
||||
applied_by
|
||||
|
||||
applied_at
|
||||
|
||||
report_json
|
||||
|
||||
created_at
|
||||
|
||||
updated_at
|
||||
|
||||
Type values:
|
||||
|
||||
foundation
|
||||
|
||||
organization
|
||||
|
||||
business
|
||||
|
||||
demo_uat
|
||||
|
||||
setup_state
|
||||
|
||||
Status values:
|
||||
|
||||
pending
|
||||
|
||||
applied
|
||||
|
||||
skipped
|
||||
|
||||
warning
|
||||
|
||||
failed
|
||||
|
||||
rolled_back
|
||||
|
||||
---
|
||||
|
||||
### seed_manifest_items
|
||||
|
||||
Purpose:
|
||||
|
||||
Track per-file/per-seed item checksum and result.
|
||||
|
||||
Suggested fields:
|
||||
|
||||
id
|
||||
|
||||
seed_manifest_id
|
||||
|
||||
item_key
|
||||
|
||||
source_file
|
||||
|
||||
checksum
|
||||
|
||||
status
|
||||
|
||||
imported_count
|
||||
|
||||
updated_count
|
||||
|
||||
skipped_count
|
||||
|
||||
error_count
|
||||
|
||||
warning_count
|
||||
|
||||
report_json
|
||||
|
||||
created_at
|
||||
|
||||
updated_at
|
||||
|
||||
---
|
||||
|
||||
## State Machine Rules
|
||||
|
||||
Use:
|
||||
|
||||
docs/setup/setup-state-machine.md
|
||||
|
||||
Required events:
|
||||
|
||||
CHECK_READINESS
|
||||
|
||||
INSTALL_FOUNDATION
|
||||
|
||||
CREATE_ORGANIZATION
|
||||
|
||||
CREATE_ADMIN
|
||||
|
||||
CONFIGURE_SCOPE
|
||||
|
||||
CONFIGURE_SEQUENCES
|
||||
|
||||
CONFIGURE_APPROVAL
|
||||
|
||||
VALIDATE_CSV
|
||||
|
||||
IMPORT_CSV
|
||||
|
||||
RUN_VERIFICATION
|
||||
|
||||
COMPLETE_SETUP
|
||||
|
||||
FAIL_STEP
|
||||
|
||||
CANCEL_SETUP
|
||||
|
||||
RESUME_SETUP
|
||||
|
||||
RESET_STEP
|
||||
|
||||
For D.7.8, implement only non-destructive events.
|
||||
|
||||
Do not implement RESET_STEP destructive behavior.
|
||||
|
||||
RESET_STEP can return:
|
||||
|
||||
not implemented until D.7.7
|
||||
|
||||
---
|
||||
|
||||
## Persistence Rules
|
||||
|
||||
Every setup step should persist:
|
||||
|
||||
- step key
|
||||
- status
|
||||
- input hash
|
||||
- output summary/report
|
||||
- warnings
|
||||
- errors
|
||||
- completed timestamp
|
||||
|
||||
If the same step is re-run:
|
||||
|
||||
- update same step row
|
||||
- keep latest report
|
||||
- mark dependent later steps as stale when needed
|
||||
|
||||
Staleness rules:
|
||||
|
||||
- readiness changed → all later steps stale
|
||||
- organization changed → admin, scope, sequence, approval, CSV, verification stale
|
||||
- scope changed → sequence, approval, CSV, verification stale
|
||||
- sequence changed → verification stale
|
||||
- approval changed → CSV and verification stale
|
||||
- CSV preview changed → commit stale
|
||||
- CSV commit changed → verification stale
|
||||
|
||||
---
|
||||
|
||||
## Setup Run Behavior
|
||||
|
||||
### Current Run
|
||||
|
||||
GET /api/setup/run/current
|
||||
|
||||
Returns:
|
||||
|
||||
- active setup run if exists
|
||||
- latest completed setup run if no active run
|
||||
- setup step summaries
|
||||
- manifest summaries
|
||||
- completion status
|
||||
|
||||
### Start Run
|
||||
|
||||
POST /api/setup/run/start
|
||||
|
||||
Creates new setup run.
|
||||
|
||||
Rules:
|
||||
|
||||
- super_admin only
|
||||
- if active run exists, return existing run unless `forceNew=true`
|
||||
- mode defaults to production
|
||||
- target organization optional until resolved
|
||||
|
||||
### Save Step
|
||||
|
||||
POST /api/setup/run/step
|
||||
|
||||
Persists step report.
|
||||
|
||||
Input:
|
||||
|
||||
- setupRunId
|
||||
- stepKey
|
||||
- status
|
||||
- inputHash
|
||||
- output
|
||||
- warnings
|
||||
- errors
|
||||
|
||||
Rules:
|
||||
|
||||
- validate step key
|
||||
- update run status based on state machine
|
||||
- mark downstream stale steps as needed
|
||||
|
||||
### Complete Run
|
||||
|
||||
POST /api/setup/run/complete
|
||||
|
||||
Rules:
|
||||
|
||||
- all required steps must be passed/warning acknowledged
|
||||
- blocking failure prevents completion
|
||||
- verification must be latest and not stale
|
||||
- writes completed_at and status completed
|
||||
- returns final report
|
||||
|
||||
### Report
|
||||
|
||||
GET /api/setup/run/report
|
||||
|
||||
Returns:
|
||||
|
||||
- setup run summary
|
||||
- steps
|
||||
- manifests
|
||||
- final readiness/verification/import summaries
|
||||
|
||||
---
|
||||
|
||||
## Seed Manifest Behavior
|
||||
|
||||
When CSV commit succeeds, create or update a manifest.
|
||||
|
||||
Recommended package:
|
||||
|
||||
crm-business-import
|
||||
|
||||
Manifest item per committed CSV file.
|
||||
|
||||
For each file:
|
||||
|
||||
- source_file
|
||||
- checksum
|
||||
- status
|
||||
- imported_count
|
||||
- updated_count
|
||||
- skipped_count
|
||||
- error_count
|
||||
- warning_count
|
||||
- report_json
|
||||
|
||||
Version:
|
||||
|
||||
1.0.0
|
||||
|
||||
Source:
|
||||
|
||||
csv
|
||||
|
||||
Type:
|
||||
|
||||
business
|
||||
|
||||
Checksum behavior:
|
||||
|
||||
- same version + same checksum = skipped/already applied
|
||||
- same version + changed checksum = warning unless force mode
|
||||
- new checksum after successful import creates new manifest revision or new manifest row depending on chosen implementation
|
||||
|
||||
If D.7.5 import is dryRun:
|
||||
|
||||
- do not write seed manifest
|
||||
- optionally persist setup step output only
|
||||
|
||||
---
|
||||
|
||||
## API Security
|
||||
|
||||
- all routes protected
|
||||
- require super_admin for D.7.8
|
||||
- never expose raw SQL errors
|
||||
- never expose passwords, password hashes, secrets, storage credentials
|
||||
- report only safe summaries
|
||||
- setup reports can include filenames and counts, not raw CSV contents
|
||||
|
||||
---
|
||||
|
||||
## UI Updates
|
||||
|
||||
Update:
|
||||
|
||||
src/features/setup/components/setup-wizard.tsx
|
||||
|
||||
Add:
|
||||
|
||||
- load current setup run on mount
|
||||
- resume banner
|
||||
- persisted step status
|
||||
- stale step badge
|
||||
- completed setup summary
|
||||
- save step result after readiness, preview, commit, verification
|
||||
- complete setup button on finish step
|
||||
- report panel from persisted data
|
||||
|
||||
Important:
|
||||
|
||||
The wizard should still work if persistence API fails, but must show a warning.
|
||||
|
||||
---
|
||||
|
||||
## Out Of Scope
|
||||
|
||||
- Destructive reset/reseed
|
||||
- RESET_STEP implementation
|
||||
- installation profile engine
|
||||
- plugin runtime
|
||||
- CSV parser changes unless needed for checksum
|
||||
- setup template changes
|
||||
- storage import
|
||||
- attachment import
|
||||
- new CRM behavior
|
||||
- production setup lock enforcement beyond completed status display
|
||||
|
||||
---
|
||||
|
||||
## Deliverables
|
||||
|
||||
Required schema/migration:
|
||||
|
||||
src/db/schema.ts
|
||||
|
||||
drizzle migration file
|
||||
|
||||
Required services:
|
||||
|
||||
src/features/setup/server/setup-state.service.ts
|
||||
src/features/setup/server/seed-manifest.service.ts
|
||||
|
||||
Required API routes:
|
||||
|
||||
src/app/api/setup/run/current/route.ts
|
||||
src/app/api/setup/run/start/route.ts
|
||||
src/app/api/setup/run/step/route.ts
|
||||
src/app/api/setup/run/complete/route.ts
|
||||
src/app/api/setup/run/report/route.ts
|
||||
|
||||
Required UI update:
|
||||
|
||||
src/features/setup/components/setup-wizard.tsx
|
||||
|
||||
Optional helpers:
|
||||
|
||||
src/features/setup/server/setup-state-machine.ts
|
||||
src/features/setup/server/setup-report.service.ts
|
||||
|
||||
---
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
✓ setup_runs table exists.
|
||||
|
||||
✓ setup_run_steps table exists.
|
||||
|
||||
✓ seed_manifests table exists.
|
||||
|
||||
✓ seed_manifest_items table exists.
|
||||
|
||||
✓ Drizzle migration generated.
|
||||
|
||||
✓ Current setup run API works.
|
||||
|
||||
✓ Start setup run API works.
|
||||
|
||||
✓ Save setup step API works.
|
||||
|
||||
✓ Complete setup run API works.
|
||||
|
||||
✓ Setup report API works.
|
||||
|
||||
✓ Wizard can resume current run after refresh.
|
||||
|
||||
✓ Wizard shows persisted step statuses.
|
||||
|
||||
✓ Wizard marks stale dependent steps after rerun.
|
||||
|
||||
✓ CSV commit creates seed manifest records when commit succeeds.
|
||||
|
||||
✓ dryRun commit does not create seed manifest records.
|
||||
|
||||
✓ Completed setup run stores final report.
|
||||
|
||||
✓ All APIs require super_admin.
|
||||
|
||||
✓ No destructive reset logic is implemented.
|
||||
|
||||
✓ No secrets or raw CSV contents are persisted.
|
||||
|
||||
✓ Typecheck passes or unrelated failures are documented.
|
||||
|
||||
---
|
||||
|
||||
## Suggested Verification
|
||||
|
||||
Run:
|
||||
|
||||
npm run db:generate
|
||||
|
||||
npm run db:migrate
|
||||
|
||||
npm run typecheck
|
||||
|
||||
Run scoped lint:
|
||||
|
||||
npx oxlint src/features/setup src/app/api/setup src/app/dashboard/administration/setup src/db/schema.ts
|
||||
|
||||
Manual test:
|
||||
|
||||
1. Open Setup Wizard.
|
||||
2. Start setup run.
|
||||
3. Run readiness.
|
||||
4. Refresh browser.
|
||||
5. Confirm readiness result persists.
|
||||
6. Upload CSV and preview.
|
||||
7. Refresh browser.
|
||||
8. Confirm preview step status persists without raw CSV content.
|
||||
9. Commit CSV.
|
||||
10. Confirm seed manifest and manifest item rows exist.
|
||||
11. Run verification.
|
||||
12. Complete setup.
|
||||
13. Refresh browser.
|
||||
14. Confirm completed setup summary appears.
|
||||
15. Try as non-super_admin.
|
||||
16. Confirm access denied.
|
||||
|
||||
---
|
||||
|
||||
## Follow-up
|
||||
|
||||
After D.7.8:
|
||||
|
||||
D.7.7 – Scoped Reset and Reseed Engine
|
||||
|
||||
D.7.9 – Installation Profile and Plugin Runtime Enhancement
|
||||
749
plans/task-d.7.9.md
Normal file
749
plans/task-d.7.9.md
Normal file
@@ -0,0 +1,749 @@
|
||||
# Task D.7.9 – Installation Profiles & Setup Plugin Registry
|
||||
|
||||
## Objective
|
||||
|
||||
Transform the ALLA OS Setup Platform into a fully extensible platform by introducing Installation Profiles and a Setup Plugin Registry.
|
||||
|
||||
The current Setup Platform (D.7.1–D.7.10) already supports:
|
||||
|
||||
- Readiness
|
||||
- Verification
|
||||
- CSV Templates
|
||||
- CSV Preview
|
||||
- CSV Commit
|
||||
- Setup Wizard
|
||||
- Setup State
|
||||
- Seed Manifest
|
||||
- Reset / Reseed
|
||||
- Golden Dataset
|
||||
|
||||
D.7.9 must remove remaining CRM-specific assumptions so future modules (CRM, HR, Asset, Inventory, Purchase, Service, etc.) can integrate into the Setup Platform without modifying the core wizard.
|
||||
|
||||
No existing setup behavior may regress.
|
||||
|
||||
---
|
||||
|
||||
# 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
|
||||
- plans/task-d.7.6.md
|
||||
- plans/task-d.7.7.md
|
||||
- plans/task-d.7.8.md
|
||||
- plans/task-d.7.10.md
|
||||
|
||||
Review
|
||||
|
||||
docs/setup/*
|
||||
|
||||
Review
|
||||
|
||||
setup/templates/*
|
||||
|
||||
Review
|
||||
|
||||
setup/golden-dataset/*
|
||||
|
||||
Review
|
||||
|
||||
src/features/setup/**
|
||||
|
||||
---
|
||||
|
||||
# Objective
|
||||
|
||||
Replace hardcoded setup behavior with configuration-driven module registration.
|
||||
|
||||
The Setup Platform must become reusable by every ALLA OS module.
|
||||
|
||||
---
|
||||
|
||||
# Implementation Scope
|
||||
|
||||
Create
|
||||
|
||||
src/features/setup/plugins/
|
||||
|
||||
Recommended structure
|
||||
|
||||
src/features/setup/plugins/
|
||||
|
||||
plugin-registry.ts
|
||||
|
||||
plugin-types.ts
|
||||
|
||||
installation-profile.ts
|
||||
|
||||
crm/
|
||||
|
||||
crm-setup-plugin.ts
|
||||
|
||||
crm-installation-profile.ts
|
||||
|
||||
foundation/
|
||||
|
||||
foundation-plugin.ts
|
||||
|
||||
---
|
||||
|
||||
# Installation Profiles
|
||||
|
||||
Introduce Installation Profiles.
|
||||
|
||||
Supported profiles
|
||||
|
||||
minimal
|
||||
|
||||
crm_starter
|
||||
|
||||
crm_demo
|
||||
|
||||
production
|
||||
|
||||
restore_backup
|
||||
|
||||
custom
|
||||
|
||||
Each profile defines
|
||||
|
||||
- visible wizard steps
|
||||
- required templates
|
||||
- verification checks
|
||||
- setup sequence
|
||||
- supported reset scopes
|
||||
- reseed targets
|
||||
- default options
|
||||
|
||||
Profile interface
|
||||
|
||||
```ts
|
||||
export interface InstallationProfile {
|
||||
|
||||
id:string;
|
||||
|
||||
name:string;
|
||||
|
||||
description:string;
|
||||
|
||||
wizardSteps:string[];
|
||||
|
||||
requiredTemplates:string[];
|
||||
|
||||
verificationChecks:string[];
|
||||
|
||||
resetScopes:string[];
|
||||
|
||||
reseedTargets:string[];
|
||||
|
||||
defaultOptions:Record<string,unknown>;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Setup Plugin Interface
|
||||
|
||||
Create
|
||||
|
||||
plugin-types.ts
|
||||
|
||||
```ts
|
||||
export interface SetupPlugin {
|
||||
|
||||
id:string;
|
||||
|
||||
version:string;
|
||||
|
||||
displayName:string;
|
||||
|
||||
description:string;
|
||||
|
||||
installationProfiles():InstallationProfile[];
|
||||
|
||||
templates():SetupTemplateDefinition[];
|
||||
|
||||
wizardSteps():SetupWizardStep[];
|
||||
|
||||
readinessChecks():SetupReadinessCheck[];
|
||||
|
||||
verificationChecks():SetupVerificationCheck[];
|
||||
|
||||
previewValidators():CsvPreviewValidator[];
|
||||
|
||||
importHandlers():CsvImporter[];
|
||||
|
||||
resetScopes():ResetScopeDefinition[];
|
||||
|
||||
reseedTargets():ReseedTargetDefinition[];
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Plugin Registry
|
||||
|
||||
Create
|
||||
|
||||
plugin-registry.ts
|
||||
|
||||
Responsibilities
|
||||
|
||||
Register plugins
|
||||
|
||||
Resolve plugins
|
||||
|
||||
Resolve installation profiles
|
||||
|
||||
Resolve templates
|
||||
|
||||
Resolve verification checks
|
||||
|
||||
Resolve reset scopes
|
||||
|
||||
Resolve reseed targets
|
||||
|
||||
Resolve wizard steps
|
||||
|
||||
Example
|
||||
|
||||
registerPlugin(new FoundationPlugin());
|
||||
|
||||
registerPlugin(new CrmSetupPlugin());
|
||||
|
||||
---
|
||||
|
||||
# Foundation Plugin
|
||||
|
||||
Move common setup behavior into Foundation Plugin.
|
||||
|
||||
Foundation Plugin owns
|
||||
|
||||
Readiness
|
||||
|
||||
Verification
|
||||
|
||||
Setup State
|
||||
|
||||
Seed Manifest
|
||||
|
||||
CSV Framework
|
||||
|
||||
Reset Framework
|
||||
|
||||
Golden Dataset framework
|
||||
|
||||
No CRM assumptions.
|
||||
|
||||
---
|
||||
|
||||
# CRM Setup Plugin
|
||||
|
||||
CRM Plugin owns
|
||||
|
||||
CRM Templates
|
||||
|
||||
CRM CSV Importers
|
||||
|
||||
CRM Verification
|
||||
|
||||
CRM Wizard Steps
|
||||
|
||||
CRM Reset Scope
|
||||
|
||||
CRM Golden Dataset registration
|
||||
|
||||
CRM Approval registration
|
||||
|
||||
CRM Document Sequence registration
|
||||
|
||||
CRM Reports registration
|
||||
|
||||
---
|
||||
|
||||
# Dynamic Wizard
|
||||
|
||||
Current wizard should stop hardcoding steps.
|
||||
|
||||
Instead
|
||||
|
||||
Plugin Registry
|
||||
|
||||
↓
|
||||
|
||||
Installation Profile
|
||||
|
||||
↓
|
||||
|
||||
Resolve Wizard Steps
|
||||
|
||||
↓
|
||||
|
||||
Render Wizard
|
||||
|
||||
Adding a module must not require editing the wizard.
|
||||
|
||||
---
|
||||
|
||||
# Dynamic Verification
|
||||
|
||||
Current verification service should allow plugins to register checks.
|
||||
|
||||
Instead of
|
||||
|
||||
CRM Check
|
||||
|
||||
Approval Check
|
||||
|
||||
PDF Check
|
||||
|
||||
Hardcoded
|
||||
|
||||
Use
|
||||
|
||||
Plugin Registry
|
||||
|
||||
↓
|
||||
|
||||
Collect Checks
|
||||
|
||||
↓
|
||||
|
||||
Execute
|
||||
|
||||
↓
|
||||
|
||||
Aggregate Report
|
||||
|
||||
---
|
||||
|
||||
# Dynamic Readiness
|
||||
|
||||
Allow plugins to register readiness checks.
|
||||
|
||||
Example
|
||||
|
||||
Storage Plugin
|
||||
|
||||
↓
|
||||
|
||||
Storage Check
|
||||
|
||||
PDF Plugin
|
||||
|
||||
↓
|
||||
|
||||
Template Check
|
||||
|
||||
CRM Plugin
|
||||
|
||||
↓
|
||||
|
||||
CRM Readiness
|
||||
|
||||
---
|
||||
|
||||
# Dynamic Template Registry
|
||||
|
||||
Extend
|
||||
|
||||
setup/templates/templates.json
|
||||
|
||||
Support
|
||||
|
||||
plugin
|
||||
|
||||
profile
|
||||
|
||||
visibility
|
||||
|
||||
Example
|
||||
|
||||
{
|
||||
"file":"customers.csv",
|
||||
"plugin":"crm",
|
||||
"profiles":[
|
||||
"crm_demo",
|
||||
"production"
|
||||
]
|
||||
}
|
||||
|
||||
Wizard automatically filters templates.
|
||||
|
||||
---
|
||||
|
||||
# Dynamic Navigation
|
||||
|
||||
Wizard should display
|
||||
|
||||
Installed Modules
|
||||
|
||||
Foundation
|
||||
|
||||
CRM
|
||||
|
||||
Approval
|
||||
|
||||
Storage
|
||||
|
||||
Future
|
||||
|
||||
HR
|
||||
|
||||
Asset
|
||||
|
||||
Inventory
|
||||
|
||||
Purchase
|
||||
|
||||
Modules not installed
|
||||
|
||||
↓
|
||||
|
||||
Hidden
|
||||
|
||||
---
|
||||
|
||||
# Profile Resolution
|
||||
|
||||
Selecting
|
||||
|
||||
crm_demo
|
||||
|
||||
Automatically
|
||||
|
||||
Enable
|
||||
|
||||
CRM plugin
|
||||
|
||||
Foundation plugin
|
||||
|
||||
Demo dataset
|
||||
|
||||
CRM templates
|
||||
|
||||
CRM verification
|
||||
|
||||
Demo reset
|
||||
|
||||
Disable
|
||||
|
||||
Restore Backup steps
|
||||
|
||||
Selecting
|
||||
|
||||
minimal
|
||||
|
||||
Only
|
||||
|
||||
Foundation
|
||||
|
||||
Verification
|
||||
|
||||
No CRM
|
||||
|
||||
---
|
||||
|
||||
# API Updates
|
||||
|
||||
Extend
|
||||
|
||||
GET /api/setup/templates
|
||||
|
||||
Include
|
||||
|
||||
plugin
|
||||
|
||||
profile
|
||||
|
||||
visible
|
||||
|
||||
supported
|
||||
|
||||
Update
|
||||
|
||||
GET /api/setup/readiness
|
||||
|
||||
Collect plugin readiness.
|
||||
|
||||
Update
|
||||
|
||||
POST /api/setup/verify
|
||||
|
||||
Collect plugin verification.
|
||||
|
||||
No API breaking changes.
|
||||
|
||||
---
|
||||
|
||||
# Setup Wizard Updates
|
||||
|
||||
Wizard
|
||||
|
||||
↓
|
||||
|
||||
Load Installation Profiles
|
||||
|
||||
↓
|
||||
|
||||
User selects profile
|
||||
|
||||
↓
|
||||
|
||||
Resolve Plugin Graph
|
||||
|
||||
↓
|
||||
|
||||
Build Wizard
|
||||
|
||||
↓
|
||||
|
||||
Render Steps
|
||||
|
||||
↓
|
||||
|
||||
Run Setup
|
||||
|
||||
Wizard must no longer contain CRM-specific logic.
|
||||
|
||||
---
|
||||
|
||||
# Golden Dataset Integration
|
||||
|
||||
Allow every plugin to register
|
||||
|
||||
Golden Dataset
|
||||
|
||||
Example
|
||||
|
||||
CRM
|
||||
|
||||
↓
|
||||
|
||||
setup/golden-dataset/crm/
|
||||
|
||||
Future
|
||||
|
||||
HR
|
||||
|
||||
↓
|
||||
|
||||
setup/golden-dataset/hr/
|
||||
|
||||
Asset
|
||||
|
||||
↓
|
||||
|
||||
setup/golden-dataset/asset/
|
||||
|
||||
---
|
||||
|
||||
# Future Module Example
|
||||
|
||||
Adding
|
||||
|
||||
Asset
|
||||
|
||||
Should require only
|
||||
|
||||
registerPlugin(
|
||||
|
||||
AssetSetupPlugin
|
||||
|
||||
);
|
||||
|
||||
No modification
|
||||
|
||||
Wizard
|
||||
|
||||
Verification
|
||||
|
||||
Reset
|
||||
|
||||
Template Registry
|
||||
|
||||
CSV Engine
|
||||
|
||||
---
|
||||
|
||||
# Out Of Scope
|
||||
|
||||
New business module
|
||||
|
||||
HR implementation
|
||||
|
||||
Asset implementation
|
||||
|
||||
Inventory implementation
|
||||
|
||||
Purchase implementation
|
||||
|
||||
Plugin marketplace
|
||||
|
||||
External plugin loading
|
||||
|
||||
Remote plugins
|
||||
|
||||
Installation package download
|
||||
|
||||
Backup restore implementation
|
||||
|
||||
CRM business behavior changes
|
||||
|
||||
---
|
||||
|
||||
# Deliverables
|
||||
|
||||
Required
|
||||
|
||||
src/features/setup/plugins/plugin-types.ts
|
||||
|
||||
src/features/setup/plugins/plugin-registry.ts
|
||||
|
||||
src/features/setup/plugins/installation-profile.ts
|
||||
|
||||
src/features/setup/plugins/foundation/foundation-plugin.ts
|
||||
|
||||
src/features/setup/plugins/crm/crm-setup-plugin.ts
|
||||
|
||||
src/features/setup/plugins/crm/crm-installation-profile.ts
|
||||
|
||||
Update
|
||||
|
||||
Setup Wizard
|
||||
|
||||
Readiness Service
|
||||
|
||||
Verification Service
|
||||
|
||||
Template Metadata Service
|
||||
|
||||
Template Registry
|
||||
|
||||
Optional
|
||||
|
||||
docs/setup/setup-plugin-development.md
|
||||
|
||||
docs/setup/installation-profiles.md
|
||||
|
||||
---
|
||||
|
||||
# Acceptance Criteria
|
||||
|
||||
✓ Installation Profiles exist.
|
||||
|
||||
✓ Plugin Registry exists.
|
||||
|
||||
✓ Foundation Plugin exists.
|
||||
|
||||
✓ CRM Plugin exists.
|
||||
|
||||
✓ Wizard builds dynamically from selected profile.
|
||||
|
||||
✓ Wizard no longer hardcodes CRM steps.
|
||||
|
||||
✓ Readiness collects plugin checks.
|
||||
|
||||
✓ Verification collects plugin checks.
|
||||
|
||||
✓ Template registry supports plugin ownership.
|
||||
|
||||
✓ Template registry supports profile visibility.
|
||||
|
||||
✓ Golden Dataset supports plugin registration.
|
||||
|
||||
✓ Future modules can integrate by registering one plugin.
|
||||
|
||||
✓ Existing Setup Wizard behavior remains unchanged.
|
||||
|
||||
✓ Existing APIs remain backward compatible.
|
||||
|
||||
✓ Existing CSV Preview/Commit logic is unaffected.
|
||||
|
||||
✓ Typecheck passes.
|
||||
|
||||
✓ Existing setup integration tests continue to pass.
|
||||
|
||||
---
|
||||
|
||||
# Suggested Verification
|
||||
|
||||
Run
|
||||
|
||||
npm run typecheck
|
||||
|
||||
npm run test:setup
|
||||
|
||||
Verify
|
||||
|
||||
Minimal Profile
|
||||
|
||||
↓
|
||||
|
||||
Foundation only
|
||||
|
||||
CRM Starter
|
||||
|
||||
↓
|
||||
|
||||
CRM steps only
|
||||
|
||||
CRM Demo
|
||||
|
||||
↓
|
||||
|
||||
CRM + Demo dataset
|
||||
|
||||
Production
|
||||
|
||||
↓
|
||||
|
||||
Production profile
|
||||
|
||||
Confirm
|
||||
|
||||
Readiness still PASS
|
||||
|
||||
Verification still PASS
|
||||
|
||||
CSV Preview unchanged
|
||||
|
||||
CSV Commit unchanged
|
||||
|
||||
Setup Resume unchanged
|
||||
|
||||
Golden Dataset unchanged
|
||||
|
||||
Register a temporary mock plugin
|
||||
|
||||
↓
|
||||
|
||||
Confirm
|
||||
|
||||
Wizard automatically includes plugin steps
|
||||
|
||||
Verification automatically executes plugin checks
|
||||
|
||||
Template API exposes plugin templates
|
||||
|
||||
Without modifying Setup Wizard source code.
|
||||
|
||||
---
|
||||
|
||||
# Completion Criteria
|
||||
|
||||
After D.7.9
|
||||
|
||||
The ALLA OS Setup Platform is officially module-driven.
|
||||
|
||||
All future modules (CRM, HR, Asset, Purchase, Inventory, Service, Calendar, etc.) must integrate through the Setup Plugin Registry rather than extending the Setup Wizard directly.
|
||||
|
||||
D.7.9 marks the architectural freeze of Setup Platform v1.0.
|
||||
192
plans/task-p.7.2.md
Normal file
192
plans/task-p.7.2.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# Task P.7.2 – SMTP / Email Configuration Platform
|
||||
|
||||
## Objective
|
||||
|
||||
Implement a secure SMTP / Email Configuration Platform for ALLA OS.
|
||||
|
||||
The goal is to let administrators configure, verify, and use outbound email safely for system notifications such as approval alerts, password reset, invitation emails, setup warnings, and future workflow notifications.
|
||||
|
||||
This task must integrate with the existing Setup Platform as an optional readiness/verification step.
|
||||
|
||||
Email configuration must not block First-run Setup unless explicitly required by the selected installation profile.
|
||||
|
||||
---
|
||||
|
||||
## Review Before Implementation
|
||||
|
||||
Review:
|
||||
|
||||
- AGENTS.md
|
||||
- docs/standards/project-foundations.md
|
||||
- docs/standards/architecture-rules.md
|
||||
- docs/standards/ui-ux-rules.md
|
||||
- docs/standards/task-review-checklist.md
|
||||
- docs/setup/verification-matrix.md
|
||||
- docs/setup/setup-wizard-blueprint.md
|
||||
- docs/setup/installation-profiles.md
|
||||
- src/features/setup/**
|
||||
- src/features/foundation/notifications/**
|
||||
- src/app/api/setup/readiness/route.ts
|
||||
- src/app/api/setup/verify/route.ts
|
||||
- src/db/schema.ts
|
||||
- existing Auth.js password reset / invitation flow if present
|
||||
|
||||
---
|
||||
|
||||
## Scope
|
||||
|
||||
Create email configuration foundation.
|
||||
|
||||
Required features:
|
||||
|
||||
- SMTP configuration CRUD
|
||||
- Secure secret handling
|
||||
- SMTP connection test
|
||||
- Send test email
|
||||
- Email provider readiness check
|
||||
- Integration with Setup Readiness / Verification
|
||||
- Optional Setup Wizard step
|
||||
- Audit-safe reporting
|
||||
- No secret exposure in API responses
|
||||
|
||||
---
|
||||
|
||||
## Data Model
|
||||
|
||||
Add table:
|
||||
|
||||
email_configurations
|
||||
|
||||
Suggested fields:
|
||||
|
||||
id
|
||||
|
||||
organization_id nullable
|
||||
|
||||
provider_type
|
||||
|
||||
name
|
||||
|
||||
host
|
||||
|
||||
port
|
||||
|
||||
secure
|
||||
|
||||
username
|
||||
|
||||
password_encrypted
|
||||
|
||||
from_email
|
||||
|
||||
from_name
|
||||
|
||||
reply_to_email
|
||||
|
||||
is_default
|
||||
|
||||
is_active
|
||||
|
||||
last_test_status
|
||||
|
||||
last_tested_at
|
||||
|
||||
last_test_error
|
||||
|
||||
created_by
|
||||
|
||||
updated_by
|
||||
|
||||
created_at
|
||||
|
||||
updated_at
|
||||
|
||||
Provider type values:
|
||||
|
||||
smtp
|
||||
|
||||
future values:
|
||||
|
||||
sendgrid
|
||||
ses
|
||||
mailgun
|
||||
microsoft_graph
|
||||
|
||||
---
|
||||
|
||||
## Secret Handling
|
||||
|
||||
SMTP password must never be stored as plain text.
|
||||
|
||||
Use existing encryption utility if available.
|
||||
|
||||
If none exists, create foundation crypto helper:
|
||||
|
||||
src/features/foundation/secrets/server/crypto.ts
|
||||
|
||||
Rules:
|
||||
|
||||
- encryption key from environment variable
|
||||
- missing key blocks saving password
|
||||
- API never returns password_encrypted
|
||||
- UI shows password as "configured" or "not configured"
|
||||
- password can be replaced, not read
|
||||
|
||||
Required environment:
|
||||
|
||||
EMAIL_CONFIG_ENCRYPTION_KEY
|
||||
|
||||
Suggested validation:
|
||||
|
||||
- minimum 32 bytes
|
||||
- base64 or hex recommended
|
||||
|
||||
---
|
||||
|
||||
## Server Services
|
||||
|
||||
Create:
|
||||
|
||||
src/features/foundation/email/server/email-config.service.ts
|
||||
src/features/foundation/email/server/email-test.service.ts
|
||||
src/features/foundation/email/server/email-provider.ts
|
||||
src/features/foundation/email/server/smtp-provider.ts
|
||||
|
||||
Responsibilities:
|
||||
|
||||
email-config.service.ts
|
||||
|
||||
- list configs
|
||||
- get config
|
||||
- create config
|
||||
- update config
|
||||
- delete/deactivate config
|
||||
- set default config
|
||||
- validate config
|
||||
- mask secret output
|
||||
|
||||
email-test.service.ts
|
||||
|
||||
- test SMTP connection
|
||||
- send test email
|
||||
- update last_test_status
|
||||
- update last_tested_at
|
||||
- store safe last_test_error
|
||||
|
||||
email-provider.ts
|
||||
|
||||
- provider interface
|
||||
|
||||
smtp-provider.ts
|
||||
|
||||
- nodemailer implementation or existing mail library integration
|
||||
|
||||
---
|
||||
|
||||
## Provider Interface
|
||||
|
||||
```ts
|
||||
export interface EmailProvider {
|
||||
testConnection(config: EmailProviderConfig): Promise<EmailTestResult>;
|
||||
sendEmail(input: SendEmailInput): Promise<SendEmailResult>;
|
||||
}
|
||||
2
setup/ALLA-ONVALLA/approval-matrix.csv
Normal file
2
setup/ALLA-ONVALLA/approval-matrix.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,entity_type,workflow_code,branch_code,product_type_code,min_amount,max_amount,currency,priority,is_default,is_active,description
|
||||
|
||||
|
1
setup/ALLA-ONVALLA/approval-steps.csv
Normal file
1
setup/ALLA-ONVALLA/approval-steps.csv
Normal file
@@ -0,0 +1 @@
|
||||
organization_code,workflow_code,step_number,role_code,role_name,approval_mode,is_required,sla_hours,calendar_mode,timeout_action
|
||||
|
1
setup/ALLA-ONVALLA/approval-workflows.csv
Normal file
1
setup/ALLA-ONVALLA/approval-workflows.csv
Normal file
@@ -0,0 +1 @@
|
||||
organization_code,workflow_code,workflow_name,entity_type,description,is_system,is_active
|
||||
|
3
setup/ALLA-ONVALLA/branches.csv
Normal file
3
setup/ALLA-ONVALLA/branches.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
organization_code,branch_code,branch_name,prefix,address,tax_id,phone,email,sort_order,is_active
|
||||
ALLA,head_office,Head Office,AL,"933, 935, 937,939 ซอยอ่อนนุช 46 ถนนอ่อนนุช แขวงอ่อนนุช เขตสวนหลวง กรุงเทพมหานคร 10250",0107558000393,023220776,head.office@example.com,1,true
|
||||
ONVALLA,head_office,Head Office,ON,เลขที่ 50 หมู่ 20 ตำบลลำลูกกา อำเภอลำลูกกา จังหวัดปทุมธานี 12150,0107558000393,021935380,eastern@example.com,2,true
|
||||
|
2
setup/ALLA-ONVALLA/crm-role-assignments.csv
Normal file
2
setup/ALLA-ONVALLA/crm-role-assignments.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,user_email,crm_role_code,is_primary,branch_scope_mode,branch_codes,product_type_scope_mode,product_type_codes,is_active
|
||||
|
||||
|
6
setup/ALLA-ONVALLA/document-sequences.csv
Normal file
6
setup/ALLA-ONVALLA/document-sequences.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
organization_code,branch_code,product_type_code,document_type,prefix,period,current_number,padding_length,format,reset_policy,is_active
|
||||
ALLA,head_office,crane,customer,CUS,yearly,0,4,{prefix}-{yyyy}-{running},period,true
|
||||
ALLA,head_office,crane,lead,LD,yearly,0,4,{prefix}-{yyyy}-{running},period,true
|
||||
ALLA,head_office,crane,opportunity,OP,yearly,0,4,{prefix}-{yyyy}-{running},period,true
|
||||
ALLA,head_office,crane,quotation,QT-AL-CR,monthly,0,4,{prefix}-{yy}{MM}-{running},period,true
|
||||
ONVALLA,head_office,crane,quotation,QT-ON-CR,monthly,0,4,{prefix}-{yy}{MM}-{running},period,true
|
||||
|
133
setup/ALLA-ONVALLA/master-options.csv
Normal file
133
setup/ALLA-ONVALLA/master-options.csv
Normal file
@@ -0,0 +1,133 @@
|
||||
organization_code,category,code,label,value,parent_category,parent_code,sort_order,is_active,metadata_json
|
||||
ALLA,crm_customer_group,construction,Construction,,,,1,true,{}
|
||||
ALLA,crm_customer_group,industrial,Industrial,,,,2,true,{}
|
||||
|
||||
ALLA,crm_customer_sub_group,factory,Factory,,crm_customer_group,industrial,1,true,{}
|
||||
ALLA,crm_customer_sub_group,warehouse,Warehouse,,crm_customer_group,industrial,2,true,{}
|
||||
|
||||
ALLA,crm_customer_status,active,Active,,,,1,true,{}
|
||||
ALLA,crm_customer_status,inactive,Inactive,,,,2,true,{}
|
||||
ALLA,crm_customer_status,prospect,Prospect,,,,3,true,{}
|
||||
|
||||
ALLA,crm_customer_type,end_customer,End Customer,,,,1,true,{}
|
||||
ALLA,crm_customer_type,contractor,Contractor,,,,2,true,{}
|
||||
ALLA,crm_customer_type,consultant,Consultant,,,,3,true,{}
|
||||
ALLA,crm_customer_type,developer,Developer,,,,4,true,{}
|
||||
|
||||
ALLA,crm_lead_channel,call_in,Call in,,,,1,true,{}
|
||||
ALLA,crm_lead_channel,ecommerce,E-commerce,,,,2,true,{}
|
||||
ALLA,crm_lead_channel,email,E-mail,,,,3,true,{}
|
||||
ALLA,crm_lead_channel,line_oa,Line OA,,,,4,true,{}
|
||||
ALLA,crm_lead_channel,visit,Visit,,,,5,true,{}
|
||||
ALLA,crm_lead_channel,walk_in,Walk In,,,,6,true,{}
|
||||
ALLA,crm_lead_channel,facebook,Facebook,,,,7,true,{}
|
||||
ALLA,crm_lead_channel,website_contact,Website Contact,,,,8,true,{}
|
||||
ALLA,crm_lead_channel,bci,BCI,,,,9,true,{}
|
||||
|
||||
ALLA,crm_lead_awareness,google_search,Google Search / Website,,,,1,true,{}
|
||||
ALLA,crm_lead_awareness,social_media,Social media,,,,2,true,{}
|
||||
ALLA,crm_lead_awareness,email_marketing,Email Marketing,,,,3,true,{}
|
||||
ALLA,crm_lead_awareness,visit,Visit,,,,4,true,{}
|
||||
ALLA,crm_lead_awareness,exhibition_event,Exhibition / Event,,,,5,true,{}
|
||||
ALLA,crm_lead_awareness,brochure_catalog,Brochure / Catalog,,,,6,true,{}
|
||||
ALLA,crm_lead_awareness,word_of_mouth,Word of mouth,,,,7,true,{}
|
||||
ALLA,crm_lead_awareness,corporate_car,Corporate Car,,,,8,true,{}
|
||||
ALLA,crm_lead_awareness,product_label,Product Label,,,,9,true,{}
|
||||
ALLA,crm_lead_awareness,re_purchasing,Re-purchasing,,,,10,true,{}
|
||||
ALLA,crm_lead_awareness,introducing,Introducing,,,,11,true,{}
|
||||
ALLA,crm_lead_awareness,bci,BCI,,,,12,true,{}
|
||||
|
||||
ALLA,crm_lead_priority,high,High,,,,1,true,{}
|
||||
ALLA,crm_lead_priority,medium,Medium,,,,2,true,{}
|
||||
ALLA,crm_lead_priority,low,Low,,,,3,true,{}
|
||||
|
||||
ALLA,crm_followup_status,new,New,,,,1,true,{}
|
||||
ALLA,crm_followup_status,contacted,Contacted,,,,2,true,{}
|
||||
ALLA,crm_followup_status,follow_up,Follow Up,,,,3,true,{}
|
||||
ALLA,crm_followup_status,closed,Closed,,,,4,true,{}
|
||||
|
||||
ALLA,crm_lost_reason,price,ราคา,,,,1,true,{}
|
||||
ALLA,crm_lost_reason,delivery_time,ระยะเวลาจัดส่ง,,,,2,true,{}
|
||||
ALLA,crm_lost_reason,salesperson,พนักงานขาย,,,,3,true,{}
|
||||
ALLA,crm_lost_reason,service,การบริการ,,,,4,true,{}
|
||||
ALLA,crm_lost_reason,customer,ลูกค้า,,,,5,true,{}
|
||||
ALLA,crm_lost_reason,product_quality,คุณภาพสินค้า,,,,6,true,{}
|
||||
ALLA,crm_lost_reason,other,อื่นๆ,,,,7,true,{}
|
||||
ALLA,crm_lost_reason,transfer,Transfer,,,,8,true,{}
|
||||
|
||||
ALLA,crm_project_party_role,billing_customer,Billing Customer,,,,1,true,{}
|
||||
ALLA,crm_project_party_role,end_customer,End Customer,,,,2,true,{}
|
||||
ALLA,crm_project_party_role,contractor,Contractor,,,,3,true,{}
|
||||
ALLA,crm_project_party_role,consultant,Consultant,,,,4,true,{}
|
||||
ALLA,crm_project_party_role,developer,Developer,,,,5,true,{}
|
||||
ALLA,crm_project_party_role,architect,Architect,,,,6,true,{}
|
||||
|
||||
ALLA,crm_quotation_type,standard,Standard,,,,1,true,{}
|
||||
ALLA,crm_quotation_type,revision,Revision,,,,2,true,{}
|
||||
|
||||
|
||||
ONVALLA,crm_customer_group,construction,Construction,,,,1,true,{}
|
||||
ONVALLA,crm_customer_group,industrial,Industrial,,,,2,true,{}
|
||||
|
||||
ONVALLA,crm_customer_sub_group,factory,Factory,,crm_customer_group,industrial,1,true,{}
|
||||
ONVALLA,crm_customer_sub_group,warehouse,Warehouse,,crm_customer_group,industrial,2,true,{}
|
||||
|
||||
ONVALLA,crm_customer_status,active,Active,,,,1,true,{}
|
||||
ONVALLA,crm_customer_status,inactive,Inactive,,,,2,true,{}
|
||||
ONVALLA,crm_customer_status,prospect,Prospect,,,,3,true,{}
|
||||
|
||||
ONVALLA,crm_customer_type,end_customer,End Customer,,,,1,true,{}
|
||||
ONVALLA,crm_customer_type,contractor,Contractor,,,,2,true,{}
|
||||
ONVALLA,crm_customer_type,consultant,Consultant,,,,3,true,{}
|
||||
ONVALLA,crm_customer_type,developer,Developer,,,,4,true,{}
|
||||
|
||||
ONVALLA,crm_lead_channel,call_in,Call in,,,,1,true,{}
|
||||
ONVALLA,crm_lead_channel,ecommerce,E-commerce,,,,2,true,{}
|
||||
ONVALLA,crm_lead_channel,email,E-mail,,,,3,true,{}
|
||||
ONVALLA,crm_lead_channel,line_oa,Line OA,,,,4,true,{}
|
||||
ONVALLA,crm_lead_channel,visit,Visit,,,,5,true,{}
|
||||
ONVALLA,crm_lead_channel,walk_in,Walk In,,,,6,true,{}
|
||||
ONVALLA,crm_lead_channel,facebook,Facebook,,,,7,true,{}
|
||||
ONVALLA,crm_lead_channel,website_contact,Website Contact,,,,8,true,{}
|
||||
ONVALLA,crm_lead_channel,bci,BCI,,,,9,true,{}
|
||||
|
||||
ONVALLA,crm_lead_awareness,google_search,Google Search / Website,,,,1,true,{}
|
||||
ONVALLA,crm_lead_awareness,social_media,Social media,,,,2,true,{}
|
||||
ONVALLA,crm_lead_awareness,email_marketing,Email Marketing,,,,3,true,{}
|
||||
ONVALLA,crm_lead_awareness,visit,Visit,,,,4,true,{}
|
||||
ONVALLA,crm_lead_awareness,exhibition_event,Exhibition / Event,,,,5,true,{}
|
||||
ONVALLA,crm_lead_awareness,brochure_catalog,Brochure / Catalog,,,,6,true,{}
|
||||
ONVALLA,crm_lead_awareness,word_of_mouth,Word of mouth,,,,7,true,{}
|
||||
ONVALLA,crm_lead_awareness,corporate_car,Corporate Car,,,,8,true,{}
|
||||
ONVALLA,crm_lead_awareness,product_label,Product Label,,,,9,true,{}
|
||||
ONVALLA,crm_lead_awareness,re_purchasing,Re-purchasing,,,,10,true,{}
|
||||
ONVALLA,crm_lead_awareness,introducing,Introducing,,,,11,true,{}
|
||||
ONVALLA,crm_lead_awareness,bci,BCI,,,,12,true,{}
|
||||
|
||||
ONVALLA,crm_lead_priority,high,High,,,,1,true,{}
|
||||
ONVALLA,crm_lead_priority,medium,Medium,,,,2,true,{}
|
||||
ONVALLA,crm_lead_priority,low,Low,,,,3,true,{}
|
||||
|
||||
ONVALLA,crm_followup_status,new,New,,,,1,true,{}
|
||||
ONVALLA,crm_followup_status,contacted,Contacted,,,,2,true,{}
|
||||
ONVALLA,crm_followup_status,follow_up,Follow Up,,,,3,true,{}
|
||||
ONVALLA,crm_followup_status,closed,Closed,,,,4,true,{}
|
||||
|
||||
ONVALLA,crm_lost_reason,price,ราคา,,,,1,true,{}
|
||||
ONVALLA,crm_lost_reason,delivery_time,ระยะเวลาจัดส่ง,,,,2,true,{}
|
||||
ONVALLA,crm_lost_reason,salesperson,พนักงานขาย,,,,3,true,{}
|
||||
ONVALLA,crm_lost_reason,service,การบริการ,,,,4,true,{}
|
||||
ONVALLA,crm_lost_reason,customer,ลูกค้า,,,,5,true,{}
|
||||
ONVALLA,crm_lost_reason,product_quality,คุณภาพสินค้า,,,,6,true,{}
|
||||
ONVALLA,crm_lost_reason,other,อื่นๆ,,,,7,true,{}
|
||||
ONVALLA,crm_lost_reason,transfer,Transfer,,,,8,true,{}
|
||||
|
||||
ONVALLA,crm_project_party_role,billing_customer,Billing Customer,,,,1,true,{}
|
||||
ONVALLA,crm_project_party_role,end_customer,End Customer,,,,2,true,{}
|
||||
ONVALLA,crm_project_party_role,contractor,Contractor,,,,3,true,{}
|
||||
ONVALLA,crm_project_party_role,consultant,Consultant,,,,4,true,{}
|
||||
ONVALLA,crm_project_party_role,developer,Developer,,,,5,true,{}
|
||||
ONVALLA,crm_project_party_role,architect,Architect,,,,6,true,{}
|
||||
|
||||
ONVALLA,crm_quotation_type,standard,Standard,,,,1,true,{}
|
||||
ONVALLA,crm_quotation_type,revision,Revision,,,,2,true,{}
|
||||
|
27
setup/ALLA-ONVALLA/memberships.csv
Normal file
27
setup/ALLA-ONVALLA/memberships.csv
Normal file
@@ -0,0 +1,27 @@
|
||||
organization_code,user_email,membership_role,business_role,permissions,branch_scope_codes,product_type_scope_codes
|
||||
ALLA,super_admin@allaos.local,admin,system_admin,*,*,*
|
||||
ALLA,gm.uat@allaos.local,user,general_manager,crm.dashboard.read|crm.customer.read|crm.lead.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office|eastern|northern,crane|dockdoor|solar|service
|
||||
ALLA,ceo.uat@allaos.local,user,executive,crm.dashboard.read|crm.approval.read,head_office|eastern|northern,crane|dockdoor|solar|service
|
||||
ALLA,head_mk.uat@allaos.local,user,marketing_manager,crm.dashboard.read|crm.lead.read|crm.lead.create|crm.lead.update|crm.lead.assign,head_office,crane|dockdoor|solar
|
||||
ALLA,mk.uat@allaos.local,user,marketing,crm.lead.read|crm.lead.create,head_office,crane|dockdoor|solar
|
||||
ALLA,manager.uat@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office|eastern|northern,crane|dockdoor|solar|service
|
||||
ALLA,mgr_crane.uat@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,eastern,crane
|
||||
ALLA,sales_crane.uat@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,eastern,crane
|
||||
ALLA,mgr_dock.uat@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office,dockdoor
|
||||
ALLA,sales_dock.uat@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,head_office,dockdoor
|
||||
ALLA,mgr_solar.uat@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,northern,solar
|
||||
ALLA,sales_solar.uat@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,northern,solar
|
||||
ALLA,sales.uat@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,head_office|eastern,crane|dockdoor
|
||||
|
||||
ONVALLA,gm.onvalla@allaos.local,user,general_manager,crm.dashboard.read|crm.customer.read|crm.lead.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office|eastern|northern,crane|dockdoor|solar|service
|
||||
ONVALLA,ceo.onvalla@allaos.local,user,executive,crm.dashboard.read|crm.approval.read,head_office|eastern|northern,crane|dockdoor|solar|service
|
||||
ONVALLA,head_mk.onvalla@allaos.local,user,marketing_manager,crm.dashboard.read|crm.lead.read|crm.lead.create|crm.lead.update|crm.lead.assign,head_office,crane|dockdoor|solar
|
||||
ONVALLA,mk.onvalla@allaos.local,user,marketing,crm.lead.read|crm.lead.create,head_office,crane|dockdoor|solar
|
||||
ONVALLA,manager.onvalla@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office|eastern|northern,crane|dockdoor|solar|service
|
||||
ONVALLA,mgr_crane.onvalla@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,eastern,crane
|
||||
ONVALLA,sales_crane.onvalla@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,eastern,crane
|
||||
ONVALLA,mgr_dock.onvalla@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office,dockdoor
|
||||
ONVALLA,sales_dock.onvalla@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,head_office,dockdoor
|
||||
ONVALLA,mgr_solar.onvalla@allaos.local,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,northern,solar
|
||||
ONVALLA,sales_solar.onvalla@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,northern,solar
|
||||
ONVALLA,sales.onvalla@allaos.local,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,head_office|eastern,crane|dockdoor
|
||||
|
3
setup/ALLA-ONVALLA/organizations.csv
Normal file
3
setup/ALLA-ONVALLA/organizations.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
organization_code,organization_name,slug,created_by_email,tax_id,default_currency,phone,email,address,logo_url,plan,status
|
||||
ALLA,ALLA Company Limited,alla,super_admin@allaos.local,1200101745173,THB,02-000-0000,admin@alla.example,99/9 Rama IX Road Bangkok,,enterprise,active
|
||||
ONVALLA,ONVALLA Demo Company,onvalla,super_admin@allaos.local,1200101745178,THB,02-000-0099,admin@onvalla.example,88/8 Demo Road Bangkok,,enterprise,active
|
||||
|
5
setup/ALLA-ONVALLA/product-types.csv
Normal file
5
setup/ALLA-ONVALLA/product-types.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
organization_code,product_type_code,product_type_name,document_prefix,sort_order,is_active,metadata_json
|
||||
ALLA,crane,Crane,CR,1,true,{}
|
||||
ALLA,dockdoor,DocK Door,DK,2,true,{}
|
||||
ONVALLA,crane,Crane,CR,3,true,{}
|
||||
ONVALLA,solarcell,Solar cell,SC,4,true,{}
|
||||
|
26
setup/ALLA-ONVALLA/users.csv
Normal file
26
setup/ALLA-ONVALLA/users.csv
Normal file
@@ -0,0 +1,26 @@
|
||||
email,name,system_role,password,active_organization_code,image_url,reset_password
|
||||
super_admin@allaos.local,System Administrator,super_admin,ChangeMe123!,ALLA,,FALSE
|
||||
gm.uat@allaos.local,General Manager,user,ChangeMe123!,ALLA,,FALSE
|
||||
ceo.uat@allaos.local,Chief Executive Officer,user,ChangeMe123!,ALLA,,FALSE
|
||||
head_mk.uat@allaos.local,Head of Marketing,user,ChangeMe123!,ALLA,,FALSE
|
||||
mk.uat@allaos.local,Marketing User,user,ChangeMe123!,ALLA,,FALSE
|
||||
manager.uat@allaos.local,Sales Director,user,ChangeMe123!,ALLA,,FALSE
|
||||
mgr_crane.uat@allaos.local,Crane Sales Manager,user,ChangeMe123!,ALLA,,FALSE
|
||||
sales_crane.uat@allaos.local,Crane Sales,user,ChangeMe123!,ALLA,,FALSE
|
||||
mgr_dock.uat@allaos.local,Dock Door Sales Manager,user,ChangeMe123!,ALLA,,FALSE
|
||||
sales_dock.uat@allaos.local,Dock Door Sales,user,ChangeMe123!,ALLA,,FALSE
|
||||
mgr_solar.uat@allaos.local,Solar Sales Manager,user,ChangeMe123!,ALLA,,FALSE
|
||||
sales_solar.uat@allaos.local,Solar Sales,user,ChangeMe123!,ALLA,,FALSE
|
||||
sales.uat@allaos.local,General Sales,user,ChangeMe123!,ALLA,,FALSE
|
||||
gm.onvalla@allaos.local,General Manager,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
ceo.onvalla@allaos.local,Chief Executive Officer,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
head_mk.onvalla@allaos.local,Head of Marketing,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
mk.onvalla@allaos.local,Marketing User,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
manager.onvalla@allaos.local,Sales Director,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
mgr_crane.onvalla@allaos.local,Crane Sales Manager,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
sales_crane.onvalla@allaos.local,Crane Sales,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
mgr_dock.onvalla@allaos.local,Dock Door Sales Manager,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
sales_dock.onvalla@allaos.local,Dock Door Sales,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
mgr_solar.onvalla@allaos.local,Solar Sales Manager,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
sales_solar.onvalla@allaos.local,Solar Sales,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
sales.onvalla@allaos.local,General Sales,user,ChangeMe123!,ONVALLA,,FALSE
|
||||
|
31
setup/golden-dataset/README.md
Normal file
31
setup/golden-dataset/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# ALLA OS Setup Golden Dataset
|
||||
|
||||
This dataset is the canonical setup fixture for development, CI contract checks, QA, UAT, customer demo, and regression testing.
|
||||
|
||||
It mirrors the official setup template registry and is intentionally safe sample data.
|
||||
|
||||
## Dataset Summary
|
||||
|
||||
- Organizations: `ALLA`, `ONVALLA`
|
||||
- Users: IT, Marketing, Sales, Sales Manager, CEO
|
||||
- Customers: 10
|
||||
- Contacts: 20
|
||||
- Leads: 20
|
||||
- Opportunities: 15
|
||||
- Quotations: 20
|
||||
- Branches: 3
|
||||
- Product types: 3
|
||||
- Quotation statuses include draft, pending approval, approved, rejected, and revision.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Apply migrations.
|
||||
2. Run setup readiness.
|
||||
3. Start setup run.
|
||||
4. Preview all CSV files in this directory.
|
||||
5. Commit with the returned `previewHash`.
|
||||
6. Run verification.
|
||||
7. Complete setup.
|
||||
8. Use reset preview APIs for maintenance tests.
|
||||
|
||||
Do not edit headers manually. Headers must remain identical to `setup/templates/*.csv`.
|
||||
3
setup/golden-dataset/approval-matrix.csv
Normal file
3
setup/golden-dataset/approval-matrix.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
organization_code,entity_type,workflow_code,branch_code,product_type_code,min_amount,max_amount,currency,priority,is_default,is_active,description
|
||||
ALLA,quotation,quotation_standard,head_office,crane,0,5000000,THB,100,true,true,Default crane approval
|
||||
ALLA,quotation,quotation_standard,eastern,hoist,0,3000000,THB,90,false,true,Eastern hoist approval
|
||||
|
3
setup/golden-dataset/approval-steps.csv
Normal file
3
setup/golden-dataset/approval-steps.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
organization_code,workflow_code,step_number,role_code,role_name,approval_mode,is_required,sla_hours,calendar_mode,timeout_action
|
||||
ALLA,quotation_standard,1,sales_manager,Sales Manager,sequential,true,24,calendar_days,none
|
||||
ALLA,quotation_standard,2,ceo,Chief Executive Officer,sequential,true,48,calendar_days,none
|
||||
|
2
setup/golden-dataset/approval-workflows.csv
Normal file
2
setup/golden-dataset/approval-workflows.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,workflow_code,workflow_name,entity_type,description,is_system,is_active
|
||||
ALLA,quotation_standard,Quotation Standard Approval,quotation,Default quotation approval,false,true
|
||||
|
4
setup/golden-dataset/branches.csv
Normal file
4
setup/golden-dataset/branches.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
organization_code,branch_code,branch_name,prefix,address,tax_id,phone,email,sort_order,is_active
|
||||
ALLA,head_office,Head Office,HO,99/9 Rama IX Road Bangkok,0107558000393,02-000-0000,head.office@example.com,1,true
|
||||
ALLA,eastern,Eastern Branch,ES,55/5 Chonburi Industrial Estate,0107558000393,038-000-000,eastern@example.com,2,true
|
||||
ALLA,northern,Northern Branch,NO,44/4 Chiang Mai Road,0107558000393,053-000-000,northern@example.com,3,true
|
||||
|
6
setup/golden-dataset/contact-shares.csv
Normal file
6
setup/golden-dataset/contact-shares.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
organization_code,customer_code,contact_email,shared_to_user_email,shared_by_user_email,remark,is_active
|
||||
ALLA,CUS-001,anan@siam.example,sales.uat@example.com,admin@example.com,Golden share,true
|
||||
ALLA,CUS-002,chai@metro.example,sales.uat@example.com,admin@example.com,Golden share,true
|
||||
ALLA,CUS-003,ekk@north.example,manager.uat@example.com,admin@example.com,Golden share,true
|
||||
ALLA,CUS-004,golf@easternsteel.example,sales.uat@example.com,admin@example.com,Golden share,true
|
||||
ALLA,CUS-005,itt@central-log.example,sales.uat@example.com,admin@example.com,Golden share,true
|
||||
|
21
setup/golden-dataset/contacts.csv
Normal file
21
setup/golden-dataset/contacts.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,customer_code,contact_name,created_by_email,position,department,phone,mobile,email,is_primary,notes,is_active
|
||||
ALLA,CUS-001,Anan Sales,admin@example.com,Procurement Manager,Procurement,02-000-1001,081-000-0001,anan@siam.example,true,Primary contact,true
|
||||
ALLA,CUS-001,Ben Engineer,admin@example.com,Plant Engineer,Engineering,02-000-1002,081-000-0002,ben@siam.example,false,Technical contact,true
|
||||
ALLA,CUS-002,Chai Manager,admin@example.com,Project Manager,Project,02-000-1003,081-000-0003,chai@metro.example,true,Primary contact,true
|
||||
ALLA,CUS-002,Dara QS,admin@example.com,QS,Commercial,02-000-1004,081-000-0004,dara@metro.example,false,Commercial contact,true
|
||||
ALLA,CUS-003,Ekk Designer,admin@example.com,Designer,Design,02-000-1005,081-000-0005,ekk@north.example,true,Primary contact,true
|
||||
ALLA,CUS-003,Fon Architect,admin@example.com,Architect,Design,02-000-1006,081-000-0006,fon@north.example,false,Design contact,true
|
||||
ALLA,CUS-004,Golf Ops,admin@example.com,Operations Manager,Operations,02-000-1007,081-000-0007,golf@easternsteel.example,true,Primary contact,true
|
||||
ALLA,CUS-004,Hana Buyer,admin@example.com,Buyer,Procurement,02-000-1008,081-000-0008,hana@easternsteel.example,false,Buyer contact,true
|
||||
ALLA,CUS-005,Itt Logistics,admin@example.com,Logistics Manager,Logistics,02-000-1009,081-000-0009,itt@central-log.example,true,Primary contact,true
|
||||
ALLA,CUS-005,Jin Warehouse,admin@example.com,Warehouse Lead,Warehouse,02-000-1010,081-000-0010,jin@central-log.example,false,Warehouse contact,true
|
||||
ALLA,CUS-006,Kai Site,admin@example.com,Site Manager,Project,02-000-1011,081-000-0011,kai@harbor.example,true,Primary contact,true
|
||||
ALLA,CUS-006,Lek Admin,admin@example.com,Admin,Administration,02-000-1012,081-000-0012,lek@harbor.example,false,Admin contact,true
|
||||
ALLA,CUS-007,Mai Plant,admin@example.com,Plant Manager,Production,02-000-1013,081-000-0013,mai@peakfoods.example,true,Primary contact,true
|
||||
ALLA,CUS-007,Nok Maintenance,admin@example.com,Maintenance,Engineering,02-000-1014,081-000-0014,nok@peakfoods.example,false,Maintenance contact,true
|
||||
ALLA,CUS-008,Oat Packaging,admin@example.com,Factory Manager,Factory,02-000-1015,081-000-0015,oat@riverpack.example,true,Primary contact,true
|
||||
ALLA,CUS-008,Pim Buyer,admin@example.com,Buyer,Procurement,02-000-1016,081-000-0016,pim@riverpack.example,false,Buyer contact,true
|
||||
ALLA,CUS-009,Q Auto,admin@example.com,Production Manager,Production,02-000-1017,081-000-0017,q@summitauto.example,true,Primary contact,true
|
||||
ALLA,CUS-009,Rin Engineer,admin@example.com,Engineer,Engineering,02-000-1018,081-000-0018,rin@summitauto.example,false,Engineer contact,true
|
||||
ALLA,CUS-010,Som Developer,admin@example.com,Development Manager,Development,02-000-1019,081-000-0019,som@urban.example,true,Primary contact,true
|
||||
ALLA,CUS-010,Tan Project,admin@example.com,Project Coordinator,Project,02-000-1020,081-000-0020,tan@urban.example,false,Project contact,true
|
||||
|
6
setup/golden-dataset/crm-role-assignments.csv
Normal file
6
setup/golden-dataset/crm-role-assignments.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
organization_code,user_email,crm_role_code,is_primary,branch_scope_mode,branch_codes,product_type_scope_mode,product_type_codes,is_active
|
||||
ALLA,admin@example.com,crm_admin,true,all,,all,,true
|
||||
ALLA,mk.uat@example.com,marketing,true,selected,head_office,selected,crane|hoist,true
|
||||
ALLA,sales.uat@example.com,sales,true,selected,head_office|eastern,selected,crane|hoist,true
|
||||
ALLA,manager.uat@example.com,sales_manager,true,all,,all,,true
|
||||
ALLA,ceo.uat@example.com,ceo,true,all,,all,,true
|
||||
|
11
setup/golden-dataset/customers.csv
Normal file
11
setup/golden-dataset/customers.csv
Normal file
@@ -0,0 +1,11 @@
|
||||
organization_code,customer_code,customer_name,customer_type,customer_status,created_by_email,branch_code,abbr,tax_id,address,province,district,sub_district,postal_code,country,phone,fax,email,website,lead_channel,customer_group,customer_sub_group,owner_user_email,notes,is_active
|
||||
ALLA,CUS-001,Siam Factory,end_customer,active,admin@example.com,head_office,SF,0105559000001,1 Factory Road,Bangkok,Bang Kapi,Hua Mak,10240,TH,02-100-0001,,contact@siam.example,https://siam.example,website,industrial,factory,sales.uat@example.com,Golden customer 1,true
|
||||
ALLA,CUS-002,Metro Contractor,contractor,active,admin@example.com,eastern,MC,0105559000002,2 Contractor Road,Chonburi,Mueang,Saen Suk,20000,TH,02-100-0002,,contact@metro.example,https://metro.example,referral,industrial,factory,sales.uat@example.com,Golden customer 2,true
|
||||
ALLA,CUS-003,North Design,consultant,prospect,admin@example.com,northern,ND,0105559000003,3 Design Road,Chiang Mai,Mueang,Suthep,50200,TH,02-100-0003,,contact@north.example,https://north.example,event,industrial,factory,manager.uat@example.com,Golden customer 3,true
|
||||
ALLA,CUS-004,Eastern Steel,end_customer,active,admin@example.com,eastern,ES,0105559000004,4 Steel Road,Rayong,Mueang,Noen Phra,21000,TH,02-100-0004,,contact@easternsteel.example,https://easternsteel.example,website,industrial,factory,sales.uat@example.com,Golden customer 4,true
|
||||
ALLA,CUS-005,Central Logistics,end_customer,active,admin@example.com,head_office,CL,0105559000005,5 Logistics Road,Bangkok,Lat Krabang,Lat Krabang,10520,TH,02-100-0005,,contact@central-log.example,https://central-log.example,referral,industrial,factory,sales.uat@example.com,Golden customer 5,true
|
||||
ALLA,CUS-006,Harbor Engineering,contractor,prospect,admin@example.com,eastern,HE,0105559000006,6 Harbor Road,Chonburi,Sriracha,Sriracha,20110,TH,02-100-0006,,contact@harbor.example,https://harbor.example,event,industrial,factory,manager.uat@example.com,Golden customer 6,true
|
||||
ALLA,CUS-007,Peak Foods,end_customer,active,admin@example.com,northern,PF,0105559000007,7 Food Road,Lamphun,Mueang,Nai Mueang,51000,TH,02-100-0007,,contact@peakfoods.example,https://peakfoods.example,website,industrial,factory,sales.uat@example.com,Golden customer 7,true
|
||||
ALLA,CUS-008,River Packaging,end_customer,active,admin@example.com,head_office,RP,0105559000008,8 Packaging Road,Pathum Thani,Khlong Luang,Khlong Nueng,12120,TH,02-100-0008,,contact@riverpack.example,https://riverpack.example,referral,industrial,factory,sales.uat@example.com,Golden customer 8,true
|
||||
ALLA,CUS-009,Summit Auto,end_customer,active,admin@example.com,eastern,SA,0105559000009,9 Auto Road,Chachoengsao,Bang Pakong,Bang Pakong,24130,TH,02-100-0009,,contact@summitauto.example,https://summitauto.example,event,industrial,factory,manager.uat@example.com,Golden customer 9,true
|
||||
ALLA,CUS-010,Urban Developer,contractor,prospect,admin@example.com,head_office,UD,0105559000010,10 Tower Road,Bangkok,Pathum Wan,Lumphini,10330,TH,02-100-0010,,contact@urban.example,https://urban.example,website,industrial,factory,sales.uat@example.com,Golden customer 10,true
|
||||
|
55
setup/golden-dataset/dataset.json
Normal file
55
setup/golden-dataset/dataset.json
Normal file
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "alla-os-setup-golden-dataset",
|
||||
"version": "1.0.0",
|
||||
"generatedFrom": "plans/task-d.7.10.md",
|
||||
"templateRegistry": "setup/templates/templates.json",
|
||||
"description": "Canonical ALLA OS setup dataset for development, CI contract checks, QA, UAT, demos, and regression testing.",
|
||||
"organizations": ["ALLA", "ONVALLA"],
|
||||
"counts": {
|
||||
"organizations": 2,
|
||||
"users": 5,
|
||||
"customers": 10,
|
||||
"contacts": 20,
|
||||
"leads": 20,
|
||||
"opportunities": 15,
|
||||
"quotations": 20,
|
||||
"branches": 3,
|
||||
"productTypes": 3
|
||||
},
|
||||
"workflow": [
|
||||
"migration",
|
||||
"readiness",
|
||||
"template_registry",
|
||||
"preview",
|
||||
"commit",
|
||||
"verification",
|
||||
"manifest",
|
||||
"resume",
|
||||
"reset"
|
||||
],
|
||||
"expectedQuotationStatuses": ["draft", "pending_approval", "approved", "rejected", "revision"],
|
||||
"files": [
|
||||
"users.csv",
|
||||
"organizations.csv",
|
||||
"memberships.csv",
|
||||
"crm-role-assignments.csv",
|
||||
"master-options.csv",
|
||||
"branches.csv",
|
||||
"product-types.csv",
|
||||
"document-sequences.csv",
|
||||
"approval-workflows.csv",
|
||||
"approval-steps.csv",
|
||||
"approval-matrix.csv",
|
||||
"customers.csv",
|
||||
"contacts.csv",
|
||||
"contact-shares.csv",
|
||||
"leads.csv",
|
||||
"opportunities.csv",
|
||||
"opportunity-parties.csv",
|
||||
"quotations.csv",
|
||||
"quotation-items.csv",
|
||||
"quotation-parties.csv",
|
||||
"quotation-topics.csv",
|
||||
"quotation-topic-items.csv"
|
||||
]
|
||||
}
|
||||
5
setup/golden-dataset/document-sequences.csv
Normal file
5
setup/golden-dataset/document-sequences.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
organization_code,branch_code,product_type_code,document_type,prefix,period,current_number,padding_length,format,reset_policy,is_active
|
||||
ALLA,head_office,crane,customer,CUS,yearly,0,4,{prefix}-{yyyy}-{running},yearly,true
|
||||
ALLA,head_office,crane,lead,LD,yearly,0,4,{prefix}-{yyyy}-{running},yearly,true
|
||||
ALLA,head_office,crane,opportunity,OP,yearly,0,4,{prefix}-{yyyy}-{running},yearly,true
|
||||
ALLA,head_office,crane,quotation,QT-HO-CR,monthly,0,4,{prefix}-{yy}{MM}-{running},monthly,true
|
||||
|
21
setup/golden-dataset/leads.csv
Normal file
21
setup/golden-dataset/leads.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,lead_code,status,created_by_email,branch_code,customer_code,contact_email,description,project_name,project_location,lead_channel,product_type_code,priority,estimated_value,awareness_code,followup_status,lost_reason,outcome,owner_marketing_user_email,assigned_sales_owner_email,assignment_remark
|
||||
ALLA,LD-001,new,mk.uat@example.com,head_office,CUS-001,anan@siam.example,Crane inquiry,Plant crane upgrade,Bangkok,website,crane,high,1200000,website,new,,,mk.uat@example.com,sales.uat@example.com,Assigned from golden dataset
|
||||
ALLA,LD-002,contacted,mk.uat@example.com,eastern,CUS-002,chai@metro.example,Hoist inquiry,Warehouse hoist,Chonburi,referral,hoist,medium,450000,referral,contacted,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-003,new,mk.uat@example.com,northern,CUS-003,ekk@north.example,Service inquiry,Maintenance plan,Chiang Mai,event,service,medium,150000,event,new,,,mk.uat@example.com,manager.uat@example.com,Assigned
|
||||
ALLA,LD-004,new,mk.uat@example.com,eastern,CUS-004,golf@easternsteel.example,Crane expansion,Steel bay crane,Rayong,website,crane,high,2200000,website,new,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-005,contacted,mk.uat@example.com,head_office,CUS-005,itt@central-log.example,Hoist replacement,Logistics hoist,Bangkok,referral,hoist,medium,600000,referral,contacted,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-006,new,mk.uat@example.com,eastern,CUS-006,kai@harbor.example,Project crane,Harbor yard,Chonburi,event,crane,high,3000000,event,new,,,mk.uat@example.com,manager.uat@example.com,Assigned
|
||||
ALLA,LD-007,new,mk.uat@example.com,northern,CUS-007,mai@peakfoods.example,Food plant service,Service contract,Lamphun,website,service,low,120000,website,new,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-008,contacted,mk.uat@example.com,head_office,CUS-008,oat@riverpack.example,Packaging crane,Packaging line,Pathum Thani,referral,crane,medium,950000,referral,contacted,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-009,new,mk.uat@example.com,eastern,CUS-009,q@summitauto.example,Auto hoist,Assembly hoist,Chachoengsao,event,hoist,high,780000,event,new,,,mk.uat@example.com,manager.uat@example.com,Assigned
|
||||
ALLA,LD-010,new,mk.uat@example.com,head_office,CUS-010,som@urban.example,Tower crane,Developer project,Bangkok,website,crane,high,4200000,website,new,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-011,new,mk.uat@example.com,head_office,CUS-001,ben@siam.example,Spare service,Siam service,Bangkok,referral,service,low,90000,referral,new,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-012,contacted,mk.uat@example.com,eastern,CUS-002,dara@metro.example,Contractor crane,Metro project,Chonburi,event,crane,medium,1300000,event,contacted,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-013,new,mk.uat@example.com,northern,CUS-003,fon@north.example,Design assist,North plant,Chiang Mai,website,hoist,medium,500000,website,new,,,mk.uat@example.com,manager.uat@example.com,Assigned
|
||||
ALLA,LD-014,new,mk.uat@example.com,eastern,CUS-004,hana@easternsteel.example,Steel service,Rayong steel,Rayong,referral,service,low,110000,referral,new,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-015,contacted,mk.uat@example.com,head_office,CUS-005,jin@central-log.example,Warehouse crane,Central warehouse,Bangkok,event,crane,high,1800000,event,contacted,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-016,new,mk.uat@example.com,eastern,CUS-006,lek@harbor.example,Harbor hoist,Harbor support,Chonburi,website,hoist,medium,650000,website,new,,,mk.uat@example.com,manager.uat@example.com,Assigned
|
||||
ALLA,LD-017,new,mk.uat@example.com,northern,CUS-007,nok@peakfoods.example,Maintenance hoist,Food maintenance,Lamphun,referral,hoist,low,250000,referral,new,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-018,contacted,mk.uat@example.com,head_office,CUS-008,pim@riverpack.example,Line upgrade,Packaging expansion,Pathum Thani,event,crane,medium,1400000,event,contacted,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
ALLA,LD-019,new,mk.uat@example.com,eastern,CUS-009,rin@summitauto.example,Auto service,Summit service,Chachoengsao,website,service,low,160000,website,new,,,mk.uat@example.com,manager.uat@example.com,Assigned
|
||||
ALLA,LD-020,new,mk.uat@example.com,head_office,CUS-010,tan@urban.example,Developer hoist,Tower support,Bangkok,referral,hoist,medium,820000,referral,new,,,mk.uat@example.com,sales.uat@example.com,Assigned
|
||||
|
21
setup/golden-dataset/master-options.csv
Normal file
21
setup/golden-dataset/master-options.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,category,code,label,value,parent_category,parent_code,sort_order,is_active,metadata_json
|
||||
ALLA,crm_customer_type,end_customer,End Customer,,,,1,true,{}
|
||||
ALLA,crm_customer_type,contractor,Contractor,,,,2,true,{}
|
||||
ALLA,crm_customer_type,consultant,Consultant,,,,3,true,{}
|
||||
ALLA,crm_customer_status,active,Active,,,,1,true,{}
|
||||
ALLA,crm_customer_status,prospect,Prospect,,,,2,true,{}
|
||||
ALLA,crm_lead_channel,website,Website,,,,1,true,{}
|
||||
ALLA,crm_lead_channel,referral,Referral,,,,2,true,{}
|
||||
ALLA,crm_lead_channel,event,Event,,,,3,true,{}
|
||||
ALLA,crm_lead_priority,high,High,,,,1,true,{}
|
||||
ALLA,crm_lead_priority,medium,Medium,,,,2,true,{}
|
||||
ALLA,crm_lead_priority,low,Low,,,,3,true,{}
|
||||
ALLA,crm_followup_status,new,New,,,,1,true,{}
|
||||
ALLA,crm_followup_status,contacted,Contacted,,,,2,true,{}
|
||||
ALLA,crm_lost_reason,budget,Budget mismatch,,,,1,true,{}
|
||||
ALLA,crm_project_party_role,end_customer,End Customer,,,,1,true,{}
|
||||
ALLA,crm_project_party_role,contractor,Contractor,,,,2,true,{}
|
||||
ALLA,crm_project_party_role,consultant,Consultant,,,,3,true,{}
|
||||
ALLA,crm_quotation_type,standard,Standard,,,,1,true,{}
|
||||
ALLA,crm_customer_group,industrial,Industrial,,,,1,true,{}
|
||||
ALLA,crm_customer_sub_group,factory,Factory,crm_customer_group,industrial,1,true,{}
|
||||
|
6
setup/golden-dataset/memberships.csv
Normal file
6
setup/golden-dataset/memberships.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
organization_code,user_email,membership_role,business_role,permissions,branch_scope_codes,product_type_scope_codes
|
||||
ALLA,admin@example.com,admin,sales_manager,crm.dashboard.read|crm.customer.read|crm.customer.create|crm.lead.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office|eastern|northern,crane|hoist|service
|
||||
ALLA,mk.uat@example.com,user,marketing,crm.lead.read|crm.lead.create,head_office,crane|hoist
|
||||
ALLA,sales.uat@example.com,user,sales,crm.customer.read|crm.opportunity.read|crm.quotation.read,head_office|eastern,crane|hoist
|
||||
ALLA,manager.uat@example.com,user,sales_manager,crm.dashboard.read|crm.customer.read|crm.opportunity.read|crm.quotation.read|crm.approval.read,head_office|eastern|northern,crane|hoist|service
|
||||
ALLA,ceo.uat@example.com,user,executive,crm.dashboard.read|crm.approval.read,head_office|eastern|northern,crane|hoist|service
|
||||
|
16
setup/golden-dataset/opportunities.csv
Normal file
16
setup/golden-dataset/opportunities.csv
Normal file
@@ -0,0 +1,16 @@
|
||||
organization_code,opportunity_code,customer_code,title,product_type_code,status,priority,created_by_email,updated_by_email,lead_code,contact_email,branch_code,description,requirement,project_name,project_location,outcome_status,lead_channel,estimated_value,chance_percent,expected_close_date,competitor,source,notes,is_hot_project,pipeline_stage,assigned_to_user_email
|
||||
ALLA,OP-001,CUS-001,Siam crane upgrade,crane,open,high,sales.uat@example.com,sales.uat@example.com,LD-001,anan@siam.example,head_office,Crane upgrade,10 ton crane,Plant crane upgrade,Bangkok,open,website,1200000,70,2026-08-15,Competitor A,website,Golden opportunity,true,proposal,sales.uat@example.com
|
||||
ALLA,OP-002,CUS-002,Metro warehouse hoist,hoist,open,medium,sales.uat@example.com,sales.uat@example.com,LD-002,chai@metro.example,eastern,Warehouse hoist,5 ton hoist,Warehouse hoist,Chonburi,open,referral,450000,60,2026-08-20,Competitor B,referral,Golden opportunity,false,qualification,sales.uat@example.com
|
||||
ALLA,OP-003,CUS-003,North service plan,service,open,medium,manager.uat@example.com,manager.uat@example.com,LD-003,ekk@north.example,northern,Service plan,Annual maintenance,Maintenance plan,Chiang Mai,open,event,150000,50,2026-09-01,,event,Golden opportunity,false,qualification,manager.uat@example.com
|
||||
ALLA,OP-004,CUS-004,Eastern steel bay crane,crane,open,high,sales.uat@example.com,sales.uat@example.com,LD-004,golf@easternsteel.example,eastern,Steel bay crane,20 ton crane,Steel bay crane,Rayong,open,website,2200000,75,2026-09-10,Competitor C,website,Golden opportunity,true,proposal,sales.uat@example.com
|
||||
ALLA,OP-005,CUS-005,Central logistics hoist,hoist,open,medium,sales.uat@example.com,sales.uat@example.com,LD-005,itt@central-log.example,head_office,Hoist replacement,Replacement hoist,Logistics hoist,Bangkok,open,referral,600000,65,2026-09-15,,referral,Golden opportunity,false,proposal,sales.uat@example.com
|
||||
ALLA,OP-006,CUS-006,Harbor yard crane,crane,open,high,manager.uat@example.com,manager.uat@example.com,LD-006,kai@harbor.example,eastern,Harbor crane,Outdoor crane,Harbor yard,Chonburi,open,event,3000000,80,2026-10-01,Competitor D,event,Golden opportunity,true,proposal,manager.uat@example.com
|
||||
ALLA,OP-007,CUS-007,Peak service contract,service,open,low,sales.uat@example.com,sales.uat@example.com,LD-007,mai@peakfoods.example,northern,Service contract,Annual contract,Food service,Lamphun,open,website,120000,40,2026-08-30,,website,Golden opportunity,false,qualification,sales.uat@example.com
|
||||
ALLA,OP-008,CUS-008,River packaging crane,crane,open,medium,sales.uat@example.com,sales.uat@example.com,LD-008,oat@riverpack.example,head_office,Packaging crane,Line crane,Packaging line,Pathum Thani,open,referral,950000,55,2026-09-20,Competitor E,referral,Golden opportunity,false,proposal,sales.uat@example.com
|
||||
ALLA,OP-009,CUS-009,Summit auto hoist,hoist,open,high,manager.uat@example.com,manager.uat@example.com,LD-009,q@summitauto.example,eastern,Auto hoist,Assembly hoist,Assembly hoist,Chachoengsao,open,event,780000,60,2026-09-25,,event,Golden opportunity,false,proposal,manager.uat@example.com
|
||||
ALLA,OP-010,CUS-010,Urban tower crane,crane,open,high,sales.uat@example.com,sales.uat@example.com,LD-010,som@urban.example,head_office,Tower crane,Tower project,Developer project,Bangkok,open,website,4200000,70,2026-10-10,Competitor F,website,Golden opportunity,true,proposal,sales.uat@example.com
|
||||
ALLA,OP-011,CUS-001,Siam spare service,service,open,low,sales.uat@example.com,sales.uat@example.com,LD-011,ben@siam.example,head_office,Spare service,Service package,Siam service,Bangkok,open,referral,90000,45,2026-08-28,,referral,Golden opportunity,false,qualification,sales.uat@example.com
|
||||
ALLA,OP-012,CUS-002,Metro contractor crane,crane,open,medium,sales.uat@example.com,sales.uat@example.com,LD-012,dara@metro.example,eastern,Contractor crane,Site crane,Metro project,Chonburi,open,event,1300000,55,2026-09-18,Competitor G,event,Golden opportunity,false,proposal,sales.uat@example.com
|
||||
ALLA,OP-013,CUS-003,North design hoist,hoist,open,medium,manager.uat@example.com,manager.uat@example.com,LD-013,fon@north.example,northern,Design hoist,Hoist plan,North plant,Chiang Mai,open,website,500000,50,2026-09-12,,website,Golden opportunity,false,qualification,manager.uat@example.com
|
||||
ALLA,OP-014,CUS-004,Eastern steel service,service,open,low,sales.uat@example.com,sales.uat@example.com,LD-014,hana@easternsteel.example,eastern,Steel service,Service visit,Rayong steel,Rayong,open,referral,110000,45,2026-08-26,,referral,Golden opportunity,false,qualification,sales.uat@example.com
|
||||
ALLA,OP-015,CUS-005,Central warehouse crane,crane,open,high,sales.uat@example.com,sales.uat@example.com,LD-015,jin@central-log.example,head_office,Warehouse crane,Warehouse crane,Central warehouse,Bangkok,open,event,1800000,65,2026-09-30,Competitor H,event,Golden opportunity,true,proposal,sales.uat@example.com
|
||||
|
16
setup/golden-dataset/opportunity-parties.csv
Normal file
16
setup/golden-dataset/opportunity-parties.csv
Normal file
@@ -0,0 +1,16 @@
|
||||
organization_code,opportunity_code,customer_code,role_code,remark
|
||||
ALLA,OP-001,CUS-001,end_customer,End customer
|
||||
ALLA,OP-002,CUS-002,contractor,Contractor
|
||||
ALLA,OP-003,CUS-003,consultant,Consultant
|
||||
ALLA,OP-004,CUS-004,end_customer,End customer
|
||||
ALLA,OP-005,CUS-005,end_customer,End customer
|
||||
ALLA,OP-006,CUS-006,contractor,Contractor
|
||||
ALLA,OP-007,CUS-007,end_customer,End customer
|
||||
ALLA,OP-008,CUS-008,end_customer,End customer
|
||||
ALLA,OP-009,CUS-009,end_customer,End customer
|
||||
ALLA,OP-010,CUS-010,contractor,Contractor
|
||||
ALLA,OP-011,CUS-001,end_customer,End customer
|
||||
ALLA,OP-012,CUS-002,contractor,Contractor
|
||||
ALLA,OP-013,CUS-003,consultant,Consultant
|
||||
ALLA,OP-014,CUS-004,end_customer,End customer
|
||||
ALLA,OP-015,CUS-005,end_customer,End customer
|
||||
|
3
setup/golden-dataset/organizations.csv
Normal file
3
setup/golden-dataset/organizations.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
organization_code,organization_name,slug,created_by_email,tax_id,default_currency,phone,email,address,logo_url,plan,status
|
||||
ALLA,ALLA Company Limited,alla,admin@example.com,0107558000393,THB,02-000-0000,admin@alla.example,99/9 Rama IX Road Bangkok,,enterprise,active
|
||||
ONVALLA,ONVALLA Demo Company,onvalla,admin@example.com,0107558000401,THB,02-000-0099,admin@onvalla.example,88/8 Demo Road Bangkok,,demo,active
|
||||
|
4
setup/golden-dataset/product-types.csv
Normal file
4
setup/golden-dataset/product-types.csv
Normal file
@@ -0,0 +1,4 @@
|
||||
organization_code,product_type_code,product_type_name,document_prefix,sort_order,is_active,metadata_json
|
||||
ALLA,crane,Crane,CR,1,true,{}
|
||||
ALLA,hoist,Hoist,HO,2,true,{}
|
||||
ALLA,service,Service,SV,3,true,{}
|
||||
|
21
setup/golden-dataset/quotation-items.csv
Normal file
21
setup/golden-dataset/quotation-items.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,quotation_code,item_number,product_type_code,description,quantity,unit_price,total_price,unit,discount,discount_type,tax_rate,notes,sort_order
|
||||
ALLA,QT-HO-CR-2607-001,1,crane,Crane system package,1,1000000,1000000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-002,1,hoist,Hoist system package,1,450000,450000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-003,1,service,Service package,1,150000,150000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-004,1,crane,Steel bay crane package,1,2200000,2200000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-005,1,hoist,Logistics hoist package,1,600000,600000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-006,1,crane,Harbor crane package,1,3000000,3000000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-007,1,service,Annual service package,1,120000,120000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-008,1,crane,Packaging crane package,1,950000,950000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-009,1,hoist,Auto hoist package,1,780000,780000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-010,1,crane,Tower crane package,1,4200000,4200000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-011,1,service,Spare service package,1,90000,90000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-012,1,crane,Contractor crane package,1,1300000,1300000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-013,1,hoist,Design hoist package,1,500000,500000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-014,1,service,Steel service package,1,110000,110000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-015,1,crane,Warehouse crane package,1,1800000,1800000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-016,1,hoist,Harbor hoist support,1,650000,650000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-017,1,hoist,Maintenance hoist package,1,250000,250000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-018,1,crane,Line upgrade package,1,1400000,1400000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-019,1,service,Auto service package,1,160000,160000,set,0,amount,7,Golden item,1
|
||||
ALLA,QT-HO-CR-2607-020,1,hoist,Developer hoist package,1,820000,820000,set,0,amount,7,Golden item,1
|
||||
|
21
setup/golden-dataset/quotation-parties.csv
Normal file
21
setup/golden-dataset/quotation-parties.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,quotation_code,customer_code,role_code,is_primary,remark
|
||||
ALLA,QT-HO-CR-2607-001,CUS-001,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-002,CUS-002,contractor,true,Contractor
|
||||
ALLA,QT-HO-CR-2607-003,CUS-003,consultant,true,Consultant
|
||||
ALLA,QT-HO-CR-2607-004,CUS-004,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-005,CUS-005,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-006,CUS-006,contractor,true,Contractor
|
||||
ALLA,QT-HO-CR-2607-007,CUS-007,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-008,CUS-008,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-009,CUS-009,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-010,CUS-010,contractor,true,Contractor
|
||||
ALLA,QT-HO-CR-2607-011,CUS-001,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-012,CUS-002,contractor,true,Contractor
|
||||
ALLA,QT-HO-CR-2607-013,CUS-003,consultant,true,Consultant
|
||||
ALLA,QT-HO-CR-2607-014,CUS-004,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-015,CUS-005,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-016,CUS-006,contractor,true,Contractor
|
||||
ALLA,QT-HO-CR-2607-017,CUS-007,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-018,CUS-008,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-019,CUS-009,end_customer,true,End customer
|
||||
ALLA,QT-HO-CR-2607-020,CUS-010,contractor,true,Contractor
|
||||
|
21
setup/golden-dataset/quotation-topic-items.csv
Normal file
21
setup/golden-dataset/quotation-topic-items.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,quotation_code,topic_key,content,sort_order
|
||||
ALLA,QT-HO-CR-2607-001,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-002,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-003,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-004,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-005,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-006,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-007,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-008,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-009,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-010,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-011,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-012,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-013,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-014,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-015,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-016,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-017,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-018,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-019,scope,Supply and installation according to golden dataset scope.,1
|
||||
ALLA,QT-HO-CR-2607-020,scope,Supply and installation according to golden dataset scope.,1
|
||||
|
21
setup/golden-dataset/quotation-topics.csv
Normal file
21
setup/golden-dataset/quotation-topics.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,quotation_code,topic_key,topic_type,title,sort_order
|
||||
ALLA,QT-HO-CR-2607-001,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-002,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-003,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-004,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-005,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-006,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-007,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-008,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-009,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-010,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-011,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-012,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-013,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-014,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-015,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-016,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-017,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-018,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-019,scope,terms,Scope of Supply,1
|
||||
ALLA,QT-HO-CR-2607-020,scope,terms,Scope of Supply,1
|
||||
|
21
setup/golden-dataset/quotations.csv
Normal file
21
setup/golden-dataset/quotations.csv
Normal file
@@ -0,0 +1,21 @@
|
||||
organization_code,quotation_code,customer_code,quotation_date,quotation_type,status,currency,subtotal,total_amount,created_by_email,updated_by_email,opportunity_code,contact_email,branch_code,valid_until,project_name,project_location,attention,reference,notes,revision,parent_quotation_code,revision_remark,exchange_rate,discount,discount_type,tax_rate,tax_amount,chance_percent,is_hot_project,competitor,salesman_email,is_sent,sent_at,sent_via
|
||||
ALLA,QT-HO-CR-2607-001,CUS-001,2026-07-01,standard,draft,THB,1000000,1070000,sales.uat@example.com,sales.uat@example.com,OP-001,anan@siam.example,head_office,2026-08-01,Plant crane upgrade,Bangkok,Anan Sales,REF-001,Golden quotation,0,,,1,0,amount,7,70000,70,true,Competitor A,sales.uat@example.com,false,,
|
||||
ALLA,QT-HO-CR-2607-002,CUS-002,2026-07-02,standard,pending_approval,THB,450000,481500,sales.uat@example.com,sales.uat@example.com,OP-002,chai@metro.example,eastern,2026-08-02,Warehouse hoist,Chonburi,Chai Manager,REF-002,Golden quotation,0,,,1,0,amount,7,31500,60,false,Competitor B,sales.uat@example.com,true,2026-07-03,email
|
||||
ALLA,QT-HO-CR-2607-003,CUS-003,2026-07-03,standard,approved,THB,150000,160500,manager.uat@example.com,manager.uat@example.com,OP-003,ekk@north.example,northern,2026-08-03,Maintenance plan,Chiang Mai,Ekk Designer,REF-003,Golden quotation,0,,,1,0,amount,7,10500,50,false,,manager.uat@example.com,true,2026-07-04,email
|
||||
ALLA,QT-HO-CR-2607-004,CUS-004,2026-07-04,standard,rejected,THB,2200000,2354000,sales.uat@example.com,sales.uat@example.com,OP-004,golf@easternsteel.example,eastern,2026-08-04,Steel bay crane,Rayong,Golf Ops,REF-004,Golden quotation,0,,,1,0,amount,7,154000,75,true,Competitor C,sales.uat@example.com,true,2026-07-05,email
|
||||
ALLA,QT-HO-CR-2607-005,CUS-005,2026-07-05,standard,revision,THB,600000,642000,sales.uat@example.com,sales.uat@example.com,OP-005,itt@central-log.example,head_office,2026-08-05,Logistics hoist,Bangkok,Itt Logistics,REF-005,Golden quotation,1,QT-HO-CR-2607-002,Revised scope,1,0,amount,7,42000,65,false,,sales.uat@example.com,true,2026-07-06,email
|
||||
ALLA,QT-HO-CR-2607-006,CUS-006,2026-07-06,standard,draft,THB,3000000,3210000,manager.uat@example.com,manager.uat@example.com,OP-006,kai@harbor.example,eastern,2026-08-06,Harbor yard,Chonburi,Kai Site,REF-006,Golden quotation,0,,,1,0,amount,7,210000,80,true,Competitor D,manager.uat@example.com,false,,
|
||||
ALLA,QT-HO-CR-2607-007,CUS-007,2026-07-07,standard,pending_approval,THB,120000,128400,sales.uat@example.com,sales.uat@example.com,OP-007,mai@peakfoods.example,northern,2026-08-07,Food service,Lamphun,Mai Plant,REF-007,Golden quotation,0,,,1,0,amount,7,8400,40,false,,sales.uat@example.com,true,2026-07-08,email
|
||||
ALLA,QT-HO-CR-2607-008,CUS-008,2026-07-08,standard,approved,THB,950000,1016500,sales.uat@example.com,sales.uat@example.com,OP-008,oat@riverpack.example,head_office,2026-08-08,Packaging line,Pathum Thani,Oat Packaging,REF-008,Golden quotation,0,,,1,0,amount,7,66500,55,false,Competitor E,sales.uat@example.com,true,2026-07-09,email
|
||||
ALLA,QT-HO-CR-2607-009,CUS-009,2026-07-09,standard,rejected,THB,780000,834600,manager.uat@example.com,manager.uat@example.com,OP-009,q@summitauto.example,eastern,2026-08-09,Assembly hoist,Chachoengsao,Q Auto,REF-009,Golden quotation,0,,,1,0,amount,7,54600,60,false,,manager.uat@example.com,true,2026-07-10,email
|
||||
ALLA,QT-HO-CR-2607-010,CUS-010,2026-07-10,standard,revision,THB,4200000,4494000,sales.uat@example.com,sales.uat@example.com,OP-010,som@urban.example,head_office,2026-08-10,Developer project,Bangkok,Som Developer,REF-010,Golden quotation,1,QT-HO-CR-2607-001,Revision 1,1,0,amount,7,294000,70,true,Competitor F,sales.uat@example.com,true,2026-07-11,email
|
||||
ALLA,QT-HO-CR-2607-011,CUS-001,2026-07-11,standard,draft,THB,90000,96300,sales.uat@example.com,sales.uat@example.com,OP-011,ben@siam.example,head_office,2026-08-11,Siam service,Bangkok,Ben Engineer,REF-011,Golden quotation,0,,,1,0,amount,7,6300,45,false,,sales.uat@example.com,false,,
|
||||
ALLA,QT-HO-CR-2607-012,CUS-002,2026-07-12,standard,pending_approval,THB,1300000,1391000,sales.uat@example.com,sales.uat@example.com,OP-012,dara@metro.example,eastern,2026-08-12,Metro project,Chonburi,Dara QS,REF-012,Golden quotation,0,,,1,0,amount,7,91000,55,false,Competitor G,sales.uat@example.com,true,2026-07-13,email
|
||||
ALLA,QT-HO-CR-2607-013,CUS-003,2026-07-13,standard,approved,THB,500000,535000,manager.uat@example.com,manager.uat@example.com,OP-013,fon@north.example,northern,2026-08-13,North plant,Chiang Mai,Fon Architect,REF-013,Golden quotation,0,,,1,0,amount,7,35000,50,false,,manager.uat@example.com,true,2026-07-14,email
|
||||
ALLA,QT-HO-CR-2607-014,CUS-004,2026-07-14,standard,rejected,THB,110000,117700,sales.uat@example.com,sales.uat@example.com,OP-014,hana@easternsteel.example,eastern,2026-08-14,Rayong steel,Rayong,Hana Buyer,REF-014,Golden quotation,0,,,1,0,amount,7,7700,45,false,,sales.uat@example.com,true,2026-07-15,email
|
||||
ALLA,QT-HO-CR-2607-015,CUS-005,2026-07-15,standard,revision,THB,1800000,1926000,sales.uat@example.com,sales.uat@example.com,OP-015,jin@central-log.example,head_office,2026-08-15,Central warehouse,Bangkok,Jin Warehouse,REF-015,Golden quotation,1,QT-HO-CR-2607-012,Revision 1,1,0,amount,7,126000,65,true,Competitor H,sales.uat@example.com,true,2026-07-16,email
|
||||
ALLA,QT-HO-CR-2607-016,CUS-006,2026-07-16,standard,draft,THB,650000,695500,manager.uat@example.com,manager.uat@example.com,OP-006,lek@harbor.example,eastern,2026-08-16,Harbor support,Chonburi,Lek Admin,REF-016,Golden quotation,0,,,1,0,amount,7,45500,50,false,,manager.uat@example.com,false,,
|
||||
ALLA,QT-HO-CR-2607-017,CUS-007,2026-07-17,standard,pending_approval,THB,250000,267500,sales.uat@example.com,sales.uat@example.com,OP-007,nok@peakfoods.example,northern,2026-08-17,Food maintenance,Lamphun,Nok Maintenance,REF-017,Golden quotation,0,,,1,0,amount,7,17500,40,false,,sales.uat@example.com,true,2026-07-18,email
|
||||
ALLA,QT-HO-CR-2607-018,CUS-008,2026-07-18,standard,approved,THB,1400000,1498000,sales.uat@example.com,sales.uat@example.com,OP-008,pim@riverpack.example,head_office,2026-08-18,Packaging expansion,Pathum Thani,Pim Buyer,REF-018,Golden quotation,0,,,1,0,amount,7,98000,55,false,,sales.uat@example.com,true,2026-07-19,email
|
||||
ALLA,QT-HO-CR-2607-019,CUS-009,2026-07-19,standard,rejected,THB,160000,171200,manager.uat@example.com,manager.uat@example.com,OP-009,rin@summitauto.example,eastern,2026-08-19,Summit service,Chachoengsao,Rin Engineer,REF-019,Golden quotation,0,,,1,0,amount,7,11200,35,false,,manager.uat@example.com,true,2026-07-20,email
|
||||
ALLA,QT-HO-CR-2607-020,CUS-010,2026-07-20,standard,revision,THB,820000,877400,sales.uat@example.com,sales.uat@example.com,OP-010,tan@urban.example,head_office,2026-08-20,Tower support,Bangkok,Tan Project,REF-020,Golden quotation,1,QT-HO-CR-2607-017,Revision 1,1,0,amount,7,57400,50,false,,sales.uat@example.com,true,2026-07-21,email
|
||||
|
6
setup/golden-dataset/users.csv
Normal file
6
setup/golden-dataset/users.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
email,name,system_role,password,active_organization_code,image_url,reset_password
|
||||
admin@example.com,System Administrator,super_admin,ChangeMe123!,ALLA,,false
|
||||
mk.uat@example.com,Marketing User,user,ChangeMe123!,ALLA,,false
|
||||
sales.uat@example.com,Sales User,user,ChangeMe123!,ALLA,,false
|
||||
manager.uat@example.com,Sales Manager,user,ChangeMe123!,ALLA,,false
|
||||
ceo.uat@example.com,Chief Executive Officer,user,ChangeMe123!,ALLA,,false
|
||||
|
91
setup/templates/README.md
Normal file
91
setup/templates/README.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# ALLA OS Setup CSV Templates
|
||||
|
||||
This folder contains the supported static CSV template pack for Task D.7.3.
|
||||
|
||||
Rules:
|
||||
|
||||
- UTF-8 text.
|
||||
- Comma delimiter.
|
||||
- LF line endings.
|
||||
- One header row and one safe sample row per CSV.
|
||||
- No unsupported template files are generated.
|
||||
- No production data, formulas, secrets, or binary references are included.
|
||||
|
||||
## Sample Dataset
|
||||
|
||||
All templates use one consistent sample dataset:
|
||||
|
||||
- Organization: `ALLA`
|
||||
- Branch: `head_office`
|
||||
- Product type: `crane`
|
||||
- Currency: `THB`
|
||||
- Administrator: `admin@example.com`
|
||||
- Marketing: `mk.uat@example.com`
|
||||
- Sales: `sales.uat@example.com`
|
||||
- Manager: `manager.uat@example.com`
|
||||
- CEO: `ceo.uat@example.com`
|
||||
- Customer: `CUS-001`
|
||||
- Lead: `LD-001`
|
||||
- Opportunity: `OP-001`
|
||||
- Quotation: `QT-HO-CR-2607-001`
|
||||
|
||||
## Import Order
|
||||
|
||||
| Order | File | Purpose |
|
||||
| --- | --- | --- |
|
||||
| 01 | `users.csv` | Setup-managed users |
|
||||
| 02 | `organizations.csv` | Tenant organizations |
|
||||
| 03 | `memberships.csv` | Organization memberships |
|
||||
| 05 | `crm-role-assignments.csv` | CRM role assignments |
|
||||
| 06 | `master-options.csv` | Generic master options |
|
||||
| 07 | `branches.csv` | Branch options |
|
||||
| 08 | `product-types.csv` | Product type options |
|
||||
| 14 | `document-sequences.csv` | Document numbering |
|
||||
| 15 | `approval-workflows.csv` | Approval workflows |
|
||||
| 16 | `approval-steps.csv` | Approval workflow steps |
|
||||
| 17 | `approval-matrix.csv` | Approval routing matrix |
|
||||
| 30 | `customers.csv` | CRM customers |
|
||||
| 32 | `contacts.csv` | Customer contacts |
|
||||
| 33 | `contact-shares.csv` | Contact sharing grants |
|
||||
| 34 | `leads.csv` | Marketing leads |
|
||||
| 36 | `opportunities.csv` | Sales opportunities |
|
||||
| 37 | `opportunity-parties.csv` | Opportunity project parties |
|
||||
| 40 | `quotations.csv` | Quotation headers |
|
||||
| 41 | `quotation-items.csv` | Quotation line items |
|
||||
| 42 | `quotation-parties.csv` | Quotation project parties |
|
||||
| 43 | `quotation-topics.csv` | Quotation topic headers |
|
||||
| 44 | `quotation-topic-items.csv` | Quotation topic rows |
|
||||
|
||||
## Relationship Rules
|
||||
|
||||
- `organization_code` links rows to the organization import context.
|
||||
- `user_email`, `created_by_email`, `updated_by_email`, and role-related email fields resolve to `users.email`.
|
||||
- `branch_code` resolves to `ms_options` category `crm_branch`.
|
||||
- `product_type_code` resolves to `ms_options` category `crm_product_type`.
|
||||
- `customer_code`, `lead_code`, `opportunity_code`, and `quotation_code` are business keys within the organization.
|
||||
- `topic_key` is an import-only alias linking `quotation-topics.csv` to `quotation-topic-items.csv`.
|
||||
- Pipe-delimited fields, such as permission or scope lists, use `|`.
|
||||
|
||||
## Placeholders
|
||||
|
||||
These templates intentionally leave sensitive or runtime values empty:
|
||||
|
||||
- `users.csv` has an empty `password` sample value.
|
||||
- Runtime approval and PDF artifact fields are not present.
|
||||
- Binary attachment paths are not present.
|
||||
|
||||
## Unsupported Templates
|
||||
|
||||
The following files are documented but not generated because the current schema does not support them as safe first-class setup imports:
|
||||
|
||||
- `departments.csv`
|
||||
- `teams.csv`
|
||||
- `warehouses.csv`
|
||||
- `sites.csv`
|
||||
- `services.csv`
|
||||
- `price-books.csv`
|
||||
- `tax-rates.csv`
|
||||
- `attachments.csv`
|
||||
- `email-settings.csv`
|
||||
|
||||
See `docs/setup/csv-template-spec.md` and `docs/setup/import-mapping.md` for the full contract.
|
||||
2
setup/templates/approval-matrix.csv
Normal file
2
setup/templates/approval-matrix.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,entity_type,workflow_code,branch_code,product_type_code,min_amount,max_amount,currency,priority,is_default,is_active,description
|
||||
ALLA,quotation,quotation_standard,head_office,crane,0,5000000,THB,100,true,true,Default crane approval
|
||||
|
2
setup/templates/approval-steps.csv
Normal file
2
setup/templates/approval-steps.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,workflow_code,step_number,role_code,role_name,approval_mode,is_required,sla_hours,calendar_mode,timeout_action
|
||||
ALLA,quotation_standard,1,sales_manager,Sales Manager,sequential,true,24,calendar_days,none
|
||||
|
2
setup/templates/approval-workflows.csv
Normal file
2
setup/templates/approval-workflows.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,workflow_code,workflow_name,entity_type,description,is_system,is_active
|
||||
ALLA,quotation_standard,Quotation Standard Approval,quotation,Default quotation approval,false,true
|
||||
|
2
setup/templates/branches.csv
Normal file
2
setup/templates/branches.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,branch_code,branch_name,prefix,address,tax_id,phone,email,sort_order,is_active
|
||||
ALLA,head_office,Head Office,HO,99/9 Rama IX Road Bangkok,0107558000393,02-000-0000,head.office@example.com,1,true
|
||||
|
2
setup/templates/contact-shares.csv
Normal file
2
setup/templates/contact-shares.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,customer_code,contact_email,shared_to_user_email,shared_by_user_email,remark,is_active
|
||||
ALLA,CUS-001,anan@siam.example,sales.uat@example.com,admin@example.com,Shared for setup sample,true
|
||||
|
2
setup/templates/contacts.csv
Normal file
2
setup/templates/contacts.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,customer_code,contact_name,created_by_email,position,department,phone,mobile,email,is_primary,notes,is_active
|
||||
ALLA,CUS-001,Anan Sales,admin@example.com,Procurement Manager,Procurement,02-000-1001,081-000-0001,anan@siam.example,true,Primary procurement contact,true
|
||||
|
2
setup/templates/crm-role-assignments.csv
Normal file
2
setup/templates/crm-role-assignments.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,user_email,crm_role_code,is_primary,branch_scope_mode,branch_codes,product_type_scope_mode,product_type_codes,is_active
|
||||
ALLA,admin@example.com,crm_admin,true,all,,all,,true
|
||||
|
2
setup/templates/customers.csv
Normal file
2
setup/templates/customers.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,customer_code,customer_name,customer_type,customer_status,created_by_email,branch_code,abbr,tax_id,address,province,district,sub_district,postal_code,country,phone,fax,email,website,lead_channel,customer_group,customer_sub_group,owner_user_email,notes,is_active
|
||||
ALLA,CUS-001,Siam Manufacturing,company,active,admin@example.com,head_office,SIAM,0105555000001,100 Industrial Road,Bangkok,Bang Na,Bang Na,10260,Thailand,02-000-1000,,contact@siam.example,https://siam.example,website,industrial,factory,sales.uat@example.com,Initial setup sample customer,true
|
||||
|
2
setup/templates/document-sequences.csv
Normal file
2
setup/templates/document-sequences.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,branch_code,product_type_code,document_type,prefix,period,current_number,padding_length,format,reset_policy,is_active
|
||||
ALLA,head_office,crane,quotation,QT-HO-CR-,2607,0,3,{prefix}{period}-{running},period,true
|
||||
|
2
setup/templates/leads.csv
Normal file
2
setup/templates/leads.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,lead_code,status,created_by_email,branch_code,customer_code,contact_email,description,project_name,project_location,lead_channel,product_type_code,priority,estimated_value,awareness_code,followup_status,lost_reason,outcome,owner_marketing_user_email,assigned_sales_owner_email,assignment_remark
|
||||
ALLA,LD-001,assigned,mk.uat@example.com,head_office,CUS-001,anan@siam.example,Customer requested crane consultation,Warehouse Crane,Bangkok Warehouse,website,crane,high,1000000,google_search_website,quotation_preparation,,open,mk.uat@example.com,sales.uat@example.com,Assigned from setup sample
|
||||
|
2
setup/templates/master-options.csv
Normal file
2
setup/templates/master-options.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,category,code,label,value,parent_category,parent_code,sort_order,is_active,metadata_json
|
||||
ALLA,crm_customer_group,industrial,Industrial,industrial,,,1,true,{}
|
||||
|
2
setup/templates/memberships.csv
Normal file
2
setup/templates/memberships.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,user_email,membership_role,business_role,permissions,branch_scope_codes,product_type_scope_codes
|
||||
ALLA,admin@example.com,admin,crm_admin,crm.dashboard.read|crm.role.read|crm.user_role_assignment.read,head_office,crane
|
||||
|
2
setup/templates/opportunities.csv
Normal file
2
setup/templates/opportunities.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,opportunity_code,customer_code,title,product_type_code,status,priority,created_by_email,updated_by_email,lead_code,contact_email,branch_code,description,requirement,project_name,project_location,outcome_status,lead_channel,estimated_value,chance_percent,expected_close_date,competitor,source,notes,is_hot_project,pipeline_stage,assigned_to_user_email
|
||||
ALLA,OP-001,CUS-001,Warehouse Crane Expansion,crane,negotiation,high,sales.uat@example.com,sales.uat@example.com,LD-001,anan@siam.example,head_office,Crane expansion opportunity,Overhead crane with installation,Warehouse Crane,Bangkok Warehouse,open,website,1000000,70,2026-08-31,,setup,Initial setup sample opportunity,false,opportunity,sales.uat@example.com
|
||||
|
2
setup/templates/opportunity-parties.csv
Normal file
2
setup/templates/opportunity-parties.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,opportunity_code,customer_code,role_code,remark
|
||||
ALLA,OP-001,CUS-001,end_customer,Primary project owner
|
||||
|
2
setup/templates/organizations.csv
Normal file
2
setup/templates/organizations.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,organization_name,slug,created_by_email,tax_id,default_currency,phone,email,address,logo_url,plan,status
|
||||
ALLA,ALLA Public Company Limited,alla,admin@example.com,0107558000393,THB,02-000-0000,info@example.com,99/9 Rama IX Road Bangkok,,enterprise,active
|
||||
|
2
setup/templates/product-types.csv
Normal file
2
setup/templates/product-types.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,product_type_code,product_type_name,document_prefix,sort_order,is_active,metadata_json
|
||||
ALLA,crane,Crane,CR,1,true,{}
|
||||
|
2
setup/templates/quotation-items.csv
Normal file
2
setup/templates/quotation-items.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,quotation_code,item_number,product_type_code,description,quantity,unit_price,total_price,unit,discount,discount_type,tax_rate,notes,sort_order
|
||||
ALLA,QT-HO-CR-2607-001,1,crane,Crane installation package,1,1000000,1000000,set,0,,7,Setup sample quotation item,1
|
||||
|
2
setup/templates/quotation-parties.csv
Normal file
2
setup/templates/quotation-parties.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,quotation_code,customer_code,role_code,is_primary,remark
|
||||
ALLA,QT-HO-CR-2607-001,CUS-001,end_customer,true,Primary quotation customer
|
||||
|
2
setup/templates/quotation-topic-items.csv
Normal file
2
setup/templates/quotation-topic-items.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,quotation_code,topic_key,content,sort_order
|
||||
ALLA,QT-HO-CR-2607-001,scope-main,Supply and install one overhead crane system,1
|
||||
|
2
setup/templates/quotation-topics.csv
Normal file
2
setup/templates/quotation-topics.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,quotation_code,topic_key,topic_type,title,sort_order
|
||||
ALLA,QT-HO-CR-2607-001,scope-main,scope,Scope of Work,1
|
||||
|
2
setup/templates/quotations.csv
Normal file
2
setup/templates/quotations.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
organization_code,quotation_code,customer_code,quotation_date,quotation_type,status,currency,subtotal,total_amount,created_by_email,updated_by_email,opportunity_code,contact_email,branch_code,valid_until,project_name,project_location,attention,reference,notes,revision,parent_quotation_code,revision_remark,exchange_rate,discount,discount_type,tax_rate,tax_amount,chance_percent,is_hot_project,competitor,salesman_email,is_sent,sent_at,sent_via
|
||||
ALLA,QT-HO-CR-2607-001,CUS-001,2026-07-02,crane,draft,THB,1000000,1070000,sales.uat@example.com,sales.uat@example.com,OP-001,anan@siam.example,head_office,2026-08-01,Warehouse Crane,Bangkok Warehouse,Anan Sales,SETUP-SAMPLE,Initial setup sample quotation,0,,,1,0,,7,70000,70,false,,sales.uat@example.com,false,,
|
||||
|
255
setup/templates/templates.json
Normal file
255
setup/templates/templates.json
Normal file
@@ -0,0 +1,255 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"generatedFrom": "docs/setup/csv-template-spec.md",
|
||||
"dataset": {
|
||||
"organizationCode": "ALLA",
|
||||
"branchCode": "head_office",
|
||||
"productTypeCode": "crane",
|
||||
"currency": "THB",
|
||||
"administratorEmail": "admin@example.com",
|
||||
"marketingEmail": "mk.uat@example.com",
|
||||
"salesEmail": "sales.uat@example.com",
|
||||
"managerEmail": "manager.uat@example.com",
|
||||
"ceoEmail": "ceo.uat@example.com"
|
||||
},
|
||||
"templates": [
|
||||
{
|
||||
"file": "users.csv",
|
||||
"seedType": "organization",
|
||||
"importOrder": 1,
|
||||
"supported": true,
|
||||
"requiredColumns": ["email", "name", "system_role"],
|
||||
"description": "Setup-managed users."
|
||||
},
|
||||
{
|
||||
"file": "organizations.csv",
|
||||
"seedType": "organization",
|
||||
"importOrder": 2,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "organization_name", "slug", "created_by_email"],
|
||||
"description": "Tenant organizations."
|
||||
},
|
||||
{
|
||||
"file": "memberships.csv",
|
||||
"seedType": "organization",
|
||||
"importOrder": 3,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "user_email", "membership_role", "business_role"],
|
||||
"description": "App-level organization memberships."
|
||||
},
|
||||
{
|
||||
"file": "crm-role-assignments.csv",
|
||||
"seedType": "organization",
|
||||
"importOrder": 5,
|
||||
"supported": true,
|
||||
"requiredColumns": [
|
||||
"organization_code",
|
||||
"user_email",
|
||||
"crm_role_code",
|
||||
"is_primary",
|
||||
"branch_scope_mode",
|
||||
"product_type_scope_mode"
|
||||
],
|
||||
"description": "CRM role assignments and scopes."
|
||||
},
|
||||
{
|
||||
"file": "master-options.csv",
|
||||
"seedType": "foundation",
|
||||
"importOrder": 6,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "category", "code", "label"],
|
||||
"description": "Generic governed master options."
|
||||
},
|
||||
{
|
||||
"file": "branches.csv",
|
||||
"seedType": "organization",
|
||||
"importOrder": 7,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "branch_code", "branch_name"],
|
||||
"description": "Branch options mapped to ms_options category crm_branch."
|
||||
},
|
||||
{
|
||||
"file": "product-types.csv",
|
||||
"seedType": "organization",
|
||||
"importOrder": 8,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "product_type_code", "product_type_name"],
|
||||
"description": "Product type options mapped to ms_options category crm_product_type."
|
||||
},
|
||||
{
|
||||
"file": "document-sequences.csv",
|
||||
"seedType": "foundation",
|
||||
"importOrder": 14,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "document_type", "prefix", "period"],
|
||||
"description": "Document numbering configuration."
|
||||
},
|
||||
{
|
||||
"file": "approval-workflows.csv",
|
||||
"seedType": "foundation",
|
||||
"importOrder": 15,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "workflow_code", "workflow_name", "entity_type"],
|
||||
"description": "Approval workflow headers."
|
||||
},
|
||||
{
|
||||
"file": "approval-steps.csv",
|
||||
"seedType": "foundation",
|
||||
"importOrder": 16,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "workflow_code", "step_number", "role_code", "role_name"],
|
||||
"description": "Approval workflow steps."
|
||||
},
|
||||
{
|
||||
"file": "approval-matrix.csv",
|
||||
"seedType": "foundation",
|
||||
"importOrder": 17,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "entity_type", "workflow_code", "priority", "is_default"],
|
||||
"description": "Approval workflow routing matrix."
|
||||
},
|
||||
{
|
||||
"file": "customers.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 30,
|
||||
"supported": true,
|
||||
"requiredColumns": [
|
||||
"organization_code",
|
||||
"customer_code",
|
||||
"customer_name",
|
||||
"customer_type",
|
||||
"customer_status",
|
||||
"created_by_email"
|
||||
],
|
||||
"description": "CRM customers."
|
||||
},
|
||||
{
|
||||
"file": "contacts.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 32,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "customer_code", "contact_name", "created_by_email"],
|
||||
"description": "Customer contacts."
|
||||
},
|
||||
{
|
||||
"file": "contact-shares.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 33,
|
||||
"supported": true,
|
||||
"requiredColumns": [
|
||||
"organization_code",
|
||||
"customer_code",
|
||||
"contact_email",
|
||||
"shared_to_user_email",
|
||||
"shared_by_user_email"
|
||||
],
|
||||
"description": "Contact sharing grants."
|
||||
},
|
||||
{
|
||||
"file": "leads.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 34,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "lead_code", "status", "created_by_email"],
|
||||
"description": "Marketing-owned leads."
|
||||
},
|
||||
{
|
||||
"file": "opportunities.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 36,
|
||||
"supported": true,
|
||||
"requiredColumns": [
|
||||
"organization_code",
|
||||
"opportunity_code",
|
||||
"customer_code",
|
||||
"title",
|
||||
"product_type_code",
|
||||
"status",
|
||||
"priority",
|
||||
"created_by_email",
|
||||
"updated_by_email"
|
||||
],
|
||||
"description": "Sales opportunities."
|
||||
},
|
||||
{
|
||||
"file": "opportunity-parties.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 37,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "opportunity_code", "customer_code", "role_code"],
|
||||
"description": "Opportunity project parties."
|
||||
},
|
||||
{
|
||||
"file": "quotations.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 40,
|
||||
"supported": true,
|
||||
"requiredColumns": [
|
||||
"organization_code",
|
||||
"quotation_code",
|
||||
"customer_code",
|
||||
"quotation_date",
|
||||
"quotation_type",
|
||||
"status",
|
||||
"currency",
|
||||
"subtotal",
|
||||
"total_amount",
|
||||
"created_by_email",
|
||||
"updated_by_email"
|
||||
],
|
||||
"description": "Quotation headers."
|
||||
},
|
||||
{
|
||||
"file": "quotation-items.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 41,
|
||||
"supported": true,
|
||||
"requiredColumns": [
|
||||
"organization_code",
|
||||
"quotation_code",
|
||||
"item_number",
|
||||
"product_type_code",
|
||||
"description",
|
||||
"quantity",
|
||||
"unit_price",
|
||||
"total_price"
|
||||
],
|
||||
"description": "Quotation line items."
|
||||
},
|
||||
{
|
||||
"file": "quotation-parties.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 42,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "quotation_code", "customer_code", "role_code"],
|
||||
"description": "Quotation project parties."
|
||||
},
|
||||
{
|
||||
"file": "quotation-topics.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 43,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "quotation_code", "topic_key", "topic_type", "title"],
|
||||
"description": "Quotation topic headers."
|
||||
},
|
||||
{
|
||||
"file": "quotation-topic-items.csv",
|
||||
"seedType": "business",
|
||||
"importOrder": 44,
|
||||
"supported": true,
|
||||
"requiredColumns": ["organization_code", "quotation_code", "topic_key", "content"],
|
||||
"description": "Quotation topic rows."
|
||||
}
|
||||
],
|
||||
"unsupportedTemplates": [
|
||||
"departments.csv",
|
||||
"teams.csv",
|
||||
"warehouses.csv",
|
||||
"sites.csv",
|
||||
"services.csv",
|
||||
"price-books.csv",
|
||||
"tax-rates.csv",
|
||||
"attachments.csv",
|
||||
"email-settings.csv"
|
||||
]
|
||||
}
|
||||
2
setup/templates/users.csv
Normal file
2
setup/templates/users.csv
Normal file
@@ -0,0 +1,2 @@
|
||||
email,name,system_role,password,active_organization_code,image_url,reset_password
|
||||
admin@allaos.local,System Administrator,super_admin,gikiyd[ibKym,ALLA,,FALSE
|
||||
|
33
src/app/administration/setup/page.tsx
Normal file
33
src/app/administration/setup/page.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import { SetupWizard } from "@/features/setup/components/setup-wizard";
|
||||
import { getBootstrapSetupStatus } from "@/features/setup/server/setup-bootstrap.service";
|
||||
|
||||
export const metadata = {
|
||||
title: "ALLA OS Setup",
|
||||
};
|
||||
|
||||
export default async function BootstrapSetupPage() {
|
||||
const status = await getBootstrapSetupStatus();
|
||||
|
||||
if (status.initialized) {
|
||||
redirect("/auth/sign-in");
|
||||
}
|
||||
|
||||
return (
|
||||
<main className="min-h-screen bg-background py-8 px-4">
|
||||
<div className="flex w-full flex-col gap-6">
|
||||
<div className="space-y-2">
|
||||
<h1 className="text-3xl font-semibold tracking-normal">
|
||||
ALLA OS Setup
|
||||
</h1>
|
||||
<p className="max-w-3xl text-sm text-muted-foreground">
|
||||
Preview setup CSV files from SETUP_IMPORT_DIR, run the import, then
|
||||
complete setup.
|
||||
</p>
|
||||
</div>
|
||||
<SetupWizard mode="public" tokenRequired={status.tokenRequired} />
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
116
src/app/api/notifications/email-configurations/[id]/route.ts
Normal file
116
src/app/api/notifications/email-configurations/[id]/route.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import {
|
||||
deleteEmailConfiguration,
|
||||
getEmailConfiguration,
|
||||
updateEmailConfiguration,
|
||||
} from '@/features/foundation/email/server/email-config.service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
const emailConfigurationSchema = z.object({
|
||||
providerType: z.literal('smtp').default('smtp'),
|
||||
name: z.string().trim().min(1).max(120),
|
||||
host: z.string().trim().min(1).max(255),
|
||||
port: z.number().int().min(1).max(65535),
|
||||
secure: z.boolean(),
|
||||
username: z.string().trim().max(255).nullable().optional(),
|
||||
password: z.string().trim().max(1000).nullable().optional(),
|
||||
clearPassword: z.boolean().optional(),
|
||||
fromEmail: z.string().trim().email(),
|
||||
fromName: z.string().trim().max(255).nullable().optional(),
|
||||
replyToEmail: z.string().trim().email().nullable().optional(),
|
||||
isDefault: z.boolean().optional(),
|
||||
isActive: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export async function GET(
|
||||
_request: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const { organization } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.notificationsAdmin,
|
||||
});
|
||||
const { id } = await context.params;
|
||||
const configuration = await getEmailConfiguration(organization.id, id);
|
||||
|
||||
if (!configuration) {
|
||||
return NextResponse.json({ message: 'Email configuration was not found.' }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json(configuration);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'Unable to load email configuration' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function PATCH(
|
||||
request: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.notificationsAdmin,
|
||||
});
|
||||
const { id } = await context.params;
|
||||
const payload = emailConfigurationSchema.parse(await request.json());
|
||||
|
||||
return NextResponse.json(
|
||||
await updateEmailConfiguration({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
id,
|
||||
values: payload,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Invalid email configuration payload', errors: error.flatten() },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'Unable to update email configuration' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
_request: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.notificationsAdmin,
|
||||
});
|
||||
const { id } = await context.params;
|
||||
|
||||
await deleteEmailConfiguration({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
id,
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'Unable to delete email configuration' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import { sendTestEmail } from '@/features/foundation/email/server/email-test.service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
const sendTestEmailSchema = z.object({
|
||||
recipientEmail: z.string().trim().email(),
|
||||
});
|
||||
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.notificationsAdmin,
|
||||
});
|
||||
const { id } = await context.params;
|
||||
const payload = sendTestEmailSchema.parse(await request.json());
|
||||
|
||||
return NextResponse.json(
|
||||
await sendTestEmail({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
configurationId: id,
|
||||
recipientEmail: payload.recipientEmail,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Invalid test email payload', errors: error.flatten() },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'Unable to send test email' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { testEmailConfigurationConnection } from '@/features/foundation/email/server/email-test.service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
export async function POST(
|
||||
_request: NextRequest,
|
||||
context: { params: Promise<{ id: string }> }
|
||||
) {
|
||||
try {
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.notificationsAdmin,
|
||||
});
|
||||
const { id } = await context.params;
|
||||
|
||||
return NextResponse.json(
|
||||
await testEmailConfigurationConnection({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
configurationId: id,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'Unable to test email configuration' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
73
src/app/api/notifications/email-configurations/route.ts
Normal file
73
src/app/api/notifications/email-configurations/route.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { z } from 'zod';
|
||||
import {
|
||||
createEmailConfiguration,
|
||||
listEmailConfigurations,
|
||||
} from '@/features/foundation/email/server/email-config.service';
|
||||
import { PERMISSIONS } from '@/lib/auth/rbac';
|
||||
import { AuthError, requireOrganizationAccess } from '@/lib/auth/session';
|
||||
|
||||
const emailConfigurationSchema = z.object({
|
||||
providerType: z.literal('smtp').default('smtp'),
|
||||
name: z.string().trim().min(1).max(120),
|
||||
host: z.string().trim().min(1).max(255),
|
||||
port: z.number().int().min(1).max(65535),
|
||||
secure: z.boolean(),
|
||||
username: z.string().trim().max(255).nullable().optional(),
|
||||
password: z.string().trim().max(1000).nullable().optional(),
|
||||
clearPassword: z.boolean().optional(),
|
||||
fromEmail: z.string().trim().email(),
|
||||
fromName: z.string().trim().max(255).nullable().optional(),
|
||||
replyToEmail: z.string().trim().email().nullable().optional(),
|
||||
isDefault: z.boolean().optional(),
|
||||
isActive: z.boolean().optional(),
|
||||
});
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const { organization } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.notificationsAdmin,
|
||||
});
|
||||
|
||||
return NextResponse.json(await listEmailConfigurations(organization.id));
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'Unable to load email configurations' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { organization, session } = await requireOrganizationAccess({
|
||||
permission: PERMISSIONS.notificationsAdmin,
|
||||
});
|
||||
const payload = emailConfigurationSchema.parse(await request.json());
|
||||
|
||||
return NextResponse.json(
|
||||
await createEmailConfiguration({
|
||||
organizationId: organization.id,
|
||||
userId: session.user.id,
|
||||
values: payload,
|
||||
}),
|
||||
{ status: 201 }
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof AuthError) {
|
||||
return NextResponse.json({ message: error.message }, { status: error.status });
|
||||
}
|
||||
if (error instanceof z.ZodError) {
|
||||
return NextResponse.json(
|
||||
{ message: 'Invalid email configuration payload', errors: error.flatten() },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ message: error.message }, { status: 400 });
|
||||
}
|
||||
|
||||
return NextResponse.json({ message: 'Unable to create email configuration' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user