Skip to content

feat: add projectType metadata field (standard | shorts)#804

Closed
kseungyong wants to merge 1 commit into
OpenCut-app:mainfrom
kseungyong:feat/project-type-field
Closed

feat: add projectType metadata field (standard | shorts)#804
kseungyong wants to merge 1 commit into
OpenCut-app:mainfrom
kseungyong:feat/project-type-field

Conversation

@kseungyong
Copy link
Copy Markdown

@kseungyong kseungyong commented May 18, 2026

Summary

Adds an optional discriminator field `projectType` to `TProjectMetadata`. This is foundational for upcoming Shorts-flavored features (9:16 preset, YouTube Shorts export preset, vertical-safe text positioning) that need to branch on user intent rather than infer it from canvas dimensions.

Changes

  • `project/types.ts` — Add `PROJECT_TYPES` const + `TProjectType` type. Add optional `projectType` field to `TProjectMetadata`.
  • `core/managers/project-manager.ts` — `createNewProject` accepts optional `projectType`, defaults to `"standard"`.
  • `project/tests/project-type.test.ts` — Type invariants.

Field is optional → existing stored projects in IndexedDB load unchanged.

Why Optional

No storage migration needed. Code paths that branch on type use `?? "standard"`.

Test Plan

  • `bun test apps/web/src/project/tests/project-type.test.ts` passes (3 tests)
  • `bunx tsc --noEmit` produces no new errors from this change
  • Lint clean for modified files

Summary by CodeRabbit

  • New Features

    • Projects now support types ("standard" and "shorts").
    • Project creation accepts an optional project type, defaulting to "standard" when omitted.
  • Tests

    • Added test coverage validating project types, defaulting behavior, and declared type order.

Review Change Stack

@vercel
Copy link
Copy Markdown

vercel Bot commented May 18, 2026

@kseungyong is attempting to deploy a commit to the OpenCut OSS Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 93bae906-2ae9-43bb-803b-18397a91f90b

📥 Commits

Reviewing files that changed from the base of the PR and between a1620a9 and 7131f88.

📒 Files selected for processing (3)
  • apps/web/src/core/managers/project-manager.ts
  • apps/web/src/project/__tests__/project-type.test.ts
  • apps/web/src/project/types.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/web/src/core/managers/project-manager.ts
  • apps/web/src/project/types.ts

📝 Walkthrough

Walkthrough

Defines PROJECT_TYPES and TProjectType, adds an optional projectType to TProjectMetadata, updates ProjectManager.createNewProject to accept and persist projectType (defaulting to "standard"), and adds tests validating the contract and defaulting.

Changes

Project Type System

Layer / File(s) Summary
Project type contract definition
apps/web/src/project/types.ts
PROJECT_TYPES is defined as a const literal tuple and TProjectType is derived as a union. TProjectMetadata interface is extended with an optional projectType field.
Project manager projectType handling
apps/web/src/core/managers/project-manager.ts
createNewProject method signature accepts an optional projectType parameter and stores it in metadata.projectType, defaulting to "standard" when omitted. TProjectType is imported to type the parameter.
Project type contract validation
apps/web/src/project/__tests__/project-type.test.ts
Test suite verifies that PROJECT_TYPES includes "standard" and "shorts", that a missing projectType defaults to "standard", and that the declared order is preserved.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A rabbit hops through code with cheer,
Two types in a bundle, kept near,
When a project is born, the choice is clear,
"standard" by default, no fear,
Hooray for types and tests, hip-hip-hooray! 🐇🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a projectType metadata field with two possible values (standard and shorts).
Description check ✅ Passed The description provides a comprehensive summary, detailed changes across three files, explains the rationale for optional field design, and includes a test plan with verification steps.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/web/src/core/managers/project-manager.ts (1)

98-98: ⚡ Quick win

Use a shared default project type constant instead of a hardcoded string.

Line 98 hardcodes "standard", which duplicates domain data already centralized in project types. Pulling the default from a shared exported constant avoids future drift.

♻️ Proposed fix
--- a/apps/web/src/project/types.ts
+++ b/apps/web/src/project/types.ts
@@
 export const PROJECT_TYPES = ["standard", "shorts"] as const;
 export type TProjectType = (typeof PROJECT_TYPES)[number];
