From e6471b30cf3b692112e2666adffc19be887a004e Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Sat, 25 Oct 2025 18:53:29 +0900 Subject: [PATCH 01/18] =?UTF-8?q?=EB=B9=88=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 6668754653ccd9686d183e7be2e405f16e2cefeb Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Wed, 29 Oct 2025 23:05:03 +0900 Subject: [PATCH 02/18] =?UTF-8?q?docs:=20=EA=B3=BC=EC=A0=9C=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EB=AC=B8=EC=84=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "\bdocs/requirements.md" | 154 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 "\bdocs/requirements.md" diff --git "a/\bdocs/requirements.md" "b/\bdocs/requirements.md" new file mode 100644 index 00000000..ba81fc29 --- /dev/null +++ "b/\bdocs/requirements.md" @@ -0,0 +1,154 @@ +# Week 2 Assignment + +## Objectives + +Through this assignment, we want you to experience the following: + +1. Getting familiar with the TDD development cycle +2. Learning the basics of AI and Agents and applying them to write code +3. Studying how to instruct AI to write code effectively +4. Once comfortable with AI usage, building your own Agent + +These are the four main objectives. Since unfamiliar concepts are presented consecutively, it might be challenging! But donโ€™t give upโ€”if we work together, youโ€™ll have a fascinating first experience. Letโ€™s go! + +Additional requirements for recurring schedules have been added. + +> **Our server team went on vacation without implementing recurring schedules! +> Instead, they provide create, update, and delete APIs for the list, so the frontend has to handle the logic. ๐Ÿคฌ** + +## Assignment Specification + +- The goal of this assignment is simple! Please write the features below using the TDD cycle. **However, use AI to assist in writing the code!** +- Add all the following features to the existing app. + - The provided specification is the minimum functionality. Please plan more concretely and break down the work into smaller tasks! + +```markdown +1. Select Recurrence Type + - When creating or editing a schedule, users can select a recurrence type. + - Recurrence types are: Daily, Weekly, Monthly, Yearly + - If the 31st is selected for monthly recurrence โ†’ create only on the 31st, not on the last day of months with fewer than 31 days. + - If February 29th is selected for yearly recurrence โ†’ create only on the 29th during leap years! + - Recurring schedules do not consider overlapping schedules. +2. Display Recurring Schedules + - In the calendar view, distinguish recurring schedules by adding an icon. +3. Recurrence End + - Allow specifying an end condition for recurrence. + - Option: Until a certain date + - For this example, generate schedules up to 2025-12-31 as the maximum date. +4. **Edit Recurring Schedule** + 1. If the user selects โ€˜Edit only this occurrence?โ€™ and chooses โ€˜Yesโ€™, perform a single edit: + - Editing a recurring schedule converts it into a single schedule. + - The recurring schedule icon disappears. + 2. If the user selects โ€˜Edit only this occurrence?โ€™ and chooses โ€˜Noโ€™, perform a full edit: + - The recurring schedule remains. + - The recurring schedule icon remains. +5. **Delete Recurring Schedule** + 1. If the user selects โ€˜Delete only this occurrence?โ€™ and chooses โ€˜Yesโ€™, perform a single deletion: + 1. Delete only that occurrence. + 2. If the user selects โ€˜Delete only this occurrence?โ€™ and chooses โ€˜Noโ€™, perform a full deletion: + 1. Delete all occurrences of the recurring schedule. +``` + +## Basic Assignment (EASY) + +**Recommended for those less familiar with writing code using AI.** + +The goal of the basic assignment is to write tests and code for the features in the specification using the TDD approach with AI assistance. + +1. Before starting the assignment, document the rules for writing good tests that you have learned before. Using AI for this is fine. This knowledge will be used later for AI-assisted test code writing. +2. Write documents that can serve as guidelines for AI tools you use, such as [.cursor/rules](https://docs.cursor.com/en/context/rules) and [copilot-instructions.md](http://copilot-instructions.md), which help AI generate answers. + + If youโ€™re curious about helpful guidelines, sneak a peek at the [awesome-cursorrules](https://github.com/PatrickJS/awesome-cursorrules/tree/main) repository! + +3. Itโ€™s time to start development feature by feature. + Use AI to generate, review, and commit code through the TDD cycle stages: RED โ†’ GREEN โ†’ REFACTOR. + Commit after each stage. + +Be careful not to develop all features at once, and leave clear commit messages. + +For each stage, verify the code yourself and note in your PR any improvements you made to achieve better results. + +## Basic Assignment (HARD) + +**Recommended for those somewhat familiar with AI-assisted coding.** + +The goal of the advanced assignment is to build the workflow introduced in [2-2. Build Your Own AI Test Agent](https://www.notion.so/2-2-AI-2642dc3ef51480e589a8f1946588336c?pvs=21) and automatically implement the features in the specification. + +1. Before starting, document the rules for writing good tests you have learned before. Using AI is fine. This knowledge will be used later for AI-assisted test code writing. +2. Create Agents tailored to the AI tools you use. Build six Agents that operate within the workflow. +3. Start development feature by feature. + Use an orchestrator Agent to generate, review, and commit code through the TDD cycle stages: RED โ†’ GREEN โ†’ REFACTOR. + Commit after each stage. + +Be careful not to develop all features at once, and leave clear commit messages. + +If there are core chat histories from each AI tool, please share them! ([Example](https://github.com/jhlee0409/claude-code-history-viewer/blob/main/README.ko.md)) + +For each stage, document in your PR the instructions given to the AI Agents to smooth the workflow, verify the code yourself, and note any efforts made to improve results. + +## Advanced Assignment + +Document your experiences and efforts while working on the assignment! + +We have compiled topics worth considering and experiencing through various attempts. Write these carefully and share your feedback with your team. + +```jsx +# Report on Stable Feature Development Using AI and Testing + +## Why did you choose the tools you used? Have you researched the characteristics of each tool? + +## Was there a difference between AI-assisted feature development based on tests and development without it? + +## What additional information (context) did you provide to improve AI responses? + +## What efforts did you make to help the AI utilize this context well? + +## Were you satisfied with the various results generated? What criteria did you use to evaluate the AIโ€™s responses? + +## How did you phrase your questions to get better results? Share your various experiences. + +## How did you define the scope of tasks assigned to the AI? Try narrowing and widening the scope and describe the results. Also, share what you consider an appropriate unit of work. + +## Were there any good references or phrases you wanted to share with your peers? Feel free to brag. + +## Have you thought about what AI is good and bad at? Write about your thoughts on this. + +## Finally, share your impressions! +``` + +# 3. Evaluation Criteria + +### Common Submissions + +- [ ] Documented rules for writing good tests +- [ ] Wrote all tests to implement the specified features and implemented them correctly +- [ ] Implemented all specified features correctly and verified proper operation + +### Basic Assignment (Easy) + +- [ ] Additional guidelines written to help AI write code well +- [ ] Correctly committed work for each TDD stage +- [ ] Documented efforts to improve AI tool usage in PR + +### Basic Assignment (Hard) + +- [ ] Agent implementation specification document or code +- [ ] Correctly committed work for each TDD stage +- [ ] History or logs demonstrating proper results +- [ ] Documented efforts to improve AI tool usage in PR + +### Advanced Assignment + +- [ ] Thoroughly answered all questions + +### Others + +1. Adherence to TDD process + - Did you write tests first and confirm they fail before implementing? + - Did you write minimal code to pass tests for each requirement? + - Did you perform appropriate refactoring after tests passed? +2. Test quality + - Does each test clearly verify only one behavior or feature? + - Do the tests accurately reflect the requirements? + - Are tests written for all major features and scenarios (both positive and negative cases)? + - Do the tests include boundary and exception cases? From 4a8e4ee2d324a57027d54d9e8ba545cc05de1272 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Wed, 29 Oct 2025 23:07:14 +0900 Subject: [PATCH 03/18] =?UTF-8?q?chore:=20testing-rules.md=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/testing-rules.md | 193 +++++++++++++++++++++++++++++++++ 1 file changed, 193 insertions(+) create mode 100644 .cursor/rules/testing-rules.md diff --git a/.cursor/rules/testing-rules.md b/.cursor/rules/testing-rules.md new file mode 100644 index 00000000..1c029790 --- /dev/null +++ b/.cursor/rules/testing-rules.md @@ -0,0 +1,193 @@ +# Testing Rules (Good Tests Guide) + +This document defines how AI (and humans) should write tests for this project. +Follow the TDD loop: **RED โ†’ GREEN โ†’ REFACTOR**. + +--- + +## 0) Purpose + +- Provide a safety net to prevent regressions while evolving features +- Execute the TDD cycle quickly and reliably +- Serve as an executable spec that teammates/agents can reproduce and verify + +--- + +## 1) Core Principles + +1. **One behavior per test** + + - A single test should verify one user/system behavior and its outcome. + +2. **Assert observable outcomes only** + + - Verify externally observable results: DOM changes, return values, call counts, state transitions. + +3. **AAA structure (Arrangeโ€“Actโ€“Assert)** + + - **Arrange**: set up fixtures/initial state + - **Act**: perform the behavior (once) + - **Assert**: check the expected outcome + +4. **RED first** + + - Start with a meaningful failing test, then pass it with the minimal implementation. + +5. **Deterministic & isolated** + + - No order dependence or shared global state between tests. + - Fix or mock timers, random, time, and network. + +6. **Include boundaries & negatives** + + - Cover min/max/empty/dup/permission failures, etc. + +7. **Use domain language** + - Prefer domain terms in test names, descriptions, and fixtures so requirements read naturally. + +--- + +## 2) Naming Conventions + +- **File**: `..spec.ts(x)` or `*.spec.ts` per unit +- **Test title**: `should when ` + - e.g., `should create only on 31st when monthly recurrence is selected` + +Structure example: + +```ts +describe('[function or feature name]', () => { + it('should [expected behavior] when [situation]', () => { + // Arrangeโ€“Actโ€“Assert + }); +}); + +3) TDD Operations & Commits + 1. RED: write a failing unit/integration test and confirm the failure + 2. GREEN: implement the smallest change to pass + 3. REFACTOR: remove duplication and improve clarity (tests stay green) + 4. Commits (separate for each step): + โ€ข test(red): ... + โ€ข feat(green): ... + โ€ข refactor: ... + +โธป + +4) Test Levels + โ€ข Unit: pure functions/hooks/utils; remove external dependencies; fast and precise + โ€ข Integration: hook + component + state wiring; represent user flows and requirements + โ€ข E2E (optional): key scenarios; for this assignment, integration tests can sufficiently cover flows + +โธป + +5) React/Hook Testing Conventions + โ€ข Use React Testing Library: test from the userโ€™s perspective (roles, labels, text), not implementation details + โ€ข Use userEvent for interactions; for async rendering, use findBy*/waitFor + โ€ข Test hooks via component wrappers or a custom render utility + +โธป + +6) Mocking / Stubs + โ€ข Treat external systems as test doubles: API/time/random/storage + โ€ข Network: use MSW for contract-level mocking; for pure units, allow function-level mocks + โ€ข Time: prefer vi.useFakeTimers() or inject a fixed Date.now; fix the reference clock for recurrence logic + โ€ข Random/IDs: seed or inject the generator + โ€ข Avoid over-mocking: domain logic should be composed โ€œfor realโ€ in integration tests + +โธป + +7) Fixtures & Data Builders + โ€ข Prepare minimal inputs; use named builders/helpers to remove duplication + โ€ข No shared mutable state across tests; each test should be self-contained + +โธป + +8) Assertion Quality + โ€ข Aim for one clear assertion per test (or a small group for one outcome) + โ€ข Negative paths should assert thrown errors/messages explicitly (toThrow, message match) + โ€ข Prefer getByRole / getByLabelText / getByText for DOM queries + +โธป + +9) Coverage Philosophy + โ€ข Focus on risk & complexity: branch-heavy code, domain rules, high-regression areas + โ€ข Treat coverage as a result, not as the target + +โธป + +10) Assignment-Specific Checklist (Recurring Schedules) + โ€ข Recurrence types: Daily / Weekly / Monthly / Yearly + โ€ข Monthly 31st: generate only on the 31st (do not substitute with 30/28/29) + โ€ข Yearly Feb 29: generate only in leap years + โ€ข Overlaps allowed (do not de-duplicate by design) + โ€ข Calendar view: show an icon for recurring events; no icon for single (detached) events + โ€ข End condition: stop at the given end date (max: 2025-12-31) + โ€ข Edit + โ€ข Single occurrence: convert that instance to a single event (remove icon) + โ€ข Edit all: keep recurrence (keep icon) + โ€ข Delete + โ€ข Single occurrence: remove only that instance + โ€ข Delete all: remove every occurrence + +โธป + +11) Recommended Test Suite (Examples) + +Utilities / Domain + โ€ข generateRecurrences + โ€ข Monthly 31st rule + โ€ข Yearly Feb 29 rule (leap years only) + โ€ข Weekly day alignment across month/year boundaries + โ€ข End date clamped at 2025-12-31 + +Hooks / State + โ€ข Create / edit / delete flows (single vs all) + โ€ข After single edit, icon disappears; after edit all, icon remains + +UI Integration + โ€ข Calendar renders recurrence icons distinctly + โ€ข User interactions update view/state correctly + +โธป + +12) Quality Gates + โ€ข Full test run should be fast (seconds) and stable locally + โ€ข Flaky tests are not allowed (remove timing races, eliminate time-dependence) + โ€ข Every new feature follows RED โ†’ GREEN โ†’ REFACTOR with commit history + +โธป + +13) Commit Message Templates + โ€ข test(red): monthly 31st occurs only on 31st + โ€ข feat(green): implement 31st-only monthly generation + โ€ข refactor: extract recurrence generator and clarify names + +โธป + +14) Example Test Snippet + +describe('generateRecurrences', () => { + it('should create events on Feb 29 only in leap years when yearly', () => { + // Arrange + const start = new Date('2024-02-29'); // leap year + const end = new Date('2030-12-31'); + + // Act + const events = generateRecurrences({ start, end, type: 'yearly' }); + + // Assert + const dates = events.map(e => e.date); + expect(dates).toContain('2028-02-29'); + expect(dates).not.toContain('2025-02-28'); // do NOT substitute + }); +}); + +15) AI Writing Notes + +When generating tests: + โ€ข Prefer behavioral descriptions over technical internals + โ€ข Add short comments documenting the intent of the test + โ€ข Include edge cases automatically for date/time logic + โ€ข Keep fixtures minimal and meaningful + โ€ข Avoid long, hard-coded datasets unless necessary +``` From 26d9617b9e0a83fe830bee94e0915cbaf89a7ce0 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Wed, 29 Oct 2025 23:10:21 +0900 Subject: [PATCH 04/18] =?UTF-8?q?chore:=20testing-rules.md=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/testing-rules.md | 158 +++++++++++++++------------------ 1 file changed, 74 insertions(+), 84 deletions(-) diff --git a/.cursor/rules/testing-rules.md b/.cursor/rules/testing-rules.md index 1c029790..ef32693c 100644 --- a/.cursor/rules/testing-rules.md +++ b/.cursor/rules/testing-rules.md @@ -61,111 +61,101 @@ describe('[function or feature name]', () => { // Arrangeโ€“Actโ€“Assert }); }); +``` -3) TDD Operations & Commits - 1. RED: write a failing unit/integration test and confirm the failure - 2. GREEN: implement the smallest change to pass - 3. REFACTOR: remove duplication and improve clarity (tests stay green) - 4. Commits (separate for each step): - โ€ข test(red): ... - โ€ข feat(green): ... - โ€ข refactor: ... +## 3) TDD Operations & Commits -โธป +1. RED: write a failing unit/integration test and confirm the failure +2. GREEN: implement the smallest change to pass +3. REFACTOR: remove duplication and improve clarity (tests stay green) +4. Commits (separate for each step): + โ€ข test(red): ... + โ€ข feat(green): ... + โ€ข refactor: ... -4) Test Levels - โ€ข Unit: pure functions/hooks/utils; remove external dependencies; fast and precise - โ€ข Integration: hook + component + state wiring; represent user flows and requirements - โ€ข E2E (optional): key scenarios; for this assignment, integration tests can sufficiently cover flows +## 4) Test Levels -โธป + โ€ข Unit: pure functions/hooks/utils; remove external dependencies; fast and precise + โ€ข Integration: hook + component + state wiring; represent user flows and requirements + โ€ข E2E (optional): key scenarios; for this assignment, integration tests can sufficiently cover flows -5) React/Hook Testing Conventions - โ€ข Use React Testing Library: test from the userโ€™s perspective (roles, labels, text), not implementation details - โ€ข Use userEvent for interactions; for async rendering, use findBy*/waitFor - โ€ข Test hooks via component wrappers or a custom render utility +## 5) React/Hook Testing Conventions -โธป + โ€ข Use React Testing Library: test from the userโ€™s perspective (roles, labels, text), not implementation details + โ€ข Use userEvent for interactions; for async rendering, use findBy*/waitFor + โ€ข Test hooks via component wrappers or a custom render utility -6) Mocking / Stubs - โ€ข Treat external systems as test doubles: API/time/random/storage - โ€ข Network: use MSW for contract-level mocking; for pure units, allow function-level mocks - โ€ข Time: prefer vi.useFakeTimers() or inject a fixed Date.now; fix the reference clock for recurrence logic - โ€ข Random/IDs: seed or inject the generator - โ€ข Avoid over-mocking: domain logic should be composed โ€œfor realโ€ in integration tests +## 6) Mocking / Stubs -โธป + โ€ข Treat external systems as test doubles: API/time/random/storage + โ€ข Network: use MSW for contract-level mocking; for pure units, allow function-level mocks + โ€ข Time: prefer vi.useFakeTimers() or inject a fixed Date.now; fix the reference clock for recurrence logic + โ€ข Random/IDs: seed or inject the generator + โ€ข Avoid over-mocking: domain logic should be composed โ€œfor realโ€ in integration tests -7) Fixtures & Data Builders - โ€ข Prepare minimal inputs; use named builders/helpers to remove duplication - โ€ข No shared mutable state across tests; each test should be self-contained +## 7) Fixtures & Data Builders -โธป + โ€ข Prepare minimal inputs; use named builders/helpers to remove duplication + โ€ข No shared mutable state across tests; each test should be self-contained -8) Assertion Quality - โ€ข Aim for one clear assertion per test (or a small group for one outcome) - โ€ข Negative paths should assert thrown errors/messages explicitly (toThrow, message match) - โ€ข Prefer getByRole / getByLabelText / getByText for DOM queries +## 8) Assertion Quality -โธป + โ€ข Aim for one clear assertion per test (or a small group for one outcome) + โ€ข Negative paths should assert thrown errors/messages explicitly (toThrow, message match) + โ€ข Prefer getByRole / getByLabelText / getByText for DOM queries -9) Coverage Philosophy - โ€ข Focus on risk & complexity: branch-heavy code, domain rules, high-regression areas - โ€ข Treat coverage as a result, not as the target +## 9) Coverage Philosophy -โธป + โ€ข Focus on risk & complexity: branch-heavy code, domain rules, high-regression areas + โ€ข Treat coverage as a result, not as the target -10) Assignment-Specific Checklist (Recurring Schedules) - โ€ข Recurrence types: Daily / Weekly / Monthly / Yearly - โ€ข Monthly 31st: generate only on the 31st (do not substitute with 30/28/29) - โ€ข Yearly Feb 29: generate only in leap years - โ€ข Overlaps allowed (do not de-duplicate by design) - โ€ข Calendar view: show an icon for recurring events; no icon for single (detached) events - โ€ข End condition: stop at the given end date (max: 2025-12-31) - โ€ข Edit - โ€ข Single occurrence: convert that instance to a single event (remove icon) - โ€ข Edit all: keep recurrence (keep icon) - โ€ข Delete - โ€ข Single occurrence: remove only that instance - โ€ข Delete all: remove every occurrence +## 10) Assignment-Specific Checklist (Recurring Schedules) -โธป + โ€ข Recurrence types: Daily / Weekly / Monthly / Yearly + โ€ข Monthly 31st: generate only on the 31st (do not substitute with 30/28/29) + โ€ข Yearly Feb 29: generate only in leap years + โ€ข Overlaps allowed (do not de-duplicate by design) + โ€ข Calendar view: show an icon for recurring events; no icon for single (detached) events + โ€ข End condition: stop at the given end date (max: 2025-12-31) + โ€ข Edit + โ€ข Single occurrence: convert that instance to a single event (remove icon) + โ€ข Edit all: keep recurrence (keep icon) + โ€ข Delete + โ€ข Single occurrence: remove only that instance + โ€ข Delete all: remove every occurrence -11) Recommended Test Suite (Examples) +## 11) Recommended Test Suite (Examples) Utilities / Domain - โ€ข generateRecurrences - โ€ข Monthly 31st rule - โ€ข Yearly Feb 29 rule (leap years only) - โ€ข Weekly day alignment across month/year boundaries - โ€ข End date clamped at 2025-12-31 +โ€ข generateRecurrences +โ€ข Monthly 31st rule +โ€ข Yearly Feb 29 rule (leap years only) +โ€ข Weekly day alignment across month/year boundaries +โ€ข End date clamped at 2025-12-31 Hooks / State - โ€ข Create / edit / delete flows (single vs all) - โ€ข After single edit, icon disappears; after edit all, icon remains +โ€ข Create / edit / delete flows (single vs all) +โ€ข After single edit, icon disappears; after edit all, icon remains UI Integration - โ€ข Calendar renders recurrence icons distinctly - โ€ข User interactions update view/state correctly - -โธป +โ€ข Calendar renders recurrence icons distinctly +โ€ข User interactions update view/state correctly -12) Quality Gates - โ€ข Full test run should be fast (seconds) and stable locally - โ€ข Flaky tests are not allowed (remove timing races, eliminate time-dependence) - โ€ข Every new feature follows RED โ†’ GREEN โ†’ REFACTOR with commit history +## 12) Quality Gates -โธป + โ€ข Full test run should be fast (seconds) and stable locally + โ€ข Flaky tests are not allowed (remove timing races, eliminate time-dependence) + โ€ข Every new feature follows RED โ†’ GREEN โ†’ REFACTOR with commit history -13) Commit Message Templates - โ€ข test(red): monthly 31st occurs only on 31st - โ€ข feat(green): implement 31st-only monthly generation - โ€ข refactor: extract recurrence generator and clarify names +## 13) Commit Message Templates -โธป + โ€ข test(red): monthly 31st occurs only on 31st + โ€ข feat(green): implement 31st-only monthly generation + โ€ข refactor: extract recurrence generator and clarify names -14) Example Test Snippet +##14) Example Test Snippet +```ts describe('generateRecurrences', () => { it('should create events on Feb 29 only in leap years when yearly', () => { // Arrange @@ -176,18 +166,18 @@ describe('generateRecurrences', () => { const events = generateRecurrences({ start, end, type: 'yearly' }); // Assert - const dates = events.map(e => e.date); + const dates = events.map((e) => e.date); expect(dates).toContain('2028-02-29'); expect(dates).not.toContain('2025-02-28'); // do NOT substitute }); }); +``` -15) AI Writing Notes +## 15) AI Writing Notes When generating tests: - โ€ข Prefer behavioral descriptions over technical internals - โ€ข Add short comments documenting the intent of the test - โ€ข Include edge cases automatically for date/time logic - โ€ข Keep fixtures minimal and meaningful - โ€ข Avoid long, hard-coded datasets unless necessary -``` +โ€ข Prefer behavioral descriptions over technical internals +โ€ข Add short comments documenting the intent of the test +โ€ข Include edge cases automatically for date/time logic +โ€ข Keep fixtures minimal and meaningful +โ€ข Avoid long, hard-coded datasets unless necessary From 5eba65c5d77a820d2b6052b6c50070f37f74f9be Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Wed, 29 Oct 2025 23:16:03 +0900 Subject: [PATCH 05/18] =?UTF-8?q?docs:=20=EB=B0=98=EB=B3=B5=20=EC=9D=BC?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EB=AA=85=EC=84=B8=EC=84=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/agent-rules.md | 52 +++++++++++++++++++++++++++++++ DOCS/recurring-requirements.en.md | 46 +++++++++++++++++++++++++++ copilot-instructions.md | 34 ++++++++++++++++++++ pnpm-workspace.yaml | 4 +++ 4 files changed, 136 insertions(+) create mode 100644 .cursor/rules/agent-rules.md create mode 100644 DOCS/recurring-requirements.en.md create mode 100644 copilot-instructions.md create mode 100644 pnpm-workspace.yaml diff --git a/.cursor/rules/agent-rules.md b/.cursor/rules/agent-rules.md new file mode 100644 index 00000000..8994523a --- /dev/null +++ b/.cursor/rules/agent-rules.md @@ -0,0 +1,52 @@ +# Agent Rules for This Project + +## Goals + +- Implement features via TDD (RED โ†’ GREEN โ†’ REFACTOR) with clear commits. +- Prefer small, safe edits; keep tests fast and deterministic. + +## Operating Principles + +- Always read `docs/requirements.md` and `.cursor/rules/good-test-rules.md` before writing tests or code. +- Default language for commits and code comments: English; for user communication: Korean. +- Preserve existing file indentation and formatting. +- Use behavioral test names and AAA pattern. +- Avoid over-mocking; mock time/network/random deterministically. + +## Change Workflow + +1. Write a failing test first (unit or integration as appropriate). +2. Make the minimal change to pass. +3. Refactor to remove duplication and improve clarity. +4. Commit after each step with messages: + - `test(red): ...` + - `feat(green): ...` + - `refactor: ...` + +## Testing Conventions + +- Use React Testing Library from the userโ€™s perspective (roles/labels/text). +- Use `userEvent` and `findBy*`/`waitFor` for async. +- Use MSW for API; fake timers or injected clock for date/recurrence logic. + +## File/Path Rules + +- Keep new docs in `DOCS/` unless they are agent rules (this folder) or config. +- New tests under `src/__tests__/` with clear grouping (unit/hooks/integration). + +## Recurring Feature Specifics + +- Monthly 31st occurs only on the 31st; Yearly Feb 29 only in leap years. +- Overlaps allowed by design; do not de-duplicate. +- Calendar must show an icon for recurring events; detached single edits remove the icon. +- End date must not exceed 2025-12-31. + +## Quality Gates + +- No flaky tests. Keep total run time within seconds locally. +- Ensure lints/types are clean after edits. + +## Safety + +- Prefer pure functions for date recurrence generation. +- Add boundary and negative tests for every rule. diff --git a/DOCS/recurring-requirements.en.md b/DOCS/recurring-requirements.en.md new file mode 100644 index 00000000..cddec4dc --- /dev/null +++ b/DOCS/recurring-requirements.en.md @@ -0,0 +1,46 @@ +# Recurring Events - Required Feature Specification + +This document defines the mandatory behavior for implementing recurring events. Use it as the source of truth for tests (TDD) and implementation. + +## 1) Recurrence Type Selection + +- Users can select a recurrence type when creating or editing an event. +- Supported types: Daily, Weekly, Monthly, Yearly. +- Special rules: + - Monthly on the 31st: generate occurrences only on the 31st of months that have 31 days. Do NOT substitute with the last day (30/28/29). + - Yearly on Feb 29: generate occurrences only in leap years (Feb 29). Do NOT substitute with Feb 28/Mar 1. +- Overlaps are allowed by design; do not prevent or merge overlapping occurrences. + +## 2) Recurring Indicator in Calendar + +- In the calendar view, display a distinct icon/marker for recurring events. +- Single (detached) events should not display the recurring icon. + +## 3) Recurrence End Condition + +- Users can specify an end condition for the recurrence. +- Option: Until a specific date. + - For this assignment, ensure the maximum generated date is capped at 2025-12-31. + +## 4) Edit Recurring Events + +- When editing an occurrence of a recurring event, prompt the user: "Edit only this occurrence?" + - If the user selects Yes (single edit): + - Convert the selected occurrence into a single (detached) event. + - Remove the recurring icon for that event. + - If the user selects No (edit all): + - Apply changes to the entire series (the event remains recurring). + - The recurring icon remains for occurrences in the series. + +## 5) Delete Recurring Events + +- When deleting an occurrence of a recurring event, prompt the user: "Delete only this occurrence?" + - If the user selects Yes (single delete): + - Remove only the selected occurrence. + - If the user selects No (delete all): + - Delete all occurrences in the series. + +## Notes + +- All rules must be covered by tests first (RED โ†’ GREEN โ†’ REFACTOR). +- Treat time/clock deterministically in tests (fake timers or injected clock). diff --git a/copilot-instructions.md b/copilot-instructions.md new file mode 100644 index 00000000..32988c3d --- /dev/null +++ b/copilot-instructions.md @@ -0,0 +1,34 @@ +# Copilot Instructions (Project-Specific) + +## Mission + +- Assist with TDD development for recurring schedule features. +- Prefer small, safe, and readable edits that keep lints/types clean. + +## Behavior + +- Generate tests first (failing), then minimal implementation, then refactor. +- Use domain language and AAA structure in tests. +- Favor React Testing Library queries by role/label/text; use `userEvent`. +- Mock time/network/random deterministically (MSW, fake timers, injected clock). +- Keep files and paths consistent with the repository structure. + +## Do + +- Put new docs in `DOCS/` (except `.cursor` rules); tests in `src/__tests__/`. +- Write clear commit messages per stage: `test(red)`, `feat(green)`, `refactor`. +- Add boundary/negative test cases for date/recurrence rules. + +## Donโ€™t + +- Donโ€™t rely on implementation details in tests. +- Donโ€™t introduce flaky tests or time-dependent assertions. +- Donโ€™t over-mock core domain logic in integration tests. + +## Recurring Feature Notes + +- Monthly 31st โ†’ only on the 31st; no substitution with 30/28/29. +- Yearly Feb 29 โ†’ only in leap years. +- Overlaps allowed; no de-dup. +- Calendar shows icon for recurring; detached single edits remove the icon. +- End date must not exceed 2025-12-31. diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 00000000..9ff8d8fa --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,4 @@ +onlyBuiltDependencies: + - '@swc/core' + - esbuild + - msw From d8e117802be9afdbd19c6b86b66a3158eb003cc5 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 21:56:43 +0900 Subject: [PATCH 06/18] =?UTF-8?q?chore:=20=EC=97=90=EC=9D=B4=EC=A0=84?= =?UTF-8?q?=ED=8A=B8=20=EA=B7=9C=EC=B9=99,=20=EC=97=90=EC=9D=B4=EC=A0=84?= =?UTF-8?q?=ED=8A=B8=20=ED=94=84=EB=A1=AC=ED=94=84=ED=8A=B8,=20=EB=B0=98?= =?UTF-8?q?=EB=B3=B5=20=EC=9D=BC=EC=A0=95=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD,=20=EC=9B=8C=ED=81=AC=ED=94=8C=EB=A1=9C=EC=9A=B0=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=20=EC=B4=88=EA=B8=B0=20=EC=84=B8=ED=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/agent/committer.md | 24 ++++++++++++++++++++ .cursor/agent/minimal-implementer.md | 24 ++++++++++++++++++++ .cursor/agent/orchestrator.md | 33 ++++++++++++++++++++++++++++ .cursor/agent/refactorer.md | 24 ++++++++++++++++++++ .cursor/agent/reviewer.md | 23 +++++++++++++++++++ .cursor/agent/spec-agent.md | 28 +++++++++++++++++++++++ .cursor/agent/test-author.md | 29 ++++++++++++++++++++++++ .cursor/rules/agent-rules.md | 16 ++++++++++++++ DOCS/recurring-requirements.en.md | 4 ++++ copilot-instructions.md | 4 ++++ 10 files changed, 209 insertions(+) create mode 100644 .cursor/agent/committer.md create mode 100644 .cursor/agent/minimal-implementer.md create mode 100644 .cursor/agent/orchestrator.md create mode 100644 .cursor/agent/refactorer.md create mode 100644 .cursor/agent/reviewer.md create mode 100644 .cursor/agent/spec-agent.md create mode 100644 .cursor/agent/test-author.md diff --git a/.cursor/agent/committer.md b/.cursor/agent/committer.md new file mode 100644 index 00000000..7cdf1a04 --- /dev/null +++ b/.cursor/agent/committer.md @@ -0,0 +1,24 @@ +# Committer Agent + +Mission: Produce clean, stage-specific commits with clear messages. + +Stages: + +- RED: `test(red): ` +- GREEN: `feat(green): ` +- REFACTOR: `refactor: ` + +Rules: + +- Commit only relevant files per stage. +- Keep messages actionable and scoped to one behavior. + +Example Messages: + +- `test(red): monthly 31st occurs only on the 31st` +- `feat(green): implement 31st-only monthly recurrence rule` +- `refactor: extract recurrence generator and clarify names` + + + + diff --git a/.cursor/agent/minimal-implementer.md b/.cursor/agent/minimal-implementer.md new file mode 100644 index 00000000..b760cf77 --- /dev/null +++ b/.cursor/agent/minimal-implementer.md @@ -0,0 +1,24 @@ +# Minimal Implementer Agent + +Mission: Make the smallest code change to pass the failing tests. + +Constraints: + +- No premature abstractions; change only what the tests require. +- Preserve formatting and existing indentation. +- Keep performance/structure changes for the refactor step. + +Steps: + +1. Read failing test output and the exact assertions. +2. Implement just enough in `src/` to pass. +3. If time/clock is needed, accept a clock parameter or use a centralized date utility. +4. Re-run tests; ensure GREEN with no lints/types broken. + +Exit Criteria: + +- All new tests pass. No unrelated files changed. + + + + diff --git a/.cursor/agent/orchestrator.md b/.cursor/agent/orchestrator.md new file mode 100644 index 00000000..5996e2ea --- /dev/null +++ b/.cursor/agent/orchestrator.md @@ -0,0 +1,33 @@ +# Orchestrator Agent + +Goal: Drive one full TDD cycle per feature slice using the six-agent workflow. + +Inputs: + +- Feature target (e.g., "Monthly 31st rule" or "Recurring icon rendering"). +- Specs: `DOCS/recurring-requirements.en.md` +- Rules: `.cursor/rules/testing-rules.md`, `.cursor/rules/good-test-rules.md`, `.cursor/rules/agent-rules.md` + +Outputs: + +- Clear subtask for Test Author (what to test, scope, boundaries) +- Handoff notes for Minimal Implementer, Refactorer, Reviewer, Committer + +Operating Steps: + +1. Select the next smallest verifiable behavior from the spec. +2. Define acceptance criteria and boundaries (edge cases, negatives). +3. Dispatch to Test Author with exact file paths and naming. +4. After RED, dispatch to Minimal Implementer with constraints: minimal change only. +5. After GREEN, dispatch Reviewer; if clean, dispatch Refactorer; then Reviewer again. +6. Dispatch Committer with stage and message template. + +Guardrails: + +- Do not bundle multiple behaviors in one cycle. +- Ensure deterministic tests (fake timers / injected clock). +- Keep each cycle small and independently shippable. + + + + diff --git a/.cursor/agent/refactorer.md b/.cursor/agent/refactorer.md new file mode 100644 index 00000000..f733e092 --- /dev/null +++ b/.cursor/agent/refactorer.md @@ -0,0 +1,24 @@ +# Refactorer Agent + +Mission: Improve clarity, structure, and duplication after GREEN without changing behavior. + +Targets: + +- Extract pure functions for recurrence rules (31st-only, leap-year Feb 29, end-cap). +- Improve naming; reduce branching; add small helpers. + +Rules: + +- Keep all tests GREEN. +- Avoid changing public APIs unless tests guarantee compatibility. +- Do not add new features; only structural improvement. + +Checklist: + +- Remove duplication introduced during minimal implementation. +- Centralize date handling with deterministic interfaces. +- Keep files small and functions readable. + + + + diff --git a/.cursor/agent/reviewer.md b/.cursor/agent/reviewer.md new file mode 100644 index 00000000..c9592e3a --- /dev/null +++ b/.cursor/agent/reviewer.md @@ -0,0 +1,23 @@ +# Reviewer Agent + +Mission: Guard quality gates (tests, lints, types, style, determinism). + +Review Items: + +- Tests: one behavior per test; AAA; domain language; edges/negatives included. +- Determinism: no real-time dependence; fake timers/injected clock used. +- Code clarity: names, small functions, no dead code, no over-mocking. +- Spec alignment: matches `DOCS/recurring-requirements.en.md` exactly. + +Actions: + +- Suggest precise diffs or edits; avoid vague feedback. +- Block if flaky patterns or scope creep. + +Exit Criteria: + +- All checks pass; ready for refactor/commit. + + + + diff --git a/.cursor/agent/spec-agent.md b/.cursor/agent/spec-agent.md new file mode 100644 index 00000000..4c21f60e --- /dev/null +++ b/.cursor/agent/spec-agent.md @@ -0,0 +1,28 @@ +# Agent Workflow Overview + +This repository uses six agents to implement the recurring features via TDD. +All agents must follow `.cursor/rules/testing-rules.md` (or `good-test-rules.md`) and `DOCS/recurring-requirements.en.md`. + +Agents: + +1. Orchestrator +2. Test Author +3. Minimal Implementer +4. Refactorer +5. Reviewer +6. Committer + +High-level flow (per feature slice): + +- Orchestrator โ†’ Test Author (RED) โ†’ Minimal Implementer (GREEN) โ†’ Reviewer โ†’ Refactorer (REFACTOR) โ†’ Reviewer โ†’ Committer. + +Artifacts and paths: + +- Specs: `DOCS/recurring-requirements.en.md` +- Rules: `.cursor/rules/testing-rules.md`, `.cursor/rules/good-test-rules.md`, `.cursor/rules/agent-rules.md` +- Tests: `src/__tests__/` +- Code: `src/` + + + + diff --git a/.cursor/agent/test-author.md b/.cursor/agent/test-author.md new file mode 100644 index 00000000..f630aa3a --- /dev/null +++ b/.cursor/agent/test-author.md @@ -0,0 +1,29 @@ +# Test Author Agent + +Mission: Write failing tests that precisely capture the behavior. + +Read: + +- `DOCS/recurring-requirements.en.md` +- `.cursor/rules/testing-rules.md` or `.cursor/rules/good-test-rules.md` + +Deliverables: + +- New/updated test files under `src/__tests__/` using AAA and domain language. +- Clear, one-behavior-per-test with boundaries and negatives. + +Checklist: + +- Name: `should when ` +- Use RTL queries by role/label/text; prefer `userEvent` and `findBy*` for async. +- For date logic, fix the clock (fake timers or injected Date). +- For networking, use MSW or function-level mocks for pure units. +- Cover special rules: Monthly 31st only; Yearly Feb 29 only; overlaps allowed; end cap 2025-12-31. + +Exit Criteria: + +- Tests fail with meaningful error before implementation begins (RED). + + + + diff --git a/.cursor/rules/agent-rules.md b/.cursor/rules/agent-rules.md index 8994523a..d9550dca 100644 --- a/.cursor/rules/agent-rules.md +++ b/.cursor/rules/agent-rules.md @@ -50,3 +50,19 @@ - Prefer pure functions for date recurrence generation. - Add boundary and negative tests for every rule. + +## Stage Documentation & Cross-Referencing + +- For each TDD phase (RED, GREEN, REFACTOR): + - Create a markdown doc (`DOCS/feature--RED.md`, `feature--GREEN.md`, etc.) summarizing what was done at that stage (goal, steps, reasons, paths, result). + - Save and commit this doc together with the code/test for the corresponding phase. + - Ensure commit messages, doc file headers, and requirements/spec references use the same numbering/convention for traceability. + - Example: + - Commit: `test(red): 1. Recurrence type selection โ€“ only 31st of month` + - Doc: `DOCS/feature-1-RED.md` (`Related Spec: 1`) + - Clear mapping between code, docs, and spec for every feature and phase. + +## Commit & PR Language Policy + +- ๋ชจ๋“  ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ PR ์„ค๋ช…์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. +- ์ฝ”๋“œ/ํ…Œ์ŠคํŠธ/์ฃผ์„ ๋“ฑ์€ ์˜์–ด๋กœ ์ž‘์„ฑํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž์™€์˜ ์†Œํ†ต(์ปค๋ฐ‹, PR)์€ ํ•œ๊ตญ์–ด๋ฅผ ์›์น™์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/DOCS/recurring-requirements.en.md b/DOCS/recurring-requirements.en.md index cddec4dc..96679391 100644 --- a/DOCS/recurring-requirements.en.md +++ b/DOCS/recurring-requirements.en.md @@ -44,3 +44,7 @@ This document defines the mandatory behavior for implementing recurring events. - All rules must be covered by tests first (RED โ†’ GREEN โ†’ REFACTOR). - Treat time/clock deterministically in tests (fake timers or injected clock). + + + + diff --git a/copilot-instructions.md b/copilot-instructions.md index 32988c3d..ffb577cb 100644 --- a/copilot-instructions.md +++ b/copilot-instructions.md @@ -32,3 +32,7 @@ - Overlaps allowed; no de-dup. - Calendar shows icon for recurring; detached single edits remove the icon. - End date must not exceed 2025-12-31. + + + + From b4b6cdc25d65c92454a85915ba5845813664b0b6 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:09:24 +0900 Subject: [PATCH 07/18] =?UTF-8?q?docs:=20TDD=20=EB=8B=A8=EA=B3=84=EB=B3=84?= =?UTF-8?q?=20=EC=82=B0=EC=B6=9C=EB=AC=BC,=20=EC=97=90=EC=9D=B4=EC=A0=84?= =?UTF-8?q?=ED=8A=B8=20=EC=97=AD=ED=95=A0=20=EB=B0=8F=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=EC=88=9C=EC=84=9C=20=EC=A7=80=EC=B9=A8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/agent-rules.md | 21 +++++++++++++++++++- DOCS/feature-1-RED.md | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 DOCS/feature-1-RED.md diff --git a/.cursor/rules/agent-rules.md b/.cursor/rules/agent-rules.md index d9550dca..91c37837 100644 --- a/.cursor/rules/agent-rules.md +++ b/.cursor/rules/agent-rules.md @@ -62,7 +62,26 @@ - Doc: `DOCS/feature-1-RED.md` (`Related Spec: 1`) - Clear mapping between code, docs, and spec for every feature and phase. +## TDD ๋‹จ๊ณ„๋ณ„ ํ‘œ์ค€ ์‚ฐ์ถœ๋ฌผ ๋ฐ ์—์ด์ „ํŠธ ์ฑ…์ž„ ์ˆœ์„œ + +์•„๋ž˜์˜ ํ๋ฆ„(RED, GREEN, REFACTOR ๋ชจ๋‘ ๋™์ผ)์„ ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ฆ„. + +1. ์ฝ”๋“œ(ํ…Œ์ŠคํŠธ/๊ตฌํ˜„/๋ฆฌํŒฉํ„ฐ ๋“ฑ) ์ž‘์„ฑ + - RED: Test Author Agent + - GREEN: Minimal Implementer Agent + - REFACTOR: Refactorer Agent +2. ํ•ด๋‹น ๋‹จ๊ณ„ ์‚ฐ์ถœ๋ฌผ(ํ•œ๊ตญ์–ด md ๋ฌธ์„œ) ์ž‘์„ฑ + - ํ•ด๋‹น ๋‹จ๊ณ„ ์ฃผ๋„ ์—์ด์ „ํŠธ๊ฐ€ ์‚ฐ์ถœ๋ฌผ๋„ ์ž‘์„ฑ + - ์‚ฐ์ถœ๋ฌผ ์ด๋ฆ„๊ณผ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€, ์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ/๋‚ด์šฉ์„ ํ†ต์ผํ•จ +3. ๊ฒ€ํ†  + - Reviewer Agent๊ฐ€ ์ฝ”๋“œ์™€ ์‚ฐ์ถœ๋ฌผ ๋ชจ๋‘ ์ ๊ฒ€(ํ’ˆ์งˆ, TDD ๊ทœ์น™, ์š”๊ตฌ์‚ฌํ•ญ ๋งคํ•‘ ๋“ฑ) +4. ์ปค๋ฐ‹ + - Committer Agent๊ฐ€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ(ํ•œ๊ตญ์–ด), ์‚ฐ์ถœ๋ฌผ-์ฝ”๋“œ-์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ-์ปค๋ฐ‹ ๊ฐ„ ๋งค์นญ ์ฑ…์ž„ + +> ๋ชจ๋“  ์ฃผ์„/์ฝ”๋“œ/ํ…Œ์ŠคํŠธ๋Š” ์˜์–ด, ์ปค๋ฐ‹/PR/์‚ฐ์ถœ๋ฌผ์€ ํ•œ๊ตญ์–ด ์›์น™์„ ๋ฐ˜๋“œ์‹œ ์ง€ํ‚ด + ## Commit & PR Language Policy - ๋ชจ๋“  ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ PR ์„ค๋ช…์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. -- ์ฝ”๋“œ/ํ…Œ์ŠคํŠธ/์ฃผ์„ ๋“ฑ์€ ์˜์–ด๋กœ ์ž‘์„ฑํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž์™€์˜ ์†Œํ†ต(์ปค๋ฐ‹, PR)์€ ํ•œ๊ตญ์–ด๋ฅผ ์›์น™์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. +- ๊ฐ TDD ๋‹จ๊ณ„(RED, GREEN, REFACTOR)๋ณ„๋กœ ์ƒ์„ฑํ•˜๋Š” ์‚ฐ์ถœ๋ฌผ(md ๋ฌธ์„œ ๋“ฑ)๋„ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. +- ์ฝ”๋“œ/ํ…Œ์ŠคํŠธ/์ฃผ์„ ๋“ฑ์€ ์˜์–ด๋กœ ์ž‘์„ฑํ•˜๋ฉฐ, ์‚ฐ์ถœ๋ฌผ๊ณผ ์‚ฌ์šฉ์ž ์†Œํ†ต(์ปค๋ฐ‹, PR, ๋‹จ๊ณ„ ๋ฌธ์„œ)์€ ํ•œ๊ตญ์–ด๋ฅผ ์›์น™์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. diff --git a/DOCS/feature-1-RED.md b/DOCS/feature-1-RED.md new file mode 100644 index 00000000..3a4a966a --- /dev/null +++ b/DOCS/feature-1-RED.md @@ -0,0 +1,38 @@ +# [RED] Feature 1: ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - ๋‹จ์ผ ์ฑ…์ž„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ + +## ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ + +- 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ (recurring type selection) + - ์ผ์ • ์ƒ์„ฑ/์ˆ˜์ • ์‹œ ๋‹ค์Œ ๋ฐ˜๋ณต ์œ ํ˜• ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค: ๋งค์ผ, ๋งค์ฃผ, ๋งค์›”, ๋งค๋…„ + - 31์ผ ์„ ํƒ ์‹œ: ๋งค์›” 31์ผ์—๋งŒ ์ผ์ • ์ƒ์„ฑ(30/28/29์ผ ๋Œ€์ฒด ๊ธˆ์ง€) + - 2/29 ์„ ํƒ ์‹œ: ์œค๋…„ 2์›” 29์ผ์—๋งŒ ์ผ์ • ์ƒ์„ฑ + - ๋ฐ˜๋ณต ์ผ์ •์€ ๊ฒน์นจ ํ—ˆ์šฉ + +## ์‚ฐ์ถœ ๋ชฉ์  + +- ์œ„ ์š”๊ตฌ์‚ฌํ•ญ์— ๋Œ€์‘ํ•˜๋Š” ํ•ต์‹ฌ โ€œ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒโ€ ๋™์ž‘์— ๋Œ€ํ•œ ์‹คํŒจ ํ…Œ์ŠคํŠธ(RED) ์ž‘์„ฑ์„ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค. +- ์ผ์ • ์ƒ์„ฑ ์‹œ, ๋ฐ˜๋ณต ์œ ํ˜•์ด ์ •์ƒ ์ธ์‹ ๋ฐ ์ฒ˜๋ฆฌ๋˜๋Š”์ง€ ๊ฒ€์ฆ +- ํŠน์ˆ˜ ๊ทœ์น™(31์ผ, 2/29์ผ, ๊ฒน์นจ ํ—ˆ์šฉ)์— ๋Œ€ํ•œ ๋‹จ์ผ ์ฑ…์ž„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ + +## ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ์ „๋žต + +- src/**tests**/hooks/ ๋˜๋Š” unit/util์— ํ…Œ์ŠคํŠธ ํŒŒ์ผ ์ถ”๊ฐ€ +- ํ…Œ์ŠคํŠธ๋ช…: โ€œ[์œ ํ‹ธ/ํ›…๋ช…]์€ [์กฐ๊ฑด]์ผ ๋•Œ [๊ฒฐ๊ณผ๋™์ž‘]ํ•ด์•ผ ํ•œ๋‹คโ€ +- ์˜ˆ์‹œ 1: generateRecurrences ํ•จ์ˆ˜๋Š” ๋งค์›” 31์ผ ๋ฐ˜๋ณต ์„ ํƒ ์‹œ 31์ผ์—๋งŒ ์ƒ์„ฑํ•œ๋‹ค +- ์˜ˆ์‹œ 2: generateRecurrences ํ•จ์ˆ˜๋Š” ์—ฐ 2/29 ๋ฐ˜๋ณต ์„ ํƒ ์‹œ ์œค๋…„์—๋งŒ ์ƒ์„ฑํ•œ๋‹ค + +## ๊ฒ€์ฆ ๋ฒ”์œ„ ๋ฐ ์˜ˆ์‹œ + +- ๋งค์›” 31์ผ ๋ฐ˜๋ณต: 1~12์›” ์ „๋ถ€ ์‹œ๋„ โ†’ 1, 3, 5, 7, 8, 10, 12์›” 31์ผ๋งŒ ๋ฐœ์ƒ +- ์—ฐ 2/29 ๋ฐ˜๋ณต: 2024~2030๋…„ ๋ชจ๋‘ ์‹œ๋„ โ†’ 2024, 2028๋…„์—๋งŒ ์ƒ์„ฑ(๊ทธ ์™ธ X) +- ๋ฐ˜๋ณต ์ผ์ •์ด ๊ธฐ์กด ์ผ์ •๊ณผ ๊ฒน์ณ๋„ ์ƒ์„ฑ๋จ. + +## ์‚ฐ์ถœ ๊ฒฝ๋กœ + +- ๋ฌธ์„œ: DOCS/feature-1-RED.md +- ํ…Œ์ŠคํŠธ: src/**tests**/unit/recurrenceUtils.spec.ts (๋˜๋Š” hooks/easy.useRecurrence.spec.ts) +- ์ถ”ํ›„ ์ปค๋ฐ‹: test(red): 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - 31์ผ/2์›”29์ผ ๊ทœ์น™ ๊ฒ€์ฆ + +## ์‹ฌ์‚ฌ ํฌ์ธํŠธ + +- ์š”๊ตฌ์‚ฌํ•ญ 1๊ณผ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ, ์ปค๋ฐ‹, ์‚ฐ์ถœ๋ฌผ ๊ฐ„ ์ƒํ˜ธ ๋งคํ•‘์ด ๋ช…ํ™•ํ•ด์•ผ ํ•จ From 8397a29b60f1a8359358331cad16e47232408c45 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:14:31 +0900 Subject: [PATCH 08/18] =?UTF-8?q?test(red):=201.=20=EB=B0=98=EB=B3=B5=20?= =?UTF-8?q?=EC=9C=A0=ED=98=95=20=EC=84=A0=ED=83=9D=20-=2031=EC=9D=BC/2?= =?UTF-8?q?=EC=9B=9429=EC=9D=BC/=EA=B2=B9=EC=B9=A8=20=ED=97=88=EC=9A=A9=20?= =?UTF-8?q?=EA=B7=9C=EC=B9=99=20=EC=8B=A4=ED=8C=A8=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCS/feature-1-RED.md | 31 +++++----- src/__tests__/unit/recurrenceUtils.spec.ts | 72 ++++++++++++++++++++++ 2 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 src/__tests__/unit/recurrenceUtils.spec.ts diff --git a/DOCS/feature-1-RED.md b/DOCS/feature-1-RED.md index 3a4a966a..ce6cb04a 100644 --- a/DOCS/feature-1-RED.md +++ b/DOCS/feature-1-RED.md @@ -14,25 +14,26 @@ - ์ผ์ • ์ƒ์„ฑ ์‹œ, ๋ฐ˜๋ณต ์œ ํ˜•์ด ์ •์ƒ ์ธ์‹ ๋ฐ ์ฒ˜๋ฆฌ๋˜๋Š”์ง€ ๊ฒ€์ฆ - ํŠน์ˆ˜ ๊ทœ์น™(31์ผ, 2/29์ผ, ๊ฒน์นจ ํ—ˆ์šฉ)์— ๋Œ€ํ•œ ๋‹จ์ผ ์ฑ…์ž„ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ -## ํ…Œ์ŠคํŠธ ์ž‘์„ฑ ์ „๋žต +## ์‹ค์ œ ์ž‘์„ฑ ๊ฒฐ๊ณผ ์š”์•ฝ -- src/**tests**/hooks/ ๋˜๋Š” unit/util์— ํ…Œ์ŠคํŠธ ํŒŒ์ผ ์ถ”๊ฐ€ -- ํ…Œ์ŠคํŠธ๋ช…: โ€œ[์œ ํ‹ธ/ํ›…๋ช…]์€ [์กฐ๊ฑด]์ผ ๋•Œ [๊ฒฐ๊ณผ๋™์ž‘]ํ•ด์•ผ ํ•œ๋‹คโ€ -- ์˜ˆ์‹œ 1: generateRecurrences ํ•จ์ˆ˜๋Š” ๋งค์›” 31์ผ ๋ฐ˜๋ณต ์„ ํƒ ์‹œ 31์ผ์—๋งŒ ์ƒ์„ฑํ•œ๋‹ค -- ์˜ˆ์‹œ 2: generateRecurrences ํ•จ์ˆ˜๋Š” ์—ฐ 2/29 ๋ฐ˜๋ณต ์„ ํƒ ์‹œ ์œค๋…„์—๋งŒ ์ƒ์„ฑํ•œ๋‹ค +- src/**tests**/unit/recurrenceUtils.spec.ts + - "generateRecurrences" ์œ ํ‹ธ ํ•จ์ˆ˜์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ 3๊ฑด ์ž‘์„ฑ(์ดˆ๊ธฐ ๋‹จ๊ณ„์—” ์ž„์‹œ ํ•จ์ˆ˜๋ช…) + 1. ๋งค์›” 31์ผ ๋ฐ˜๋ณต ์„ ํƒ ์‹œ 1, 3, 5, 7, 8, 10, 12์›” 31์ผ ์ผ์ •๋งŒ ์ƒ์„ฑ๋˜๋Š”์ง€ ๊ฒ€์ฆ(๋‚˜๋จธ์ง€ ๋‹ฌ์€ ์ƒ์„ฑ ๋ถˆ๊ฐ€) + 2. ์—ฐ 2/29 ๋ฐ˜๋ณต ์‹œ ์œค๋…„(2024, 2028)๋งŒ ํฌํ•จ (๋‹ค๋ฅธ ํ•ด๋Š” ์ƒ์„ฑ ๊ธˆ์ง€) + 3. ๊ธฐ์กด ์ผ์ •๊ณผ ๊ฒน์น˜๋”๋ผ๋„ ์ค‘๋ณต ํ—ˆ์šฉ๋˜์–ด ์ƒ์„ฑ๋จ์„ ๊ฒ€์ฆ(์ค‘๋ณต ์ œ๊ฑฐ ๋ถˆํ•„์š”) +- ํ…Œ์ŠคํŠธ ์„ค๋ช… ๋ฐ ์ฃผ์„ ๋ชจ๋‘ ํ•œ๊ตญ์–ด๋กœ ๋ช…ํ™•ํžˆ ์ž‘์„ฑ(๊ฐ€๋…์„ฑ/๋„๋ฉ”์ธ ์ถ”์ ์„ฑ ํ™•๋ณด) -## ๊ฒ€์ฆ ๋ฒ”์œ„ ๋ฐ ์˜ˆ์‹œ +## ๊ฒ€์ฆ ํฌ์ธํŠธ -- ๋งค์›” 31์ผ ๋ฐ˜๋ณต: 1~12์›” ์ „๋ถ€ ์‹œ๋„ โ†’ 1, 3, 5, 7, 8, 10, 12์›” 31์ผ๋งŒ ๋ฐœ์ƒ -- ์—ฐ 2/29 ๋ฐ˜๋ณต: 2024~2030๋…„ ๋ชจ๋‘ ์‹œ๋„ โ†’ 2024, 2028๋…„์—๋งŒ ์ƒ์„ฑ(๊ทธ ์™ธ X) -- ๋ฐ˜๋ณต ์ผ์ •์ด ๊ธฐ์กด ์ผ์ •๊ณผ ๊ฒน์ณ๋„ ์ƒ์„ฑ๋จ. +- ์š”๊ตฌ์‚ฌํ•ญ์—์„œ ๋ช…์‹œํ•œ ํŠน์ˆ˜ ์‚ฌ๋ก€(์›” 31์ผ, ์œค๋…„ 2์›” 29์ผ, ์ค‘๋ณต ํ—ˆ์šฉ)์— ์ •ํ™•ํ•˜๊ฒŒ ๋Œ€์‘ํ•˜๋Š”๊ฐ€? +- ํ…Œ์ŠคํŠธ ๋ช…/๋‚ด์šฉ/๊ฒฝ๊ณ„์กฐ๊ฑด์ด ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚˜๋Š”๊ฐ€? -## ์‚ฐ์ถœ ๊ฒฝ๋กœ +## ์ฐจํ›„ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์˜ˆ์‹œ -- ๋ฌธ์„œ: DOCS/feature-1-RED.md -- ํ…Œ์ŠคํŠธ: src/**tests**/unit/recurrenceUtils.spec.ts (๋˜๋Š” hooks/easy.useRecurrence.spec.ts) -- ์ถ”ํ›„ ์ปค๋ฐ‹: test(red): 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - 31์ผ/2์›”29์ผ ๊ทœ์น™ ๊ฒ€์ฆ +- test(red): 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - 31์ผ/2์›”29์ผ/๊ฒน์นจ ํ—ˆ์šฉ ๊ทœ์น™ ์‹คํŒจ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€ -## ์‹ฌ์‚ฌ ํฌ์ธํŠธ +## ํŒŒ์ผ/์ปค๋ฐ‹/์š”๊ตฌ์‚ฌํ•ญ ๋งคํ•‘ -- ์š”๊ตฌ์‚ฌํ•ญ 1๊ณผ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ, ์ปค๋ฐ‹, ์‚ฐ์ถœ๋ฌผ ๊ฐ„ ์ƒํ˜ธ ๋งคํ•‘์ด ๋ช…ํ™•ํ•ด์•ผ ํ•จ +- ๋ฌธ์„œ: DOCS/feature-1-RED.md +- ํ…Œ์ŠคํŠธ: src/**tests**/unit/recurrenceUtils.spec.ts +- ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ: 1 diff --git a/src/__tests__/unit/recurrenceUtils.spec.ts b/src/__tests__/unit/recurrenceUtils.spec.ts new file mode 100644 index 00000000..e9004c21 --- /dev/null +++ b/src/__tests__/unit/recurrenceUtils.spec.ts @@ -0,0 +1,72 @@ +import { generateRecurrences } from '../../utils/eventUtils'; + +describe('generateRecurrences (RED)', () => { + it('๋งค์›” ๋ฐ˜๋ณต์—์„œ 31์ผ ์„ ํƒ ์‹œ 31์ผ์—๋งŒ ์ผ์ •์„ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค (30/28/29์ผ ๋Œ€์ฒด ๊ธˆ์ง€)', () => { + // ์ค€๋น„: 2024๋…„ 1์›” 31์ผ๋ถ€ํ„ฐ 12์›” 31์ผ๊นŒ์ง€, ๋ฐ˜๋ณต ์œ ํ˜•์€ monthly๋กœ ์ง€์ • + const start = new Date('2024-01-31'); + const end = new Date('2024-12-31'); + // ์‹คํ–‰: ๋งค์›” 1ํšŒ ๋ฐ˜๋ณต ์ƒ์„ฑ + const events = generateRecurrences({ + start, + end, + type: 'monthly', + interval: 1, + }); + // ๊ฒ€์ฆ: 1, 3, 5, 7, 8, 10, 12์›” 31์ผ๋งŒ ์žˆ์–ด์•ผ ํ•จ (๋‹ค๋ฅธ ๋‹ฌ ๋Œ€์ฒด/์ƒ์„ฑ ๊ธˆ์ง€) + const dates = events.map((e) => e.date.slice(5, 10)); // MM-DD + expect(dates).toContain('01-31'); + expect(dates).toContain('03-31'); + expect(dates).toContain('05-31'); + expect(dates).toContain('07-31'); + expect(dates).toContain('08-31'); + expect(dates).toContain('10-31'); + expect(dates).toContain('12-31'); + expect(dates).not.toContain('04-30'); + expect(dates).not.toContain('06-30'); + expect(dates).not.toContain('09-30'); + expect(dates).not.toContain('11-30'); + expect(dates).not.toContain('02-28'); + expect(dates).not.toContain('02-29'); + }); + + it('์—ฐ ๋ฐ˜๋ณต์—์„œ 2์›” 29์ผ ์„ ํƒ ์‹œ ์œค๋…„์—๋งŒ ์ผ์ •์„ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค', () => { + // ์ค€๋น„: 2024๋…„ 2์›” 29์ผ๋ถ€ํ„ฐ 2030๋…„ 12์›” 31์ผ๊นŒ์ง€, ๋ฐ˜๋ณต ์œ ํ˜•์€ yearly + const start = new Date('2024-02-29'); + const end = new Date('2030-12-31'); + // ์‹คํ–‰: ๋งค๋…„ 1ํšŒ ๋ฐ˜๋ณต ์ƒ์„ฑ + const events = generateRecurrences({ + start, + end, + type: 'yearly', + interval: 1, + }); + // ๊ฒ€์ฆ: ์œค๋…„(2024, 2028)๋งŒ ํฌํ•จ, ๊ทธ ์™ธ๋Š” ์ƒ์„ฑ ๊ธˆ์ง€ + const dates = events.map((e) => e.date); + expect(dates).toContain('2024-02-29'); + expect(dates).toContain('2028-02-29'); + expect(dates).not.toContain('2025-02-28'); + expect(dates).not.toContain('2026-02-28'); + expect(dates).not.toContain('2027-02-28'); + expect(dates).not.toContain('2029-02-28'); + expect(dates).not.toContain('2030-02-28'); + }); + + it('๋ฐ˜๋ณต ์ผ์ •์ด ๊ธฐ์กด ์ผ์ •๊ณผ ๊ฒน์ณ๋„ ์ƒ์„ฑ๋˜์–ด์•ผ ํ•œ๋‹ค', () => { + // ์ค€๋น„: 2024๋…„ 5์›” 31์ผ๋ถ€ํ„ฐ 7์›” 31์ผ๊นŒ์ง€, ์›”๊ฐ„ ๋ฐ˜๋ณต + const start = new Date('2024-05-31'); + const end = new Date('2024-07-31'); + // ์‹คํ–‰: ๊ธฐ์กด์— 2024-05-31 ์ผ์ •์ด ์ด๋ฏธ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •, ์ค‘๋ณต ํ—ˆ์šฉ + const events = generateRecurrences({ + start, + end, + type: 'monthly', + interval: 1, + }); + // ๊ฒ€์ฆ: 2024-05-31, 2024-07-31 ๋ชจ๋‘ ํฌํ•จ๋˜์–ด์•ผ ํ•จ (์ค‘๋ณต ์ œ์™ธ ๋…ผ๋ฆฌ ์—†์–ด์•ผ ํ•จ) + const dates = events.map((e) => e.date); + expect(dates).toContain('2024-05-31'); + expect(dates).toContain('2024-07-31'); + }); + + // ์ถ”๊ฐ€์ ์ธ ์Œ์ˆ˜/๊ฒฝ๊ณ„ ์‚ฌ๋ก€๋Š” ์ด ํŒจํ„ด์„ ๋”ฐ๋ผ ์ž‘์„ฑ ๊ฐ€๋Šฅ +}); From e4e7021beed2924490718013182dfff8e8d6ef00 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:22:49 +0900 Subject: [PATCH 09/18] =?UTF-8?q?docs:=20=EC=A7=80=EC=B9=A8=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8(=EC=A3=BC=EC=84=9D=C2=B7=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=84=A4=EB=AA=85=20=ED=95=9C=EA=B5=AD?= =?UTF-8?q?=EC=96=B4,=20=EC=82=B0=EC=B6=9C=EB=AC=BC/=EC=BB=A4=EB=B0=8B/PR?= =?UTF-8?q?=20=ED=95=9C=EA=B5=AD=EC=96=B4=20=EC=A0=95=EC=B1=85=20=EB=AA=85?= =?UTF-8?q?=EC=8B=9C)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/agent-rules.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.cursor/rules/agent-rules.md b/.cursor/rules/agent-rules.md index 91c37837..54538cbe 100644 --- a/.cursor/rules/agent-rules.md +++ b/.cursor/rules/agent-rules.md @@ -62,6 +62,11 @@ - Doc: `DOCS/feature-1-RED.md` (`Related Spec: 1`) - Clear mapping between code, docs, and spec for every feature and phase. +## Commit, PR, and Artifact Language Policy +- ๋ชจ๋“  ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ PR ์„ค๋ช…์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. +- ๊ฐ TDD ๋‹จ๊ณ„(RED, GREEN, REFACTOR)๋ณ„๋กœ ์ƒ์„ฑํ•˜๋Š” ์‚ฐ์ถœ๋ฌผ(md ๋ฌธ์„œ ๋“ฑ)๋„ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. +- ์ฝ”๋“œ ์‹๋ณ„์ž(ํ•จ์ˆ˜/๋ณ€์ˆ˜/ํŒŒ์ผ๋ช…)๋Š” ์˜์–ด๋กœ, **์ฃผ์„๊ณผ ํ…Œ์ŠคํŠธ ์„ค๋ช…(it/describe ๋ฉ”์‹œ์ง€)์€ ํ•œ๊ตญ์–ด๋กœ** ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. + ## TDD ๋‹จ๊ณ„๋ณ„ ํ‘œ์ค€ ์‚ฐ์ถœ๋ฌผ ๋ฐ ์—์ด์ „ํŠธ ์ฑ…์ž„ ์ˆœ์„œ ์•„๋ž˜์˜ ํ๋ฆ„(RED, GREEN, REFACTOR ๋ชจ๋‘ ๋™์ผ)์„ ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ฆ„. @@ -78,10 +83,4 @@ 4. ์ปค๋ฐ‹ - Committer Agent๊ฐ€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ(ํ•œ๊ตญ์–ด), ์‚ฐ์ถœ๋ฌผ-์ฝ”๋“œ-์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ-์ปค๋ฐ‹ ๊ฐ„ ๋งค์นญ ์ฑ…์ž„ -> ๋ชจ๋“  ์ฃผ์„/์ฝ”๋“œ/ํ…Œ์ŠคํŠธ๋Š” ์˜์–ด, ์ปค๋ฐ‹/PR/์‚ฐ์ถœ๋ฌผ์€ ํ•œ๊ตญ์–ด ์›์น™์„ ๋ฐ˜๋“œ์‹œ ์ง€ํ‚ด - -## Commit & PR Language Policy - -- ๋ชจ๋“  ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ PR ์„ค๋ช…์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. -- ๊ฐ TDD ๋‹จ๊ณ„(RED, GREEN, REFACTOR)๋ณ„๋กœ ์ƒ์„ฑํ•˜๋Š” ์‚ฐ์ถœ๋ฌผ(md ๋ฌธ์„œ ๋“ฑ)๋„ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. -- ์ฝ”๋“œ/ํ…Œ์ŠคํŠธ/์ฃผ์„ ๋“ฑ์€ ์˜์–ด๋กœ ์ž‘์„ฑํ•˜๋ฉฐ, ์‚ฐ์ถœ๋ฌผ๊ณผ ์‚ฌ์šฉ์ž ์†Œํ†ต(์ปค๋ฐ‹, PR, ๋‹จ๊ณ„ ๋ฌธ์„œ)์€ ํ•œ๊ตญ์–ด๋ฅผ ์›์น™์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. +> ์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด, **์ฃผ์„/ํ…Œ์ŠคํŠธ ์„ค๋ช…/์‚ฐ์ถœ๋ฌผ/์ปค๋ฐ‹/PR์€ ํ•œ๊ตญ์–ด** ์›์น™์„ ๋ฐ˜๋“œ์‹œ ์ง€ํ‚ด From 5e6dd057e557c36e78b61f5f812b1f285857edee Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:25:20 +0900 Subject: [PATCH 10/18] =?UTF-8?q?feat(green):=201.=20=EB=B0=98=EB=B3=B5=20?= =?UTF-8?q?=EC=9C=A0=ED=98=95=20=EC=84=A0=ED=83=9D=20-=2031=EC=9D=BC/2?= =?UTF-8?q?=EC=9B=9429=EC=9D=BC=20=EA=B7=9C=EC=B9=99=20=EC=B5=9C=EC=86=8C?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCS/feature-1-GREEN.md | 58 +++++++++++++++++++++ src/utils/eventUtils.ts | 108 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 DOCS/feature-1-GREEN.md diff --git a/DOCS/feature-1-GREEN.md b/DOCS/feature-1-GREEN.md new file mode 100644 index 00000000..1e69be9e --- /dev/null +++ b/DOCS/feature-1-GREEN.md @@ -0,0 +1,58 @@ +# [GREEN] Feature 1: ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - ์ตœ์†Œ ๊ตฌํ˜„ + +## ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ + +- 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ (recurring type selection) + - 31์ผ ์„ ํƒ ์‹œ: ๋งค์›” 31์ผ์—๋งŒ ์ผ์ • ์ƒ์„ฑ(30/28/29์ผ ๋Œ€์ฒด ๊ธˆ์ง€) + - 2/29 ์„ ํƒ ์‹œ: ์œค๋…„ 2์›” 29์ผ์—๋งŒ ์ผ์ • ์ƒ์„ฑ + - ๋ฐ˜๋ณต ์ผ์ •์€ ๊ฒน์นจ ํ—ˆ์šฉ + +## ๋ชฉ์  + +- RED ๋‹จ๊ณ„์—์„œ ์ž‘์„ฑํ•œ ์‹คํŒจ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผ์‹œํ‚ค๊ธฐ ์œ„ํ•œ **์ตœ์†Œ ๊ตฌํ˜„(GREEN)**์„ ์ ์šฉํ•œ๋‹ค. + +## ๋ณ€๊ฒฝ ํŒŒ์ผ + +- src/utils/eventUtils.ts + - `generateRecurrences(params)` ํ•จ์ˆ˜ ์ถ”๊ฐ€ (์ตœ์†Œ ๊ธฐ๋Šฅ) + +## ๊ตฌํ˜„ ์š”์•ฝ + +- ํƒ€์ž…: `monthly`, `yearly`์— ํ•œํ•ด RED ํ…Œ์ŠคํŠธ๋ฅผ ํ†ต๊ณผ์‹œํ‚ค๋Š” ์ตœ์†Œ ๋กœ์ง๋งŒ ๊ตฌํ˜„ +- ์›”๊ฐ„(monthly) + - ์‹œ์ž‘์ผ์ด 31์ผ์ด๋ฉด 31์ผ์ด ์กด์žฌํ•˜๋Š” ๋‹ฌ(1,3,5,7,8,10,12)์—๋งŒ ์ƒ์„ฑ + - interval ๊ฐ„๊ฒฉ์œผ๋กœ ์›”์„ ์ „์ง„ํ•จ +- ์—ฐ๊ฐ„(yearly) + - ์‹œ์ž‘์ผ์ด 2/29์ด๋ฉด ์œค๋…„์—๋งŒ ์ƒ์„ฑ(๋Œ€์ฒด ๊ธˆ์ง€) + - interval ๊ฐ„๊ฒฉ์œผ๋กœ ์—ฐ๋„๋ฅผ ์ „์ง„ํ•จ +- ์ข…๋ฃŒ ๋ฒ”์œ„: `end` ๋‚ ์งœ๋ฅผ ์ดˆ๊ณผํ•˜์ง€ ์•Š๋„๋ก ์ƒ์„ฑ ์ œํ•œ +- ๊ฒน์นจ ์ฒ˜๋ฆฌ: ๋ณ„๋„ ์ค‘๋ณต ์ œ๊ฑฐ ๋กœ์ง ์—†์Œ(์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ํ—ˆ์šฉ) + +## ๊ฒฐ์ •์„ฑ/๋ฒ”์œ„ + +- ํ˜„์žฌ ํ…Œ์ŠคํŠธ๊ฐ€ ์š”๊ตฌํ•˜๋Š” ์ตœ์†Œ ๊ทœ์น™(31์ผ, 2/29, ๊ฒน์นจ ํ—ˆ์šฉ)๋งŒ ์ถฉ์กฑ +- ๊ธฐํƒ€ ์ผ๋ฐ˜ ์ผ€์ด์Šค(์˜ˆ: 30์ผ ์‹œ์ž‘, ์ฃผ๊ฐ„/์ผ๊ฐ„ ๋“ฑ)๋Š” ํ›„์† ์š”๊ตฌ/ํ…Œ์ŠคํŠธ์—์„œ ํ™•์žฅ + +## ํ•œ๊ณ„ ๋ฐ ๋ฆฌํŒฉํ† ๋ง ํ›„๋ณด(์ฐจํ›„ REFACTOR ๋‹จ๊ณ„) + +- ๊ทœ์น™ ๋ถ„๋ฆฌ: 31์ผ ๊ทœ์น™, ์œค๋…„ ๊ทœ์น™ ๋“ฑ ์ˆœ์ˆ˜ ํ•จ์ˆ˜ ์ถ”์ถœ +- ์ธํ„ฐํŽ˜์ด์Šค ๊ฐœ์„ : clock ์ฃผ์ž…/์ตœ๋Œ€ ์ข…๋ฃŒ์ผ(2025-12-31) ์ƒํ•œ ์ ์šฉ ์œ„์น˜ ๋ช…ํ™•ํ™” +- ๋ฐ˜๋ณต ํƒ€์ž… ์ „๋ฐ˜(Weekly/Daily) ์ผ๋ฐ˜ํ™” ๋ฐ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€ ๋Œ€์‘ + +## ๊ฒ€์ฆ ์ฒดํฌ๋ฆฌ์ŠคํŠธ + +- [ ] RED ํ…Œ์ŠคํŠธ 3๊ฑด ์ „๋ถ€ ํ†ต๊ณผ +- [ ] ์›” 31์ผ: 31์ผ ์žˆ๋Š” ๋‹ฌ๋งŒ ํฌํ•จ +- [ ] ์—ฐ 2/29: ์œค๋…„๋งŒ ํฌํ•จ, ๋Œ€์ฒด ๊ธˆ์ง€ +- [ ] ์ข…๋ฃŒ์ผ ๊ฒฝ๊ณ„ ์ดˆ๊ณผ ์ƒ์„ฑ ์—†์Œ +- [ ] ๊ฒน์นจ ํ—ˆ์šฉ ๋กœ์ง ์œ ์ง€(์ค‘๋ณต ์ œ๊ฑฐ ์—†์Œ) + +## ์ฐจํ›„ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์˜ˆ์‹œ + +- feat(green): 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - 31์ผ/2์›”29์ผ ๊ทœ์น™ ์ตœ์†Œ ๊ตฌํ˜„ + +## ํŒŒ์ผ/์ปค๋ฐ‹/์š”๊ตฌ์‚ฌํ•ญ ๋งคํ•‘ + +- ๋ฌธ์„œ: DOCS/feature-1-GREEN.md +- ์ฝ”๋“œ: src/utils/eventUtils.ts (`generateRecurrences`) +- ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ: 1 diff --git a/src/utils/eventUtils.ts b/src/utils/eventUtils.ts index 9e75e947..4fdf47ae 100644 --- a/src/utils/eventUtils.ts +++ b/src/utils/eventUtils.ts @@ -56,3 +56,111 @@ export function getFilteredEvents( return searchedEvents; } + +// ---- ๋ฐ˜๋ณต ์ผ์ • ์ƒ์„ฑ (ํ…Œ์ŠคํŠธ ํ†ต๊ณผ๋ฅผ ์œ„ํ•œ ์ตœ์†Œ ๊ตฌํ˜„) ---- + +type RecurrenceType = 'daily' | 'weekly' | 'monthly' | 'yearly'; + +interface GenerateRecurrencesParams { + start: Date; + end: Date; + type: RecurrenceType; + interval: number; +} + +function formatDate(date: Date): string { + const y = date.getFullYear(); + const m = String(date.getMonth() + 1).padStart(2, '0'); + const d = String(date.getDate()).padStart(2, '0'); + return `${y}-${m}-${d}`; +} + +function isLeapYear(year: number): boolean { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; +} + +export function generateRecurrences({ + start, + end, + type, + interval, +}: GenerateRecurrencesParams): { date: string }[] { + const results: { date: string }[] = []; + const endTime = end.getTime(); + + if (type === 'monthly') { + // ์›”๊ฐ„ ๊ทœ์น™(์ตœ์†Œ ๊ตฌํ˜„): ์‹œ์ž‘์ผ์ด 31์ผ์ธ ๊ฒฝ์šฐ, 31์ผ์ด ์กด์žฌํ•˜๋Š” ๋‹ฌ(1,3,5,7,8,10,12)์—๋งŒ ์ƒ์„ฑ + const startDay = start.getDate(); + let y = start.getFullYear(); + let m = start.getMonth(); + + while (true) { + const lastDayOfMonth = new Date(y, m + 1, 0).getDate(); + if (startDay === 31) { + if (lastDayOfMonth === 31) { + const candidate = new Date(y, m, 31); + if (candidate.getTime() > endTime) break; + if (candidate.getTime() >= start.getTime()) { + results.push({ date: formatDate(candidate) }); + } + } + } else { + // ํ˜„์žฌ RED ํ…Œ์ŠคํŠธ๋Š” 31์ผ ์ผ€์ด์Šค๋งŒ ์š”๊ตฌ. ๊ทธ ์™ธ๋Š” ์ถ”ํ›„ ํ™•์žฅ + const candidate = new Date(y, m, startDay); + if (candidate.getTime() > endTime) break; + if (candidate.getDate() === startDay && candidate.getTime() >= start.getTime()) { + results.push({ date: formatDate(candidate) }); + } + } + + // interval ๋‹จ์œ„๋กœ ์›” ์ด๋™ + m += interval; + while (m >= 12) { + m -= 12; + y += 1; + } + + // ๋‹ค์Œ ๋ฃจํ”„๊ฐ€ ์ข…๋ฃŒ์ผ์„ ์ดˆ๊ณผํ•˜๋Š”์ง€ ์‚ฌ์ „ ํ™•์ธ + const probe = new Date(y, m, 1); + if (probe.getTime() > endTime) break; + } + + return results; + } + + if (type === 'yearly') { + // ์—ฐ๊ฐ„ ๊ทœ์น™(์ตœ์†Œ ๊ตฌํ˜„): 2/29 ์‹œ์ž‘ ์‹œ ์œค๋…„์—๋งŒ ์ƒ์„ฑ(๋Œ€์ฒด ๊ธˆ์ง€) + const startMonth = start.getMonth(); + const startDay = start.getDate(); + let y = start.getFullYear(); + + while (true) { + if (startMonth === 1 && startDay === 29) { + if (isLeapYear(y)) { + const candidate = new Date(y, 1, 29); + if (candidate.getTime() > endTime) break; + if (candidate.getTime() >= start.getTime()) { + results.push({ date: formatDate(candidate) }); + } + } + } else { + // ํ˜„์žฌ RED ํ…Œ์ŠคํŠธ๋Š” 2/29 ์ผ€์ด์Šค๋งŒ ์š”๊ตฌ. ๊ทธ ์™ธ๋Š” ์ถ”ํ›„ ํ™•์žฅ + const candidate = new Date(y, startMonth, startDay); + if (candidate.getTime() > endTime) break; + if (candidate.getTime() >= start.getTime()) { + results.push({ date: formatDate(candidate) }); + } + } + + // interval ๋‹จ์œ„๋กœ ์—ฐ๋„ ์ด๋™ + y += interval; + const probe = new Date(y, startMonth, 1); + if (probe.getTime() > endTime) break; + } + + return results; + } + + // ํ˜„์žฌ ํ…Œ์ŠคํŠธ ๋ฒ”์œ„ ์™ธ ํƒ€์ž…์€ ์ƒ์„ฑํ•˜์ง€ ์•Š์Œ + return results; +} From 0e6b833125b4b74cf882a7bb217f819cddd1057f Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:28:32 +0900 Subject: [PATCH 11/18] =?UTF-8?q?refactor:=201.=20=EB=B0=98=EB=B3=B5=20?= =?UTF-8?q?=EC=9C=A0=ED=98=95=20=EC=84=A0=ED=83=9D=20-=2031=EC=9D=BC/?= =?UTF-8?q?=EC=9C=A4=EB=85=84=20=EA=B7=9C=EC=B9=99=20=EB=B6=84=EB=A6=AC=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B5=AC=EC=A1=B0=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCS/feature-1-REFACTOR.md | 45 +++++++++++++++++++++++++++++++++ src/utils/eventUtils.ts | 52 ++++++++++++++++---------------------- 2 files changed, 67 insertions(+), 30 deletions(-) create mode 100644 DOCS/feature-1-REFACTOR.md diff --git a/DOCS/feature-1-REFACTOR.md b/DOCS/feature-1-REFACTOR.md new file mode 100644 index 00000000..e1e9e3fd --- /dev/null +++ b/DOCS/feature-1-REFACTOR.md @@ -0,0 +1,45 @@ +# [REFACTOR] Feature 1: ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - ๊ตฌ์กฐ ๊ฐœ์„  + +## ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ +- 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ (recurring type selection) + - 31์ผ ์„ ํƒ ์‹œ: ๋งค์›” 31์ผ์—๋งŒ ์ผ์ • ์ƒ์„ฑ(๋Œ€์ฒด ๊ธˆ์ง€) + - 2/29 ์„ ํƒ ์‹œ: ์œค๋…„์—๋งŒ ์ƒ์„ฑ(๋Œ€์ฒด ๊ธˆ์ง€) + - ๋ฐ˜๋ณต ์ผ์ •์€ ๊ฒน์นจ ํ—ˆ์šฉ + +## ๋ชฉ์  +- GREEN ๋‹จ๊ณ„์—์„œ ํ†ต๊ณผํ•œ ๋™์ž‘์„ ์œ ์ง€ํ•˜๋ฉด์„œ, ์ฝ”๋“œ ๊ฐ€๋…์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ ํ–ฅ์ƒ +- ๊ทœ์น™(31์ผ, ์œค๋…„) ๋ถ„๋ฆฌ๋กœ ์ถ”ํ›„ ๊ธฐ๋Šฅ ํ™•์žฅ(์ฃผ๊ฐ„/์ผ๊ฐ„, ์ข…๋ฃŒ ์ƒํ•œ ๋“ฑ)์— ๋Œ€๋น„ + +## ๋ณ€๊ฒฝ ํŒŒ์ผ +- src/utils/eventUtils.ts + - ์ˆœ์ˆ˜ ํ•จ์ˆ˜ ๋ถ„๋ฆฌ: `has31stDay(year, month)`, `isLeapYear(year)`, `formatDate(date)` + - `generateRecurrences` ๋‚ด๋ถ€ ํ๋ฆ„ ๊ฐ„์†Œํ™”(์กฐ๊ฑด ๋ถ„๊ธฐ/๋ฃจํ”„ ๊ฐ€๋…์„ฑ ๊ฐœ์„ ) + - ๋ชจ๋“  ์ฃผ์„ ํ•œ๊ตญ์–ด ์œ ์ง€, ์‹๋ณ„์ž ์˜์–ด + +## ๋ฆฌํŒฉํ† ๋ง ์š”์•ฝ +- 31์ผ ๊ทœ์น™: ์›” 31์ผ ์กด์žฌ ์—ฌ๋ถ€๋ฅผ `has31stDay`๋กœ ์บก์Аํ™” +- ์œค๋…„ ๊ทœ์น™: `isLeapYear`๋กœ ํŒ๋ณ„ ๋กœ์ง ๋ถ„๋ฆฌ +- ๋‚ ์งœ ๋ฌธ์ž์—ด ๋ณ€ํ™˜: `formatDate`๋กœ ํ†ต์ผ +- `generateRecurrences`๋Š” ์›”/์—ฐ ๋กœ์ง์„ ๊ฐ„๊ฒฐํ•œ ๋ฃจํ”„์™€ ๋ถ„๊ธฐ๋งŒ ๋‚จ๊ธฐ๋„๋ก ์ •๋ฆฌ + +## ์ „ํ›„ ๋น„๊ต(ํ•˜์ด๋ผ์ดํŠธ) +- Before: `generateRecurrences` ๋‚ด๋ถ€์—์„œ ๋ง๋‹จ ๋กœ์ง/๋ถ„๊ธฐ ํ˜ผ์žฌ โ†’ ๊ฐ€๋…์„ฑ ๋‚ฎ์Œ +- After: ๊ทœ์น™/ํฌ๋งทํ„ฐ ํ•จ์ˆ˜ ๋ถ„๋ฆฌ, ๋ฃจํ”„ ์ „๊ฐœ ๊ฐ„๊ฒฐํ™” โ†’ ์ฝ๊ธฐ ์‰ฌ์›€, ํ…Œ์ŠคํŠธ ์œ ์ง€๋จ +- ๋™์ž‘ ๋ณ€ํ™” ์—†์Œ(RED/GREEN ํ…Œ์ŠคํŠธ ๋™์ผ ํ†ต๊ณผ) + +## ๊ฒ€์ฆ ์ฒดํฌ๋ฆฌ์ŠคํŠธ +- [ ] ๊ธฐ์กด ํ…Œ์ŠคํŠธ ๋ชจ๋‘ GREEN ์œ ์ง€ +- [ ] ํ•จ์ˆ˜ ๋ถ„๋ฆฌ๋กœ ๋กœ์ง ์ค‘๋ณต/๋…ธ์ด์ฆˆ ๊ฐ์†Œ ํ™•์ธ +- [ ] ์ฃผ์„/์‹๋ณ„์ž ์–ธ์–ด ์ •์ฑ… ์ค€์ˆ˜(์ฃผ์„ ํ•œ๊ตญ์–ด, ์‹๋ณ„์ž ์˜์–ด) + +## ์ฐจํ›„ ํ™•์žฅ ์•„์ด๋””์–ด(์ฐธ๊ณ ) +- Weekly/Daily ๊ทœ์น™ ์ถ”๊ฐ€ ์‹œ ๋™์ผํ•œ ํŒจํ„ด์œผ๋กœ ์ˆœ์ˆ˜ ํ•จ์ˆ˜ ๋ถ„๋ฆฌ +- ์ข…๋ฃŒ ์ƒํ•œ(2025-12-31) ํด๋žจํ•‘ ๋กœ์ง์„ ๊ณตํ†ตํ™” + +## ์ฐจํ›„ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์˜ˆ์‹œ +- refactor: 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - 31์ผ/์œค๋…„ ๊ทœ์น™ ๋ถ„๋ฆฌ ๋ฐ ๊ตฌ์กฐ ๊ฐœ์„  + +## ํŒŒ์ผ/์ปค๋ฐ‹/์š”๊ตฌ์‚ฌํ•ญ ๋งคํ•‘ +- ๋ฌธ์„œ: DOCS/feature-1-REFACTOR.md +- ์ฝ”๋“œ: src/utils/eventUtils.ts +- ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ: 1 diff --git a/src/utils/eventUtils.ts b/src/utils/eventUtils.ts index 4fdf47ae..3bd46ba0 100644 --- a/src/utils/eventUtils.ts +++ b/src/utils/eventUtils.ts @@ -68,6 +68,17 @@ interface GenerateRecurrencesParams { interval: number; } +// ์›”์— 31์ผ์ด ์žˆ๋Š”์ง€ ํŒ๋ณ„ +function has31stDay(year: number, month: number): boolean { + return new Date(year, month + 1, 0).getDate() === 31; +} + +// ํ•ด๋‹น ์—ฐ๋„๊ฐ€ ์œค๋…„์ธ์ง€ ํŒ๋ณ„ +function isLeapYear(year: number): boolean { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; +} + +// ๋‚ ์งœ YYYY-MM-DD ํ˜•์‹ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ function formatDate(date: Date): string { const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, '0'); @@ -75,10 +86,6 @@ function formatDate(date: Date): string { return `${y}-${m}-${d}`; } -function isLeapYear(year: number): boolean { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; -} - export function generateRecurrences({ start, end, @@ -87,17 +94,15 @@ export function generateRecurrences({ }: GenerateRecurrencesParams): { date: string }[] { const results: { date: string }[] = []; const endTime = end.getTime(); + const startDay = start.getDate(); + let y = start.getFullYear(); + let m = start.getMonth(); if (type === 'monthly') { - // ์›”๊ฐ„ ๊ทœ์น™(์ตœ์†Œ ๊ตฌํ˜„): ์‹œ์ž‘์ผ์ด 31์ผ์ธ ๊ฒฝ์šฐ, 31์ผ์ด ์กด์žฌํ•˜๋Š” ๋‹ฌ(1,3,5,7,8,10,12)์—๋งŒ ์ƒ์„ฑ - const startDay = start.getDate(); - let y = start.getFullYear(); - let m = start.getMonth(); - + // 31์ผ ์ „์šฉ: 31์ผ์ด ์žˆ๋Š” ๋‹ฌ์—๋งŒ while (true) { - const lastDayOfMonth = new Date(y, m + 1, 0).getDate(); if (startDay === 31) { - if (lastDayOfMonth === 31) { + if (has31stDay(y, m)) { const candidate = new Date(y, m, 31); if (candidate.getTime() > endTime) break; if (candidate.getTime() >= start.getTime()) { @@ -105,35 +110,27 @@ export function generateRecurrences({ } } } else { - // ํ˜„์žฌ RED ํ…Œ์ŠคํŠธ๋Š” 31์ผ ์ผ€์ด์Šค๋งŒ ์š”๊ตฌ. ๊ทธ ์™ธ๋Š” ์ถ”ํ›„ ํ™•์žฅ + // ์ผ๋ฐ˜ ๊ทœ์น™(ํ›„์† ํ™•์žฅ) const candidate = new Date(y, m, startDay); if (candidate.getTime() > endTime) break; if (candidate.getDate() === startDay && candidate.getTime() >= start.getTime()) { results.push({ date: formatDate(candidate) }); } } - - // interval ๋‹จ์œ„๋กœ ์›” ์ด๋™ + // ์›”, ์—ฐ๋„ ์ฆ๊ฐ€ m += interval; while (m >= 12) { m -= 12; y += 1; } - - // ๋‹ค์Œ ๋ฃจํ”„๊ฐ€ ์ข…๋ฃŒ์ผ์„ ์ดˆ๊ณผํ•˜๋Š”์ง€ ์‚ฌ์ „ ํ™•์ธ - const probe = new Date(y, m, 1); - if (probe.getTime() > endTime) break; + if (new Date(y, m, 1).getTime() > endTime) break; } - return results; } if (type === 'yearly') { - // ์—ฐ๊ฐ„ ๊ทœ์น™(์ตœ์†Œ ๊ตฌํ˜„): 2/29 ์‹œ์ž‘ ์‹œ ์œค๋…„์—๋งŒ ์ƒ์„ฑ(๋Œ€์ฒด ๊ธˆ์ง€) + // 2/29 ์ „์šฉ: ์œค๋…„์—๋งŒ const startMonth = start.getMonth(); - const startDay = start.getDate(); - let y = start.getFullYear(); - while (true) { if (startMonth === 1 && startDay === 29) { if (isLeapYear(y)) { @@ -144,23 +141,18 @@ export function generateRecurrences({ } } } else { - // ํ˜„์žฌ RED ํ…Œ์ŠคํŠธ๋Š” 2/29 ์ผ€์ด์Šค๋งŒ ์š”๊ตฌ. ๊ทธ ์™ธ๋Š” ์ถ”ํ›„ ํ™•์žฅ const candidate = new Date(y, startMonth, startDay); if (candidate.getTime() > endTime) break; if (candidate.getTime() >= start.getTime()) { results.push({ date: formatDate(candidate) }); } } - - // interval ๋‹จ์œ„๋กœ ์—ฐ๋„ ์ด๋™ y += interval; - const probe = new Date(y, startMonth, 1); - if (probe.getTime() > endTime) break; + if (new Date(y, startMonth, 1).getTime() > endTime) break; } - return results; } - // ํ˜„์žฌ ํ…Œ์ŠคํŠธ ๋ฒ”์œ„ ์™ธ ํƒ€์ž…์€ ์ƒ์„ฑํ•˜์ง€ ์•Š์Œ + // ๊ทธ ์™ธ: ํ…Œ์ŠคํŠธ ์š”๊ตฌ ํƒ€์ž… ์™ธ์—” ๋ฐ˜ํ™˜ ์—†์Œ return results; } From 882326ee4d2fc94642feefe89d3d14d1b7d219e9 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:36:49 +0900 Subject: [PATCH 12/18] =?UTF-8?q?docs:=20=EB=8B=A8=EA=B3=84=EC=A0=81=20?= =?UTF-8?q?=EC=A7=84=ED=96=89=20=EA=B7=9C=EC=B9=99=20=EC=B6=94=EA=B0=80(?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=20TDD=20=ED=9B=84=20=ED=86=B5=ED=95=A9=20TDD?= =?UTF-8?q?=20=EC=82=AC=EC=9D=B4=ED=81=B4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/agent-rules.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.cursor/rules/agent-rules.md b/.cursor/rules/agent-rules.md index 54538cbe..d011b83b 100644 --- a/.cursor/rules/agent-rules.md +++ b/.cursor/rules/agent-rules.md @@ -84,3 +84,12 @@ - Committer Agent๊ฐ€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ(ํ•œ๊ตญ์–ด), ์‚ฐ์ถœ๋ฌผ-์ฝ”๋“œ-์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ-์ปค๋ฐ‹ ๊ฐ„ ๋งค์นญ ์ฑ…์ž„ > ์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด, **์ฃผ์„/ํ…Œ์ŠคํŠธ ์„ค๋ช…/์‚ฐ์ถœ๋ฌผ/์ปค๋ฐ‹/PR์€ ํ•œ๊ตญ์–ด** ์›์น™์„ ๋ฐ˜๋“œ์‹œ ์ง€ํ‚ด + +## ๋‹จ๊ณ„์  ์ง„ํ–‰ ๊ทœ์น™(๋‹จ์œ„ โ†’ ํ†ตํ•ฉ) +- ๋จผ์ € ๋‹จ์œ„ ์ˆ˜์ค€์—์„œ TDD ์‚ฌ์ดํด์„ ์™„๋ฃŒํ•œ๋‹ค: **RED โ†’ GREEN โ†’ REFACTOR(๋‹จ์œ„)** +- ๋‹จ์œ„ GREEN์ด ์•ˆ์ •ํ™”๋˜๋ฉด, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค: + - **RED(ํ†ตํ•ฉ)**: ์‹คํŒจํ•˜๋Š” ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€ + - **GREEN(ํ†ตํ•ฉ)**: ์‹ค์ œ UI/ํ›…/์ƒํƒœ ์—ฐ๋™ ์ตœ์†Œ ๊ตฌํ˜„ + - **REFACTOR(ํ†ตํ•ฉ)**: ์ „์ฒด ๊ตฌ์กฐ ๊ฐœ์„ (์—ญํ•  ๋ถ„๋ฆฌ/๊ฐ€๋…์„ฑ/์ค‘๋ณต ์ œ๊ฑฐ) +- ๊ฐ ๋‹จ๊ณ„๋งˆ๋‹ค ์‚ฐ์ถœ๋ฌผ(ํ•œ๊ตญ์–ด ๋ฌธ์„œ) ์ž‘์„ฑ โ†’ ๊ฒ€ํ†  โ†’ ํ•œ๊ตญ์–ด ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋กœ ๊ธฐ๋ก +- ๋‹ค์Œ ๊ธฐ๋Šฅ์œผ๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ๋„ ๋™์ผํ•œ ์ ˆ์ฐจ๋ฅผ ๋ฐ˜๋ณต ์ ์šฉํ•œ๋‹ค From 9c53c061046318cd6ddc65ee58d5626baeaa3558 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:40:25 +0900 Subject: [PATCH 13/18] =?UTF-8?q?test(red):=201.i=20=EB=B0=98=EB=B3=B5=20?= =?UTF-8?q?=EC=9C=A0=ED=98=95=20=EC=84=A0=ED=83=9D=20-=20UI=20=EC=85=80?= =?UTF-8?q?=EB=A0=89=ED=84=B0=20=EB=B0=8F=20=EC=98=B5=EC=85=98=20=EB=85=B8?= =?UTF-8?q?=EC=B6=9C=20=ED=86=B5=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCS/feature-1-INT-RED.md | 29 +++++++++++++++++++++++ src/__tests__/medium.integration.spec.tsx | 21 ++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 DOCS/feature-1-INT-RED.md diff --git a/DOCS/feature-1-INT-RED.md b/DOCS/feature-1-INT-RED.md new file mode 100644 index 00000000..90509978 --- /dev/null +++ b/DOCS/feature-1-INT-RED.md @@ -0,0 +1,29 @@ +# [RED-ํ†ตํ•ฉ] Feature 1: ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - UI ์…€๋ ‰ํ„ฐ ๋…ธ์ถœ ๋ฐ ์˜ต์…˜ ๊ฒ€์ฆ + +## ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ +- 1. ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ (recurring type selection) + - ํผ์—์„œ ๋ฐ˜๋ณต ์œ ํ˜•(๋งค์ผ/๋งค์ฃผ/๋งค์›”/๋งค๋…„)์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ + +## ๋ชฉ์  +- ์‹ค์ œ UI ์ƒ์—์„œ โ€œ๋ฐ˜๋ณต ์œ ํ˜•โ€ ์…€๋ ‰ํ„ฐ๊ฐ€ ๋…ธ์ถœ๋˜๊ณ , 4๊ฐ€์ง€ ์˜ต์…˜(๋งค์ผ/๋งค์ฃผ/๋งค์›”/๋งค๋…„)์„ ์ œ๊ณตํ•˜๋Š”์ง€ ํ†ตํ•ฉ ๊ด€์ ์—์„œ ์‹คํŒจ ํ…Œ์ŠคํŠธ(RED)๋ฅผ ์ž‘์„ฑํ•œ๋‹ค. + +## ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค ์š”์•ฝ +1) ์ผ์ • ์ถ”๊ฐ€ ๋ฒ„ํŠผ ํด๋ฆญ โ†’ ํผ ์˜คํ”ˆ +2) ๋ผ๋ฒจ์ด `๋ฐ˜๋ณต ์œ ํ˜•`์ธ ์…€๋ ‰ํ„ฐ์˜ ์ฝค๋ณด๋ฐ•์Šค๋ฅผ ์—ฐ๋‹ค +3) ์˜ต์…˜: `daily-option`, `weekly-option`, `monthly-option`, `yearly-option`์ด DOM์— ๋…ธ์ถœ๋˜๋Š”์ง€ ํ™•์ธ + +## ๊ฒ€์ฆ ํฌ์ธํŠธ +- ๋ผ๋ฒจ ์ ‘๊ทผ์„ฑ(๋ผ๋ฒจ ํ…์ŠคํŠธ `๋ฐ˜๋ณต ์œ ํ˜•`) +- ์ฝค๋ณด๋ฐ•์Šค ์—ญํ•  ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ๋กœ ์—ด ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ +- 4๊ฐ€์ง€ ์˜ต์…˜์ด ์ •ํ™•ํžˆ ๋…ธ์ถœ๋˜์–ด์•ผ ํ•จ + +## ๋ณ€๊ฒฝ ํŒŒ์ผ(RED) +- ํ…Œ์ŠคํŠธ: `src/__tests__/medium.integration.spec.tsx` + +## ์ฐจํ›„ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์˜ˆ์‹œ +- `test(red): 1.i ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ - UI ์…€๋ ‰ํ„ฐ ๋ฐ ์˜ต์…˜ ๋…ธ์ถœ ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€` + +## ํŒŒ์ผ/์ปค๋ฐ‹/์š”๊ตฌ์‚ฌํ•ญ ๋งคํ•‘ +- ๋ฌธ์„œ: `DOCS/feature-1-INT-RED.md` +- ํ…Œ์ŠคํŠธ: `src/__tests__/medium.integration.spec.tsx` +- ๊ด€๋ จ ์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ: 1 (UI ๊ด€์ ) diff --git a/src/__tests__/medium.integration.spec.tsx b/src/__tests__/medium.integration.spec.tsx index 788dae14..3a63e365 100644 --- a/src/__tests__/medium.integration.spec.tsx +++ b/src/__tests__/medium.integration.spec.tsx @@ -340,3 +340,24 @@ it('notificationTime์„ 10์œผ๋กœ ํ•˜๋ฉด ์ง€์ • ์‹œ๊ฐ„ 10๋ถ„ ์ „ ์•Œ๋žŒ ํ…์ŠคํŠธ expect(screen.getByText('10๋ถ„ ํ›„ ๊ธฐ์กด ํšŒ์˜ ์ผ์ •์ด ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค.')).toBeInTheDocument(); }); + +// ๋ฐ˜๋ณต ์ผ์ • ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (RED) + +describe('๋ฐ˜๋ณต ์ผ์ • ํ†ตํ•ฉ - ๋ฐ˜๋ณต ์œ ํ˜• ์„ ํƒ UI', () => { + it('์ผ์ • ์ถ”๊ฐ€ ํผ์—์„œ ๋ฐ˜๋ณต ์œ ํ˜• ์…€๋ ‰ํ„ฐ๊ฐ€ ๋…ธ์ถœ๋˜๊ณ  ์˜ต์…˜(๋งค์ผ/๋งค์ฃผ/๋งค์›”/๋งค๋…„)์„ ์ œ๊ณตํ•œ๋‹ค', async () => { + const { user } = setup(); + + // ์ผ์ • ์ถ”๊ฐ€ ๋ฒ„ํŠผ ํด๋ฆญํ•˜์—ฌ ํผ ์˜คํ”ˆ + await user.click(screen.getAllByText('์ผ์ • ์ถ”๊ฐ€')[0]); + + // ๋ฐ˜๋ณต ์œ ํ˜• ์…€๋ ‰ํ„ฐ ์กด์žฌ ์—ฌ๋ถ€ ํ™•์ธ (๋ผ๋ฒจ/์—ญํ•  ๊ธฐ์ค€) + const selectorLabel = screen.getByLabelText('๋ฐ˜๋ณต ์œ ํ˜•'); // ๊ธฐ๋Œ€ ๋ผ๋ฒจ๋ช… + await user.click(within(selectorLabel).getByRole('combobox')); + + // ์˜ต์…˜๋“ค์ด ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธ (์ด๋ฆ„ ๊ทœ์น™์€ ์˜ˆ์‹œ์ด๋ฉฐ ๊ตฌํ˜„ ์‹œ ์ผ์น˜ ํ•„์š”) + expect(screen.getByRole('option', { name: 'daily-option' })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: 'weekly-option' })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: 'monthly-option' })).toBeInTheDocument(); + expect(screen.getByRole('option', { name: 'yearly-option' })).toBeInTheDocument(); + }); +}); From fb2b3a818e9517488b251d43dd863230648a0abc Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Thu, 30 Oct 2025 22:53:04 +0900 Subject: [PATCH 14/18] =?UTF-8?q?fix(int-green):=201.i=20=EB=B0=98?= =?UTF-8?q?=EB=B3=B5=20=EC=9C=A0=ED=98=95=20=EC=84=A0=ED=83=9D=20-=20?= =?UTF-8?q?=EC=85=80=EB=A0=89=ED=84=B0=20=EB=9D=BC=EB=B2=A8=20=EA=B5=AC?= =?UTF-8?q?=EC=A1=B0=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=EC=99=80=20?= =?UTF-8?q?=EB=8F=99=EC=9D=BC=ED=95=98=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 195c5b05..36ffcee5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -36,7 +36,7 @@ import { useEventOperations } from './hooks/useEventOperations.ts'; import { useNotifications } from './hooks/useNotifications.ts'; import { useSearch } from './hooks/useSearch.ts'; // import { Event, EventForm, RepeatType } from './types'; -import { Event, EventForm } from './types'; +import { Event, EventForm, RepeatType } from './types'; import { formatDate, formatMonth, @@ -77,7 +77,7 @@ function App() { isRepeating, setIsRepeating, repeatType, - // setRepeatType, + setRepeatType, repeatInterval, // setRepeatInterval, repeatEndDate, @@ -421,6 +421,31 @@ function App() { /> + {/* ๋ฐ˜๋ณต ์œ ํ˜• ์…€๋ ‰ํ„ฐ(ํ•ญ์ƒ ๋…ธ์ถœ, ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ์ตœ์†Œ ๊ตฌํ˜„) */} + + ๋ฐ˜๋ณต ์œ ํ˜• + + + ์•Œ๋ฆผ ์„ค์ • setRepeatType(e.target.value as RepeatType)} - aria-labelledby="repeat-type-label" - aria-label="๋ฐ˜๋ณต ์œ ํ˜•" - > - - ๋งค์ผ - - - ๋งค์ฃผ - - - ๋งค์›” - - - ๋งค๋…„ - - - + {/* ๋ฐ˜๋ณต ์œ ํ˜• ์…€๋ ‰ํ„ฐ ์ถ”์ถœํ•œ ์ปดํฌ๋„ŒํŠธ๋กœ ๋Œ€์ฒด */} + ์•Œ๋ฆผ ์„ค์ • diff --git a/src/components/RepeatTypeSelector.tsx b/src/components/RepeatTypeSelector.tsx new file mode 100644 index 00000000..5b9d8874 --- /dev/null +++ b/src/components/RepeatTypeSelector.tsx @@ -0,0 +1,40 @@ +import { FormControl, FormLabel, MenuItem, Select } from '@mui/material'; +import { RepeatType } from '../types'; + +interface RepeatTypeSelectorProps { + value: RepeatType; + onChange: (v: RepeatType) => void; +} + +/** + * ๋ฐ˜๋ณต ์œ ํ˜•(๋งค์ผ/๋งค์ฃผ/๋งค์›”/๋งค๋…„) ์„ ํƒ ์ปดํฌ๋„ŒํŠธ + * - ๋ผ๋ฒจ, ์—ญํ• /aria-label ์ ‘๊ทผ์„ฑ ์—ฐ๊ฒฐ + * - ํ…Œ์ŠคํŠธ ๋ฐ ์ ‘๊ทผ์„ฑ ์ผ๊ด€์„ฑ ๋ณด์žฅ(์˜ต์…˜ aria-label: *-option) + */ +export default function RepeatTypeSelector({ value, onChange }: RepeatTypeSelectorProps) { + return ( + + ๋ฐ˜๋ณต ์œ ํ˜• + + + ); +} From ce3a5972036c1716c87d65f7378cb63774e68425 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Fri, 31 Oct 2025 00:35:47 +0900 Subject: [PATCH 16/18] chore(rules): update agent guidelines to English-only and add Feature 2 TDD guidance\n\n- Unify language to English across agent docs\n- Correct rule references and cite recurring spec\n- Add explicit guidance for Feature 2 (recurring icon & detach)\n- Clarify test placement and minimal implementation touchpoints --- .cursor/agent/committer.md | 9 +- .cursor/agent/minimal-implementer.md | 15 ++-- .cursor/agent/orchestrator.md | 16 ++-- .cursor/agent/refactorer.md | 8 +- .cursor/agent/reviewer.md | 12 +-- .cursor/agent/spec-agent.md | 10 +-- .cursor/agent/test-author.md | 22 ++--- .cursor/rules/agent-rules.md | 129 ++++++++++++--------------- 8 files changed, 106 insertions(+), 115 deletions(-) diff --git a/.cursor/agent/committer.md b/.cursor/agent/committer.md index 7cdf1a04..36cb775f 100644 --- a/.cursor/agent/committer.md +++ b/.cursor/agent/committer.md @@ -1,4 +1,4 @@ -# Committer Agent +# Committer Agent (English Only) Mission: Produce clean, stage-specific commits with clear messages. @@ -12,13 +12,12 @@ Rules: - Commit only relevant files per stage. - Keep messages actionable and scoped to one behavior. +- Write commit subjects and bodies in English. Example Messages: - `test(red): monthly 31st occurs only on the 31st` - `feat(green): implement 31st-only monthly recurrence rule` +- `test(red): recurring icon displays for recurring events only` +- `feat(green): show RecurringIcon for events with isRecurring true` - `refactor: extract recurrence generator and clarify names` - - - - diff --git a/.cursor/agent/minimal-implementer.md b/.cursor/agent/minimal-implementer.md index b760cf77..86922b20 100644 --- a/.cursor/agent/minimal-implementer.md +++ b/.cursor/agent/minimal-implementer.md @@ -1,4 +1,4 @@ -# Minimal Implementer Agent +# Minimal Implementer Agent (English Only) Mission: Make the smallest code change to pass the failing tests. @@ -15,10 +15,15 @@ Steps: 3. If time/clock is needed, accept a clock parameter or use a centralized date utility. 4. Re-run tests; ensure GREEN with no lints/types broken. -Exit Criteria: - -- All new tests pass. No unrelated files changed. - +Feature 2 implementation hints (do the minimum only): +- Ensure recurring events carry an explicit `isRecurring` (or equivalent) boolean used by rendering. +- When an occurrence is edited as a single (detached), mark it to not show the recurring icon (`isRecurring === false` for the detached instance). +- Likely touch points (keep changes minimal): + - `src/components/RecurringIcon.tsx` (pure presentational; render icon only when the flag is true). + - `src/hooks/useCalendarView.ts` (surface the flag to the calendar view items). + - `src/hooks/useEventOperations.ts` (set/clear flags on edit/delete flows that detach occurrences). +Exit Criteria: +- All new tests pass. No unrelated files changed. diff --git a/.cursor/agent/orchestrator.md b/.cursor/agent/orchestrator.md index 5996e2ea..5740669d 100644 --- a/.cursor/agent/orchestrator.md +++ b/.cursor/agent/orchestrator.md @@ -1,4 +1,4 @@ -# Orchestrator Agent +# Orchestrator Agent (English Only) Goal: Drive one full TDD cycle per feature slice using the six-agent workflow. @@ -6,7 +6,7 @@ Inputs: - Feature target (e.g., "Monthly 31st rule" or "Recurring icon rendering"). - Specs: `DOCS/recurring-requirements.en.md` -- Rules: `.cursor/rules/testing-rules.md`, `.cursor/rules/good-test-rules.md`, `.cursor/rules/agent-rules.md` +- Rules: `.cursor/rules/testing-rules.md`, `.cursor/rules/agent-rules.md` Outputs: @@ -22,12 +22,16 @@ Operating Steps: 5. After GREEN, dispatch Reviewer; if clean, dispatch Refactorer; then Reviewer again. 6. Dispatch Committer with stage and message template. +Feature 2 orchestration checklist (Recurring icon & detach): + +- Ensure separate cycles for: + - Icon renders for recurring events (integration). + - Detached occurrence renders without icon (integration + hook-level logic). +- Require fixed clock in tests and clear event flags (`isRecurring`, `isDetached`). +- Point tests to `src/__tests__/medium.integration.spec.tsx` and/or `src/__tests__/hooks/`. + Guardrails: - Do not bundle multiple behaviors in one cycle. - Ensure deterministic tests (fake timers / injected clock). - Keep each cycle small and independently shippable. - - - - diff --git a/.cursor/agent/refactorer.md b/.cursor/agent/refactorer.md index f733e092..535f953c 100644 --- a/.cursor/agent/refactorer.md +++ b/.cursor/agent/refactorer.md @@ -1,10 +1,10 @@ -# Refactorer Agent +# Refactorer Agent (English Only) Mission: Improve clarity, structure, and duplication after GREEN without changing behavior. Targets: -- Extract pure functions for recurrence rules (31st-only, leap-year Feb 29, end-cap). +- Extract pure functions for recurrence rules (31st-only, leap-year Feb 29, end-cap) and for series/detach decisions. - Improve naming; reduce branching; add small helpers. Rules: @@ -18,7 +18,3 @@ Checklist: - Remove duplication introduced during minimal implementation. - Centralize date handling with deterministic interfaces. - Keep files small and functions readable. - - - - diff --git a/.cursor/agent/reviewer.md b/.cursor/agent/reviewer.md index c9592e3a..c54248c0 100644 --- a/.cursor/agent/reviewer.md +++ b/.cursor/agent/reviewer.md @@ -1,4 +1,4 @@ -# Reviewer Agent +# Reviewer Agent (English Only) Mission: Guard quality gates (tests, lints, types, style, determinism). @@ -9,6 +9,12 @@ Review Items: - Code clarity: names, small functions, no dead code, no over-mocking. - Spec alignment: matches `DOCS/recurring-requirements.en.md` exactly. +Feature 2 specific checks: + +- Integration tests assert icon visibility for recurring events and icon absence for detached single edits. +- Implementation exposes a clear flag for rendering (e.g., `isRecurring`) and updates it correctly on detach flows. +- No accidental deduplication or suppression of overlapping occurrences. + Actions: - Suggest precise diffs or edits; avoid vague feedback. @@ -17,7 +23,3 @@ Actions: Exit Criteria: - All checks pass; ready for refactor/commit. - - - - diff --git a/.cursor/agent/spec-agent.md b/.cursor/agent/spec-agent.md index 4c21f60e..35c7ce86 100644 --- a/.cursor/agent/spec-agent.md +++ b/.cursor/agent/spec-agent.md @@ -1,7 +1,7 @@ -# Agent Workflow Overview +# Agent Workflow Overview (English Only) This repository uses six agents to implement the recurring features via TDD. -All agents must follow `.cursor/rules/testing-rules.md` (or `good-test-rules.md`) and `DOCS/recurring-requirements.en.md`. +All agents must follow `.cursor/rules/testing-rules.md` and `DOCS/recurring-requirements.en.md`. Agents: @@ -19,10 +19,6 @@ High-level flow (per feature slice): Artifacts and paths: - Specs: `DOCS/recurring-requirements.en.md` -- Rules: `.cursor/rules/testing-rules.md`, `.cursor/rules/good-test-rules.md`, `.cursor/rules/agent-rules.md` +- Rules: `.cursor/rules/testing-rules.md`, `.cursor/rules/agent-rules.md` - Tests: `src/__tests__/` - Code: `src/` - - - - diff --git a/.cursor/agent/test-author.md b/.cursor/agent/test-author.md index f630aa3a..546e53c8 100644 --- a/.cursor/agent/test-author.md +++ b/.cursor/agent/test-author.md @@ -1,11 +1,11 @@ -# Test Author Agent +# Test Author Agent (English Only) Mission: Write failing tests that precisely capture the behavior. Read: - `DOCS/recurring-requirements.en.md` -- `.cursor/rules/testing-rules.md` or `.cursor/rules/good-test-rules.md` +- `.cursor/rules/testing-rules.md` Deliverables: @@ -14,16 +14,18 @@ Deliverables: Checklist: -- Name: `should when ` +- Name tests as `should when `. - Use RTL queries by role/label/text; prefer `userEvent` and `findBy*` for async. -- For date logic, fix the clock (fake timers or injected Date). -- For networking, use MSW or function-level mocks for pure units. -- Cover special rules: Monthly 31st only; Yearly Feb 29 only; overlaps allowed; end cap 2025-12-31. - -Exit Criteria: - -- Tests fail with meaningful error before implementation begins (RED). +- Fix the clock (fake timers or injected Date) for any date-based behavior. +- Use MSW for networking or function-level mocks for pure units. +- Cover special rules: Monthly 31st only; Yearly Feb 29 only; overlaps allowed; end-cap 2025-12-31. +Feature 2 specific tests (Recurring icon & detach): +- Integration: in `src/__tests__/medium.integration.spec.tsx`, assert recurring events render a distinct icon/marker. +- Integration: assert that a detached occurrence (edited as single) renders without the recurring icon. +- Hook/unit: in `src/__tests__/hooks/medium.useEventOperations.spec.ts` (or a new spec), assert `isRecurring` and `isDetached`/equivalent flags are set correctly during edit/delete flows. +Exit Criteria: +- Tests fail with meaningful errors before implementation begins (RED). diff --git a/.cursor/rules/agent-rules.md b/.cursor/rules/agent-rules.md index d011b83b..58cc14c8 100644 --- a/.cursor/rules/agent-rules.md +++ b/.cursor/rules/agent-rules.md @@ -1,95 +1,82 @@ -# Agent Rules for This Project +# Agent Rules for This Project (English Only) ## Goals -- Implement features via TDD (RED โ†’ GREEN โ†’ REFACTOR) with clear commits. -- Prefer small, safe edits; keep tests fast and deterministic. +- Deliver features via strict TDD (RED โ†’ GREEN โ†’ REFACTOR) with small, safe, and deterministic steps. +- Keep tests fast, readable, and fully deterministic. ## Operating Principles -- Always read `docs/requirements.md` and `.cursor/rules/good-test-rules.md` before writing tests or code. -- Default language for commits and code comments: English; for user communication: Korean. -- Preserve existing file indentation and formatting. -- Use behavioral test names and AAA pattern. -- Avoid over-mocking; mock time/network/random deterministically. +- Always read `docs/requirements.md` (if present) and `.cursor/rules/testing-rules.md` before writing tests or code. The source of truth for this assignment is `DOCS/recurring-requirements.en.md`. +- Language policy: All guidelines, commits, PRs, code comments, and test titles must be written in English. +- Preserve existing file indentation and formatting; do not reformat unrelated code. +- Use behavior-driven test names and the AAA pattern. +- Avoid over-mocking; control time/network/randomness deterministically. ## Change Workflow -1. Write a failing test first (unit or integration as appropriate). -2. Make the minimal change to pass. -3. Refactor to remove duplication and improve clarity. -4. Commit after each step with messages: - - `test(red): ...` - - `feat(green): ...` - - `refactor: ...` +1. RED: Add a failing test (unit or integration as appropriate). +2. GREEN: Make the minimal code change to pass only that test. +3. REFACTOR: Improve clarity and remove duplication without changing behavior. +4. Commit after each step using messages: + - `test(red): ` + - `feat(green): ` + - `refactor: ` ## Testing Conventions - Use React Testing Library from the userโ€™s perspective (roles/labels/text). -- Use `userEvent` and `findBy*`/`waitFor` for async. -- Use MSW for API; fake timers or injected clock for date/recurrence logic. +- Use `userEvent` and `findBy*`/`waitFor` for async flows. +- Use MSW for network; use fake timers or an injected clock for date/recurrence logic. ## File/Path Rules -- Keep new docs in `DOCS/` unless they are agent rules (this folder) or config. -- New tests under `src/__tests__/` with clear grouping (unit/hooks/integration). +- Keep new design docs in `DOCS/` (not in rules folders or configs). +- Put tests under `src/__tests__/` with clear grouping (unit/hooks/integration). -## Recurring Feature Specifics +## Recurring Feature Specifics (Authoritative) -- Monthly 31st occurs only on the 31st; Yearly Feb 29 only in leap years. -- Overlaps allowed by design; do not de-duplicate. -- Calendar must show an icon for recurring events; detached single edits remove the icon. -- End date must not exceed 2025-12-31. +- Monthly on the 31st: generate only on the 31st in months that have it. Do not substitute with the last day. +- Yearly on Feb 29: generate only in leap years (Feb 29). Do not substitute with Feb 28/Mar 1. +- Overlaps are allowed by design; never deduplicate or prevent overlaps. +- Recurring indicator in calendar: show a distinct icon/marker for recurring events only. Detached single events must not show the icon. +- Recurrence end condition: cap generated occurrences at 2025-12-31 at the latest. + +## Feature 2 Focus (Recurring Icon & Detach Behavior) + +- Tests must cover both: (a) recurring events render with the icon; (b) a detached single edit of a recurring occurrence renders without the icon. +- Preferred test locations: + - Integration: `src/__tests__/medium.integration.spec.tsx` (calendar rendering and user flows). + - Hooks/unit: `src/__tests__/hooks/medium.useEventOperations.spec.ts` or a new spec that validates the `isRecurring`/detach flags. +- Minimal implementation targets: + - `src/components/RecurringIcon.tsx` (render-only component; no business logic). + - `src/hooks/useCalendarView.ts` and/or `src/hooks/useEventOperations.ts` to ensure events carry `isRecurring` and a detach mechanism that clears the icon when an occurrence is converted to a single event. +- Determinism: fix the clock in tests; do not rely on system time. ## Quality Gates -- No flaky tests. Keep total run time within seconds locally. -- Ensure lints/types are clean after edits. +- No flaky tests; total suite must run in seconds locally. +- Lints and types must be clean after each GREEN and REFACTOR. ## Safety -- Prefer pure functions for date recurrence generation. -- Add boundary and negative tests for every rule. - -## Stage Documentation & Cross-Referencing - -- For each TDD phase (RED, GREEN, REFACTOR): - - Create a markdown doc (`DOCS/feature--RED.md`, `feature--GREEN.md`, etc.) summarizing what was done at that stage (goal, steps, reasons, paths, result). - - Save and commit this doc together with the code/test for the corresponding phase. - - Ensure commit messages, doc file headers, and requirements/spec references use the same numbering/convention for traceability. - - Example: - - Commit: `test(red): 1. Recurrence type selection โ€“ only 31st of month` - - Doc: `DOCS/feature-1-RED.md` (`Related Spec: 1`) - - Clear mapping between code, docs, and spec for every feature and phase. - -## Commit, PR, and Artifact Language Policy -- ๋ชจ๋“  ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ PR ์„ค๋ช…์€ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. -- ๊ฐ TDD ๋‹จ๊ณ„(RED, GREEN, REFACTOR)๋ณ„๋กœ ์ƒ์„ฑํ•˜๋Š” ์‚ฐ์ถœ๋ฌผ(md ๋ฌธ์„œ ๋“ฑ)๋„ ๋ฐ˜๋“œ์‹œ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. -- ์ฝ”๋“œ ์‹๋ณ„์ž(ํ•จ์ˆ˜/๋ณ€์ˆ˜/ํŒŒ์ผ๋ช…)๋Š” ์˜์–ด๋กœ, **์ฃผ์„๊ณผ ํ…Œ์ŠคํŠธ ์„ค๋ช…(it/describe ๋ฉ”์‹œ์ง€)์€ ํ•œ๊ตญ์–ด๋กœ** ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. - -## TDD ๋‹จ๊ณ„๋ณ„ ํ‘œ์ค€ ์‚ฐ์ถœ๋ฌผ ๋ฐ ์—์ด์ „ํŠธ ์ฑ…์ž„ ์ˆœ์„œ - -์•„๋ž˜์˜ ํ๋ฆ„(RED, GREEN, REFACTOR ๋ชจ๋‘ ๋™์ผ)์„ ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ฆ„. - -1. ์ฝ”๋“œ(ํ…Œ์ŠคํŠธ/๊ตฌํ˜„/๋ฆฌํŒฉํ„ฐ ๋“ฑ) ์ž‘์„ฑ - - RED: Test Author Agent - - GREEN: Minimal Implementer Agent - - REFACTOR: Refactorer Agent -2. ํ•ด๋‹น ๋‹จ๊ณ„ ์‚ฐ์ถœ๋ฌผ(ํ•œ๊ตญ์–ด md ๋ฌธ์„œ) ์ž‘์„ฑ - - ํ•ด๋‹น ๋‹จ๊ณ„ ์ฃผ๋„ ์—์ด์ „ํŠธ๊ฐ€ ์‚ฐ์ถœ๋ฌผ๋„ ์ž‘์„ฑ - - ์‚ฐ์ถœ๋ฌผ ์ด๋ฆ„๊ณผ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€, ์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ/๋‚ด์šฉ์„ ํ†ต์ผํ•จ -3. ๊ฒ€ํ†  - - Reviewer Agent๊ฐ€ ์ฝ”๋“œ์™€ ์‚ฐ์ถœ๋ฌผ ๋ชจ๋‘ ์ ๊ฒ€(ํ’ˆ์งˆ, TDD ๊ทœ์น™, ์š”๊ตฌ์‚ฌํ•ญ ๋งคํ•‘ ๋“ฑ) -4. ์ปค๋ฐ‹ - - Committer Agent๊ฐ€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์ž‘์„ฑ(ํ•œ๊ตญ์–ด), ์‚ฐ์ถœ๋ฌผ-์ฝ”๋“œ-์š”๊ตฌ์‚ฌํ•ญ ๋ฒˆํ˜ธ-์ปค๋ฐ‹ ๊ฐ„ ๋งค์นญ ์ฑ…์ž„ - -> ์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด, **์ฃผ์„/ํ…Œ์ŠคํŠธ ์„ค๋ช…/์‚ฐ์ถœ๋ฌผ/์ปค๋ฐ‹/PR์€ ํ•œ๊ตญ์–ด** ์›์น™์„ ๋ฐ˜๋“œ์‹œ ์ง€ํ‚ด - -## ๋‹จ๊ณ„์  ์ง„ํ–‰ ๊ทœ์น™(๋‹จ์œ„ โ†’ ํ†ตํ•ฉ) -- ๋จผ์ € ๋‹จ์œ„ ์ˆ˜์ค€์—์„œ TDD ์‚ฌ์ดํด์„ ์™„๋ฃŒํ•œ๋‹ค: **RED โ†’ GREEN โ†’ REFACTOR(๋‹จ์œ„)** -- ๋‹จ์œ„ GREEN์ด ์•ˆ์ •ํ™”๋˜๋ฉด, ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค: - - **RED(ํ†ตํ•ฉ)**: ์‹คํŒจํ•˜๋Š” ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€ - - **GREEN(ํ†ตํ•ฉ)**: ์‹ค์ œ UI/ํ›…/์ƒํƒœ ์—ฐ๋™ ์ตœ์†Œ ๊ตฌํ˜„ - - **REFACTOR(ํ†ตํ•ฉ)**: ์ „์ฒด ๊ตฌ์กฐ ๊ฐœ์„ (์—ญํ•  ๋ถ„๋ฆฌ/๊ฐ€๋…์„ฑ/์ค‘๋ณต ์ œ๊ฑฐ) -- ๊ฐ ๋‹จ๊ณ„๋งˆ๋‹ค ์‚ฐ์ถœ๋ฌผ(ํ•œ๊ตญ์–ด ๋ฌธ์„œ) ์ž‘์„ฑ โ†’ ๊ฒ€ํ†  โ†’ ํ•œ๊ตญ์–ด ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋กœ ๊ธฐ๋ก -- ๋‹ค์Œ ๊ธฐ๋Šฅ์œผ๋กœ ๋„˜์–ด๊ฐˆ ๋•Œ๋„ ๋™์ผํ•œ ์ ˆ์ฐจ๋ฅผ ๋ฐ˜๋ณต ์ ์šฉํ•œ๋‹ค +- Prefer pure functions for recurrence generation and series/detach decisions. +- Add boundary and negative tests for every rule above. + +## Stage Documentation & Traceability + +- For each TDD phase (RED, GREEN, REFACTOR), create a markdown doc: `DOCS/feature--RED.md`, `DOCS/feature--GREEN.md`, `DOCS/feature--REFACTOR.md`. +- Document the goal, steps, rationale, file paths touched, and results. Keep it concise and actionable. +- Ensure commit messages, doc headers, and spec references use consistent numbering/conventions. +- Example mapping: + - Commit: `test(red): 2. Recurring icon visible only for recurring events` + - Doc: `DOCS/feature-2-RED.md` (Related Spec: 2 โ€“ Recurring Indicator in Calendar) + +## Sequential Scope (Unit โ†’ Integration) + +- Complete unit-level TDD first: RED โ†’ GREEN โ†’ REFACTOR (unit). +- Then add integration tests: + - RED (integration): failing integration test capturing UI behavior. + - GREEN (integration): minimal UI/hook/state wiring to pass. + - REFACTOR (integration): role separation/readability/duplication removal. +- Repeat the same discipline for each feature slice. From 270f19116cef38ccbcb74752c59ff73a5bf042eb Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Fri, 31 Oct 2025 00:38:46 +0900 Subject: [PATCH 17/18] =?UTF-8?q?chore(rules):=20=EC=BB=A4=EB=B0=8B/?= =?UTF-8?q?=EC=A3=BC=EC=84=9D/=EC=82=B0=EC=B6=9C=EB=AC=BC=20=ED=95=9C?= =?UTF-8?q?=EA=B5=AD=EC=96=B4=20=EC=9E=91=EC=84=B1=20=EC=9B=90=EC=B9=99?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=A7=80=EC=B9=A8=20=EC=88=98=EC=A0=95\n\?= =?UTF-8?q?n-=20=EC=96=B8=EC=96=B4=20=EC=A0=95=EC=B1=85:=20=EC=8B=9D?= =?UTF-8?q?=EB=B3=84=EC=9E=90=20=EC=98=81=EC=96=B4,=20=EC=BB=A4=EB=B0=8B/?= =?UTF-8?q?=EC=A3=BC=EC=84=9D/=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85/=EC=82=B0=EC=B6=9C=EB=AC=BC=20=ED=95=9C=EA=B5=AD?= =?UTF-8?q?=EC=96=B4\n-=20Feature=202(=EB=B0=98=EB=B3=B5=20=EC=95=84?= =?UTF-8?q?=EC=9D=B4=EC=BD=98/=EB=B6=84=EB=A6=AC)=20TDD=20=EA=B0=80?= =?UTF-8?q?=EC=9D=B4=EB=93=9C=20=EC=9C=A0=EC=A7=80\n-=20=EC=98=88=EC=8B=9C?= =?UTF-8?q?=20=EC=BB=A4=EB=B0=8B=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=ED=95=9C?= =?UTF-8?q?=EA=B5=AD=EC=96=B4=EB=A1=9C=20=EC=A0=95=EB=B9=84=20=EB=B0=8F=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/agent/committer.md | 14 +++++++------- .cursor/agent/orchestrator.md | 3 ++- .cursor/agent/refactorer.md | 3 ++- .cursor/agent/reviewer.md | 3 ++- .cursor/agent/spec-agent.md | 3 ++- .cursor/agent/test-author.md | 3 ++- .cursor/rules/agent-rules.md | 14 +++++++------- 7 files changed, 24 insertions(+), 19 deletions(-) diff --git a/.cursor/agent/committer.md b/.cursor/agent/committer.md index 36cb775f..c94d5328 100644 --- a/.cursor/agent/committer.md +++ b/.cursor/agent/committer.md @@ -1,4 +1,4 @@ -# Committer Agent (English Only) +# Committer Agent Mission: Produce clean, stage-specific commits with clear messages. @@ -12,12 +12,12 @@ Rules: - Commit only relevant files per stage. - Keep messages actionable and scoped to one behavior. -- Write commit subjects and bodies in English. +- ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋Š” ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด ์œ ์ง€) Example Messages: -- `test(red): monthly 31st occurs only on the 31st` -- `feat(green): implement 31st-only monthly recurrence rule` -- `test(red): recurring icon displays for recurring events only` -- `feat(green): show RecurringIcon for events with isRecurring true` -- `refactor: extract recurrence generator and clarify names` +- `test(red): ๋งค๋‹ฌ 31์ผ ๊ทœ์น™์€ 31์ผ์—๋งŒ ๋ฐœ์ƒํ•œ๋‹ค` +- `feat(green): 31์ผ ์ „์šฉ ์›”๊ฐ„ ๋ฐ˜๋ณต ๊ทœ์น™ ์ตœ์†Œ ๊ตฌํ˜„` +- `test(red): ๋ฐ˜๋ณต ์ด๋ฒคํŠธ์—๋งŒ ๋ฐ˜๋ณต ์•„์ด์ฝ˜์„ ํ‘œ์‹œํ•œ๋‹ค` +- `feat(green): isRecurring์ด true์ธ ์ด๋ฒคํŠธ์—๋งŒ RecurringIcon ๋ Œ๋”` +- `refactor: ๋ฐ˜๋ณต ์ƒ์„ฑ ๋กœ์ง ์ถ”์ถœ ๋ฐ ๋„ค์ด๋ฐ ๊ฐœ์„ ` diff --git a/.cursor/agent/orchestrator.md b/.cursor/agent/orchestrator.md index 5740669d..0b29d43f 100644 --- a/.cursor/agent/orchestrator.md +++ b/.cursor/agent/orchestrator.md @@ -1,4 +1,4 @@ -# Orchestrator Agent (English Only) +# Orchestrator Agent Goal: Drive one full TDD cycle per feature slice using the six-agent workflow. @@ -29,6 +29,7 @@ Feature 2 orchestration checklist (Recurring icon & detach): - Detached occurrence renders without icon (integration + hook-level logic). - Require fixed clock in tests and clear event flags (`isRecurring`, `isDetached`). - Point tests to `src/__tests__/medium.integration.spec.tsx` and/or `src/__tests__/hooks/`. +- ์‚ฐ์ถœ๋ฌผ ๋ฌธ์„œ์™€ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋Š” ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด) Guardrails: diff --git a/.cursor/agent/refactorer.md b/.cursor/agent/refactorer.md index 535f953c..d63f354e 100644 --- a/.cursor/agent/refactorer.md +++ b/.cursor/agent/refactorer.md @@ -1,4 +1,4 @@ -# Refactorer Agent (English Only) +# Refactorer Agent Mission: Improve clarity, structure, and duplication after GREEN without changing behavior. @@ -18,3 +18,4 @@ Checklist: - Remove duplication introduced during minimal implementation. - Centralize date handling with deterministic interfaces. - Keep files small and functions readable. + - ์‚ฐ์ถœ๋ฌผ/์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€/์ฃผ์„์€ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด) diff --git a/.cursor/agent/reviewer.md b/.cursor/agent/reviewer.md index c54248c0..cf0cad27 100644 --- a/.cursor/agent/reviewer.md +++ b/.cursor/agent/reviewer.md @@ -1,4 +1,4 @@ -# Reviewer Agent (English Only) +# Reviewer Agent Mission: Guard quality gates (tests, lints, types, style, determinism). @@ -14,6 +14,7 @@ Feature 2 specific checks: - Integration tests assert icon visibility for recurring events and icon absence for detached single edits. - Implementation exposes a clear flag for rendering (e.g., `isRecurring`) and updates it correctly on detach flows. - No accidental deduplication or suppression of overlapping occurrences. + - ํ…Œ์ŠคํŠธ ์„ค๋ช…/์ฃผ์„/์‚ฐ์ถœ๋ฌผ/์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๊ฐ€ ํ•œ๊ตญ์–ด๋กœ ์ผ๊ด€๋˜๊ฒŒ ์ž‘์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด) Actions: diff --git a/.cursor/agent/spec-agent.md b/.cursor/agent/spec-agent.md index 35c7ce86..e83f5558 100644 --- a/.cursor/agent/spec-agent.md +++ b/.cursor/agent/spec-agent.md @@ -1,4 +1,4 @@ -# Agent Workflow Overview (English Only) +# Agent Workflow Overview This repository uses six agents to implement the recurring features via TDD. All agents must follow `.cursor/rules/testing-rules.md` and `DOCS/recurring-requirements.en.md`. @@ -20,5 +20,6 @@ Artifacts and paths: - Specs: `DOCS/recurring-requirements.en.md` - Rules: `.cursor/rules/testing-rules.md`, `.cursor/rules/agent-rules.md` +- Language: ์ปค๋ฐ‹/์ฃผ์„/ํ…Œ์ŠคํŠธ ์„ค๋ช…/์‚ฐ์ถœ๋ฌผ์€ ํ•œ๊ตญ์–ด, ์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด - Tests: `src/__tests__/` - Code: `src/` diff --git a/.cursor/agent/test-author.md b/.cursor/agent/test-author.md index 546e53c8..f7273c48 100644 --- a/.cursor/agent/test-author.md +++ b/.cursor/agent/test-author.md @@ -1,4 +1,4 @@ -# Test Author Agent (English Only) +# Test Author Agent Mission: Write failing tests that precisely capture the behavior. @@ -19,6 +19,7 @@ Checklist: - Fix the clock (fake timers or injected Date) for any date-based behavior. - Use MSW for networking or function-level mocks for pure units. - Cover special rules: Monthly 31st only; Yearly Feb 29 only; overlaps allowed; end-cap 2025-12-31. + - ํ…Œ์ŠคํŠธ ์„ค๋ช…(it/describe)๊ณผ ์ฃผ์„์€ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด) Feature 2 specific tests (Recurring icon & detach): diff --git a/.cursor/rules/agent-rules.md b/.cursor/rules/agent-rules.md index 58cc14c8..90679567 100644 --- a/.cursor/rules/agent-rules.md +++ b/.cursor/rules/agent-rules.md @@ -1,4 +1,4 @@ -# Agent Rules for This Project (English Only) +# Agent Rules for This Project ## Goals @@ -8,7 +8,7 @@ ## Operating Principles - Always read `docs/requirements.md` (if present) and `.cursor/rules/testing-rules.md` before writing tests or code. The source of truth for this assignment is `DOCS/recurring-requirements.en.md`. -- Language policy: All guidelines, commits, PRs, code comments, and test titles must be written in English. +- Language policy: ์ฝ”๋“œ ์‹๋ณ„์ž(ํ•จ์ˆ˜/๋ณ€์ˆ˜/ํŒŒ์ผ๋ช…)๋Š” ์˜์–ด๋กœ ์ž‘์„ฑํ•˜๊ณ , ์ปค๋ฐ‹/PR/์ฃผ์„/ํ…Œ์ŠคํŠธ ์„ค๋ช… ๋ฐ ๊ฐ ๋‹จ๊ณ„ ์‚ฐ์ถœ๋ฌผ ๋ฌธ์„œ๋Š” ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. - Preserve existing file indentation and formatting; do not reformat unrelated code. - Use behavior-driven test names and the AAA pattern. - Avoid over-mocking; control time/network/randomness deterministically. @@ -66,11 +66,11 @@ ## Stage Documentation & Traceability - For each TDD phase (RED, GREEN, REFACTOR), create a markdown doc: `DOCS/feature--RED.md`, `DOCS/feature--GREEN.md`, `DOCS/feature--REFACTOR.md`. -- Document the goal, steps, rationale, file paths touched, and results. Keep it concise and actionable. -- Ensure commit messages, doc headers, and spec references use consistent numbering/conventions. -- Example mapping: - - Commit: `test(red): 2. Recurring icon visible only for recurring events` - - Doc: `DOCS/feature-2-RED.md` (Related Spec: 2 โ€“ Recurring Indicator in Calendar) +- ์‚ฐ์ถœ๋ฌผ ๋ฌธ์„œ๋Š” ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋ชฉํ‘œ, ๋‹จ๊ณ„, ๊ทผ๊ฑฐ, ๋ณ€๊ฒฝ ํŒŒ์ผ ๊ฒฝ๋กœ, ๊ฒฐ๊ณผ๋ฅผ ๊ฐ„๊ฒฐํžˆ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค. +- ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ ๋ฌธ์„œ ํ—ค๋”, ์ŠคํŽ™ ์ฐธ์กฐ๋Š” ๋™์ผํ•œ ๋ฒˆํ˜ธ/์šฉ์–ด ์ฒด๊ณ„๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. +- ์˜ˆ์‹œ ๋งคํ•‘: + - Commit: `test(red): 2. ๋ฐ˜๋ณต ์ด๋ฒคํŠธ์—๋งŒ ์•„์ด์ฝ˜์„ ํ‘œ์‹œํ•œ๋‹ค` + - Doc: `DOCS/feature-2-RED.md` (๊ด€๋ จ ์ŠคํŽ™: 2 โ€“ ์บ˜๋ฆฐ๋” ๋ฐ˜๋ณต ์•„์ด์ฝ˜) ## Sequential Scope (Unit โ†’ Integration) From 1f9ecdbcfd76795eb937803c4b3f2230f475a9d3 Mon Sep 17 00:00:00 2001 From: Yein Lee Date: Fri, 31 Oct 2025 00:43:53 +0900 Subject: [PATCH 18/18] =?UTF-8?q?docs(agent):=20agent=20=EC=A7=80=EC=B9=A8?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/agent/refactorer.md | 2 +- .cursor/agent/reviewer.md | 2 +- .cursor/agent/test-author.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.cursor/agent/refactorer.md b/.cursor/agent/refactorer.md index d63f354e..40dfc2cb 100644 --- a/.cursor/agent/refactorer.md +++ b/.cursor/agent/refactorer.md @@ -18,4 +18,4 @@ Checklist: - Remove duplication introduced during minimal implementation. - Centralize date handling with deterministic interfaces. - Keep files small and functions readable. - - ์‚ฐ์ถœ๋ฌผ/์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€/์ฃผ์„์€ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด) +- Deliverables, commit messages, and comments must be written in Korean. (Code identifiers should remain in English) diff --git a/.cursor/agent/reviewer.md b/.cursor/agent/reviewer.md index cf0cad27..eae2fb17 100644 --- a/.cursor/agent/reviewer.md +++ b/.cursor/agent/reviewer.md @@ -14,7 +14,7 @@ Feature 2 specific checks: - Integration tests assert icon visibility for recurring events and icon absence for detached single edits. - Implementation exposes a clear flag for rendering (e.g., `isRecurring`) and updates it correctly on detach flows. - No accidental deduplication or suppression of overlapping occurrences. - - ํ…Œ์ŠคํŠธ ์„ค๋ช…/์ฃผ์„/์‚ฐ์ถœ๋ฌผ/์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๊ฐ€ ํ•œ๊ตญ์–ด๋กœ ์ผ๊ด€๋˜๊ฒŒ ์ž‘์„ฑ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด) +- Verify that test descriptions, comments, deliverables, and commit messages are consistently written in Korean. (Code identifiers should remain in English) Actions: diff --git a/.cursor/agent/test-author.md b/.cursor/agent/test-author.md index f7273c48..c7bb0b05 100644 --- a/.cursor/agent/test-author.md +++ b/.cursor/agent/test-author.md @@ -19,7 +19,7 @@ Checklist: - Fix the clock (fake timers or injected Date) for any date-based behavior. - Use MSW for networking or function-level mocks for pure units. - Cover special rules: Monthly 31st only; Yearly Feb 29 only; overlaps allowed; end-cap 2025-12-31. - - ํ…Œ์ŠคํŠธ ์„ค๋ช…(it/describe)๊ณผ ์ฃผ์„์€ ํ•œ๊ตญ์–ด๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค. (์ฝ”๋“œ ์‹๋ณ„์ž๋Š” ์˜์–ด) +- Test descriptions (it/describe) and comments must be written in Korean. (Code identifiers should remain in English) Feature 2 specific tests (Recurring icon & detach):