! 제품 버전을 정확하게 입력해 주세요.
제품 버전이 정확하게 기재되어 있지 않은 경우,
최신 버전을 기준으로 안내 드리므로
더욱 빠르고 명확한 안내를 위해
제품 버전을 정확하게 입력해 주세요!

투표 앱 만들기 - Firestore & JavaScript UI 컴포넌트 > 블로그 & Tips

본문 바로가기

투표 앱 만들기 - Firestore & JavaScript UI 컴포넌트

페이지 정보

작성자 GrapeCity 작성일 2020-06-09 00:00 조회 6,537회 댓글 0건

본문

해야 할 일 목록에서 가장 오래된 항목 중 하나는 간단한 투표 샘플 응용 프로그램이었습니다. 저는 수년 동안 이 응용 프로그램을 작성하려는 계획을 세워 왔지만 데이터베이스 배포 및 권한 부여가 처리하기 어려울 것이라는 생각 때문에 미처 착수하지 못하고 있었습니다.

그러다가 마침내 Google이 새로 출시한 유연하고 확장 가능한 NoSQL 클라우드 데이터베이스인 Firestore 덕분에 비로소 이 일에 착수하게 되었습니다.

Firestore를 사용해 데이터베이스를 손쉽게 만들고 배포할 수 있고, 저의 주된 장애물이던 사용자 인증 및 보안 규칙을 손쉽게 처리할 수 있게 되었습니다.


아래 이미지에 Customer Voice App 응용 프로그램이 어떤 모습인지 나와 있습니다.


사용자는 제안 사항을 두루 탐색하고, 주제 및 작성자를 기준으로 제안 사항을 검색하며, 인기도나 날짜를 기준으로 정렬할 수 있습니다. 또한 새로운 제안 사항을 입력하거나, 자신이 작성한 제안 사항을 편집 또는 삭제하거나, 다른 사람이 제출한 제안 사항에 투표를 할 수 있습니다.

다음 섹션에서는 응용 프로그램의 설계 및 구현에 관해 설명합니다.


응용 프로그램의 목표 및 설계

응용 프로그램을 통해 사용자는 다음 작업을 할 수 있어야 합니다.

  1. 다른 사용자의 제안 사항 보기

  2. 제안 사항 필터링 및 정렬

  3. 마음에 드는 제안 사항에 투표

  4. 생각이 바뀌면 투표 취소

  5. 제안 사항 추가, 편집, 제거


기존 SQL 데이터베이스를 사용한다면 제안 사항, 투표, 사용자에 대한 표가 있을 것입니다. SQL을 사용하여 투표수 등이 있는 뷰를 빌드할 것입니다.


Firestore는 약간 다릅니다. NoSQL 데이터베이스이므로, 몇 개의 표를 결합한 뷰를 빌드하는 것이 쉽지는 않습니다. 그러나 Firebase는 배열 및 개체를 각 데이터 항목에 저장하는 기능을 지원하므로 단일 표를 사용할 수 있고 이러한 필드를 포함하는 문서(항목)를 잘 다룰 수 있습니다.


이름유형설명
titlestring제안 사항 제목, 짧은 문자열.
descriptionstring제안 사항 설명, 선택 사항인 문자열.
authorstring제안 사항 작성자의 이메일.
votesstring[]이 제안 사항에 투표한 사용자의 이메일이 포함된 배열
voteCountnumber투표 배열의 길이(서버 측 정렬에 사용됨)
createdDate작성 날짜.
editedDate마지막 편집 날짜.
votedDate마지막 투표 날짜.


Firestore를 선택한 이유는 손쉽게 설정하고 배포할 수 있을 뿐 아니라 탁월한 성능과 보안도 제공하기 때문입니다. 무엇보다 Firestore를 사용하면 데이터 보관을 위해 서버를 설정하고 유지할 필요가 없습니다.


클라이언트 측에서는 Google의 Firestore 클라이언트 라이브러리 대신에 wijmo.cloud FirestoreCollection 클래스를 사용하기로 했습니다. Wijmo 클래스를 선택한 이유는 가볍고(Google의 클라이언트 라이브러리보다 훨씬 더 작고 사용하기 간편함) 데이터 레이어와 응용 프로그램 로직 사이에 더 나은 관심사 분리를 제공하기 때문입니다.


데이터베이스 만들기

Firestore 데이터베이스는 다음과 같은 방법으로 쉽게 만들 수 있습니다.

  1. Firebase 콘솔로 이동

  2. "프로젝트 추가" 클릭

  3. "데이터베이스" 옵션 선택

  4. 새 "제안 사항" 컬렉션 시작

  5. 컬렉션 스키마를 정의할 문서 생성


Firebase 콘솔의 외관은 다음과 같습니다.


 

보시다시피 데이터베이스를 만들고 검사하고 편집하기가 매우 쉽습니다.


데이터베이스 보안

또한 다음과 같이 콘솔을 사용해 데이터베이스 보안 규칙을 설정할 수 있습니다.


 

보안 규칙 설정 및 테스트에 관해서는 자세히 살펴보지 않겠습니다. Google은 이 주제에 관해 대규모의 문서를 제공하지만, 저는 수많은 유용한 예시를 제공하는 Firestore Security Rules Cookbook을 가장 좋아합니다.


투표 앱에 대해 작성한 규칙은 다음 사항을 보장합니다.

  1. 모든 사용자가 읽을 수 있음

  2. 로그인한 사용자는 제안 사항을 추가할 수 있음

  3. 로그인한 사용자는 누구의 제안 사항에도 투표할 수 있음(또는 자신의 투표를 제거할 수 있음)

  4. 작성자는 자신의 제안 사항을 편집/삭제할 수 있음


이 규칙은 서버에서 Firestore로 강제됩니다. 따라서 누군가 간신히 앱을 해킹하여 다른 사람의 제안 사항을 삭제하거나 다수의 투표를 추가하려 해도 데이터는 안전합니다.


규칙은 JavaScript를 아주 간소화한 버전처럼 보이는 Firestore의 보안 규칙 언어로 작성됩니다. 규칙은 다음과 같은 모습을 띠게 됩니다.

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
​
      // 1} anyone can read
      allow read: if true;
​
      // 2} logged-in users can add valid suggestions
      allow create: if isLoggedIn() && validData() && oneVote();
​
      // 3} logged-in users can vote for anyone's suggestions
      allow update: if isLoggedIn() && sameData() && oneVoteDiff();
​
      // 4) authors can edit and delete their suggestions ...
      allow update: if isAuthor() && validData() && oneVoteDiff();
      allow delete: if isAuthor();


조건 (2)에서는 로그인한 사용자가 유효한 제안 사항을 작성할 수 있다고 규정하고, 조건 (3)에서는 로그인한 사용자가 1건의 투표를 추가하거나 제거함으로써만 제안 사항을 업데이트할 수 있다고 규정하고 있음을 알 수 있습니다(제안 사항 작성자, 제목 또는 설명을 변경할 수는 없음).


모든 규칙은 allow (작업): if (조건)이라는 동일한 형식을 따릅니다. 이 경우 조건은 문서의 현재 데이터, 요청에서 수신되는 데이터, 현재 사용자의 이메일에 액세스할 수 있는 함수로 구현됩니다.


이러한 함수는 다음과 같이 구현됩니다.

 // functions
      function eMail() { // get the current user's e-mail
        return request.auth.token.email;
      }
​
      function isLoggedIn() { // user is logged in
        return eMail() != null;
      }
​
      function isAuthor() { // user is the suggestion author 
        return eMail() == resource.data.author;
      }
      function validData() { // the incoming data is valid
        let n = request.resource.data;
        return n.title != null && n.author == eMail() && 
              n.votes.size() == n.voteCount;
      }
      function sameData() { // the incoming data has no changes other than votes
        let n = request.resource.data;
        let o = resource.data;
        return n.author == o.author && n.title == o.title &&
              n.description == o.description;
      }
      function oneVote() { // the incoming data represents 0 or 1 votes
        let cnt = request.resource.data.voteCount;
        return cnt == 0 || cnt == 1;
      }
      function oneVoteDiff() { // incoming and current differ by 0 or 1 votes
        let diff = request.resource.data.voteCount - resource.data.voteCount;
        return diff >= -1 && diff <= 1;
      }


