contribution guide update + templates

This commit is contained in:
samtiz 2025-07-10 00:01:29 +09:00
parent 594f9e8d19
commit a975ba94f9
9 changed files with 337 additions and 54 deletions

31
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,31 @@
---
name: Bug Report
about: Create a report to help us improve
title: "[BUG] "
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Environment (please complete the following information):**
- OS: [e.g. macOS, Windows]
- App Version [e.g. 1.0.0]
**Additional context**
Add any other context about the problem here.

View File

@ -0,0 +1,20 @@
---
name: Feature Request
about: Suggest an idea for this project
title: "[FEAT] "
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

28
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,28 @@
---
name: Pull Request
about: Propose a change to the codebase
---
## Summary of Changes
Please provide a brief, high-level summary of the changes in this pull request.
## Related Issue
- Closes #XXX
*Please replace `XXX` with the issue number that this pull request resolves. If it does not resolve a specific issue, please explain why this change is needed.*
## Contributor's Self-Review Checklist
Please check the boxes that apply. This is a reminder of what we look for in a good pull request.
- [ ] I have read the [CONTRIBUTING.md](https://github.com/your-org/your-repo/blob/main/CONTRIBUTING.md) document.
- [ ] My code follows the project's coding style and architectural patterns as described in [DESIGN_PATTERNS.md](https://github.com/your-org/your-repo/blob/main/docs/DESIGN_PATTERNS.md).
- [ ] I have added or updated relevant tests for my changes.
- [ ] I have updated the documentation to reflect my changes (if applicable).
- [ ] My changes have been tested locally and are working as expected.
## Additional Context (Optional)
Add any other context or screenshots about the pull request here.

64
.github/workflows/assign-on-comment.yml vendored Normal file
View File

@ -0,0 +1,64 @@
name: Assign on Comment
on:
issue_comment:
types: [created]
jobs:
# Job 1: Any contributor can self-assign
self-assign:
# Only run if the comment is exactly '/assign'
if: github.event.comment.body == '/assign'
runs-on: ubuntu-latest
permissions:
issues: write
reactions: write # Permission to add a reaction to the comment
steps:
- name: Assign commenter to the issue
uses: actions/github-script@v7
with:
script: |
// Assign the commenter as the assignee
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
assignees: [context.actor]
});
// Add a rocket (🚀) reaction to indicate success
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: 'rocket'
});
# Job 2: Admin can assign others
assign-others:
# Only run if the comment starts with '/assign @' and the commenter is in the admin group
if: startsWith(github.event.comment.body, '/assign @') && contains(fromJson('["OWNER", "COLLABORATOR", "MEMBER"]'), github.event.author_association)
runs-on: ubuntu-latest
permissions:
issues: write
reactions: write # Permission to add a reaction to the comment
steps:
- name: Assign mentioned user
uses: actions/github-script@v7
with:
script: |
const mention = context.payload.comment.body.split(' ')[1];
const assignee = mention.substring(1); // Remove '@'
// Assign the mentioned user as the assignee
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
assignees: [assignee]
});
// Add a thumbs up (+1) reaction to indicate success
await github.rest.reactions.createForIssueComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: context.payload.comment.id,
content: '+1'
});

View File