+export const DEFAULT_PROJECT_TYPE: TProjectType = "standard";
--- a/apps/web/src/core/managers/project-manager.ts
+++ b/apps/web/src/core/managers/project-manager.ts
@@
 import type {
+	DEFAULT_PROJECT_TYPE,
 	TProject,
 	TProjectMetadata,
 	TProjectSortKey,
@@
-				projectType: projectType ?? "standard",
+				projectType: projectType ?? DEFAULT_PROJECT_TYPE,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/core/managers/project-manager.ts` at line 98, Replace the
hardcoded "standard" default used in the object assignment (projectType:
projectType ?? "standard") with the shared exported default constant from the
project types module (e.g. DEFAULT_PROJECT_TYPE); add the appropriate import for
that constant and use projectType: projectType ?? DEFAULT_PROJECT_TYPE so the
default value is centralized and cannot drift from the domain constants.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/project/__tests__/project-type.test.ts`:
- Around line 10-13: Replace the weak length-only assertion in the "TProjectType
only accepts known values" test with a strict equality and a compile-time
type-equality guard: assert that the runtime array equals ["standard", "shorts"]
exactly, and add a TypeScript-only check that TProjectType is exactly equal to
the union type derived from that const array (e.g. derive Expected = typeof
expected[number] from const expected = ["standard","shorts"] as const and use a
conditional type to ensure Expected extends TProjectType and TProjectType
extends Expected). This ensures both runtime values and the type alias
TProjectType cannot widen.

---

Nitpick comments:
In `@apps/web/src/core/managers/project-manager.ts`:
- Line 98: Replace the hardcoded "standard" default used in the object
assignment (projectType: projectType ?? "standard") with the shared exported
default constant from the project types module (e.g. DEFAULT_PROJECT_TYPE); add
the appropriate import for that constant and use projectType: projectType ??
DEFAULT_PROJECT_TYPE so the default value is centralized and cannot drift from
the domain constants.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fdd23259-5095-41b1-b6ae-426d75122a2f

📥 Commits

Reviewing files that changed from the base of the PR and between 6fdb155 and a1620a9.

📒 Files selected for processing (3)
  • apps/web/src/core/managers/project-manager.ts
  • apps/web/src/project/__tests__/project-type.test.ts
  • apps/web/src/project/types.ts

Comment on lines +10 to +13
test("TProjectType only accepts known values", () => {
const valid: TProjectType[] = ["standard", "shorts"];
expect(valid.length).toBe(2);
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Strengthen the invariant test so it fails when TProjectType widens.

The current check only verifies array length, so it can still pass if TProjectType becomes too broad (for example, string).

✅ Proposed stronger test
 test("TProjectType only accepts known values", () => {
-	const valid: TProjectType[] = ["standard", "shorts"];
-	expect(valid.length).toBe(2);
+	const assertKnownProjectType = (value: TProjectType): void => {
+		switch (value) {
+			case "standard":
+			case "shorts":
+				return;
+			default: {
+				const exhaustiveCheck: never = value;
+				return exhaustiveCheck;
+			}
+		}
+	};
+
+	assertKnownProjectType("standard");
+	assertKnownProjectType("shorts");
+	expect(PROJECT_TYPES).toHaveLength(2);
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/project/__tests__/project-type.test.ts` around lines 10 - 13,
Replace the weak length-only assertion in the "TProjectType only accepts known
values" test with a strict equality and a compile-time type-equality guard:
assert that the runtime array equals ["standard", "shorts"] exactly, and add a
TypeScript-only check that TProjectType is exactly equal to the union type
derived from that const array (e.g. derive Expected = typeof expected[number]
from const expected = ["standard","shorts"] as const and use a conditional type
to ensure Expected extends TProjectType and TProjectType extends Expected). This
ensures both runtime values and the type alias TProjectType cannot widen.

Adds optional projectType discriminator on TProjectMetadata so downstream features (preset pickers, export defaults, UI affordances) can branch on intent without inferring from canvas dimensions.

- New const PROJECT_TYPES and type TProjectType
- TProjectMetadata.projectType (optional for back-compat with stored projects)
- ProjectManager.createNewProject accepts optional projectType, defaults to 'standard'
- Unit tests for PROJECT_TYPES invariants
@kseungyong
Copy link
Copy Markdown
Author

Closing — continuing on a private fork. The branch feat/project-type-field (commit 7131f88b) remains on https://github.com/kseungyong/OpenCut under MIT if useful later. Thanks.

@kseungyong kseungyong closed this May 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant