CCMeMan (Conference Call Meeting Manager)
===
An all-in-one platform (or portal) for meeting (con-call) management
## API
✅ : Highest priority to implement.
- `/api/v1/users`
- [ ] POST: ✅
Register current user
- [ ] GET: ✅
Get current user
- [ ] PUT: ✅
Update current user
- [ ] DELETE:
Delete current user
Question: I'm not sure if it's better to use `/api/v1/users/me` or `api/v1/me` for `GET`, `PUT`, and `DELETE` requests on current user?
- `/api/v1/groups`
- [ ] GET: ✅
Get group list (that current user participated in)
- [ ] POST: ✅
Create a group (set current user to be a MANAGER of the new sub-group)
- `/api/v1/groups/:groupNanoId`
- [ ] POST:
Create a sub-group (set current user to be a MANAGER of the new sub-group)
- [ ] GET: ✅
Get the group
- [ ] PUT:
Update the group (current user must be a MANAGER of this group)
- [ ] DELETE:
Delete the group (current user must be a MANAGER of this group)
- `/api/v1/meetings/:groupNanoId`
- [ ] POST: ✅
Create meeting (current user must be a MANAGER/MEMBER of this group)
- [ ] GET: ✅
Get meeting list (that current user participated in)
- `?future=true` : Return future meetings only
- `?future=false` : Return past meetings only
- `?sortBy=time` : Sort by meeting time
- `/api/v1/meetings?meeting-nano-id=<meetingNanoId>`
- [x] GET: ✅
Get the meeting (if current user participated in)
- [ ] PUT:
Update the meeting (current user must be a MANAGER/MEMBER of this meeting)
- [ ] DELETE:
Delete the meeting (current user must be a MANAGER of this meeting)
---
Voting for Meeting time (I'm not sure which way is better)
- `/api/v1/votings/:groupNanoId/:meetingNanoId`
- `/api/v1/meetings/:groupNanoId/:meetingNanoId/voting` 😁
---
(I'm not sure if this is a good way to quit from a group/meeting)
- `/api/v1/me/meetings/:groupNanoId/:meetingNanoId`
- [ ] DELETE:
Quit the meeting
- `/api/v1/me/groups/:groupNanoId`
- [ ] DELETE:
Quit the group
---
(I'm not sure how to add a user to a group/meeting as a MANAGER/MEMBER/GUEST)
Could be
```
PATCH /api/v1/groups/:groupNanoId
{ op: "add|remove",
data: {
users: {
id: <userId>,
role:<Role>
}
}
}
```
?
## Premission Matrix
Create
Read
Update
Delete
### Operations on group
- After creation, the user will be assigned as a MANAGER to the new group by default.
| Group | Manager | Member | Guest | None |
| ---------- | ------- | ------ | ----- | ---- |
| Operations | CRUD | CRU | R | |
### Operations on sub-group
- **C**: To Create a new sub-group under a group, you have to be either MANAGER or MEMBER of that parent group.
- After creation, the user will be assigned as a MANAGER to the new sub-group by default.
| Sub-Group \ Group | Manager | Member | Guest | None |
| ----------------- | ------- | ------ | ----- | ---- |
| Manager | CRUD | CRUD | RUD | RUD |
| Member | CRUD | CRU | RU | RU |
| Guest | CRD | CR | R | R |
| None | CD | C | | |
### Operations on meeting
- **C**: To Create a new meeting under a group, you have to be either MANAGER or MEMBER of that group.
- If a user doesn't participated in the parent group of the meeting (i.e., **None**), they can only access the meeting page from a direct link ( `meeting/<groupNanoId>/<meetingNanoId>` ) in the front-end. It won't be browsable from a list of meetings in a group page.
- After creation, the user will be assigned as a MANAGER to the new meeting by default.
| Meeting \ Group | Manager | Member | Guest | None (direct link only) |
| ----------------------- | ------- | ------ | ----- | ----------------------- |
| Manager | CRUD | CRUD | RUD | RUD |
| Member | CRUD | CRU | RU | RU |
| Guest | CRD | CR | R | R |
| None (direct link only) | CD | C | | |
- Example code:
```javascript
// in meetings/<groupNanoId>/<meetingNanoId>
const READ = 1;
const UPDATE = 2;
const DELETE = 4;
let premission = 0;
if (isManager) { premission |= READ+UPDATE+DELETE };
if (isMember) { premission |= READ+UPDATE };
if (isGuest) { premission |= READ };
if (isGroupManager) { premission |= DELETE };
```
## Features
### Core Feature
- Create Group
- manage members (name/email)
- one-time meeting
- repeated meetings
- Scheduling (support multiple timezone display)
- Voting for time slots (ref: https://www.when2meet.com/)
- Time Selector
- React Schedule Selector
- https://github.com/bibekg/react-schedule-selector#readme
- https://medium.com/bruinmeet/react-schedule-selector-6cd5bf1f4968
- DateTime Picker
- https://github.com/its-danny/use-lilius
- https://github.com/msnegurski/tailwind-react-datepicker
- https://github.com/Hacker0x01/react-datepicker/
- https://gist.github.com/igoro00/99e9d244677ccafbf39667c24b5b35ed
- Zoom link shortcut
- Add to calendar (iCal/Google...)
- https://github.com/add2cal/add-to-calendar-button
- Generate invitation email
- Plan text for copy/paste
- SendGrid (SMTP)?
### Additional Features
- Minutes
- markdown (hackmd.io or CodiMD)
- Google Docs (just link or integration)
- Any external links to shared documents services
- Batch exporting
- Google Drive
- Github/Gitlab private repo
- Local files
### Medium-term Feature
- iOS app (swift vs react native)
- macOS app
### Long-term Feature
太遠了先別想
## Database schema?
- https://github.com/CCMeMan/ccmeman-backend/blob/dev/src/prisma/schema.prisma
```
person:
id
name
email
preferred time zone
group:
id
admin(person)
members(person)
Meetings(meeting)
MeetingGroups(meeting_group)
meeting_group:
id
Meetings(meeting)
meeting:
id
Name
DateTime
Con-call link
minutes
```
## Possible things to learn
### Front-end
- React.js
- CSS
- Bootstrap
- Tailwind
- Material UI
- Figma (UI/UX designer)
### Back-end
- Node.js?
### DB
- ~~GraphQL vs SQL?~~ Using ORM
- MongoDB vs PostgreSQL?
- ORM (Object-Relational Mapping)
- Prisma
- Sequelize
- MikroORM
### Authentication
- ~~OAuth? Google (and probably the fucking Office365)~~
- Firebase Auth
### Hosting
- Linode / Vultr / Digital Ocean
- Firebase
- GCP (free VM)?
### Deployment
- Docker + K8S
- Web App hosting
### Realtime Colabration
- Survey
- https://stackoverflow.com/questions/2043165/operational-transformation-library
- https://bestofjs.org/projects?tags=realtime&tags=db
- CRDT (Commutative Replicated Data Type)
- https://github.com/automerge/automerge
- https://github.com/yjs/yjs
- OT ( Operational Transformation)
- https://github.com/share/sharedb
---
# Learning
## Authentication and Authorization
- JWT(JSON Web Tokens)
- Basic: https://youtu.be/7Q17ubqLfaM
- Tutorial: https://youtu.be/mbsmsi7l3r4
- Display JWT: https://jwt.io/
- https://next-auth.js.org/
- Firebase
- Google Identity Services Login with React ✅
- https://www.youtube.com/watch?v=roxC8SMs7HU
- https://yeeeeees.medium.com/user-authentication-with-node-js-jwt-and-google-oauth-2-0-backend-cookbook-5-e54f40dce0e5
- passport.js
- Auth0
- JWT
- https://community.auth0.com/t/auth0-nextjs-auth0-tokens-and-external-api-help/71072
- AWS Cognito
## API
- https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design
### Documenting API
- https://dev.to/kabartolo/how-to-document-an-express-api-with-swagger-ui-and-jsdoc-50do
### How to communicate
- https://stackoverflow.com/questions/66739797/how-to-handle-a-post-request-in-next-js
## ID
- https://npmtrends.com/cuid-vs-nanoid-vs-short-uuid-vs-uuid
## Search
- Elasticsearch (ELK)
## Database
- GUI Viewer
- DBeaver https://dbeaver.io/
### PostgreSQL
- Setup using Docker
- https://zhao-li.medium.com/getting-started-with-postgresql-using-docker-compose-34d6b808c47c
### Prisma
- Learn Prisma In 60 Minutes https://youtu.be/RebA5J-rlwg
## Theme
- https://chakra-ui.com/docs/components
- How to use Tailwind with Chakra-UI https://github.com/chakra-ui/chakra-ui/issues/634
- Toast https://github.com/tailwindlabs/headlessui/discussions/439
- !!!❤️ https://chakra-ui.com/docs/components/toast#custom-component
## JavaScript
- Package Selection
- https://npmtrends.com/
- Async/Await
- Promise
- JavaScript Promises In 10 Minutes https://youtu.be/DHvZLI7Db8E
- JavaScript Async Await https://youtu.be/V_Kr9OSfDeU
- https://stackoverflow.com/questions/43302584/why-doesnt-the-code-after-await-run-right-away-isnt-it-supposed-to-be-non-blo
- Destructuring Assignment
```javascript
const obj = { a: 1, b: 2 };
const { a, b } = obj;
// is equivalent to:
// const a = obj.a;
// const b = obj.b;
```
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
- import
- Named import
- import A, { myA, Something } from './A'
- https://stackoverflow.com/questions/36795819/when-should-i-use-curly-braces-for-es6-import
- Scope: @XXXX/YYY
- https://stackoverflow.com/questions/36293481/use-of-symbol-in-node-module-names
### React.js/Next.js
- Documentation
- https://beta.reactjs.org/
- React Hooks
- https://reactjs.org/docs/hooks-reference.html
- `useContext` https://beta.reactjs.org/apis/react/useContext
- `useState`
- Why React Hook useState uses const and not let https://stackoverflow.com/questions/58860021/why-react-hook-usestate-uses-const-and-not-let
- `useRef` vs `useState`
If you don’t want to update DOM elements but want to get a value (having a state in component), you can go with useRef as an alternative to useState.
- Render fetched data
- https://devtrium.com/posts/async-functions-useeffect
- https://stackoverflow.com/questions/49938266/how-to-return-values-from-async-functions-using-async-await-from-function
- https://daveceddia.com/react-before-render/