@ -2,52 +2,57 @@
Thank you for considering contributing to **Glass by Pickle**! Contributions make the open-source community vibrant, innovative, and collaborative. We appreciate every contribution you make—big or small.
## 📌 Contribution Guidelines
### 👥 Avoid Work Duplication
Before creating an issue or submitting a pull request (PR), please check existing [Issues](https://github.com/pickle-com/glass/issues) and [Pull Requests](https://github.com/pickle-com/glass/pulls) to prevent duplicate efforts.
### ✅ Start with Approved Issues
- **Feature Requests**: Please wait for approval from core maintainers before starting work. Issues needing approval are marked with the `🚨 needs approval` label.
- **Bugs & Improvements**: You may begin immediately without explicit approval.
### 📝 Clearly Document Your Work
Provide enough context and detail to allow easy understanding. Issues and PRs should clearly communicate the problem or feature and stand alone without external references.
### 💡 Summarize Pull Requests
Include a brief summary at the top of your PR, describing the intent and scope of your changes.
### 🔗 Link Related Issues
Use GitHub keywords (`Closes #123`, `Fixes #456`) to auto-link and close issues upon PR merge.
### 🧪 Include Testing Information
Clearly state how your changes were tested.
> Example:
> "Tested locally on macOS 14, confirmed all features working as expected."
### 🧠 Future-Proof Your Descriptions
Document trade-offs, edge cases, and temporary workarounds clearly to help future maintainers understand your decisions.
This document guides you through the entire contribution process, from finding an issue to getting your pull request merged.
---
## 🔖 Issue Priorities
## 🚀 Contribution Workflow
| Issue Type | Priority |
|----------------------------------------------------|---------------------|
| Minor enhancements & non-core feature requests | 🟢 Low Priority |
| UX improvements & minor bugs | 🟡 Medium Priority |
| Core functionalities & essential features | 🟠 High Priority |
| Critical bugs & breaking issues | 🔴 Urgent |
|
To ensure a smooth and effective workflow, all contributions must go through the following process. Please follow these steps carefully.
### 1. Find or Create an Issue
All work begins with an issue. This is the central place to discuss new ideas and track progress.
- Browse our existing [**Issues**](https://github.com/pickle-com/glass/issues) to find something you'd like to work on. We recommend looking for issues labeled `good first issue` if you're new!
- If you have a new idea or find a bug that hasn't been reported, please **create a new issue** using our templates.
### 2. Claim the Issue
To avoid duplicate work, you must claim an issue before you start coding.
- On the issue you want to work on, leave a comment with the command:
```
/assign
```
- Our GitHub bot will automatically assign the issue to you. Once your profile appears in the **`Assignees`** section on the right, you are ready to start development.
### 3. Fork & Create a Branch
Now it's time to set up your local environment.
1. **Fork** the repository to your own GitHub account.
2. **Clone** your forked repository to your local machine.
3. **Create a new branch** from `main`. A clear branch name is recommended.
- For new features: `feat/short-description` (e.g., `feat/user-login-ui`)
- For bug fixes: `fix/short-description` (e.g., `fix/header-rendering-bug`)
### 4. Develop
Write your code! As you work, please adhere to our quality standards.
- **Code Style & Quality**: Our project uses `Prettier` and `ESLint` to maintain a consistent code style.
- **Architecture & Design Patterns**: All new code must be consistent with the project's architecture. Please read our **[Design Patterns Guide](https://github.com/pickle-com/glass/blob/main/docs/DESIGN_PATTERNS.md)** before making significant changes.
### 5. Create a Pull Request (PR)
Once your work is ready, create a Pull Request to the `main` branch of the original repository.
- **Fill out the PR Template**: Our template will appear automatically. Please provide a clear summary of your changes.
- **Link the Issue**: In the PR description, include the line `Closes #XXX` (e.g., `Closes #123`) to link it to the issue you resolved. This is mandatory.
- **Code Review**: A maintainer will review your code, provide feedback, and merge it.
---
# Developing
@ -86,10 +91,3 @@ npm run lint
```
If you get errors, be sure to fix them before committing.
## Making a Pull Request
- Be sure to [check the "Allow edits from maintainers" option](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) when creating your PR. (This option isn't available if you're [contributing from a fork belonging to an organization](https://github.com/orgs/community/discussions/5634))
- If your PR refers to or fixes an issue, add `refs #XXX` or `fixes #XXX` to the PR description. Replace `XXX` with the respective issue number. See more about [linking a pull request to an issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).
- Lastly, make sure to keep your branches updated (e.g., click the `Update branch` button on the GitHub PR page).

126
docs/DESIGN_PATTERNS.md Normal file
View File

@ -0,0 +1,126 @@
# Glass: Design Patterns and Architectural Overview
Welcome to the Glass project! This document is the definitive guide to the architectural patterns, conventions, and design philosophy that guide our development. Adhering to these principles is essential for building new features, maintaining the quality of our codebase, and ensuring a stable, consistent developer experience.
The architecture is designed to be modular, robust, and clear, with a strict separation of concerns.
---
## Core Architectural Principles
These are the fundamental rules that govern the entire application.
1. **Centralized Data Logic**: All data persistence logic (reading from or writing to a database) is centralized within the **Electron Main Process**. The UI layers (both Electron's renderer and the web dashboard) are forbidden from accessing data sources directly.
2. **Feature-Based Modularity**: Code is organized by feature (`src/features`) to promote encapsulation and separation of concerns. A new feature should be self-contained within its own directory.
3. **Dual-Database Repositories**: The data access layer uses a **Repository Pattern** that abstracts away the underlying database. Every repository that handles user data **must** have two implementations: one for the local `SQLite` database and one for the cloud `Firebase` database. Both must expose an identical interface.
4. **AI Provider Abstraction**: AI model interactions are abstracted using a **Factory Pattern**. To add a new provider (e.g., a new LLM), you only need to create a new provider module that conforms to the base interface in `src/common/ai/providers/` and register it in the `factory.js`.
5. **Single Source of Truth for Schema**: The schema for the local SQLite database is defined in a single location: `src/common/config/schema.js`. Any change to the database structure **must** be updated here.
6. **Encryption by Default**: All sensitive user data **must** be encrypted before being persisted to Firebase. This includes, but is not limited to, API keys, conversation titles, transcription text, and AI-generated summaries. This is handled automatically by the `createEncryptedConverter` Firestore helper.
---
## I. Electron Application Architecture (`src/`)
This section details the architecture of the core desktop application.
### 1. Overall Pattern: Service-Repository
The Electron app's logic is primarily built on a **Service-Repository** pattern, with the Views being the HTML/JS files in the `src/app` and `src/features` directories.
- **Views** (`*.html`, `*View.js`): The UI layer. Views are responsible for rendering the interface and capturing user interactions. They are intentionally kept "dumb" and delegate all significant logic to a corresponding Service.
- **Services** (`*Service.js`): Services contain the application's business logic. They act as the intermediary between Views and Repositories. For example, `sttService` contains the logic for STT, while `summaryService` handles the logic for generating summaries.
- **Repositories** (`*.repository.js`): Repositories are responsible for all data access. They are the *only* part of the application that directly interacts with `sqliteClient` or `firebaseClient`.
**Location of Modules:**
- **Feature-Specific**: If a service or repository is used by only one feature, it should reside within that feature's directory (e.g., `src/features/listen/summary/summaryService.js`).
- **Common**: If a service or repository is shared across multiple features (like `authService` or `userRepository`), it must be placed in `src/common/services/` or `src/common/repositories/` respectively.
### 2. Data Persistence: The Dual Repository Factory
The application dynamically switches between using the local SQLite database and the cloud-based Firebase Firestore.
- **SQLite**: The default data store for all users, especially those not logged in. This ensures full offline functionality. The low-level client is `src/common/services/sqliteClient.js`.
- **Firebase**: Used exclusively for users who are authenticated. This enables data synchronization across devices and with the web dashboard.
The selection mechanism is a sophisticated **Factory and Adapter Pattern** located in the `index.js` file of each repository directory (e.g., `src/common/repositories/session/index.js`).
**How it works:**
1. **Service Call**: A service makes a call to a high-level repository function, like `sessionRepository.create('ask')`. The service is unaware of the user's state or the underlying database.
2. **Repository Selection (Factory)**: The `index.js` adapter logic first determines which underlying repository to use. It imports and calls `authService.getCurrentUser()` to check the login state. If the user is logged in, it selects `firebase.repository.js`; otherwise, it defaults to `sqlite.repository.js`.
3. **UID Injection (Adapter)**: The adapter then retrieves the current user's ID (`uid`) from `authService.getCurrentUserId()`. It injects this `uid` into the actual, low-level repository call (e.g., `firebaseRepository.create(uid, 'ask')`).
4. **Execution**: The selected repository (`sqlite` or `firebase`) executes the data operation.
This powerful pattern accomplishes two critical goals:
- It makes the services completely agnostic about the underlying data source.
- It frees the services from the responsibility of managing and passing user IDs for every database query.
**Visualizing the Data Flow**
```mermaid
graph TD
subgraph "Electron Main Process"
A -- User Action --> B[Service Layer];
B -- Data Request --> C[Repository Factory];
C -- Check Login Status --> D{Decision};
D -- No --> E[SQLite Repository];
D -- Yes --> F[Firebase Repository];
E -- Access Local DB --> G[(SQLite)];
F -- Access Cloud DB --> H[(Firebase)];
G -- Return Data --> B;
H -- Return Data --> B;
B -- Update UI --> A;
end
style A fill:#D6EAF8,stroke:#3498DB
style G fill:#E8DAEF,stroke:#8E44AD
style H fill:#FADBD8,stroke:#E74C3C
```
---
## II. Web Dashboard Architecture (`pickleglass_web/`)
This section details the architecture of the Next.js web application, which serves as the user-facing dashboard for account management and cloud data viewing.
### 1. Frontend, Backend, and Main Process Communication
The web dashboard has a more complex, three-part architecture:
1. **Next.js Frontend (`app/`):** The React-based user interface.
2. **Node.js Backend (`backend_node/`):** An Express.js server that acts as an intermediary.
3. **Electron Main Process (`src/`):** The ultimate authority for all local data access.
Crucially, **the web dashboard's backend cannot access the local SQLite database directly**. It must communicate with the Electron main process to request data.
### 2. The IPC Data Flow
When the web frontend needs data that resides in the local SQLite database (e.g., viewing a non-synced session), it follows this precise flow:
1. **HTTP Request**: The Next.js frontend makes a standard API call to its own Node.js backend (e.g., `GET /api/conversations`).
2. **IPC Request**: The Node.js backend receives the HTTP request. It **does not** contain any database logic. Instead, it uses the `ipcRequest` helper from `backend_node/ipcBridge.js`.
3. **IPC Emission**: `ipcRequest` sends an event to the Electron main process over an IPC channel (`web-data-request`). It passes three things: the desired action (e.g., `'get-sessions'`), a unique channel name for the response, and a payload.
4. **Main Process Listener**: The Electron main process has a listener (`ipcMain.on('web-data-request', ...)`) that receives this request. It identifies the action and calls the appropriate **Service** or **Repository** to fetch the data from the SQLite database.
5. **IPC Response**: Once the data is retrieved, the main process sends it back to the web backend using the unique response channel provided in the request.
6. **HTTP Response**: The web backend's `ipcRequest` promise resolves with the data, and the backend sends it back to the Next.js frontend as a standard JSON HTTP response.
This round-trip ensures our core principle of centralizing data logic in the main process is never violated.
**Visualizing the IPC Data Flow**
```mermaid
sequenceDiagram
participant FE as Next.js Frontend
participant BE as Node.js Backend
participant Main as Electron Main Process
FE->>+BE: 1. HTTP GET /api/local-data
Note over BE: Receives local data request
BE->>+Main: 2. ipcRequest('get-data', responseChannel)
Note over Main: Receives request, fetches data from SQLite<br/>via Service/Repository
Main-->>-BE: 3. ipcResponse on responseChannel (data)
Note over BE: Receives data, prepares HTTP response
BE-->>-FE: 4. HTTP 200 OK (JSON data)
```

19
package-lock.json generated
View File

@ -47,7 +47,8 @@
"electron": "^30.5.1",
"electron-builder": "^26.0.12",
"electron-reloader": "^1.2.3",
"esbuild": "^0.25.5"
"esbuild": "^0.25.5",
"prettier": "^3.6.2"
},
"optionalDependencies": {
"electron-liquid-glass": "^1.0.1"
@ -9733,6 +9734,22 @@
"node": ">=10"
}
},
"node_modules/prettier": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
"integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
"dev": true,
"license": "MIT",
"bin": {
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/proc-log": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz",

View File

@ -1,9 +1,7 @@
{
"name": "pickle-glass",
"productName": "Glass",
"version": "0.2.3",
"description": "Cl*ely for Free",
"main": "src/index.js",
"scripts": {
@ -71,7 +69,8 @@
"electron": "^30.5.1",
"electron-builder": "^26.0.12",
"electron-reloader": "^1.2.3",
"esbuild": "^0.25.5"
"esbuild": "^0.25.5",
"prettier": "^3.6.2"
},
"optionalDependencies": {
"electron-liquid-glass": "^1.0.1"

View File

@ -2,7 +2,7 @@ const crypto = require('crypto');
function ipcRequest(req, channel, payload) {
return new Promise((resolve, reject) => {
// 즉시 브리지 상태 확인 - 문제있으면 바로 실패
// Immediately check bridge status and fail if it's not available.
if (!req.bridge || typeof req.bridge.emit !== 'function') {
reject(new Error('IPC bridge is not available'));
return;