데이터베이스를 만드는 데 사용한 것과 동일한 UI를 사용해 규칙을 정의하는 방식으로 데이터베이스의 보안을 유지하는 기능은 제가 가장 좋아하는 Firestore 기능 중 하나입니다.


서버에서 바로 이러한 규칙을 작성하고 테스트할 수 있으므로 클라이언트 측 앱은 추가적인 서버 측 컴포넌트 없이도 데이터베이스와 직접 교신할 수 있습니다. 또한 서버 측에서 어떤 로직을 적용하고 싶다면 클라우드 함수를 사용해 적용할 수 있습니다.


응용 프로그램 만들기

보안이 유지되는 데이터베이스를 갖추었으므로 이제 사용자가 데이터를 보고 편집할 수 있게 해주는 응용 프로그램을 만들면 됩니다.


데이터에 액세스하고 UI를 빌드할 수 있는 Wijmo를 사용해 TypeScript 응용 프로그램을 만들 것입니다. React, Angular, Vue 같은 프레임워크를 사용할 수 있지만 앱이 너무 단순하므로 그럴 필요가 없습니다.


데이터 로드

이 응용 프로그램은 Firestore에서 데이터를 로드하는 것으로 시작됩니다. wijmo.cloud.Collection 개체를 사용하여 CollectionView로 데이터를 로드합니다. CollectionView에서 데이터는 다음과 같이 클라이언트 측에 정렬, 필터링 및 그룹화됩니다.

import { Firestore, Collection, OAuth2 } from '@grapecity/wijmo.cloud';
​
const PROJECT_ID = '***';
const API_KEY = '***';
​
// get the suggestions collection
let store = new Firestore(PROJECT_ID, API_KEY);
let suggestions = new Collection(store, 'suggestions', {
    limit: 1000, // load up to 1,000 suggestions
    collectionChanged: () => updateSuggestions();
}).orderBy('created', false); // show new suggestions first (by default);
​


이 코드에서는 마지막으로 작성된 1,000건의 제안 사항을 로드합니다.


정렬, 필터링, 추가, 편집 등으로 인해 데이터가 변경되는 경우 collectionChanged 이벤트가 발생하고 updateSugggestions 메서드를 호출하여 제안 사항을 사용자에게 표시합니다.


실제 응용 프로그램은 이보다 좀 더 스마트합니다. 즉 collectionChanged 이벤트 매개 변수를 사용해 DOM에 대한 업데이트를 최소화합니다. React, Angular, View와 같은 JavaScript 프레임워크를 사용한다면 이것도 고려해야 할 것입니다.


데이터 표시하기

updateSuggestions 메서드는 "제안 사항" 요소의 콘텐츠를 다음과 같이 업데이트합니다.

// render the suggestions
function updateSuggestions() {
    let host = getElement('suggestions');
        host.innerHTML = '';
    suggestions.items.forEach(s => {
        createElement(getSuggestionHTML(s), host);
    });
}
​

createElement 메서드는 Wijmo가 제공하는 유틸리티입니다. 이 메서드는 HTML 문자열에 근거하여 새로운 DOM 요소를 만들고 주어진 부모 요소에 이를 추가합니다. 


getSuggestionHTML 메서드는 JavaScript 템플릿을 사용해 제안 사항에 대한 HTML을 빌드합니다. 이 HTML에는 현재 사용자가 제안 사항 작성자일 경우 제안 사항을 편집하고 삭제할 수 있는 버튼이 포함되어 있습니다.

// build an HTML string to represent a suggestion
function getSuggestionHTML(s: ISuggestion): string {
​
    // allow author to edit/delete the suggestion
    let editRemove = '';
    if (auth.user && s.author == auth.user.eMail) {
        editRemove = `<div class="edit-remove">
            <span class="glyphicon glyphicon-pencil edit"></span>
            <span class="glyphicon glyphicon-remove remove"></span>
        </div>`;
    };
​
    // build HTML for a suggestion
    return `<div class="suggestion">
        <div class="votes">
            <div class="count">${s.voteCount}</div>
            <div>vote${s.voteCount == 1 ? '' : 's'}</div>
        </div>
        <div class="vote">
            <div class="vote-icon">${getVoteIcon(s)}</div>
            ${editRemove}
        </div>
        <div class="body">
            <div class="title">${renderHTML(s.title)}</div>
            <div class="description">${renderHTML(s.description) || ''}</div>
        </div>`;
}


