feat: empty states, onboarding checklist, PDF exports, and supporting data #114
@@ -64,8 +64,8 @@ Simple SVG line art using the cyan brand color palette (`#06b6d4` → `#22d3ee`)
|
||||
### Visual Style
|
||||
|
||||
- Container: centered content within the page's existing layout
|
||||
- Illustration: 60-80px height, `opacity: 0.3` → `0.5` range for subtlety
|
||||
- Title: `text-foreground`, 14px, `font-semibold`
|
||||
- Illustration: 60-80px height, `opacity: 0.4` → `0.7` range (needs to be visible on `#101114` dark background)
|
||||
- Title: `text-foreground`, `text-lg` (18px), `font-semibold` (matches existing `EmptyState.tsx`)
|
||||
- Description: `text-muted-foreground`, 13px, max-width ~400px for readability
|
||||
- CTA: `bg-gradient-brand` primary button style
|
||||
- Learn more: `text-muted-foreground` with `→` arrow, hover brightens
|
||||
@@ -83,7 +83,7 @@ Dismissible `.glass-card` widget on QuickStartPage, positioned below the greetin
|
||||
- Shows for users who haven't dismissed it and haven't completed all items
|
||||
- Auto-hides with a brief "You're all set!" state once all items are checked, then disappears
|
||||
- Dismissible at any time via "×" button
|
||||
- Dismissed/completed state stored in `user_preferences` (existing JSON column)
|
||||
- Dismissed/completed state stored in a new `onboarding_dismissed` Boolean column on the `users` table (requires migration). Not using JSON — a simple column is clearer and queryable.
|
||||
- Never reappears once dismissed or completed
|
||||
|
||||
### Completion Tracking
|
||||
@@ -118,7 +118,7 @@ No new database table. A single API endpoint queries existing data to determine
|
||||
| `invited_teammate` | Team has more than 1 member |
|
||||
| `connected_psa` | Team has at least 1 PSA connection |
|
||||
|
||||
**Dismiss endpoint:** `POST /api/v1/users/onboarding-status/dismiss` — sets `dismissed=true` in user preferences.
|
||||
**Dismiss endpoint:** `POST /api/v1/users/onboarding-status/dismiss` — sets `onboarding_dismissed=True` on the user record.
|
||||
|
||||
### Checklist Variants
|
||||
|
||||
@@ -178,11 +178,11 @@ New "Branding" section on the existing Team Settings page. Team admin only. Solo
|
||||
|
||||
- File size: max 2MB
|
||||
- Content type: `image/png`, `image/jpeg`, `image/svg+xml`
|
||||
- Solo pros: same fields stored on user record or preferences — decided during implementation
|
||||
- Solo pros: branding columns (`logo_data`, `logo_content_type`, `company_display_name`) added directly to the `users` table. Same schema as teams. Solo pros without a team still get branded exports.
|
||||
|
||||
### Why Base64 in DB
|
||||
|
||||
Logos are small (< 2MB) and there's one per team. Avoids S3/file storage dependency entirely. Easy to migrate to object storage later when BYOS is implemented for supporting data.
|
||||
Logos are small (< 2MB raw, ~2.67MB base64-encoded) and there's one per team/user. The 2MB validation limit applies to the raw uploaded file size (before base64 encoding). Avoids S3/file storage dependency entirely. Easy to migrate to object storage later when BYOS is implemented for supporting data.
|
||||
|
||||
---
|
||||
|
||||
@@ -192,6 +192,12 @@ Logos are small (< 2MB) and there's one per team. Avoids S3/file storage depende
|
||||
|
||||
**New dependency:** `weasyprint` in `requirements.txt`
|
||||
|
||||
**System dependencies (required by WeasyPrint):**
|
||||
- `libpango1.0-dev`, `libcairo2-dev`, `libgdk-pixbuf2.0-dev`, `libffi-dev`
|
||||
- Must be added to the Railway Dockerfile via `apt-get install`
|
||||
- Local dev: install via system package manager (`apt-get` on Ubuntu/Debian)
|
||||
- CI: add to the e2e job's setup step
|
||||
|
||||
**Export service changes:**
|
||||
|
||||
- New `generate_pdf()` method in `export_service.py`
|
||||
@@ -201,7 +207,9 @@ Logos are small (< 2MB) and there's one per team. Avoids S3/file storage depende
|
||||
**Existing endpoint change:**
|
||||
|
||||
- `POST /sessions/{session_id}/export` gains `format: "pdf"` option
|
||||
- Returns `application/pdf` with `Content-Disposition: attachment; filename="session-export-{id}.pdf"` header
|
||||
- Update `SessionExport` schema: change `format` field pattern from `^(text|markdown|html|psa)$` to `^(text|markdown|html|psa|pdf)$`
|
||||
- PDF format returns `Response(content=pdf_bytes, media_type="application/pdf")` with `Content-Disposition: attachment; filename="session-export-{id}.pdf"` header (different return type from the existing `PlainTextResponse` used by other formats — endpoint must branch on format)
|
||||
- Non-PDF formats continue returning `PlainTextResponse` as before
|
||||
|
||||
### PDF Template Structure
|
||||
|
||||
@@ -226,9 +234,9 @@ Matches the approved mockup layout:
|
||||
### Frontend Changes
|
||||
|
||||
- Add "PDF" to the format selector in `ExportPreviewModal`
|
||||
- PDF option triggers a direct file download (no textarea preview — PDFs aren't editable inline)
|
||||
- PDF option triggers a direct file download (no textarea preview — PDFs aren't editable inline). The modal should switch to a "download-only" mode when PDF is selected: hide the textarea, show a download button with loading state. The format selector stays visible for switching between formats.
|
||||
- Show a loading spinner while PDF generates server-side
|
||||
- Existing formats (markdown, text, HTML, PSA) continue to work as before
|
||||
- Existing formats (markdown, text, HTML, PSA) continue to work as before with the textarea preview
|
||||
|
||||
### Branding Logic
|
||||
|
||||
@@ -254,19 +262,22 @@ Matches the approved mockup layout:
|
||||
| `content_type` | String(50) | Nullable. e.g., `image/png` for screenshots |
|
||||
| `sort_order` | Integer | Display ordering |
|
||||
| `created_at` | DateTime(timezone=True) | Auto-set |
|
||||
| `updated_at` | DateTime(timezone=True) | Auto-set, auto-update |
|
||||
|
||||
### API Endpoints
|
||||
|
||||
- `POST /api/v1/sessions/{session_id}/supporting-data` — add an item (label, type, content). Returns created item.
|
||||
- `GET /api/v1/sessions/{session_id}/supporting-data` — list all items for a session, ordered by `sort_order`.
|
||||
- `PATCH /api/v1/sessions/{session_id}/supporting-data/{id}` — update label or content.
|
||||
- `DELETE /api/v1/sessions/{session_id}/supporting-data/{id}` — remove an item.
|
||||
|
||||
### Validation
|
||||
|
||||
- Image size: max 5MB per screenshot
|
||||
- Image size: max 2MB per screenshot (keeps DB growth manageable — at 20 items × 2.67MB base64 = ~53MB worst case per session)
|
||||
- Text snippet: max 50,000 characters
|
||||
- Max 20 items per session
|
||||
- Only the session owner or team admins can add/delete
|
||||
- Monitor DB size growth in production — if supporting data exceeds expectations, prioritize BYOS migration
|
||||
|
||||
### Session Runner UI
|
||||
|
||||
@@ -301,9 +312,11 @@ Supporting data is included in all export formats:
|
||||
### Implementation
|
||||
|
||||
- Markdown files stored in `frontend/src/content/guides/`
|
||||
- Rendered with `react-markdown` (or similar lightweight renderer)
|
||||
- Written as React components in `frontend/src/pages/guides/` (avoids `react-markdown` dependency for only 7 short pages). Each guide is a simple functional component using existing typography classes.
|
||||
- Displayed in a `.glass-card-static` container within the standard app shell layout
|
||||
- Simple breadcrumb: "Guides → {title}"
|
||||
- Images/illustrations stored in `frontend/public/guides/` and referenced via absolute paths
|
||||
- Unknown slugs show a "Guide not found" empty state with a link back to the dashboard
|
||||
|
||||
### Guides (7)
|
||||
|
||||
@@ -385,12 +398,15 @@ These Playwright tests focus on happy paths only — one representative flow per
|
||||
## Implementation Order (Bottom-Up)
|
||||
|
||||
### PR 1: Backend Foundation
|
||||
- Team branding columns + migration
|
||||
- `onboarding_dismissed` column on `users` table + migration
|
||||
- Team branding columns (`logo_data`, `logo_content_type`, `company_display_name`) on `teams` table + migration
|
||||
- Solo pro branding columns on `users` table + migration (can combine with onboarding migration)
|
||||
- Branding CRUD endpoints
|
||||
- Supporting data table + migration
|
||||
- Supporting data CRUD endpoints
|
||||
- Onboarding status endpoint
|
||||
- WeasyPrint dependency + PDF generation in export service
|
||||
- Supporting data CRUD endpoints (POST, GET, PATCH, DELETE)
|
||||
- Onboarding status endpoint + dismiss endpoint
|
||||
- WeasyPrint dependency + system deps in Dockerfile + PDF generation in export service
|
||||
- Update `SessionExport` schema format pattern to include `pdf`
|
||||
- Backend tests for all of the above
|
||||
|
||||
### PR 2: Empty States + Guides
|
||||
|
||||
Reference in New Issue
Block a user