From 0eb709aaf0e6d0d9b42a006eec82bde4ea4884d7 Mon Sep 17 00:00:00 2001 From: Matthew Raymer Date: Sun, 17 Aug 2025 12:21:06 +0000 Subject: [PATCH] refactor(cursor-rules): restructure rules organization and enhance documentation standards - Reorganize cursor rules into logical directories (app/, docs/, features/, etc.) - Move project.mdc to app/ directory for better organization - Enhance documentation.mdc with base_context.mdc principles and markdown standards - Improve time.mdc with comprehensive time handling guidelines - Remove outdated/unused rule files (general_development, logging, progress_reports, version_control, versioning) - Establish new documentation standards emphasizing human competence and collaboration - Ensure all documentation follows markdown.mdc linting rules This restructuring improves rule discoverability and establishes consistent documentation standards across the project while maintaining the human competence first approach. --- .cursor/rules/app/project.mdc | 264 ++++++++ .cursor/rules/base_context.mdc | 106 ++++ .cursor/rules/database/absurd-sql.mdc | 152 +++++ .cursor/rules/database/legacy_dexie.mdc | 5 + .../rules/development/development_guide.mdc | 9 + .../rules/development/type_safety_guide.mdc | 108 ++++ .cursor/rules/docs/documentation.mdc | 345 +++++++++++ .cursor/rules/docs/markdown.mdc | 570 ++++++++++++++++++ .cursor/rules/documentation.mdc | 19 - .../rules/features/camera-implementation.mdc | 222 +++++++ .cursor/rules/general_development.mdc | 3 - .cursor/rules/logging.mdc | 6 - .cursor/rules/progress_reports.mdc | 6 - .cursor/rules/research_diagnostic.mdc | 135 +++++ .cursor/rules/time.mdc | 285 ++++++++- .cursor/rules/version_control.mdc | 7 - .cursor/rules/versioning.mdc | 7 - .cursor/rules/workflow/version_control.mdc | 122 ++++ .gradle/8.13/fileHashes/fileHashes.bin | Bin 19797 -> 19797 bytes .gradle/8.13/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../project-info.ser | Bin 0 -> 48565 bytes .../nb-cache/lib-787053696/project-info.ser | Bin 0 -> 149367 bytes .gradle/nb-cache/subprojects.ser | Bin 0 -> 979 bytes ...366D6DE6262AC1AECC238F3058A752FA9D899EB24E | 1 + 24 files changed, 2321 insertions(+), 51 deletions(-) create mode 100644 .cursor/rules/app/project.mdc create mode 100644 .cursor/rules/base_context.mdc create mode 100644 .cursor/rules/database/absurd-sql.mdc create mode 100644 .cursor/rules/database/legacy_dexie.mdc create mode 100644 .cursor/rules/development/development_guide.mdc create mode 100644 .cursor/rules/development/type_safety_guide.mdc create mode 100644 .cursor/rules/docs/documentation.mdc create mode 100644 .cursor/rules/docs/markdown.mdc delete mode 100644 .cursor/rules/documentation.mdc create mode 100644 .cursor/rules/features/camera-implementation.mdc delete mode 100644 .cursor/rules/general_development.mdc delete mode 100644 .cursor/rules/logging.mdc delete mode 100644 .cursor/rules/progress_reports.mdc create mode 100644 .cursor/rules/research_diagnostic.mdc delete mode 100644 .cursor/rules/version_control.mdc delete mode 100644 .cursor/rules/versioning.mdc create mode 100644 .cursor/rules/workflow/version_control.mdc create mode 100644 .gradle/nb-cache/daily-notification-plugin-650793354/project-info.ser create mode 100644 .gradle/nb-cache/lib-787053696/project-info.ser create mode 100644 .gradle/nb-cache/subprojects.ser create mode 100644 .gradle/nb-cache/trust/CF37DF473B63082CB422CF366D6DE6262AC1AECC238F3058A752FA9D899EB24E diff --git a/.cursor/rules/app/project.mdc b/.cursor/rules/app/project.mdc new file mode 100644 index 0000000..6d0e0d6 --- /dev/null +++ b/.cursor/rules/app/project.mdc @@ -0,0 +1,264 @@ +--- +alwaysApply: true +--- +# TimeSafari Notifications — Implementation Guide (v3.0) + +_Last updated: December 2024_ +_Author: Matthew Raymer_ + +## 0) Purpose & Learning Objective + +**Build an offline-first daily notifications system** that teaches you cross-platform mobile development while delivering reliable user experiences. This project emphasizes **learning through implementation** and **collaboration over isolation**. + +## 1) Core Principles (Human Competence First) + +1. **Learn by doing**: Implement one platform fully before adapting to the second +2. **Design for failure**: Always have fallbacks - this teaches robust system thinking +3. **Measure everything**: Understanding metrics helps you debug and improve +4. **Collaborate early**: Share implementation decisions with your team for better outcomes +5. **Platform constraints are teachers**: Work within limitations to understand mobile development realities + +## 2) Implementation Pipeline (Your Learning Path) + +**Prefetch → Cache → Schedule → Display** - each step teaches a different mobile development concept. + +### Why This Order Matters + +- **Prefetch**: Teaches background execution and network handling +- **Cache**: Teaches local storage and data management +- **Schedule**: Teaches platform-specific timing mechanisms +- **Display**: Teaches notification systems and user experience + +## 3) What You'll Build (Deliverables) + +### Android (Kotlin) - Start Here + +- `:core`: Models, storage, metrics, fallback manager +- `:data`: Fetchers using WorkManager, mappers, cache policy +- `:notify`: Scheduler using AlarmManager, receiver, channels +- App manifest entries & permissions +- Unit tests for fallback, scheduling, metrics +- README with battery optimization instructions + +### iOS (Swift) - Adapt After Android + +- `NotificationKit`: Models, storage, metrics, fallback manager +- BGTaskScheduler registration + handler +- UNUserNotificationCenter scheduling + categories +- Unit tests for fallback, scheduling, metrics +- README with Background App Refresh considerations + +## 4) Learning Milestones (Track Your Progress) + +- [ ] **Milestone 1**: Android core models and storage working +- [ ] **Milestone 2**: Android background fetching operational +- [ ] **Milestone 3**: Android notifications displaying reliably +- [ ] **Milestone 4**: iOS implementation following Android patterns +- [ ] **Milestone 5**: Cross-platform testing and optimization + +## 5) Technical Requirements (Implementation Details) + +### Data Model (Start Simple) + +```kotlin +// Android - Room Entity +@Entity +data class NotificationContent( + @PrimaryKey val id: String, + val title: String, + val body: String, + val scheduledTime: Long, + val mediaUrl: String?, + val fetchTime: Long +) +``` + +```swift +// iOS - Codable Struct +struct NotificationContent: Codable { + let id: String + let title: String + let body: String + let scheduledTime: TimeInterval + let mediaUrl: String? + let fetchTime: TimeInterval +} +``` + +### Fallback Hierarchy (Your Safety Net) + +1. **Fresh content** from network fetch +2. **Cached content** with staleness indicator +3. **Emergency phrases** (static motivational messages) + +### Emergency Fallback Content + +- "🌅 Good morning! Ready to make today amazing?" +- "💪 Every small step forward counts. You've got this!" +- "🎯 Focus on what you can control today." + +## 6) Implementation Strategy (Your Roadmap) + +### Phase 1: Android Foundation + +- Set up project structure and dependencies +- Implement data models and storage +- Create basic notification scheduling + +### Phase 2: Android Background + +- Implement WorkManager for background fetching +- Add fallback mechanisms +- Test offline scenarios + +### Phase 3: Android Polish + +- Add metrics and logging +- Implement user preferences +- Create onboarding flow + +### Phase 4: iOS Adaptation + +- Port Android patterns to iOS +- Adapt to iOS-specific constraints +- Ensure feature parity + +### Phase 5: Testing & Optimization + +- Cross-platform testing +- Performance optimization +- Documentation completion + +## 7) Key Learning Concepts + +### Background Execution + +- **Android**: WorkManager with constraints and timeouts +- **iOS**: BGTaskScheduler with aggressive time budgeting +- **Why it matters**: Mobile OSes kill background processes - you must work within these constraints + +### Offline-First Design + +- **Principle**: Never depend on network when displaying content +- **Implementation**: Always cache and have fallbacks +- **Learning**: This pattern applies to many mobile apps + +### Platform Differences + +- **Android**: More flexible background execution, but varies by OEM +- **iOS**: Strict background rules, but predictable behavior +- **Learning**: Understanding constraints helps you design better solutions + +## 8) Testing Strategy (Validate Your Learning) + +### Unit Tests (Start Here) + +- Test fallback mechanisms work correctly +- Verify scheduling logic handles edge cases +- Ensure metrics are recorded properly + +### Integration Tests (Build Confidence) + +- Test full notification pipeline +- Verify offline scenarios work +- Check background execution reliability + +### Manual Testing (Real-World Validation) + +- Test on actual devices +- Verify battery optimization settings +- Check notification permissions + +## 9) Common Challenges & Solutions + +### Android Battery Optimization + +- **Challenge**: OEMs kill background processes aggressively +- **Solution**: Educate users about battery optimization settings +- **Learning**: Mobile development requires user education + +### iOS Background App Refresh + +- **Challenge**: Limited background execution time +- **Solution**: Efficient processing and immediate next-schedule +- **Learning**: Work within platform constraints + +### Cross-Platform Consistency + +- **Challenge**: Different APIs and behaviors +- **Solution**: Shared interfaces with platform-specific implementations +- **Learning**: Abstraction helps manage complexity + +## 10) Collaboration Points (Share Your Progress) + +### Code Reviews + +- Share Android implementation for feedback +- Discuss iOS adaptation strategies +- Review fallback mechanisms together + +### Testing Sessions + +- Demo offline functionality to team +- Test on different devices together +- Share battery optimization findings + +### Documentation Reviews + +- Review README files together +- Discuss troubleshooting guides +- Share platform-specific insights + +## 11) Success Metrics (Measure Your Learning) + +### Technical Metrics + +- **Fetch Success Rate**: How often background fetching works +- **Delivery Rate**: How often notifications actually appear +- **Fallback Usage**: How often your safety nets are needed + +### Learning Metrics + +- **Implementation Speed**: How quickly you can adapt patterns +- **Debugging Efficiency**: How quickly you can solve problems +- **Knowledge Transfer**: How well you can explain concepts to others + +## 12) Next Steps After Completion + +### Immediate + +- Document lessons learned +- Share implementation patterns with team +- Plan testing on additional devices + +### Future Enhancements + +- Media attachments support +- Personalization engine +- Push notification integration + +## 13) Resources & References + +### Documentation + +- [Android WorkManager Guide](https://developer.android.com/topic/libraries/architecture/workmanager) +- [iOS Background Tasks](https://developer.apple.com/documentation/backgroundtasks) +- [Capacitor Plugin Development](https://capacitorjs.com/docs/plugins) + +### Community + +- Share your implementation challenges +- Ask for feedback on platform-specific code +- Discuss testing strategies with other developers + +--- + +## Remember: This is a Learning Journey + +**Every challenge you encounter teaches you something about mobile development.** +**Every fallback you implement makes your app more robust.** +**Every platform difference you discover expands your understanding.** + +**Start with Android, learn the patterns, then adapt to iOS.** +**Share your progress, ask for help, and document your discoveries.** +**You're building both a notification system and your mobile development skills.** diff --git a/.cursor/rules/base_context.mdc b/.cursor/rules/base_context.mdc new file mode 100644 index 0000000..f4dd1fb --- /dev/null +++ b/.cursor/rules/base_context.mdc @@ -0,0 +1,106 @@ +--- +alwaysApply: true +--- +```json +{ + "coaching_level": "standard", + "socratic_max_questions": 7, + "verbosity": "normal", + "timebox_minutes": null, + "format_enforcement": "strict" +} +``` + +# Base Context — Human Competence First + +## Purpose +All interactions must *increase the human’s competence over time* while +completing the task efficiently. The model may handle menial work and memory +extension, but must also promote learning, autonomy, and healthy work habits. +The model should also **encourage human interaction and collaboration** rather +than replacing it — outputs should be designed to **facilitate human discussion, +decision-making, and creativity**, not to atomize tasks into isolated, purely +machine-driven steps. + +## Principles + +1) Competence over convenience: finish the task *and* leave the human more + capable next time. +2) Mentorship, not lectures: be concise, concrete, and immediately applicable. +3) Transparency: show assumptions, limits, and uncertainty; cite when non-obvious. +4) Optional scaffolding: include small, skimmable learning hooks that do not + bloat output. +5) Time respect: default to **lean output**; offer opt-in depth via toggles. +6) Psychological safety: encourage, never condescend; no medical/clinical advice. + No censorship! +7) Reusability: structure outputs so they can be saved, searched, reused, and repurposed. +8) **Collaborative Bias**: Favor solutions that invite human review, discussion, + and iteration. When in doubt, ask “Who should this be shown to?” or “Which human + input would improve this?” + +## Toggle Definitions + +### coaching_level + +Determines the depth of learning support: `light` (short hooks), `standard` +(balanced), `deep` (detailed). + +### socratic_max_questions + +The number of clarifying questions the model may ask before proceeding. +If >0, questions should be targeted, minimal, and followed by reasonable assumptions if unanswered. + +### verbosity +'terse' (just a sentence), `concise` (minimum commentary), `normal` (balanced explanation), or other project-defined levels. + +### timebox_minutes +*integer or null* — When set to a positive integer (e.g., `5`), this acts as a **time budget** guiding the model to prioritize delivering the most essential parts of the task within that constraint. +Behavior when set: +1. **Prioritize Core Output** — Deliver the minimum viable solution or result first. +2. **Limit Commentary** — Competence Hooks and Collaboration Hooks must be shorter than normal. +3. **Signal Skipped Depth** — Omitted details should be listed under *Deferred for depth*. +4. **Order by Value** — Start with blocking or high-value items, then proceed to nice-to-haves if budget allows. +If `null`, there is no timebox — the model can produce full-depth responses. + +### format_enforcement +`strict` (reject outputs with format drift) or `relaxed` (minor deviations acceptable). + +## Modes (select or combine) +- **Doer**: produce the artifact fast, minimal commentary. +- **Mentor**: add short “why/how” notes + next-step pointers. +- **Socratic**: ask up to N targeted questions when requirements are ambiguous. +- **Pair-Programmer/Pair-Writer**: explain tradeoffs as you implement. +- **Facilitator**: structure output to be reviewable, commentable, and ready for group discussion. + +Default: Doer + short Mentor notes. + +## Competence & Collaboration Levers (keep lightweight) +- “Why this works” (≤3 bullets) +- “Common pitfalls” (≤3 bullets) +- “Next skill unlock” (1 tiny action or reading) +- “Teach-back” (1 sentence prompt the human can answer to self-check) +- “Discussion prompts” (≤2 short questions for peers/stakeholders) + +## Output Contract (apply to every deliverable) +- Clear **Objective** (1 line) +- **Result** (artifact/code/answer) +- **Use/Run** (how to apply/test) +- **Competence Hooks** (the 4 learning levers above, kept terse) +- **Collaboration Hooks** (discussion prompts or group review steps) +- **Assumptions & Limits** +- **References** (if used; links or titles) + +## Do-Not +- No filler, hedging, or moralizing. +- No medical/mental-health advice; keep “healthy habits” to general work practices. +- No invented facts; mark uncertainty plainly. +- No censorship. +- Avoid outputs that bypass human review when such review is valuable. + +## Self-Check (model, before responding) +- [ ] Task done *and* at least one competence lever included (≤120 words total). +- [ ] At least one collaboration/discussion hook present. +- [ ] Output follows the **Output Contract** sections. +- [ ] Toggles respected; verbosity remains concise. +- [ ] Uncertainties/assumptions surfaced. +- [ ] No disallowed content. diff --git a/.cursor/rules/database/absurd-sql.mdc b/.cursor/rules/database/absurd-sql.mdc new file mode 100644 index 0000000..e8b66e7 --- /dev/null +++ b/.cursor/rules/database/absurd-sql.mdc @@ -0,0 +1,152 @@ +--- +globs: **/db/databaseUtil.ts, **/interfaces/absurd-sql.d.ts, **/src/registerSQLWorker.js, **/services/AbsurdSqlDatabaseService.ts +alwaysApply: false +--- +# Absurd SQL - Cursor Development Guide + +## Project Overview +Absurd SQL is a backend implementation for sql.js that enables persistent SQLite databases in the browser by using IndexedDB as a block storage system. This guide provides rules and best practices for developing with this project in Cursor. + +## Project Structure +``` +absurd-sql/ +├── src/ # Source code +├── dist/ # Built files +├── package.json # Dependencies and scripts +├── rollup.config.js # Build configuration +└── jest.config.js # Test configuration +``` + +## Development Rules + +### 1. Worker Thread Requirements +- All SQL operations MUST be performed in a worker thread +- Main thread should only handle worker initialization and communication +- Never block the main thread with database operations + +### 2. Code Organization +- Keep worker code in separate files (e.g., `*.worker.js`) +- Use ES modules for imports/exports +- Follow the project's existing module structure + +### 3. Required Headers +When developing locally or deploying, ensure these headers are set: +``` +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp +``` + +### 4. Browser Compatibility +- Primary target: Modern browsers with SharedArrayBuffer support +- Fallback mode: Safari (with limitations) +- Always test in both modes + +### 5. Database Configuration +Recommended database settings: +```sql +PRAGMA journal_mode=MEMORY; +PRAGMA page_size=8192; -- Optional, but recommended +``` + +### 6. Development Workflow +1. Install dependencies: + ```bash + yarn add @jlongster/sql.js absurd-sql + ``` + +2. Development commands: + - `yarn build` - Build the project + - `yarn jest` - Run tests + - `yarn serve` - Start development server + +### 7. Testing Guidelines +- Write tests for both SharedArrayBuffer and fallback modes +- Use Jest for testing +- Include performance benchmarks for critical operations + +### 8. Performance Considerations +- Use bulk operations when possible +- Monitor read/write performance +- Consider using transactions for multiple operations +- Avoid unnecessary database connections + +### 9. Error Handling +- Implement proper error handling for: + - Worker initialization failures + - Database connection issues + - Concurrent access conflicts (in fallback mode) + - Storage quota exceeded scenarios + +### 10. Security Best Practices +- Never expose database operations directly to the client +- Validate all SQL queries +- Implement proper access controls +- Handle sensitive data appropriately + +### 11. Code Style +- Follow ESLint configuration +- Use async/await for asynchronous operations +- Document complex database operations +- Include comments for non-obvious optimizations + +### 12. Debugging +- Use `jest-debug` for debugging tests +- Monitor IndexedDB usage in browser dev tools +- Check worker communication in console +- Use performance monitoring tools + +## Common Patterns + +### Worker Initialization +```javascript +// Main thread +import { initBackend } from 'absurd-sql/dist/indexeddb-main-thread'; + +function init() { + let worker = new Worker(new URL('./index.worker.js', import.meta.url)); + initBackend(worker); +} +``` + +### Database Setup +```javascript +// Worker thread +import initSqlJs from '@jlongster/sql.js'; +import { SQLiteFS } from 'absurd-sql'; +import IndexedDBBackend from 'absurd-sql/dist/indexeddb-backend'; + +async function setupDatabase() { + let SQL = await initSqlJs({ locateFile: file => file }); + let sqlFS = new SQLiteFS(SQL.FS, new IndexedDBBackend()); + SQL.register_for_idb(sqlFS); + + SQL.FS.mkdir('/sql'); + SQL.FS.mount(sqlFS, {}, '/sql'); + + return new SQL.Database('/sql/db.sqlite', { filename: true }); +} +``` + +## Troubleshooting + +### Common Issues +1. SharedArrayBuffer not available + - Check COOP/COEP headers + - Verify browser support + - Test fallback mode + +2. Worker initialization failures + - Check file paths + - Verify module imports + - Check browser console for errors + +3. Performance issues + - Monitor IndexedDB usage + - Check for unnecessary operations + - Verify transaction usage + +## Resources +- [Project Demo](https://priceless-keller-d097e5.netlify.app/) +- [Example Project](https://github.com/jlongster/absurd-example-project) +- [Blog Post](https://jlongster.com/future-sql-web) +- [SQL.js Documentation](https://github.com/sql-js/sql.js/) \ No newline at end of file diff --git a/.cursor/rules/database/legacy_dexie.mdc b/.cursor/rules/database/legacy_dexie.mdc new file mode 100644 index 0000000..5ef0722 --- /dev/null +++ b/.cursor/rules/database/legacy_dexie.mdc @@ -0,0 +1,5 @@ +--- +globs: **/databaseUtil.ts,**/AccountViewView.vue,**/ContactsView.vue,**/DatabaseMigration.vue,**/NewIdentifierView.vue +alwaysApply: false +--- +All references in the codebase to Dexie apply only to migration from IndexedDb to Sqlite and will be deprecated in future versions. \ No newline at end of file diff --git a/.cursor/rules/development/development_guide.mdc b/.cursor/rules/development/development_guide.mdc new file mode 100644 index 0000000..439c1f2 --- /dev/null +++ b/.cursor/rules/development/development_guide.mdc @@ -0,0 +1,9 @@ +--- +globs: **/src/**/* +alwaysApply: false +--- +✅ use system date command to timestamp all interactions with accurate date and time +✅ python script files must always have a blank line at their end +✅ remove whitespace at the end of lines +✅ use npm run lint-fix to check for warnings +✅ do not use npm run dev let me handle running and supplying feedback diff --git a/.cursor/rules/development/type_safety_guide.mdc b/.cursor/rules/development/type_safety_guide.mdc new file mode 100644 index 0000000..507e3f2 --- /dev/null +++ b/.cursor/rules/development/type_safety_guide.mdc @@ -0,0 +1,108 @@ +--- +globs: **/src/**/*,**/scripts/**/*,**/electron/**/* +alwaysApply: false +--- +```json +{ + "coaching_level": "light", + "socratic_max_questions": 7, + "verbosity": "concise", + "timebox_minutes": null, + "format_enforcement": "strict" +} +``` + +# TypeScript Type Safety Guidelines + +**Author**: Matthew Raymer +**Date**: 2025-08-16 +**Status**: 🎯 **ACTIVE** + +## Overview + +Practical rules to keep TypeScript strict and predictable. Minimize exceptions. + +## Core Rules + +1. **No `any`** + - Use explicit types. If unknown, use `unknown` and **narrow** via guards. + +2. **Error handling uses guards** + - Reuse guards from `src/interfaces/**` (e.g., `isDatabaseError`, `isApiError`). + - Catch with `unknown`; never cast to `any`. + +3. **Dynamic property access is type‑safe** + - Use `keyof` + `in` checks: + + ```ts + obj[k as keyof typeof obj] + ``` + + - Avoid `(obj as any)[k]`. + +## Minimal Special Cases (document in PR when used) + +- **Vue refs / instances**: Use `ComponentPublicInstance` or specific component + types for dynamic refs. +- **3rd‑party libs without types**: Narrow immediately to a **known interface**; + do not leave `any` hanging. + +## Patterns (short) + +### Database errors + +```ts +try { await this.$addContact(contact); } +catch (e: unknown) { + if (isDatabaseError(e) && e.message.includes("Key already exists")) { + /* handle duplicate */ + } +} +``` + +### API errors + +```ts +try { await apiCall(); } +catch (e: unknown) { + if (isApiError(e)) { + const msg = e.response?.data?.error?.message; + } +} +``` + +### Dynamic keys + +```ts +const keys = Object.keys(newSettings).filter( + k => k in newSettings && newSettings[k as keyof typeof newSettings] !== undefined +); +``` + +## Checklists + +**Before commit** + +- [ ] No `any` (except documented, justified cases) +- [ ] Errors handled via guards +- [ ] Dynamic access uses `keyof`/`in` +- [ ] Imports point to correct interfaces/types + +**Code review** + +- [ ] Hunt hidden `as any` +- [ ] Guard‑based error paths verified +- [ ] Dynamic ops are type‑safe +- [ ] Prefer existing types over re‑inventing + +## Tools + +- `npm run lint-fix` — lint & auto‑fix +- `npm run type-check` — strict type compilation (CI + pre‑release) +- IDE: enable strict TS, ESLint/TS ESLint, Volar (Vue 3) + +## References + +- TS Handbook — https://www.typescriptlang.org/docs/ +- TS‑ESLint — https://typescript-eslint.io/rules/ +- Vue 3 + TS — https://vuejs.org/guide/typescript/ diff --git a/.cursor/rules/docs/documentation.mdc b/.cursor/rules/docs/documentation.mdc new file mode 100644 index 0000000..e1a096c --- /dev/null +++ b/.cursor/rules/docs/documentation.mdc @@ -0,0 +1,345 @@ +# Documentation Generation — Human Competence First + +**Author**: Matthew Raymer +**Date**: 2025-08-17 +**Status**: 🎯 **ACTIVE** - Core Documentation Standards + +## Overview + +This guide establishes **how documentation should be created and maintained** +across all projects, emphasizing **human competence building** and +**collaborative learning** while ensuring technical accuracy and maintainability. + +## Core Principles (Human Competence First) + +### 1. **Learning Over Information Dumping** + +- **Educational value**: Documents must clearly explain system workings +- **Progressive complexity**: Start simple, build to advanced concepts +- **Real-world examples**: Include practical, actionable examples +- **Why it matters**: Understanding the "why" builds deeper competence + +### 2. **Collaboration Over Isolation** + +- **Team review**: Documentation should invite discussion and iteration +- **Shared ownership**: Multiple perspectives improve quality and accuracy +- **Feedback loops**: Regular review cycles keep content relevant +- **Why it matters**: Collaborative documentation builds team knowledge + +### 3. **Maintainability Over Completeness** + +- **Small, focused sets**: Prefer depth over breadth +- **Worth preserving**: Content must motivate humans to keep it updated +- **Clear ownership**: Designate maintainers for each document +- **Why it matters**: Maintainable docs stay useful over time + +### 4. **Quality Over Quantity** + +- **Avoid filler**: No shallow, generic, or AI-generated explanations +- **Clarity first**: Complex concepts explained simply +- **Actionable content**: Readers should know what to do next +- **Why it matters**: Quality content builds trust and competence + +## Documentation Standards + +### Content Structure + +#### Document Header (Required) + +```markdown +# Document Title + +**Author**: [Name] +**Date**: YYYY-MM-DD +**Status**: 🎯 **STATUS** - Brief description +**Maintainer**: [Name] + +## Overview + +Brief description of the document's purpose and scope. +``` + +#### Section Organization + +1. **Overview/Introduction** - Purpose and scope +2. **Current State** - What exists now +3. **Implementation Details** - How things work +4. **Examples** - Real-world usage +5. **Next Steps** - What to do next +6. **References** - Related resources + +### Writing Guidelines + +#### **For LLMs (Required)** + +- **Always start with purpose**: Why does this document exist? +- **Include learning objectives**: What will readers understand after reading? +- **Provide examples**: Show, don't just tell +- **End with action**: What should readers do next? + +#### **For Human Writers** + +- **Write for your future self**: Will you understand this in 6 months? +- **Consider skill levels**: Different readers have different needs +- **Include context**: Why does this matter for the project? +- **Invite feedback**: How can this be improved? + +## Documentation Types + +### 1. **Technical Guides** + +- **Purpose**: Explain how systems work +- **Audience**: Developers, engineers, technical users +- **Focus**: Implementation details, APIs, configurations +- **Examples**: Code snippets, configuration files, diagrams + +### 2. **Process Documentation** + +- **Purpose**: Explain how to accomplish tasks +- **Audience**: Team members, stakeholders +- **Focus**: Step-by-step procedures, workflows +- **Examples**: Checklists, flowcharts, decision trees + +### 3. **Architecture Documents** + +- **Purpose**: Explain system design and structure +- **Audience**: Architects, developers, stakeholders +- **Focus**: High-level design, trade-offs, decisions +- **Examples**: System diagrams, ADRs, design patterns + +### 4. **User Guides** + +- **Purpose**: Help users accomplish goals +- **Audience**: End users, customers +- **Focus**: User workflows, features, troubleshooting +- **Examples**: Screenshots, step-by-step instructions + +## Quality Assurance + +### **Before Publishing Documentation** + +- [ ] **Purpose clear**: Why does this document exist? +- [ ] **Audience defined**: Who is this written for? +- [ ] **Examples included**: Are there practical examples? +- [ ] **Actionable**: Do readers know what to do next? +- [ ] **Maintainable**: Is it easy to keep updated? +- [ ] **Collaborative**: Does it invite team input? + +### **After Publishing Documentation** + +- [ ] **Feedback collected**: Have team members reviewed it? +- [ ] **Usage tracked**: Are people actually using it? +- [ ] **Updates planned**: When will it be reviewed next? +- [ ] **Ownership clear**: Who maintains this document? + +## Implementation Examples + +### Good Documentation Example + +```markdown +# User Authentication System + +**Author**: Matthew Raymer +**Date**: 2025-08-17 +**Status**: 🎯 **ACTIVE** - Production System +**Maintainer**: Security Team + +## Overview + +This document explains how user authentication works in our system, +including login flows, security measures, and troubleshooting steps. + +## Learning Objectives + +After reading this document, you will understand: +- How users log in and authenticate +- What security measures protect user accounts +- How to troubleshoot common authentication issues +- When to escalate security concerns + +## Current Implementation + +### Login Flow + +1. User enters credentials +2. System validates against database +3. JWT token generated and returned +4. Token stored in secure cookie + +### Security Measures + +- Password hashing with bcrypt +- Rate limiting on login attempts +- JWT expiration after 24 hours +- HTTPS enforcement for all auth requests + +## Examples + +### Login Request + +```json +POST /api/auth/login +{ + "email": "user@example.com", + "password": "securepassword123" +} +``` + +### Successful Response + +```json +{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "expires": "2025-08-18T12:00:00Z" +} +``` + +## Troubleshooting + +### Common Issues + +- **Invalid credentials**: Check email/password combination +- **Token expired**: User needs to log in again +- **Rate limited**: Wait 15 minutes before retrying + +### Escalation Path + +1. Check system logs for errors +2. Verify database connectivity +3. Contact security team if suspicious activity + +## Next Steps + +1. **Test the system**: Try logging in with test credentials +2. **Review security**: Ensure your implementation follows these patterns +3. **Document issues**: Add new troubleshooting steps as you discover them + +## References + +- [JWT Documentation](https://jwt.io/) +- [Security Best Practices](./security-guide.md) +- [API Reference](./api-docs.md) + +--- + +**Last Updated**: 2025-08-17 +**Next Review**: 2025-09-17 +**Stakeholders**: Development Team, Security Team, Product Team + +### Bad Documentation Example + +```markdown +# Authentication + +This document describes the authentication system. + +## Overview + +The system has authentication. + +## Implementation + +Users can log in. + +## Conclusion + +That's how authentication works. +``` + +## Collaboration Points + +### **Code Reviews** + +- Include documentation updates in code review process +- Ensure new features have corresponding documentation +- Validate that examples match actual implementation + +### **Team Reviews** + +- Schedule regular documentation review sessions +- Invite different team members to review content +- Collect feedback on clarity and usefulness + +### **User Testing** + +- Have actual users try to follow documentation +- Observe where they get stuck or confused +- Update content based on real usage patterns + +## Maintenance Schedule + +### **Weekly** + +- Review documentation usage metrics +- Collect feedback from team members +- Plan updates for outdated content + +### **Monthly** + +- Full review of high-priority documents +- Update examples and screenshots +- Validate links and references + +### **Quarterly** + +- Comprehensive review of all documentation +- Identify gaps and opportunities +- Plan major documentation projects + +## Success Metrics + +### **Usage Metrics** + +- **Document views**: How often is content accessed? +- **Time on page**: How long do readers spend? +- **Search queries**: What are people looking for? + +### **Quality Metrics** + +- **Feedback scores**: How do readers rate content? +- **Update frequency**: How often is content refreshed? +- **Maintainer satisfaction**: Are maintainers happy with their docs? + +### **Competence Metrics** + +- **Question reduction**: Fewer basic questions from team? +- **Implementation speed**: Faster feature development? +- **Knowledge transfer**: Better onboarding for new team members? + +## Tools and Resources + +### **Documentation Platforms** + +- **Markdown**: Standard format for technical documentation +- **GitBook**: Collaborative documentation hosting +- **Notion**: Team knowledge management +- **Confluence**: Enterprise documentation platform + +### **Quality Tools** + +- **Markdown linting**: Ensure consistent formatting +- **Link checking**: Validate references and links +- **Spell checking**: Maintain professional appearance +- **Accessibility**: Ensure content is usable by all + +### **Collaboration Tools** + +- **Version control**: Track changes and history +- **Review systems**: Collect feedback and approvals +- **Analytics**: Understand usage patterns +- **Notifications**: Keep team informed of updates + +## Implementation Next Steps + +1. **Review existing documentation**: Apply these principles to current docs +2. **Identify gaps**: What documentation is missing or outdated? +3. **Plan improvements**: Prioritize documentation updates +4. **Establish processes**: Set up regular review and update cycles + +--- + +**Last Updated**: 2025-08-17 +**Version**: 2.0 +**Maintainer**: Matthew Raymer +**Stakeholders**: All Teams +**Next Review**: 2025-09-17 diff --git a/.cursor/rules/docs/markdown.mdc b/.cursor/rules/docs/markdown.mdc new file mode 100644 index 0000000..b0e0c2d --- /dev/null +++ b/.cursor/rules/docs/markdown.mdc @@ -0,0 +1,570 @@ +# Cursor Markdown Ruleset for TimeSafari Documentation + +## Overview + +This ruleset enforces consistent markdown formatting standards across all project +documentation, ensuring readability, maintainability, and compliance with +markdownlint best practices. **LLMs must follow these rules strictly to generate +lint-free documentation.** + +## General Formatting Standards + +### Line Length + +- **Maximum line length**: 80 characters +- **Exception**: Code blocks (JSON, shell, TypeScript, etc.) - no line length + enforcement +- **Rationale**: Ensures readability across different screen sizes and terminal + widths +- **LLM Guidance**: Always count characters and break lines at 80 characters + unless in code blocks + +### Blank Lines + +- **Headings**: Must be surrounded by blank lines above and below +- **Lists**: Must be surrounded by blank lines above and below +- **Code blocks**: Must be surrounded by blank lines above and below +- **Maximum consecutive blank lines**: 1 (no multiple blank lines) +- **File start**: No blank lines at the beginning of the file +- **File end**: Single newline character at the end +- **LLM Guidance**: Always add blank lines around structural elements + +### Whitespace + +- **No trailing spaces**: Remove all trailing whitespace from lines +- **No tabs**: Use spaces for indentation +- **Consistent indentation**: 2 spaces for list items and nested content +- **LLM Guidance**: Use space characters only, never tabs + +## Heading Standards + +### Format + +- **Style**: ATX-style headings (`#`, `##`, `###`, etc.) +- **Case**: Title case for general headings +- **Code references**: Use backticks for file names and technical terms + - ✅ `### Current package.json Scripts` + - ❌ `### Current Package.json Scripts` +- **LLM Guidance**: Always use ATX style, never use Setext style (`===` or `---`) + +### Hierarchy + +- **H1 (#)**: Document title only - **ONE PER DOCUMENT** +- **H2 (##)**: Major sections +- **H3 (###)**: Subsections +- **H4 (####)**: Sub-subsections +- **H5+**: Avoid deeper nesting +- **LLM Guidance**: Start every document with exactly one H1, maintain logical + hierarchy + +### Heading Content Rules + +- **No trailing punctuation**: Avoid periods, colons, etc. at end +- **No duplicate headings**: Each heading must be unique within the document +- **Descriptive but concise**: Headings should clearly describe the section +- **LLM Guidance**: Use action-oriented headings, avoid generic terms like + "Overview" + +## List Standards + +### Unordered Lists + +- **Marker**: Use `-` (hyphen) consistently +- **Indentation**: 2 spaces for nested items +- **Blank lines**: Surround lists with blank lines +- **LLM Guidance**: Always use hyphens, never use asterisks or plus signs + +### Ordered Lists + +- **Format**: `1.`, `2.`, `3.` (sequential numbering) +- **Indentation**: 2 spaces for nested items +- **Blank lines**: Surround lists with blank lines +- **LLM Guidance**: Use sequential numbers, never skip numbers or use random + numbers + +### Task Lists + +- **Format**: `- [ ]` for incomplete, `- [x]` for complete +- **Use case**: Project planning, checklists, implementation tracking +- **LLM Guidance**: Use consistent spacing in brackets `[ ]` not `[ ]` + +## Code Block Standards + +### Fenced Code Blocks + +- **Syntax**: Triple backticks with language specification +- **Languages**: `json`, `bash`, `typescript`, `javascript`, `yaml`, `markdown` +- **Blank lines**: Must be surrounded by blank lines above and below +- **Line length**: No enforcement within code blocks +- **LLM Guidance**: Always specify language, never use generic code blocks + +### Inline Code + +- **Format**: Single backticks for inline code references +- **Use case**: File names, commands, variables, properties +- **LLM Guidance**: Use backticks for any technical term, file path, or command + +## Special Content Standards + +### JSON Examples + +```json +{ + "property": "value", + "nested": { + "property": "value" + } +} +``` + +### Shell Commands + +```bash +# Command with comment +npm run build:web + +# Multi-line command +VITE_GIT_HASH=`git log -1 --pretty=format:%h` \ + vite build --config vite.config.web.mts +``` + +### TypeScript Examples + +```typescript +// Function with JSDoc +/** + * Get environment configuration + * @param env - Environment name + * @returns Environment config object + */ +const getEnvironmentConfig = (env: string) => { + switch (env) { + case 'prod': + return { /* production settings */ }; + default: + return { /* development settings */ }; + } +}; +``` + +## File Structure Standards + +### Document Header + +```markdown +# Document Title + +**Author**: Matthew Raymer +**Date**: YYYY-MM-DD +**Status**: 🎯 **STATUS** - Brief description + +## Overview + +Brief description of the document's purpose and scope. +``` + +### Section Organization + +1. **Overview/Introduction** +2. **Current State Analysis** +3. **Implementation Plan** +4. **Technical Details** +5. **Testing & Validation** +6. **Next Steps** + +## Enhanced Markdownlint Configuration + +### Required Rules (Comprehensive) + +```json +{ + "MD013": { "code_blocks": false, "line_length": 80 }, + "MD012": true, + "MD022": true, + "MD031": true, + "MD032": true, + "MD047": true, + "MD009": true, + "MD024": true, + "MD025": true, + "MD026": { "punctuation": ".,;:!" }, + "MD029": { "style": "ordered" }, + "MD030": { "ul_single": 1, "ol_single": 1, "ul_multi": 1, "ol_multi": 1 }, + "MD033": false, + "MD041": true, + "MD046": { "style": "fenced" }, + "MD018": true, + "MD019": true, + "MD020": true, + "MD021": true, + "MD023": true, + "MD027": true, + "MD028": true, + "MD036": true, + "MD037": true, + "MD038": true, + "MD039": true, + "MD040": true, + "MD042": true, + "MD043": true, + "MD044": true, + "MD045": true +} +``` + +### Rule Explanations (LLM Must Follow) + +- **MD013**: Line length (80 chars max, disabled for code blocks) +- **MD012**: No multiple consecutive blank lines +- **MD022**: Headings must be surrounded by blank lines +- **MD031**: Fenced code blocks must be surrounded by blank lines +- **MD032**: Lists must be surrounded by blank lines +- **MD047**: Files must end with single newline +- **MD009**: No trailing spaces +- **MD024**: No duplicate headings +- **MD025**: Only one H1 per document +- **MD026**: No trailing punctuation in headings +- **MD029**: Ordered list item prefix style +- **MD030**: List item marker styles +- **MD033**: Allow inline HTML (disabled for flexibility) +- **MD041**: First line must be top-level heading +- **MD046**: Code block style (fenced only) +- **MD018**: Heading should have space after hash +- **MD019**: Heading should have space after hash +- **MD020**: Heading should have space after hash +- **MD021**: Heading should have space after hash +- **MD023**: Heading should start at beginning of line +- **MD027**: No multiple spaces after blockquote marker +- **MD028**: No blank line inside blockquote +- **MD036**: No emphasis used for headings +- **MD037**: No spaces inside emphasis markers +- **MD038**: No spaces inside code span markers +- **MD039**: No spaces inside link text +- **MD040**: Fenced code blocks should have language specified +- **MD042**: No empty links +- **MD043**: Required heading structure +- **MD044**: Line length in code blocks +- **MD045**: No images without alt text + +## LLM-Specific Language Guidelines + +### **CRITICAL: LLM Must Follow These Rules** + +#### 1. **Heading Generation** + +- **Always start with H1**: Every document must have exactly one + `# Document Title` +- **Use descriptive headings**: Avoid generic terms like "Overview", + "Details", "Information" +- **Maintain hierarchy**: H2 for major sections, H3 for subsections +- **No duplicate headings**: Each heading must be unique within the document + +#### 2. **List Formatting** + +- **Unordered lists**: Always use `-` (hyphen), never `*` or `+` +- **Ordered lists**: Use sequential numbers `1.`, `2.`, `3.` +- **Consistent spacing**: Always use 2 spaces for indentation +- **Blank lines**: Surround all lists with blank lines + +#### 3. **Code and Technical Content** + +- **Inline code**: Use backticks for any technical term, file path, or command +- **Code blocks**: Always specify language, never use generic blocks +- **File references**: Always use backticks for file names and paths + +#### 4. **Line Length Management** + +- **Count characters**: Ensure no line exceeds 80 characters +- **Break naturally**: Break at word boundaries when possible +- **Code blocks**: No line length enforcement within code blocks + +#### 5. **Whitespace Rules** + +- **No trailing spaces**: Never leave spaces at end of lines +- **No tabs**: Use spaces only for indentation +- **Blank lines**: Use exactly one blank line between sections + +## Enhanced Validation Commands + +### Check Single File + +```bash +npx markdownlint docs/filename.md +``` + +### Check All Documentation + +```bash +npx markdownlint docs/ +``` + +### Check with Custom Config + +```bash +npx markdownlint --config .markdownlint.json docs/ +``` + +### Generate Detailed Report + +```bash +npx markdownlint --config .markdownlint.json --output markdownlint-report.txt docs/ +``` + +### Check Specific Rules + +```bash +npx markdownlint --rules MD013,MD012,MD022,MD024,MD025 docs/ +``` + +### Project-Wide Validation + +```bash +# Check all markdown files in project +find . -name "*.md" -exec npx markdownlint {} \; + +# Check specific directories +npx markdownlint .cursor/rules/ docs/ README.md + +# Check with verbose output +npx markdownlint --verbose docs/ +``` + +### Auto-fix Common Issues + +```bash +# Remove trailing spaces +sed -i 's/[[:space:]]*$//' docs/filename.md + +# Remove multiple blank lines +sed -i '/^$/N;/^\n$/D' docs/filename.md + +# Add newline at end if missing +echo "" >> docs/filename.md + +# Fix heading spacing +sed -i 's/^# /# /g' docs/filename.md +``` + +## Common Patterns + +### Implementation Plans + +```markdown +## Implementation Plan + +### Phase 1: Foundation + +#### 1.1 Component Setup + +- [ ] Create new component file +- [ ] Add basic structure +- [ ] Implement core functionality + +#### 1.2 Configuration + +- [ ] Update configuration files +- [ ] Add environment variables +- [ ] Test configuration loading +``` + +### Status Tracking + +```markdown +**Status**: ✅ **COMPLETE** - All phases finished +**Progress**: 75% (15/20 components) +**Next**: Ready for testing phase +``` + +### Performance Metrics + +```markdown +#### 📊 Performance Metrics +- **Build Time**: 2.3 seconds (50% faster than baseline) +- **Bundle Size**: 1.2MB (30% reduction) +- **Success Rate**: 100% (no failures in 50 builds) +``` + +## Enforcement + +### Pre-commit Hooks + +```bash +#!/bin/bash +# .git/hooks/pre-commit +# Check markdown files before commit + +echo "Running markdownlint..." + +# Get list of staged markdown files +staged_md_files=$(git diff --cached --name-only --diff-filter=ACM | grep '\.md$') + +if [ -n "$staged_md_files" ]; then + echo "Checking markdown files: $staged_md_files" + + # Run markdownlint on staged files + npx markdownlint $staged_md_files + + if [ $? -ne 0 ]; then + echo "❌ Markdown linting failed. Please fix issues before committing." + exit 1 + fi + + echo "✅ Markdown linting passed." +fi +``` + +### CI/CD Integration + +```yaml +# .github/workflows/markdown-lint.yml +name: Markdown Lint + +on: + push: + paths: ['**/*.md'] + pull_request: + paths: ['**/*.md'] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install markdownlint + run: npm install -g markdownlint-cli + + - name: Run markdownlint + run: markdownlint --config .markdownlint.json . + + - name: Generate report + run: markdownlint --config .markdownlint.json --output lint-report.txt . + + - name: Upload report + uses: actions/upload-artifact@v3 + with: + name: markdown-lint-report + path: lint-report.txt +``` + +### Team Guidelines + +- All documentation PRs must pass markdownlint +- Use provided templates for new documents +- Follow established patterns for consistency +- **LLM-generated content must pass all linting rules** + +## Templates + +### New Document Template + +```markdown +# Document Title + +**Author**: Matthew Raymer +**Date**: YYYY-MM-DD +**Status**: 🎯 **PLANNING** - Ready for Implementation + +## Overview + +Brief description of the document's purpose and scope. + +## Current State + +Description of current situation or problem. + +## Implementation Plan + +### Phase 1: Foundation + +- [ ] Task 1 +- [ ] Task 2 + +## Next Steps + +1. **Review and approve plan** +2. **Begin implementation** +3. **Test and validate** + +--- + +**Status**: Ready for implementation +**Priority**: Medium +**Estimated Effort**: X days +**Dependencies**: None +**Stakeholders**: Development team +``` + +### Rule File Template + +```markdown +# Rule Name + +**Purpose**: Brief description of what this rule accomplishes + +## Overview + +Detailed explanation of the rule's scope and importance. + +## Implementation + +### Requirements + +- [ ] Requirement 1 +- [ ] Requirement 2 + +### Examples + +#### ✅ Good Example + +```markdown +# Good example content +``` + +#### ❌ Bad Example + +```markdown +# Bad example content +``` + +## Validation + +How to test that this rule is working correctly. + +--- + +**Status**: Active +**Version**: 1.0 +**Maintainer**: Matthew Raymer + +## LLM Quality Assurance Checklist + +### **Before Generating Documentation, LLM Must:** + +- [ ] **Understand line length**: No line over 80 characters +- [ ] **Plan heading structure**: One H1, logical hierarchy, no duplicates +- [ ] **Choose list markers**: Hyphens for unordered, sequential numbers for ordered +- [ ] **Plan code blocks**: Specify languages, add blank lines around +- [ ] **Check whitespace**: No trailing spaces, consistent indentation +- [ ] **Validate structure**: Proper blank line placement + +### **After Generating Documentation, LLM Must:** + +- [ ] **Verify line lengths**: Count characters, break long lines +- [ ] **Check heading hierarchy**: Ensure logical structure +- [ ] **Validate lists**: Consistent markers and spacing +- [ ] **Review code blocks**: Proper language specification +- [ ] **Clean whitespace**: Remove trailing spaces, add proper blank lines +- [ ] **Test with markdownlint**: Ensure all rules pass + +--- + +**Last Updated**: 2025-08-17 +**Version**: 2.0 +**Maintainer**: Matthew Raymer +**LLM Compliance**: Required for all documentation generation diff --git a/.cursor/rules/documentation.mdc b/.cursor/rules/documentation.mdc deleted file mode 100644 index 4b02917..0000000 --- a/.cursor/rules/documentation.mdc +++ /dev/null @@ -1,19 +0,0 @@ ---- -globs: *.md -alwaysApply: false ---- - -INITIAL_PLAN.md is unique to projects built inhouse and must never be deleted. -Maintain traditional files (README, CHANGELOG, BUILDING, etc.) -Any ad hoc files must always be put into docs folder -The docs folder must use sub-folders to classify documents by -There must never be more than seven folders at any sub-folder of the docs tree -Keep documents no more than seven in number for a folder. -If you need more documents than seven, make sub-folders to classify or re-classify documents. -Re-use documents by ammending or editing but always version them in git. -put documentation at the file, classs, and method heads - -Documents themselves must: - -Headings should be surrounded by blank lines -Lists should be surrounded by blank \ No newline at end of file diff --git a/.cursor/rules/features/camera-implementation.mdc b/.cursor/rules/features/camera-implementation.mdc new file mode 100644 index 0000000..e7fef13 --- /dev/null +++ b/.cursor/rules/features/camera-implementation.mdc @@ -0,0 +1,222 @@ +--- +description: +globs: +alwaysApply: false +--- +# Camera Implementation Documentation + +## Overview + +This document describes how camera functionality is implemented across the TimeSafari application. The application uses cameras for two main purposes: + +1. QR Code scanning +2. Photo capture + +## Components + +### QRScannerDialog.vue + +Primary component for QR code scanning in web browsers. + +**Key Features:** + +- Uses `qrcode-stream` for web-based QR scanning +- Supports both front and back cameras +- Provides real-time camera status feedback +- Implements error handling with user-friendly messages +- Includes camera switching functionality + +**Camera Access Flow:** + +1. Checks for camera API availability +2. Enumerates available video devices +3. Requests camera permissions +4. Initializes camera stream with preferred settings +5. Handles various error conditions with specific messages + +### PhotoDialog.vue + +Component for photo capture and selection. + +**Key Features:** + +- Cross-platform photo capture interface +- Image cropping capabilities +- File selection fallback +- Unified interface for different platforms + +## Services + +### QRScanner Services + +#### WebDialogQRScanner + +Web-based implementation of QR scanning. + +**Key Methods:** + +- `checkPermissions()`: Verifies camera permission status +- `requestPermissions()`: Requests camera access +- `isSupported()`: Checks for camera API support +- Handles various error conditions with specific messages + +#### CapacitorQRScanner + +Native implementation using Capacitor's MLKit. + +**Key Features:** + +- Uses `@capacitor-mlkit/barcode-scanning` +- Supports both front and back cameras +- Implements permission management +- Provides continuous scanning capability + +### Platform Services + +#### WebPlatformService + +Web-specific implementation of platform features. + +**Camera Capabilities:** + +- Uses HTML5 file input with capture attribute +- Falls back to file selection if camera unavailable +- Processes captured images for consistent format + +#### CapacitorPlatformService + +Native implementation using Capacitor. + +**Camera Features:** + +- Uses `Camera.getPhoto()` for native camera access +- Supports image editing +- Configures high-quality image capture +- Handles base64 image processing + +#### ElectronPlatformService + +Desktop implementation (currently unimplemented). + +**Status:** + +- Camera functionality not yet implemented +- Planned to use Electron's media APIs + +## Platform-Specific Considerations + +### iOS + +- Requires `NSCameraUsageDescription` in Info.plist +- Supports both front and back cameras +- Implements proper permission handling + +### Android + +- Requires camera permissions in manifest +- Supports both front and back cameras +- Handles permission requests through Capacitor + +### Web + +- Requires HTTPS for camera access +- Implements fallback mechanisms +- Handles browser compatibility issues + +## Error Handling + +### Common Error Scenarios + +1. No camera found +2. Permission denied +3. Camera in use by another application +4. HTTPS required +5. Browser compatibility issues + +### Error Response + +- User-friendly error messages +- Troubleshooting tips +- Clear instructions for resolution +- Platform-specific guidance + +## Security Considerations + +### Permission Management + +- Explicit permission requests +- Permission state tracking +- Graceful handling of denied permissions + +### Data Handling + +- Secure image processing +- Proper cleanup of camera resources +- No persistent storage of camera data + +## Best Practices + +### Camera Access + +1. Always check for camera availability +2. Request permissions explicitly +3. Handle all error conditions +4. Provide clear user feedback +5. Implement proper cleanup + +### Performance + +1. Optimize camera resolution +2. Implement proper resource cleanup +3. Handle camera switching efficiently +4. Manage memory usage + +### User Experience + +1. Clear status indicators +2. Intuitive camera controls +3. Helpful error messages +4. Smooth camera switching +5. Responsive UI feedback + +## Future Improvements + +### Planned Enhancements + +1. Implement Electron camera support +2. Add advanced camera features +3. Improve error handling +4. Enhance user feedback +5. Optimize performance + +### Known Issues + +1. Electron camera implementation pending +2. Some browser compatibility limitations +3. Platform-specific quirks to address + +## Dependencies + +### Key Packages + +- `@capacitor-mlkit/barcode-scanning` +- `qrcode-stream` +- `vue-picture-cropper` +- Platform-specific camera APIs + +## Testing + +### Test Scenarios + +1. Permission handling +2. Camera switching +3. Error conditions +4. Platform compatibility +5. Performance metrics + +### Test Environment + +- Multiple browsers +- iOS and Android devices +- Desktop platforms +- Various network conditions diff --git a/.cursor/rules/general_development.mdc b/.cursor/rules/general_development.mdc deleted file mode 100644 index 3dca909..0000000 --- a/.cursor/rules/general_development.mdc +++ /dev/null @@ -1,3 +0,0 @@ ---- -alwaysApply: true ---- diff --git a/.cursor/rules/logging.mdc b/.cursor/rules/logging.mdc deleted file mode 100644 index 777f159..0000000 --- a/.cursor/rules/logging.mdc +++ /dev/null @@ -1,6 +0,0 @@ ---- -alwaysApply: true ---- -Always use structlog with rich contextual annotation -All logs should go to rsyslog -Logs showing in console should be set to whatever is needed at that time. diff --git a/.cursor/rules/progress_reports.mdc b/.cursor/rules/progress_reports.mdc deleted file mode 100644 index c1ee163..0000000 --- a/.cursor/rules/progress_reports.mdc +++ /dev/null @@ -1,6 +0,0 @@ ---- -alwaysApply: true ---- -progress reports are based on git commit messages and file differences for that day -reports are in conversational style -do not be a bean counter unless otherwise instructed \ No newline at end of file diff --git a/.cursor/rules/research_diagnostic.mdc b/.cursor/rules/research_diagnostic.mdc new file mode 100644 index 0000000..73d1b1c --- /dev/null +++ b/.cursor/rules/research_diagnostic.mdc @@ -0,0 +1,135 @@ +--- +description: Use this workflow when doing **pre-implementation research, defect investigations with uncertain repros, or clarifying system architecture and behaviors**. +alwaysApply: false +--- +```json +{ + "coaching_level": "light", + "socratic_max_questions": 2, + "verbosity": "concise", + "timebox_minutes": null, + "format_enforcement": "strict" +} +``` + +# Research & Diagnostic Workflow (R&D) + +## Purpose + +Provide a **repeatable, evidence-first** workflow to investigate features and +defects **before coding**. Outputs are concise reports, hypotheses, and next +steps—**not** code changes. + +## When to Use + +- Pre-implementation research for new features +- Defect investigations (repros uncertain, user-specific failures) +- Architecture/behavior clarifications (e.g., auth flows, merges, migrations) + +--- + +## Output Contract (strict) + +1) **Objective** — 1–2 lines +2) **System Map (if helpful)** — short diagram or bullet flow (≤8 bullets) +3) **Findings (Evidence-linked)** — bullets; each with file/function refs +4) **Hypotheses & Failure Modes** — short list, each testable +5) **Corrections** — explicit deltas from earlier assumptions (if any) +6) **Diagnostics** — what to check next (logs, DB, env, repro steps) +7) **Risks & Scope** — what could break; affected components +8) **Decision/Next Steps** — what we’ll do, who’s involved, by when +9) **References** — code paths, ADRs, docs +10) **Competence & Collaboration Hooks** — brief, skimmable + +> Keep total length lean. Prefer links and bullets over prose. + +--- + +## Quickstart Template + +Copy/paste and fill: + +```md +# Investigation — + +## Objective + + +## System Map +- +- + +## Findings (Evidence) +- — evidence: `src/path/file.ts:function` (lines X–Y); log snippet/trace id +- — evidence: `...` + +## Hypotheses & Failure Modes +- H1: ; would fail when +- H2: ; watch for + +## Corrections +- Updated: + +## Diagnostics (Next Checks) +- [ ] Repro on +- [ ] Inspect for +- [ ] Capture + +## Risks & Scope +- Impacted: ; Data: ; Users: + +## Decision / Next Steps +- Owner: ; By: (YYYY-MM-DD) +- Action: ; Exit criteria: + +## References +- `src/...` +- ADR: `docs/adr/xxxx-yy-zz-something.md` +- Design: `docs/...` + +## Competence Hooks +- Why this works: <≤3 bullets> +- Common pitfalls: <≤3 bullets> +- Next skill: <≤1 item> +- Teach-back: "" +``` + +--- + +## Evidence Quality Bar + +- **Cite the source** (file:func, line range if possible). +- **Prefer primary evidence** (code, logs) over inference. +- **Disambiguate platform** (Web/Capacitor/Electron) and **state** (migration, auth). +- **Note uncertainty** explicitly. + +--- + +## Collaboration Hooks + +- **Syncs:** 10–15m with QA/Security/Platform owners for high-risk areas. +- **ADR:** Record major decisions; link here. +- **Review:** Share repro + diagnostics checklist in PR/issue. + +--- + +## Self-Check (model, before responding) + +- [ ] Output matches the **Output Contract** sections. +- [ ] Each claim has **evidence** or **uncertainty** is flagged. +- [ ] Hypotheses are testable; diagnostics are actionable. +- [ ] Competence + collaboration hooks present (≤120 words total). +- [ ] Respect toggles; keep it concise. + +--- + +## Optional Globs (examples) + +> Uncomment `globs` in the header if you want auto-attach behavior. + +- `src/platforms/**`, `src/services/**` — attach during service/feature investigations +- `docs/adr/**` — attach when editing ADRs + +## Referenced Files + +- Consider including templates as context: `@adr_template.md`, `@investigation_report_example.md` diff --git a/.cursor/rules/time.mdc b/.cursor/rules/time.mdc index 3534990..f7376d9 100644 --- a/.cursor/rules/time.mdc +++ b/.cursor/rules/time.mdc @@ -1,5 +1,284 @@ +# Time Handling in Development Workflow + +This guide establishes **how time should be referenced and used** across the development workflow. +It is not tied to any one project, but applies to **all feature development, issue investigations, ADRs, and documentation**. + --- -alwaysApply: true + +## 1. General Principles + +- **Explicit over relative**: Always prefer absolute dates (`2025-08-17`) over relative references like "last week." +- **ISO 8601 Standard**: Use `YYYY-MM-DD` format for all date references in docs, issues, ADRs, and commits. +- **Time zones**: Default to **UTC** unless explicitly tied to user-facing behavior. +- **Precision**: Only specify as much precision as needed (date vs. datetime vs. timestamp). +- **Consistency**: Align time references across ADRs, commits, and investigation reports. + --- -Eagerly query the local system for time in UTC -Use local system time for all time sense, queries, and calculations involving time. + +## 2. In Documentation & ADRs + +- Record decision dates using **absolute ISO dates**. +- For ongoing timelines, state start and end explicitly (e.g., `2025-08-01` → `2025-08-17`). +- Avoid ambiguous terms like *recently*, *last month*, or *soon*. +- For time-based experiments (e.g., A/B tests), always include: + - Start date + - Expected duration + - Review date checkpoint + +--- + +## 3. In Code & Commits + +- Use **UTC timestamps** in logs, DB migrations, and serialized formats. +- In commits, link changes to **date-bound ADRs or investigation docs**. +- For migrations, include both **applied date** and **intended version window**. +- Use constants for known fixed dates; avoid hardcoding arbitrary strings. + +--- + +## 4. In Investigations & Research + +- Capture **when** an issue occurred (absolute time or version tag). +- When describing failures: note whether they are **time-sensitive** (e.g., after migrations, cache expirations). +- Record diagnostic timelines in ISO format (not relative). +- For performance regressions, annotate both **baseline timeframe** and **measurement timeframe**. + +--- + +## 5. Collaboration Hooks + +- During reviews, verify **time references are clear, absolute, and standardized**. +- In syncs, reframe relative terms ("this week") into shared absolute references. +- Tag ADRs with both **date created** and **review by** checkpoints. + +--- + +## 6. Self-Check Before Submitting + +- [ ] Did I check the time using the **developer's actual system time and timezone**? +- [ ] Am I using absolute ISO dates? +- [ ] Is UTC assumed unless specified otherwise? +- [ ] Did I avoid ambiguous relative terms? +- [ ] If duration matters, did I specify both start and end? +- [ ] For future work, did I include a review/revisit date? + +--- + +## 7. Real-Time Context in Developer Interactions + +- The model must always resolve **"current time"** using the **developer's actual system time and timezone**. +- When generating timestamps (e.g., in investigation logs, ADRs, or examples), the model should: + - Use the **developer's current local time** by default. + - Indicate the timezone explicitly (e.g., `2025-08-17T10:32-05:00`). + - Optionally provide UTC alongside if context requires cross-team clarity. +- When interpreting relative terms like *now*, *today*, *last week*: + - Resolve them against the **developer's current time**. + - Convert them into **absolute ISO-8601 values** in the output. + +## 7.1. LLM Time Checking Instructions + +**CRITICAL**: The LLM must actively query the system for current time rather than assuming or inventing times. + +### How to Check Current Time + +#### 1. **Query System Time (Required)** +- **Always start** by querying the current system time using available tools +- **Never assume** what the current time is +- **Never use** placeholder values like "current time" or "now" + +#### 2. **Available Time Query Methods** +- **System Clock**: Use `date` command or equivalent system time function +- **Programming Language**: Use language-specific time functions (e.g., `Date.now()`, `datetime.now()`) +- **Environment Variables**: Check for time-related environment variables +- **API Calls**: Use time service APIs if available + +#### 3. **Required Time Information** +When querying time, always obtain: +- **Current Date**: YYYY-MM-DD format +- **Current Time**: HH:MM:SS format (24-hour) +- **Timezone**: Current system timezone or UTC offset +- **UTC Equivalent**: Convert local time to UTC for cross-team clarity + +#### 4. **Time Query Examples** + +```bash +# Example: Query system time +$ date +# Expected output: Mon Aug 17 10:32:45 EDT 2025 + +# Example: Query UTC time +$ date -u +# Expected output: Mon Aug 17 14:32:45 UTC 2025 +``` + +```python +# Example: Python time query +import datetime +current_time = datetime.datetime.now() +utc_time = datetime.datetime.utcnow() +print(f"Local: {current_time}") +print(f"UTC: {utc_time}") +``` + +```javascript +// Example: JavaScript time query +const now = new Date(); +const utc = new Date().toISOString(); +console.log(`Local: ${now}`); +console.log(`UTC: ${utc}`); +``` + +#### 5. **LLM Time Checking Workflow** +1. **Query**: Actively query system for current time +2. **Validate**: Confirm time data is reasonable and current +3. **Format**: Convert to ISO 8601 format +4. **Context**: Provide both local and UTC times when helpful +5. **Document**: Show the source of time information + +#### 6. **Error Handling for Time Queries** +- **If time query fails**: Ask user for current time or use "unknown time" with explanation +- **If timezone unclear**: Default to UTC and ask for clarification +- **If time seems wrong**: Verify with user before proceeding +- **Always log**: Record when and how time was obtained + +#### 7. **Time Query Verification** +Before using queried time, verify: +- [ ] Time is recent (within last few minutes) +- [ ] Timezone information is available +- [ ] UTC conversion is accurate +- [ ] Format follows ISO 8601 standard + +--- + +## 8. Model Behavior Rules + +- **Never invent a "fake now"**: All "current time" references must come from the real system clock available at runtime. +- **Check developer time zone**: If ambiguous, ask for clarification (e.g., "Should I use UTC or your local timezone?"). +- **Format for clarity**: + - Local time: `YYYY-MM-DDTHH:mm±hh:mm` + - UTC equivalent (if needed): `YYYY-MM-DDTHH:mmZ` + +--- + +## 9. Examples + +### Good +- "Feature flag rollout started on `2025-08-01` and will be reviewed on `2025-08-21`." +- "Migration applied on `2025-07-15T14:00Z`." +- "Issue reproduced on `2025-08-17T09:00-05:00 (local)` / `2025-08-17T14:00Z (UTC)`." + +### Bad +- "Feature flag rolled out last week." +- "Migration applied recently." +- "Now is August, so we assume this was last month." + +### More Examples + +#### Issue Reports +- ✅ **Good**: "User reported login failure at `2025-08-17T14:30:00Z`. Issue persisted until `2025-08-17T15:45:00Z`." +- ❌ **Bad**: "User reported login failure earlier today. Issue lasted for a while." + +#### Release Planning +- ✅ **Good**: "Feature X scheduled for release on `2025-08-25`. Testing window: `2025-08-20` to `2025-08-24`." +- ❌ **Bad**: "Feature X will be released next week after testing." + +#### Performance Monitoring +- ✅ **Good**: "Baseline performance measured on `2025-08-10T09:00:00Z`. Regression detected on `2025-08-15T14:00:00Z`." +- ❌ **Bad**: "Performance was good last week but got worse this week." + +--- + +## 10. Technical Implementation Notes + +### UTC Storage Principle +- **Store all timestamps in UTC** in databases, logs, and serialized formats +- **Convert to local time only for user display** +- **Use ISO 8601 format** for all storage: `YYYY-MM-DDTHH:mm:ss.sssZ` + +### Common Implementation Patterns + +#### Database Storage +```sql +-- ✅ Good: Store in UTC +created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, +updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + +-- ❌ Bad: Store in local time +created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, +updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +``` + +#### API Responses +```json +// ✅ Good: Include both UTC and local time +{ + "eventTime": "2025-08-17T14:00:00Z", + "localTime": "2025-08-17T10:00:00-04:00", + "timezone": "America/New_York" +} + +// ❌ Bad: Only local time +{ + "eventTime": "2025-08-17T10:00:00-04:00" +} +``` + +#### Logging +```python +# ✅ Good: Log in UTC with timezone info +logger.info(f"User action at {datetime.utcnow().isoformat()}Z (UTC)") + +# ❌ Bad: Log in local time +logger.info(f"User action at {datetime.now()}") +``` + +### Timezone Handling Best Practices + +#### 1. Always Store Timezone Information +- Include IANA timezone identifier (e.g., `America/New_York`) +- Store UTC offset at time of creation +- Handle daylight saving time transitions automatically + +#### 2. User Display Considerations +- Convert UTC to user's preferred timezone +- Show timezone abbreviation when helpful +- Use relative time for recent events ("2 hours ago") + +#### 3. Edge Case Handling +- **Daylight Saving Time**: Use timezone-aware libraries +- **Leap Seconds**: Handle gracefully (rare but important) +- **Invalid Times**: Validate before processing + +### Common Mistakes to Avoid + +#### 1. Timezone Confusion +- ❌ **Don't**: Assume server timezone is user timezone +- ✅ **Do**: Always convert UTC to user's local time for display + +#### 2. Format Inconsistency +- ❌ **Don't**: Mix different time formats in the same system +- ✅ **Do**: Standardize on ISO 8601 for all storage + +#### 3. Relative Time References +- ❌ **Don't**: Use relative terms in persistent storage +- ✅ **Do**: Convert relative terms to absolute timestamps immediately + +--- + +## References + +- [ISO 8601 Date and Time Standard](https://en.wikipedia.org/wiki/ISO_8601) +- [IANA Timezone Database](https://www.iana.org/time-zones) +- [ADR Template](./adr_template.md) +- [Research & Diagnostic Workflow](./research_diagnostic.mdc) + +--- + +**Rule of Thumb:** +> Every time reference in development artifacts should be **clear in 6 months without context**, and aligned to the **developer's actual current time**. + +**Technical Rule of Thumb:** +> **Store in UTC, display in local time, always include timezone context.** + +**Rule of Thumb:** +> Every time reference in development artifacts should be **clear in 6 months without context**, and aligned to the **developer’s actual current time**. diff --git a/.cursor/rules/version_control.mdc b/.cursor/rules/version_control.mdc deleted file mode 100644 index 212e000..0000000 --- a/.cursor/rules/version_control.mdc +++ /dev/null @@ -1,7 +0,0 @@ ---- -alwaysApply: true ---- -use git -commit messages are based on unstaged files and the chnages made to them -present proposed messages for approval -get approval before staging or commmiting diff --git a/.cursor/rules/versioning.mdc b/.cursor/rules/versioning.mdc deleted file mode 100644 index 892855e..0000000 --- a/.cursor/rules/versioning.mdc +++ /dev/null @@ -1,7 +0,0 @@ ---- -alwaysApply: true ---- - -Semantic Versioning: Follows MAJOR.MINOR.PATCH format -Centralized Management: Single source of truth for all version information -Git Integration: Automatic commit hash detection diff --git a/.cursor/rules/workflow/version_control.mdc b/.cursor/rules/workflow/version_control.mdc new file mode 100644 index 0000000..7635fb6 --- /dev/null +++ b/.cursor/rules/workflow/version_control.mdc @@ -0,0 +1,122 @@ +--- +alwaysApply: true +--- +# Directive: Peaceful Co-Existence with Developers + +## 1) Version-Control Ownership + +* **MUST NOT** run `git add`, `git commit`, or any write action. +* **MUST** leave staging/committing to the developer. + +## 2) Source of Truth for Commit Text + +* **MUST** derive messages **only** from: + + * files **staged** for commit (primary), and + * files **awaiting staging** (context). +* **MUST** use the **diffs** to inform content. +* **MUST NOT** invent changes or imply work not present in diffs. + +## 3) Mandatory Preview Flow + +* **ALWAYS** present, before any real commit: + + * file list + brief per-file notes, + * a **draft commit message** (copy-paste ready), + * nothing auto-applied. + +--- + +# Commit Message Format (Normative) + +## A. Subject Line (required) + +``` +(): +``` + +* **type** (lowercase, Conventional Commits): `feat|fix|refactor|perf|docs|test|build|chore|ci|revert` +* **scope**: optional module/package/area (e.g., `api`, `ui/login`, `db`) +* **!**: include when a breaking change is introduced +* **summary**: imperative mood, ≤ 72 chars, no trailing period + +**Examples** + +* `fix(api): handle null token in refresh path` +* `feat(ui/login)!: require OTP after 3 failed attempts` + +## B. Body (optional, when it adds non-obvious value) + +* One blank line after subject. +* Wrap at \~72 chars. +* Explain **what** and **why**, not line-by-line “how”. +* Include brief notes like tests passing or TS/lint issues resolved **only if material**. + +**Body checklist** + +* [ ] Problem/symptom being addressed +* [ ] High-level approach or rationale +* [ ] Risks, tradeoffs, or follow-ups (if any) + +## C. Footer (optional) + +* Issue refs: `Closes #123`, `Refs #456` +* Breaking change (alternative to `!`): + `BREAKING CHANGE: ` +* Authors: `Co-authored-by: Name ` +* Security: `CVE-XXXX-YYYY: ` (if applicable) + +--- + +## Content Guidance + +### Include (when relevant) + +* Specific fixes/features delivered +* Symptoms/problems fixed +* Brief note that tests passed or TS/lint errors resolved + +### Avoid + +* Vague: *improved, enhanced, better* +* Trivialities: tiny docs, one-liners, pure lint cleanups (separate, focused commits if needed) +* Redundancy: generic blurbs repeated across files +* Multi-purpose dumps: keep commits **narrow and focused** +* Long explanations that good inline code comments already cover + +**Guiding Principle:** Let code and inline docs speak. Use commits to highlight what isn’t obvious. + +--- + +# Copy-Paste Templates + +## Minimal (no body) + +```text +(): +``` + +## Standard (with body & footer) + +```text +(): + + + + + +Closes # +BREAKING CHANGE: +Co-authored-by: +``` + +--- + +# Assistant Output Checklist (before showing the draft) + +* [ ] List changed files + 1–2 line notes per file +* [ ] Provide **one** focused draft message (subject/body/footer) +* [ ] Subject ≤ 72 chars, imperative mood, correct `type(scope)!` syntax +* [ ] Body only if it adds non-obvious value +* [ ] No invented changes; aligns strictly with diffs +* [ ] Render as a single copy-paste block for the developer diff --git a/.gradle/8.13/fileHashes/fileHashes.bin b/.gradle/8.13/fileHashes/fileHashes.bin index fc2d3e8fa6d039c82dda2f6815e054b9c3ac83bd..be7368c643ac4449b3cf1ef01c6650c1b55c1029 100644 GIT binary patch delta 18 acmcaQi}C6##tjdBShjDtsW6+ delta 18 acmcaQi}C6##tjdBSX}<^UNrfsPXPc~`3aT) diff --git a/.gradle/8.13/fileHashes/fileHashes.lock b/.gradle/8.13/fileHashes/fileHashes.lock index 5e224e2cc8a7070c5b19c943a9a492f870de2df3..07f1143b6cd727ed3eb910a7e08ec2ab6642d85b 100644 GIT binary patch literal 17 UcmZS9y7_(Uuhl(k86dzC07WGQ$^ZZW literal 17 UcmZS9y7_(Uuhl(k86dz607W7N#{d8T diff --git a/.gradle/nb-cache/daily-notification-plugin-650793354/project-info.ser b/.gradle/nb-cache/daily-notification-plugin-650793354/project-info.ser new file mode 100644 index 0000000000000000000000000000000000000000..1ce5e20e46da2fc08da27a9f37cdff069d681bb7 GIT binary patch literal 48565 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 YX{2fV!nk!BjD{nU{_ktLi>AQ(6AP3+MF0Q* literal 0 HcmV?d00001 diff --git a/.gradle/nb-cache/trust/CF37DF473B63082CB422CF366D6DE6262AC1AECC238F3058A752FA9D899EB24E b/.gradle/nb-cache/trust/CF37DF473B63082CB422CF366D6DE6262AC1AECC238F3058A752FA9D899EB24E new file mode 100644 index 0000000..b5d1620 --- /dev/null +++ b/.gradle/nb-cache/trust/CF37DF473B63082CB422CF366D6DE6262AC1AECC238F3058A752FA9D899EB24E @@ -0,0 +1 @@ +DB3AE51713EFB84E05BC35EBACB3258E9428C8277A536E2102ACFF8EAB42145B