Skip to content

Commit b342f9b

Browse files
authored
Merge pull request #60 from boostcampwm-snu-2026-1/docs/59-multi-project-management
docs: plan multi-project management
2 parents 4e518f4 + 2aa077f commit b342f9b

8 files changed

Lines changed: 202 additions & 9 deletions

File tree

PLANS.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ M1 should include:
2929

3030
Use this section as the current execution order for agent work. Feature document numbering describes the planned product sequence, but actual issue order may change as dependencies, review feedback, or implementation risks become clearer.
3131

32-
1. #50 Arrangement WAV export -> `docs/features/21-arrangement-wav-export.md`
32+
1. #59 Multi-project management -> `docs/features/22-multi-project-management.md`
3333

3434
## Planned Milestones
3535

@@ -54,8 +54,9 @@ Use this section as the current execution order for agent work. Feature document
5454
19. Variable hybrid clip length.
5555
20. Adjustable arrangement length.
5656
21. Arrangement WAV export.
57-
22. Project JSON export/import.
58-
23. Basic effects.
57+
22. Multi-project management.
58+
23. Project JSON export/import.
59+
24. Basic effects.
5960

6061
## Backlog
6162

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Feature task specs:
7373
- [19 Variable Hybrid Clip Length](docs/features/19-variable-hybrid-clip-length.md)
7474
- [20 Adjustable Arrangement Length](docs/features/20-adjustable-arrangement-length.md)
7575
- [21 Arrangement WAV Export](docs/features/21-arrangement-wav-export.md)
76+
- [22 Multi-project Management](docs/features/22-multi-project-management.md)
7677

7778
## Initial Roadmap
7879

@@ -88,6 +89,7 @@ Feature task specs:
8889
10. Add browser-local project persistence with IndexedDB.
8990
11. Support longer hybrid clips and adjustable arrangement length.
9091
12. Render the arrangement to a downloadable WAV file.
92+
13. Manage multiple browser-local projects.
9193

9294
## Notes
9395

docs/architecture.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
1818
- Let users adjust clip and arrangement lengths through model-backed controls.
1919
- Dispatch mixer control edits such as volume, mute, solo, and master volume.
2020
- Trigger save, restore, import, and export workflows through persistence/audio APIs.
21+
- Let users create, select, rename, and delete browser-local projects through project-level UI.
2122
- Use `requestAnimationFrame` for visual playheads where needed.
2223
- Avoid owning exact audio timing.
2324

@@ -27,6 +28,7 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
2728
- Store musical time in ticks.
2829
- Provide pure transformations for creating, editing, duplicating, and deleting clips and events.
2930
- Store clip length and arrangement length as serializable musical values.
31+
- Store project identity and project metadata separately from runtime UI selection.
3032
- Provide pure transformations for creating, moving, and deleting arrangement clip instances.
3133
- Store serializable mixer settings such as track volume, mute, solo, and master volume when mixer routing exists.
3234
- Avoid references to Web Audio runtime objects.
@@ -51,6 +53,8 @@ The main rule is separation of concerns: UI rendering, persistence, and audio sc
5153
- Handle browser file import boundaries for user-provided audio files.
5254
- Keep `File`, `Blob`, object URL, IndexedDB handles, and decoded audio buffers out of model data.
5355
- Persist the active browser project and imported sample blobs through IndexedDB.
56+
- Persist a browser-local project collection when multi-project management exists.
57+
- Store the active project ID separately from the project document.
5458
- Export rendered arrangement audio as WAV without storing runtime audio objects in project JSON.
5559

5660
### Utilities
@@ -92,6 +96,8 @@ Imported browser files are also runtime or persistence-layer data. Project JSON
9296

9397
IndexedDB may store imported sample blobs or bytes outside the project JSON document. The model should reference those blobs by stable sample IDs so the audio engine can rebuild decoded runtime caches after restore.
9498

99+
When multiple local projects exist, each persisted project should have a stable project ID. Imported sample blobs should be scoped to the owning project, for example with a composite key such as `${projectId}:${sampleId}` or an equivalent indexed record shape. Switching projects should stop live playback and preview before replacing app state. Autosave must write to the intended project ID and must not accidentally overwrite another project after a switch.
100+
95101
Mixer settings such as volume, mute, solo, and master volume are serializable project or app-model data once real mixer routing exists. Mixer runtime data, including `GainNode`, `AnalyserNode`, effect nodes, meter buffers, and active routing graphs, belongs to the audio engine runtime and must not be stored in project JSON.
96102