이 템플릿에서는 renderHTML 함수를 사용해 제안 사항 제목 및 설명을 렌더링합니다. 두 필드 모두 가격 인하를 지원하므로, 이곳에서 원시 텍스트를 무결 처리한 후 사용자에게 표시될 html로 교체합니다. 이 앱에서는 다음과 같이 Remarkable 패키지를 사용해 가격 인하 콘텐츠의 서식을 지정합니다.

import { Remarkable } from 'remarkable';
const markDown = new Remarkable();
function renderHTML(text: string): string {
    text = text.replace(/[&<>]/g, (s) => {
              switch (s) {
                  case '&': return '&amp;';
                  case '<': return '&lt;';
                  case '>': return '&gt;';
              }
          });
    text = markDown.render(text);
    return text;
}


이 시점에서 응용 프로그램은 이미 데이터를 로드하여 표시할 수 있습니다. 사용자가 데이터를 편집할 수 있게 하려면 먼저 사용자가 로그인하여 인증을 받게 해야 합니다.


사용자 인증

이 앱에서는 Wijmo의 cloud.OAuth2 클래스를 사용해 사용자 인증을 수행합니다. 

이 앱의 API 키 및 클라이언트 ID를 사용해 "auth" 개체를 인스턴스화하는 것으로 시작합니다.

// create OAuth2 object for our app
const auth = new OAuth2(API_KEY, CLIENT_ID);

이어서 사용자가 앱에서 로그인 및 로그아웃할 수 있게 해주는 버튼에 "auth" 개체를 연결합니다.

// button to log in/out
let oAuthBtn = getElement('auth-btn');
oAuthBtn.addEventListener('click', () => {
    if (auth.user) {
        auth.signOut(); // user signing in
    } else {
        auth.signIn(); // user signing ouy
    }
});
​

끝으로 다음과 같이 "auth" 개체의 userChanged 이벤트를 처리하여 Firestore 개체에서 idToken 속성을 업데이트하고 화면에서 버튼 캡션과 제안 사항을 업데이트합니다.

// update button/view when user logs in or out
auth.userChanged.addHandler(s => {
    const user = s.user;
    store.idToken = user ? s.idToken : null; // update idToken
    oAuthBtn.textContent = user ? 'Sign Out' : 'Sign In';
    updateSuggestions();
});
 

Firestore 개체에서 idToken 속성을 설정하여 Firestore 인증을 활성화하고, 데이터베이스에 대해 설정하는 규칙은 서버에서 강제됩니다.


데이터 정렬

사용자가 대부분의 투표를 보거나 최신 투표를 먼저 볼 수 있도록 UI는 제안 사항 정렬을 지원합니다. 이러한 정렬 기능은 아래 강조 표시된 두 개의 버튼으로 구현됩니다.


 


이 버튼은 다음과 같이 클라이언트 측에서 정렬을 수행하므로 매우 빠르고 저렴한 비용으로 정렬할 수 있습니다(서버까지 왕복 교신할 필요 없음).

// sort the suggestions (client-side)

let sds = suggestions.sortDescriptions;
handleClick('btn-popular', () => { // popular, then new
    sds.deferUpdate(() => {
        sds.clear();
        sds.push(new SortDescription('votes.length', false));
        sds.push(new SortDescription('created', false));
    });
});
handleClick('btn-new', () => { // new, then popular
    sds.deferUpdate(() => {
        sds.clear();
        sds.push(new SortDescription('created', false));
        sds.push(new SortDescription('votes.length', false));
    });
});
​



데이터 검색 및 필터링

UI는 검색/필터링도 지원하므로 사용자는 특정 제품이나 기능을 포함하는 제안 사항 또는 자신이 작성한 제안 사항을 검색할 수 있습니다.


