Skip to content

Commit 0723537

Browse files
authored
BootstrapSpark: merge JsBootSpark features into ReactSparkPortfolio (#40)
* BootstrapSpark: merge JsBootSpark features into ReactSparkPortfolio * ci: avoid SWA preview deploys on PR to prevent staging quota failures * pr-body.txt
1 parent c79ba60 commit 0723537

59 files changed

Lines changed: 10374 additions & 199 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.documentation/memory/constitution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
No follow-up actions required.
2424
-->
2525

26-
# ReactSparkPortfolio Constitution
26+
# BootstrapSpark Constitution
2727

2828
## Core Principles
2929

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Specification Quality Checklist: Merge JsBootSpark into ReactSparkPortfolio
2+
3+
**Purpose**: Validate specification completeness and quality before proceeding to planning
4+
**Created**: 2026-04-13
5+
**Feature**: [spec.md](../spec.md)
6+
7+
## Content Quality
8+
9+
- [x] No implementation details (languages, frameworks, APIs)
10+
- [x] Focused on user value and business needs
11+
- [x] Written for non-technical stakeholders
12+
- [x] All mandatory sections completed
13+
14+
## Requirement Completeness
15+
16+
- [x] No [NEEDS CLARIFICATION] markers remain
17+
- [x] Requirements are testable and unambiguous
18+
- [x] Success criteria are measurable
19+
- [x] Success criteria are technology-agnostic (no implementation details)
20+
- [x] All acceptance scenarios are defined
21+
- [x] Edge cases are identified
22+
- [x] Scope is clearly bounded
23+
- [x] Dependencies and assumptions identified
24+
25+
## Feature Readiness
26+
27+
- [x] All functional requirements have clear acceptance criteria
28+
- [x] User scenarios cover primary flows
29+
- [x] Feature meets measurable outcomes defined in Success Criteria
30+
- [x] No implementation details leak into specification
31+
32+
## Notes
33+
34+
- FR-009 and FR-010 reference TypeScript and Zod by name — these are constitution-mandated constraints, not implementation choices, so they are acceptable in the spec.
35+
- The spec deliberately excludes JsBootSpark features that are dev-tooling only (Docker, plugin system, template CLI, Express server) since they don't translate to a React SPA context.
36+
- PWA support from JsBootSpark is not included because ReactSparkPortfolio already has its own service worker setup via Vite.
37+
- The contact form (FR-006) will be client-side only in the SPA; backend processing is out of scope for this spec (can be added later via Azure Functions if needed).
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Route Contracts: Merge JsBootSpark
2+
3+
**Feature**: 001-merge-jsbootspark
4+
**Date**: 2026-04-13
5+
6+
## New Routes
7+
8+
### GET /components
9+
10+
**Purpose**: Display basic Bootstrap 5 component showcase
11+
**Component**: `Components.tsx` (lazy loaded)
12+
**Nav location**: Showcase dropdown → "Components"
13+
**Data requirements**: None (static JSX)
14+
**SEO title**: "Components | BootstrapSpark"
15+
**SEO description**: "Browse Bootstrap 5 basic components with live interactive examples"
16+
17+
### GET /advanced-components
18+
19+
**Purpose**: Display advanced Bootstrap 5 component showcase
20+
**Component**: `AdvancedComponents.tsx` (lazy loaded)
21+
**Nav location**: Showcase dropdown → "Advanced Components"
22+
**Data requirements**: None (static JSX)
23+
**SEO title**: "Advanced Components | BootstrapSpark"
24+
**SEO description**: "Explore advanced Bootstrap 5 components including accordion, carousel, offcanvas, and more"
25+
26+
### GET /data-tables
27+
28+
**Purpose**: Interactive data table with YouTube Top 100 Songs
29+
**Component**: `DataTables.tsx` (lazy loaded)
30+
**Nav location**: Showcase dropdown → "Data Tables"
31+
**Data requirements**: `youtube-top-100-songs-2025.csv` parsed via `SongService`
32+
**SEO title**: "Data Tables | BootstrapSpark"
33+
**SEO description**: "Interactive data table showcase with sorting, search, pagination, and export"
34+
35+
### GET /song/:id
36+
37+
**Purpose**: Detail view for a single song
38+
**Component**: `SongDetail.tsx` (lazy loaded)
39+
**Nav location**: Not in nav (linked from DataTables rows)
40+
**Data requirements**: Single song from `SongService.getSongById(id)`
41+
**URL params**: `id` — 1-indexed song rank (integer, 1-100)
42+
**Error states**: Invalid ID → "Song not found" with back link
43+
**SEO title**: "{Song Title} | BootstrapSpark"
44+
45+
### GET /contact
46+
47+
**Purpose**: Contact form with client-side validation
48+
**Component**: `Contact.tsx` (existing, enhanced with Zod validation)
49+
**Nav location**: Top-level nav link "Contact"
50+
**Data requirements**: None
51+
**SEO title**: "Contact | BootstrapSpark"
52+
53+
## Modified Routes
54+
55+
### GET / (Home)
56+
57+
**Changes**: Update Hero branding from "React Spark Portfolio" to "BootstrapSpark"
58+
59+
### All existing routes
60+
61+
**Changes**: Header nav updated with new dropdown and links. Footer branding updated.
62+
63+
## SPA Routing Notes
64+
65+
- All routes handled client-side via React Router
66+
- `staticwebapp.config.json` already configured for SPA fallback (`navigationFallback`)
67+
- New routes need entries in `generateSitemap.ts` for SEO
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Service Contracts: Merge JsBootSpark
2+
3+
**Feature**: 001-merge-jsbootspark
4+
**Date**: 2026-04-13
5+
6+
## SongService
7+
8+
**File**: `src/services/SongService.ts`
9+
**Pattern**: Follows existing `ProjectService.ts` pattern (async fetch with fallback)
10+
11+
### Interface
12+
13+
```typescript
14+
/** Load and parse all songs from CSV */
15+
export const fetchAllSongs: () => Promise<Song[]>
16+
17+
/** Get a single song by rank (1-indexed) */
18+
export const getSongById: (id: number) => Promise<Song | null>
19+
20+
/** Filter songs by search query across title, channel, category */
21+
export const searchSongs: (songs: Song[], query: string) => Song[]
22+
23+
/** Sort songs by a given column */
24+
export const sortSongs: (songs: Song[], column: SortableColumn, direction: SortDirection) => Song[]
25+
26+
/** Export songs array to CSV string */
27+
export const exportToCsv: (songs: Song[]) => string
28+
29+
/** Export songs array to JSON string */
30+
export const exportToJson: (songs: Song[]) => string
31+
```
32+
33+
### Behavior
34+
35+
- `fetchAllSongs()` imports CSV via Vite `?raw`, parses rows, validates each with `SongSchema`, returns validated array
36+
- Invalid rows are skipped with a console.warn (stripped in production)
37+
- Results are cached in module-level variable (songs don't change at runtime)
38+
- All functions are pure except `fetchAllSongs` (I/O)
39+
40+
## ContactFormService (optional, client-side only)
41+
42+
**File**: Inline in `Contact.tsx` or `src/services/ContactFormService.ts`
43+
44+
### Interface
45+
46+
```typescript
47+
/** Validate contact form data, returns validated data or Zod errors */
48+
export const validateContactForm: (data: unknown) => ContactFormData | ZodError
49+
```
50+
51+
### Behavior
52+
53+
- Uses `ContactFormSchema.safeParse()` for validation
54+
- No network calls — form submission is a UI demo only
55+
- Success state shown via React state, not API response
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# Data Model: Merge JsBootSpark into ReactSparkPortfolio
2+
3+
**Feature**: 001-merge-jsbootspark
4+
**Date**: 2026-04-13
5+
6+
## Entities
7+
8+
### Song
9+
10+
Represents a YouTube song record parsed from the CSV data file.
11+
12+
| Field | Type | Required | Validation | Source |
13+
|-------|------|----------|------------|--------|
14+
| rank | number | yes | positive integer, 1-100 | derived from row index |
15+
| title | string | yes | min length 1 | CSV `title` column |
16+
| fullTitle | string | no || CSV `fulltitle` column |
17+
| description | string | no | max 500 chars (truncated) | CSV `description` column |
18+
| viewCount | number | yes | non-negative integer | CSV `view_count` column |
19+
| viewCountFormatted | string | yes | computed (e.g. "2.1B") | derived from viewCount |
20+
| duration | string | no | MM:SS format | CSV `duration_string` column |
21+
| durationSeconds | number | no | non-negative integer | CSV `duration` column |
22+
| channel | string | yes | min length 1 | CSV `channel` column |
23+
| channelUrl | string | no | valid URL or empty | CSV `channel_url` column |
24+
| channelFollowerCount | number | no | non-negative integer | CSV `channel_follower_count` column |
25+
| categories | string | no || CSV `categories` column |
26+
| tags | string | no || CSV `tags` column |
27+
| liveStatus | string | no || CSV `live_status` column |
28+
| thumbnail | string | no | valid URL or empty | CSV `thumbnail` column |
29+
30+
**State transitions**: None (read-only data).
31+
32+
**Relationships**: None (standalone entity).
33+
34+
### ContactFormData
35+
36+
Represents a contact form submission with client-side validation.
37+
38+
| Field | Type | Required | Validation |
39+
|-------|------|----------|------------|
40+
| name | string | yes | min 2 chars, max 100 chars |
41+
| email | string | yes | valid email format (Zod .email()) |
42+
| message | string | yes | min 10 chars, max 2000 chars |
43+
44+
**State transitions**: Empty → Validating → Valid/Invalid → Submitted (client-side only).
45+
46+
### ComponentExample (conceptual — no Zod schema needed)
47+
48+
Static data embedded in JSX. No runtime model required.
49+
50+
| Field | Type | Description |
51+
|-------|------|-------------|
52+
| id | string | Anchor ID for navigation (e.g., "buttons", "accordion") |
53+
| title | string | Display name (e.g., "Buttons", "Accordion") |
54+
| category | enum | "basic" or "advanced" |
55+
| icon | string | Bootstrap Icons class name |
56+
57+
### DataTableState (UI state — React hook, not a model file)
58+
59+
| Field | Type | Description |
60+
|-------|------|-------------|
61+
| searchQuery | string | Current search filter text |
62+
| sortColumn | string | Column key currently sorted by |
63+
| sortDirection | enum | "asc" or "desc" |
64+
| currentPage | number | Current pagination page (1-indexed) |
65+
| pageSize | number | Rows per page (default 10) |
66+
| filteredData | Song[] | Songs matching current search |
67+
| sortedData | Song[] | Filtered songs in current sort order |
68+
| pageData | Song[] | Current page slice of sorted data |
69+
| totalPages | number | Computed from filteredData.length / pageSize |
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
```yaml
2+
gate: analyze
3+
status: pass
4+
blocking: false
5+
severity: info
6+
summary: "All 12 functional requirements have task coverage. 3 low-severity findings identified — no blockers for implementation."
7+
```
8+
9+
# Specification Analysis Report
10+
11+
**Feature**: 001-merge-jsbootspark
12+
**Branch**: `001-merge-jsbootspark`
13+
**Date**: 2026-04-13
14+
**Artifacts Analyzed**: spec.md, plan.md, tasks.md, data-model.md, contracts/services.md, contracts/routes.md, research.md
15+
16+
## Findings
17+
18+
| ID | Category | Severity | Location(s) | Summary | Recommendation |
19+
|----|----------|----------|-------------|---------|----------------|
20+
| C1 | Coverage | LOW | spec.md FR-008, tasks.md Phase 8 | FR-008 (existing feature regression) covered only by manual verification task T043, no automated regression tests | Consider adding a smoke test for existing routes (already tracked in tasks as T043 manual check; automated tests would strengthen confidence but are not blocking) |
21+
| U1 | Underspecification | LOW | spec.md US1, tasks.md T009-T010 | Component showcase pages (T009, T010) are the largest tasks in the project — each lists 8-11 Bootstrap component sections. No sub-task granularity for individual component sections | Implementer should treat each component section as a natural commit boundary within T009/T010. Not blocking — the tasks are clear enough for execution |
22+
| I1 | Inconsistency | LOW | plan.md (Source Structure), tasks.md T004 | Plan lists `useSongData.ts` hook in project structure but tasks.md has no task to create it. T005 creates `useDataTable.ts` instead. Plan shows both hooks but only one has a task | Remove `useSongData.ts` from plan or merge its caching responsibility into `useDataTable.ts` / `SongService.ts`. The service already caches via module-level variable per contracts/services.md, so `useSongData.ts` is redundant |
23+
24+
## Coverage Summary Table
25+
26+
| Requirement Key | Has Task? | Task IDs | Notes |
27+
|----------------|-----------|----------|-------|
28+
| FR-001 (Components page) | ✅ | T006-T008, T009, T011-T014 | Full coverage |
29+
| FR-002 (Advanced Components page) | ✅ | T006-T008, T010, T011-T014 | Full coverage |
30+
| FR-003 (Data Tables page) | ✅ | T001, T002, T004, T005, T015-T019 | Full coverage |
31+
| FR-004 (Data export CSV/JSON) | ✅ | T004, T015, T018 | Export in SongService + DataTables component |
32+
| FR-005 (Song Detail page) | ✅ | T031-T034 | Full coverage |
33+
| FR-006 (Contact page) | ✅ | T003, T035-T039 | Full coverage |
34+
| FR-007 (Rename to BootstrapSpark) | ✅ | T020-T030 | 11 tasks — comprehensive rename coverage |
35+
| FR-008 (Existing features unchanged) | ✅ | T043 | Manual verification only (see finding C1) |
36+
| FR-009 (TypeScript strict) | ✅ | All implementation tasks | Enforced by tsconfig + lint |
37+
| FR-010 (Zod validation) | ✅ | T002, T003, T004, T018, T038 | Models + service + tests |
38+
| FR-011 (Theme toggle) | ✅ | T044 | Manual verification in polish phase |
39+
| FR-012 (Navigation integration) | ✅ | T008 | Header nav update task |
40+
41+
**Coverage**: 12/12 requirements have associated tasks = **100%**
42+
43+
## Constitution Alignment Issues
44+
45+
**None.** All 10 constitution principles are addressed in the plan's constitution check and reflected in tasks:
46+
47+
- **Type Safety**: All new code is TypeScript strict (enforced by existing tsconfig)
48+
- **Testing**: Test tasks included for models (T038), services (T018), and components (T013, T014, T019, T034, T039)
49+
- **Documentation**: JSDoc required on exports (constitution mandate; implementer responsibility per task)
50+
- **Error Handling**: Edge cases defined in spec; SongDetail handles invalid ID (T031); DataTables handles missing CSV (SongService contract)
51+
- **Input Validation**: Zod schemas for Song (T002) and ContactForm (T003)
52+
53+
## Unmapped Tasks
54+
55+
**None.** All 45 tasks map to at least one functional requirement or cross-cutting concern:
56+
57+
- T001-T005: Setup → FR-003, FR-004, FR-005, FR-006, FR-010
58+
- T006-T008: Foundation → FR-012
59+
- T009-T014: US1 → FR-001, FR-002
60+
- T015-T019: US2 → FR-003, FR-004
61+
- T020-T030: US5 → FR-007
62+
- T031-T034: US3 → FR-005
63+
- T035-T039: US4 → FR-006
64+
- T040-T045: Polish → FR-008, FR-009, FR-011, SC-002, SC-005
65+
66+
## Metrics
67+
68+
| Metric | Value |
69+
|--------|-------|
70+
| Total Functional Requirements | 12 |
71+
| Total Success Criteria | 7 |
72+
| Total Tasks | 45 |
73+
| Coverage % (requirements with ≥1 task) | 100% |
74+
| Ambiguity Count | 0 |
75+
| Duplication Count | 0 |
76+
| Critical Issues Count | 0 |
77+
| High Issues Count | 0 |
78+
| Medium Issues Count | 0 |
79+
| Low Issues Count | 3 |
80+
81+
## Next Actions
82+
83+
All findings are LOW severity — **no blockers for implementation**.
84+
85+
1. **Proceed to `/devspark.implement`** — artifacts are consistent and complete
86+
2. **Optional cleanup** before implementation:
87+
- Remove `useSongData.ts` from plan.md project structure (finding I1) — the SongService module-level cache makes it redundant
88+
- Consider adding automated smoke tests for existing routes during Phase 8 (finding C1) — would strengthen SC-002 confidence
89+
3. **During implementation**: Treat T009 and T010 as multi-commit tasks, with one commit per component section (finding U1)
90+
91+
Would you like me to suggest concrete remediation edits for any of these 3 findings?

0 commit comments

Comments
 (0)