97103
Arrangement placement data is serializable. A placed clip should be represented by a `ClipInstance` with stable IDs, `startTick`, `lengthTicks`, and track membership. Drag state, pointer coordinates, DOM measurements, scheduler timers, decoded buffers, and active audio nodes are runtime-only and must not be persisted.

docs/data-model.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ The initial transport UI range is 60 to 180 BPM. Implementations should validate
2525
## Core Entities
2626

2727
- `Project`: top-level serializable project document.
28+
- `ProjectSummary`: lightweight local project list item.
29+
- `ProjectCollectionState`: browser-local project collection metadata such as the active project ID.
2830
- `Track`: a lane that can contain clip instances.
2931
- `Clip`: reusable musical content. It may be a hybrid MIDI/drum clip or, later, an imported audio clip.
3032
- `ClipInstance`: placement of a clip on a track in arrangement time.
@@ -36,6 +38,34 @@ The initial transport UI range is 60 to 180 BPM. Implementations should validate
3638
- `TrackMixerState`: serializable track mixer settings when real mixer routing exists.
3739
- `MasterMixerState`: serializable master output settings when real mixer routing exists.
3840

41+
## Project Collection
42+
43+
The app should support multiple browser-local projects after the multi-project management feature.
44+
45+
`Project` remains the serializable document for one song or sketch. Each project should have a stable ID and contain the musical data already documented in this file: clips, arrangement tracks, clip instances, arrangement length, loop range, sample metadata, tempo, mixer settings, and related project fields.
46+
47+
Project collection metadata should be stored separately from individual project documents:
48+
49+
```ts
50+
export interface ProjectSummary {
51+
id: string;
52+
name: string;
53+
createdAt: number;
54+
updatedAt: number;
55+
}
56+
57+
export interface ProjectCollectionState {
58+
activeProjectId: string;
59+
projects: ProjectSummary[];
60+
}
61+
```
62+
63+
The current implementation may still have one active project in memory at a time. The multi-project feature should make the active project ID serializable browser-local state so a refresh restores the last selected project.
64+
65+
Imported sample blobs are not project JSON. In a multi-project store, imported blob records must be scoped to the owning project so two projects can safely have the same local `sampleId`. A composite key such as `${projectId}:${sampleId}` is acceptable, or the persistence layer may add a `projectId` field and an IndexedDB index if that keeps deletion and migration clearer.
66+
67+
Switching projects should not mutate the outgoing project document except for an intentional save or autosave flush. Runtime UI selection, decoded sample caches, active source nodes, transport state, and audio preview state should be reset or rebuilt for the newly active project.
68+
3969
## Hybrid Clips
4070