검색은 클라이언트 측에서도 수행됩니다. Firestore는 서버 측의 전체 텍스트 검색 기능을 지원하지 않지만, 지원한다 해도 이 경우에는 사용하지 않을 것입니다. 왜냐하면 클라이언트 측 필터링이 빠르고 유연하기 때문입니다.


다음과 같이 사용자가 필터 영역에 입력하거나 필터 지우기 버튼을 클릭할 때 사용자에게서 필터 텍스트를 가져오는 것으로 시작하겠습니다.

// filter the suggestions (client-site)
let filter = getElement('filter') as HTMLInputElement,
    filterTerms = null,
    filterTo = null;
filter.addEventListener('input', () => {
    if (filterTo) {
        clearTimeout(filterTo);
    }
    filterTo = setTimeout(() => {
        filterTerms = filter.value.toLowerCase().split(' ');
        suggestions.refresh();
    }, 300);
});
handleClick('btn-clear-filter', () => { // clear filter
    if (filter.value) {
        filter.value = '';
        filterTerms = null;
        suggestions.refresh();
    }
});


이 코드는 300ms 디바운싱 시간 제한을 기반으로 입력 이벤트를 수신 대기하며(따라서 필터가 사용자 유형에 따라 너무 자주 업데이트되지는 않음) "제안 사항" 컬렉션을 새로 고쳐 변경 사항이 준비된 후에 업데이트된 필터를 적용합니다.


"제안 사항" 컬렉션에는 아래와 같이 정의된 필터 기능이 있습니다.

// filter by title/description/author
suggestions.filter = (s: ISuggestion) => {
    let match = true;
    if (filterTerms && filterTerms.length) {
        let item = (s.title + s.description + s.author).toLowerCase();
        for (let i = 0; i < filterTerms.length && match; i++) {
            match = item.indexOf(filterTerms[i]) > -1;
        }
    }
    return match;
}​


이 필터는 검색 문자열을 별도 용어로 분할하고 "제목", "설명" 또는 "작성자" 필드에 모든 용어가 포함된 항목에 대해 true를 반환합니다.


"Alex"라는 사용자는 검색 상자에 "grid alex"를 입력하여 "grid"라는 용어가 포함되어 있고(and) 이메일 주소에 "alex"가 포함된 사용자가 제안한 모든 제안 사항을 찾을 수 있습니다.


제안 사항 작성, 편집 및 삭제

이 시점에서 앱은 제안 사항을 표시, 정렬, 필터링할 수 있습니다. 다음 단계는 사용자가 제안 사항을 추가, 편집, 제거할 수 있게 허용하는 것입니다.


제안 사항 작성

UI에는 다음과 같이 제안 사항을 추가하는 데 사용되는 입력 필드와 버튼이 있습니다.


 

사용자는 필드에 입력하고 "추가" 버튼을 클릭하거나 버튼을 직접 클릭할 수 있습니다. 이렇게 하면 Wijmo Popup 컨트롤로 구현되는 제안 사항 대화 상자가 표시됩니다

handleClick('add-suggestion', () => {
    if (!auth.user) {
        auth.signIn();
    } else {
        dlgHeader.textContent = 'Add Suggestion';
        dlgTitle.value = getValue('add-title');
        dlgDesc.value = '';
        getSuggestionDialog().show(true, (dlg: Popup) => {
            if (dlg.dialogResult == dlg.dialogResultSubmit) {
                let title = getValue('dlg-title'),
                    desc = getValue('dlg-desc');
                if (title) {
                    let now = new Date();
                    suggestions.addNew({
                        title: title,
                        description: desc,
                        author: auth.user.eMail,
                        created: now,
                        edited: now,
                        voted: now,
                        votes: [auth.user.eMail],
                        voteCount: 1
                    }, true);
                    setValue('add-title', '');
                }
            }
        });
    }
});


이 코드는 사용자가 로그인한 상태인지 확인하는 것으로 시작됩니다. 로그인 상태가 아니라면 "oauth" 개체에서 signIn 메서드를 호출하여 이를 즉시 반환합니다.


그런 다음, 코드는 대화 상자를 초기화하고, show 메서드를 호출하여 이를 사용자에게 표시합니다. 이어서 콜백 처리기를 사용해 "제안 사항" 컬렉션에서 addNew 메서드를 호출함으로써 새로운 제안 사항을 추가합니다.


이 처리기는 getValue 메서드를 사용해 기본적인 유효성 검사를 수행하고 사용자가 입력하는 텍스트에서 무례한 말을 제거합니다.

function getValue(id: string): string {

    let input = getElement(id) as any;
    return input.validity.valid
        ? noBadWords(input.value.trim())
        : null;
}
// https://github.com/MauriceButler/badwords
const badWords = /\b(4r5e|5h1t|5hit|a55|…)\b/gi;
function noBadWords(text: string): string {
    return text
        ? text.replace(badWords, match => Array(match.length + 1).join('✱'))
        : '';
}


클라이언트 측에서 사용자가 입력한 텍스트를 무결 처리하는 것도 좋지만, 실제 사례에서는 이를 위해 서버 기능을 사용하는 것이 더 안전합니다. 서버 측에서는 이 로직이 해커의 공격으로부터 보호를 받습니다.


제안 사항 투표, 편집 및 삭제

UI에는 각 제안 사항에 대한 "영역 편집"이 포함되어 있습니다. 이를 통해 "투표" 아이콘을 표시하여 사용자가 자신의 투표를 추가하거나 제안 사항에서 투표를 제거할 수 있습니다. 또한 현재 사용자가 제안 사항 작성자인 경우 다음과 같이 "편집" 및 "삭제" 버튼도 표시합니다.


 


세 개의 버튼을 처리하는 이 코드는 제안 사항을 식별하고 사용자가 로그인 상태인지 확인하는 블록으로 시작됩니다.