4171
Early clips may contain both drum events and note events. This keeps the M1 editor focused: one clip can hold a drum pattern and a piano roll phrase.
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Feature: 22 Multi-project Management
2+
3+
## Status
4+
Planned
5+
6+
## Goal
7+
8+
Allow users to manage more than one browser-local project instead of being limited to a single hard-coded active project.
9+
10+
## Context
11+
12+
The current app persists one active project in IndexedDB using a fixed `ACTIVE_PROJECT_ID`. The transport bar displays `Project 1`, and there is no project-level UI for creating, switching, renaming, or deleting separate songs.
13+
14+
Multiple local projects should stay browser-first and lightweight. This feature is not a cloud account system or a file browser. It should extend the existing IndexedDB persistence model so users can keep separate sketches in the same browser profile.
15+
16+
## Scope
17+
18+
Included:
19+
20+
- Store multiple serializable project documents in IndexedDB.
21+
- Store the active project ID separately from project documents.
22+
- Restore the last active project on app startup.
23+
- Add a transport bar project menu that shows the active project name.
24+
- Support creating a new blank project.
25+
- Support switching between existing projects.
26+
- Support renaming the active project.
27+
- Support deleting a project with confirmation.
28+
- Stop playback and audio preview before switching projects.
29+
- Keep imported sample blobs scoped to the owning project so projects cannot collide on sample IDs.
30+
- Migrate the existing single active project into the multi-project shape where practical.
31+
32+
Excluded:
33+
34+
- Cloud sync or user accounts.
35+
- Cross-device collaboration.
36+
- File-system project export/import.
37+
- Project templates beyond the current default blank project.
38+
- Project duplication unless it is trivial after the base workflow exists.
39+
- A full project dashboard page.
40+
- Sharing projects between browsers or devices.
41+
42+
## Constraints
43+
44+
- Project data must remain serializable.
45+
- Runtime objects such as `AudioContext`, `AudioBuffer`, `File`, object URLs, active source nodes, and mixer nodes must not be stored in project JSON.
46+
- Switching projects must not let pending autosave write the old project into the new project ID.
47+
- Persistence code should stay separate from React rendering and audio scheduling.
48+
- The audio engine must not depend on IndexedDB or project menu UI.
49+
- Use CSS Modules and semantic design tokens for project menu UI.
50+
- Do not introduce a runtime dependency for IndexedDB or menu behavior unless the implementation clearly justifies it.
51+
52+
## Proposed Model
53+
54+
Use a stable project ID per project instead of one fixed `ACTIVE_PROJECT_ID`.
55+
56+
Illustrative shape:
57+
58+
```ts
59+
export interface ProjectSummary {
60+
id: string;
61+
name: string;
62+
createdAt: number;
63+
updatedAt: number;
64+
}
65+
66+
export interface ProjectCollectionState {
67+
activeProjectId: string;
68+
projects: ProjectSummary[];
69+
}
70+
```
71+
72+
`PersistedProjectDocument.id` should become the actual project ID. Existing project document fields such as clips, arrangement tracks, clip instances, sample metadata, tempo, mixer state, arrangement length, and loop range remain serializable project data.
73+
74+
Imported sample blob storage should include project ownership. Acceptable first-pass strategies:
75+
76+
- Use a composite blob key such as `${projectId}:${sampleId}`.
77+
- Or add `projectId` to each imported sample blob record and query/delete by project ID if IndexedDB indexes are added.
78+
79+
The implementation should choose the smaller safe migration path and document it in the PR.
80+
81+
## UI Direction
82+
83+
The project menu belongs in the transport bar near the current project name/save status area.
84+
85+
The first project menu should include:
86+
87+
- Current project name.
88+
- List of local projects.
89+
- `New Project`.
90+
- `Rename Project`.
91+
- `Delete Project`.
92+
93+
Switching projects should close the menu, stop playback/preview, save or flush the current project state if practical, load the selected project, and reset selection to valid clip/instrument defaults.
94+
95+
## Done when
96+
97+
- Users can create, select, rename, and delete browser-local projects from the transport bar.
98+
- Refreshing the browser restores the last active project.
99+
- Each project restores its own clips, arrangement, mixer state, sample metadata, and imported sample blobs.
100+
- Deleting a project requires confirmation and does not delete another project's sample blobs.
101+
- Existing single-project IndexedDB data is preserved as an initial project after migration where practical.
102+
- Autosave writes to the intended project after creating or switching projects.
103+
- The transport bar displays the active project name from project state, not a hard-coded value.
104+
- The PR documents any migration limitations.
105+
106+
## Verification
107+
108+
Run:
109+
110+
- `npm run typecheck --if-present`
111+
- `npm run lint --if-present`
112+
- `npm run test --if-present`
113+
- `npm run build --if-present`
114+
115+
Manual check:
116+
117+
- Start from an existing single-project browser profile if possible.
118+
- Confirm the old project appears as a local project after migration.
119+
- Create a second project and verify it starts blank.
120+
- Rename a project and refresh the browser.
121+
- Switch between projects and confirm clips, arrangement placements, mixer state, and tempo remain separate.
122+
- Import a WAV file in one project, refresh, and verify the imported audio belongs only to that project.
123+
- Delete a project and confirm another project still loads correctly.
124+
125+
## PR notes
126+
127+
- Summarize IndexedDB store/key changes.
128+
- Explain active project ID persistence.
129+
- Explain imported sample blob scoping and deletion behavior.
130+
- Mention any unsupported project operations, such as duplication or file export/import.

docs/product.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ Build a browser-first mini DAW for creating electronic music with short clips. T
1313
## Core Workflow
1414