getElement('suggestions').addEventListener('click', (e: MouseEvent) => {
    if (e.target instanceof HTMLSpanElement) {
​
        // get the suggestion
        let sHost = closest(e.target, '.suggestion') as HTMLElement;
        if (sHost) {
            let index = getSuggestionIndex(sHost),
                s = suggestions.items[index];
​
            // user must be logged in
            if (!auth.user) {
                auth.signIn();
                return;
            }


그다음 코드 블록에서는 아래와 같이 투표 버튼에 대한 클릭을 처리합니다.

    // add/remove vote
            if (hasClass(e.target, 'up') || hasClass(e.target, 'down')) {
                suggestions.editItem(s);
                let index = s.votes.indexOf(auth.user.eMail);
                if (index < 0) {
                    s.votes.push(auth.user.eMail);
                } else {
                    s.votes.splice(index, 1);
                }
                s.voteCount = s.votes.length;
                s.voted = new Date();
                suggestions.commitEdit();
            }


이 코드는 editItem 메서드를 호출하여 제안 사항 편집을 시작하고, votes 배열에서 사용자의 이메일 주소를 추가 또는 제거하며, 서버에서 commitEdit를 호출하여 문서를 업데이트합니다.


그다음 블록에서는 "편집" 버튼을 처리합니다.

          // edit suggestion
            else if (hasClass(e.target, 'edit')) {
                dlgHeader.textContent = 'Edit Suggestion';
                dlgTitle.value = s.title;
                dlgDesc.value = s.description || '';
                getSuggestionDialog().show(true, (dlg: Popup) => {
                    if (dlg.dialogResult == dlg.dialogResultSubmit) {
                        let title = getValue('dlg-title'),
                            desc = getValue('dlg-desc');
                        if (title) {
                            suggestions.editItem(s);
                            s.title = title;
                            s.description = desc;
                            s.edited = new Date();
                            suggestions.commitEdit();
                        }
                    }
                });
            }​


새로운 제안 사항을 추가할 때 사용한 동일한 대화 상자(헤더만 다름)를 사용합니다.


사용자가 변경 사항을 확인하면 editItem을 호출하고, 항목을 업데이트하며, 전과 같이 commitEdit를 호출하여 수정된 항목을 저장합니다.


마지막 블록에서는 다음과 같이 "삭제" 버튼을 처리합니다.


          // remove suggestion
            else if (hasClass(e.target, 'remove')) {
                getConfirmDialog().show(true, (dlg: Popup) => {
                    if (dlg.dialogResult == dlg.dialogResultSubmit) {
                        suggestions.remove(s);
                    }
                });
            }


이 코드에서는 사용자가 정말 제안 사항을 삭제하길 원하는지 확인하는 대화 상자를 표시하며, 이 경우 "제안 사항" 컬렉션에서 remove 메서드를 호출합니다.


이 작업(추가, 편집, 제거)을 마치면 컬렉션은 collectionChanged 이벤트를 발생시키고 UI는 자동으로 업데이트됩니다.


다음 단계

이제 샘플 응용 프로그램이 준비되었습니다. 이 응용 프로그램은 데이터 기반의 특수한 서버리스 웹 앱으로서, 약 15k의 TypeScript(축소되지 않음) 코드로 구현됩니다.


Wijmo의 cloud 모듈을 사용하거나 사용할 계획이라면 이 샘플이 제품 문서화의 보완물로 유용하게 쓰이기를 바랍니다. 그렇지 않다면 여러분이 관심을 갖는 계기가 되길 바랍니다.


대부분의 흥미로운 샘플과 마찬가지로 이 모듈은 성장할 여지가 많습니다. 제가 추가하고 싶은 기능으로 다음과 같은 것들이 있습니다.

  1. 다른 사용자가 게시한 제안 사항에 사용자가 메모를 추가할 수 있는 기능

  2. 사용자가 구독하고 제안 사항의 상태가 변경되면 알림을 받을 수 있는 기능

  3. 제안 사항에 우선 순위와 현재 상태를 지정할 수 있는 필드 추가

  4. 서버에서 데이터를 무결 처리하고 유효성 검사할 수 있는 클라우드 함수 추가


결론

Firestore는 훌륭한 도구입니다. 서버를 설정하여 유지 관리하지 않고도 빠르고 안전한 데이터베이스를 손쉽게 만들고 사용할 수 있는 방법을 제공합니다.

Wijmo의 cloud 모듈은 이러한 Firestore의 성능을 더욱 향상시킵니다!

  • Collection 클래스를 사용하여 Firestore REST API를 통해 데이터에 직접 액세스함으로써 응용 프로그램을 간결하고 빠른 상태로 유지하십시오.

  • Snapshot 클래스를 사용하여 Google의 Firestore 클라이언트 라이브러리를 통해 데이터에 액세스하십시오. 이 라이브러리는 클라이언트 측 캐싱(분리된 시나리오에 유용함) 및 실시간 알림(일부 응용 프로그램에 중요함)과 같은 고급 기능을 제공합니다.

  • Collection 또는 Snapshot 클래스를 사용하는 경우 고급 클라이언트 측 정렬, 필터링, 그룹화, 편집 지원 등 Wijmo의 CollectionView 클래스에서 사용할 수 있는 모든 기능이 제공됩니다.

  • OAuth2 클래스를 사용하여 사용자 권한 부여를 빠르고 쉽고 안전하게 구현하십시오.


투표 샘플이 마음에 드셨으면 하는 바람입니다.

아래의 링크를 통해서 직접 Customer Voice App에 제안 사항을 직접 추가해볼 수 있습니다.



  • 페이스북으로 공유
  • 트위터로  공유
  • 링크 복사
  • 카카오톡으로 보내기

댓글목록

등록된 댓글이 없습니다.

메시어스 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기

태그1

인기글

더보기
  • 인기 게시물이 없습니다.
메시어스 홈페이지를 통해 제품에 대해서 더 자세히 알아 보세요!
홈페이지 바로가기
이메일 : sales-kor@mescius.com | 전화 : 1670-0583 | 경기도 과천시 과천대로 7길 33, 디테크타워 B동 1107호 메시어스(주) 대표자 : 허경명 | 사업자등록번호 : 123-84-00981 | 통신판매업신고번호 : 2013-경기안양-00331 ⓒ 2024 MESCIUS inc. All rights reserved.