1515
1. Open the browser app.
16-
2. Create or select a 1-bar clip.
17-
3. Build a clip with drum events and pitched notes, or import a local WAV file as an audio clip.
18-
4. Start loop playback and edit while listening.
19-
5. Place clips on the `SONG` arrangement timeline.
20-
6. Play the arranged timeline to build a larger song.
21-
7. Balance arrangement tracks with basic mixer controls.
16+
2. Create or select a browser-local project.
17+
3. Create or select a 1-bar clip.
18+
4. Build a clip with drum events and pitched notes, or import a local WAV file as an audio clip.
19+
5. Start loop playback and edit while listening.
20+
6. Place clips on the `SONG` arrangement timeline.
21+
7. Play the arranged timeline to build a larger song.
22+
8. Balance arrangement tracks with basic mixer controls.
2223

2324
## MVP Definition
2425

@@ -48,6 +49,7 @@ The MVP is a browser-first 1-bar hybrid clip editor with:
4849
- Playback timing is stable enough for simple electronic music loops.
4950
- Users can place clips on an arrangement timeline and hear the placed clips in song order.
5051
- Users can adjust track and master levels and mute or solo tracks during arrangement playback.
52+
- Users can keep separate songs or sketches as multiple local browser projects.
5153
- Project data can be represented as JSON without runtime audio objects.
5254
- The codebase separates UI rendering, project state, persistence, and audio scheduling.
5355
- Future contributors can pick up feature specs and implement small, reviewable tasks.

docs/testing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ CI uses `--if-present` while the repository is still before the Vite scaffold.
2424
- Arrangement clip instance creation, movement, deletion, and snapping: unit tests.
2525
- Arrangement scheduler event expansion from clip instances: unit tests where practical.
2626
- IndexedDB persistence adapters, migrations, and serialization boundaries: unit or integration tests with mocked storage where practical.
27+
- Multi-project store operations: unit or integration tests for create, list, rename, delete, active project selection, and migration from the single active project shape.
2728
- Project autosave/manual restore checks should verify that imported audio metadata and blobs remain separated.
2829
- Variable hybrid clip length should cover 1, 2, and 4 bar tick lengths, editor grid derivation, shortening behavior, and arrangement default instance length.
2930
- WAV encoder header, duration, and sample conversion helpers: unit tests.
@@ -83,6 +84,9 @@ tests/unit/utils/tick-time.test.ts
8384
- Imported audio clip metadata and runtime-cache separation.
8485
- Imported file persistence limitations across refresh.
8586
- IndexedDB restore behavior for imported sample metadata and blobs.
87+
- Multi-project active project migration and restore behavior.
88+
- Autosave writing to the wrong project after a project switch.
89+
- Imported sample blob collisions between projects.
8690
- Project export/import.
8791
- WAV export duration and missing-source failure behavior.
8892
- Scheduler timing.
@@ -115,6 +119,7 @@ Manual audio checks should verify:
115119
- WAV import checks should verify valid WAV import, invalid file rejection, imported clip selection, displayed duration metadata, and clear behavior after refresh when imported file persistence is not implemented.
116120
- Arrangement placement checks should verify dragging clips into tracks, moving placed clips, deleting placed clips, and playback from `SONG` mode.
117121
- Imported audio clip arrangement checks should verify clear missing-source behavior after refresh until imported file persistence exists.
122+
- Multi-project checks should verify creating, renaming, switching, deleting, refreshing, and imported audio isolation across projects.
118123

119124
Use headphones or speakers at a safe volume. Record browser, OS, and device details when reporting audio timing issues.
120125

docs/ui-design.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,23 @@ Arrangement export should be presented as an explicit command, likely near the e
156156
- Download a WAV file when export completes.
157157
- Do not imply MP3 or cloud export support until those features exist.
158158

159+
## Project Menu
160+
161+
Multi-project management should live in the transport bar, near the active project name and save status.
162+
163+
The first project menu should:
164+
165+
- Display the active project name from project state, not a hard-coded label.
166+
- Open a compact menu or popover from the project-name area.
167+
- List browser-local projects.
168+
- Provide `New Project`, `Rename Project`, and `Delete Project` actions.
169+
- Make project switching explicit and stop playback or preview before replacing app state.
170+
- Show clear confirmation before deleting a project.
171+
172+
Do not introduce a full dashboard page for the first multi-project feature. Keep the menu compact enough to fit the editor-focused workflow.
173+
174+
Use CSS Modules and semantic design tokens. Inline styles are not expected for this menu because geometry is not tick-derived editor layout.
175+
159176
## Arrangement Mixer Panel
160177

161178
The mixer should start as a bottom dock inside `SONG` mode, below the arrangement timeline.

0 commit comments

Comments
 (0)