Quasar capacitor App 라이선스

SongWoo Yu·2025년 6월 9일
0

Quasar - Vue3

목록 보기
6/7

@capacitor/device 플러그인을 설치

cd /src-capcitor
npm install @capcitor/device
npx cap sync

설치에 실패한다면 Quasar의 capcitor 버전이 한 단계 낮기 때문일 것이다. 그렇다고 함부로 Quasar 프로젝트의 capcitor 버전을 업그레이드해선 안 된다. 보통 프로젝트 초기라면 Quasar에서 보증하는 버전이 설치되어 있을 것이기 때문에 함부로 업그레이드하면 문제가 발생할 수 있다. 업데이트는 최대한 조심해야 한다.

그렇다면 플러그인의 버전을 한 단계 낮추는 방향으로 진행한다.
나는 한 단계 낮은 6버전의 최상위 상용버전을 설치했다. 아마존 Q-developer CLI를 사용하면 해당 버전을 시각화하여 쉽게 찾을 수 있다.

npm install @capacitor/device@6.0.2
npx cap sync

안드로이드 id VS 디바이스 id VS IMEI VS Serial number

  1. Device id : Android Setting Secure ID(SSAID)로 앱별로 갖는 고유한 값이다. 앱 재설치 시에도 유지된다. 따라서 앱에서 디바이스를 식별하는 안전한 방법이다. Android id의 APP 버전인 것이다. 디바이스 초기화시에는 새롭게 생성된다.
  2. 안드로이드 id : 안드로이드 ID는 기기의 고유 식별자로, Android 기기를 처음 부팅할 때 생성된다. 즉 초기화시에는 다시 생성되므로 주의해야 한다.
  3. IMEI (International Mobile Equipment Identity) : 모바일 기기의 고유 하드웨어 식별번호이다. 안드로이드 id와 비슷한 것으로 간주하곤 한다.
  4. 시리얼 넘버 : 제조사가 하드웨어에 부여한 번호로 기기별 고유값이다. 따라서 초기화에도 변화하지 않는다. 특별한 권한이 필요하므로 앱에서는 잘 사용되지 않는다. 다만 내 기기를 반영구적으로 식별하고 싶을 때, 별도로 저장해놓고 설정에서 확인할 수 있다.

Device id 가져오기; Device.getId()

<script setup>
import { ref } from 'vue';
import { Device } from '@capacitor/device';
import { useQuasar } from 'quasar';

const $q = useQuasar();
const deviceId = ref(null);

const getDeviceId = async () => {
  try {
    const id = await Device.getId();
    deviceId.value = id.identifier; // 안드로이드 ID
    $q.notify({
      color: 'positive',
      message: `디바이스 ID: ${deviceId.value}`,
      icon: 'check'
    });
  } catch (error) {
    console.error('디바이스 ID 가져오기 실패:', error);
    $q.notify({
      color: 'negative',
      message: '디바이스 ID를 가져오지 못했습니다.',
      icon: 'error'
    });
  }
};

// 컴포넌트 마운트 시 디바이스 ID 가져오기
onMounted(() => {
  getDeviceId();
});
</script>

<template>
  <div>
    <q-btn label="디바이스 ID 확인" color="primary" @click="getDeviceId" />
    <div v-if="deviceId">디바이스 ID: {{ deviceId }}</div>
  </div>
</template>

위는 예시 파일이다. 이렇게 capcitor plugin이 잘 작동한다면 다음 단계로 넘어간다.

✅ db의 구조를 변경하여 디바이스의 라이센스를 관리할 준비를 한다.
✅ 추가적으로 디바이스 핑거포인트(디바이스의 고유한 특성들을 조합한 식별자)를 생성해서 식별할 수도 있다.
✅ Quasar에서는 main페이지(첫 페이지)에서 라이센스를 확인하고, index.js에 가드를 추가하여 기능의 접근 및 페이지 접근을 제한할 수 있다.
✅ 웹에는 디바이스 관리 시스템을 만든다.

서버 DB 구조 변경

-- DEVICE 테이블 확장/수정
ALTER TABLE "DEVICE" 
ADD COLUMN IF NOT EXISTS device_name TEXT NOT NULL,           -- '1호기', '2호기' 등
ADD COLUMN IF NOT EXISTS device_id TEXT UNIQUE NOT NULL,      -- Android Settings Secure ID
ADD COLUMN IF NOT EXISTS serial_number TEXT,                 -- 하드웨어 시리얼 넘버 (서버/웹 관리용)
ADD COLUMN IF NOT EXISTS device_model TEXT,                  -- 기기 모델명 (예: SM-T870)
ADD COLUMN IF NOT EXISTS manufacturer TEXT,                  -- 제조사 (예: samsung)
ADD COLUMN IF NOT EXISTS os_version TEXT,                    -- OS 버전
ADD COLUMN IF NOT EXISTS license_start_date TIMESTAMP WITH TIME ZONE,  -- 라이센스 시작일
ADD COLUMN IF NOT EXISTS license_end_date TIMESTAMP WITH TIME ZONE,    -- 라이센스 만료일
ADD COLUMN IF NOT EXISTS device_enable_yn BOOLEAN DEFAULT false,       -- 라이센스 활성화 여부
ADD COLUMN IF NOT EXISTS last_check_date TIMESTAMP WITH TIME ZONE,     -- 마지막 라이센스 확인일
ADD COLUMN IF NOT EXISTS notes TEXT,                         -- 관리자 메모
ADD COLUMN IF NOT EXISTS created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();

-- 인덱스 추가 (성능 향상)
CREATE INDEX IF NOT EXISTS idx_device_device_id ON "DEVICE"(device_id);
CREATE INDEX IF NOT EXISTS idx_device_serial_number ON "DEVICE"(serial_number);
CREATE INDEX IF NOT EXISTS idx_device_enable_yn ON "DEVICE"(device_enable_yn);

-- 업데이트 트리거 (updated_at 자동 갱신)
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ language 'plpgsql';

CREATE TRIGGER update_device_updated_at 
    BEFORE UPDATE ON "DEVICE"
    FOR EACH ROW 
    EXECUTE FUNCTION update_updated_at_column();

만약 null과 관련된 문제가 발생한다면 이미 레코드가 존재하는 경우에 새로운 컬럼을 not null로 만들게 되면 기존에 있는 레코드가 규칙을 위반하게 되므로 컬럼을 생성할 수 없다. 레코드를 삭제하고 만들든가, 아니면 nullable로 만들어주면 가능하다.

  1. device id, license_start/end_date, created_at, updated_at 컬럼을 생성한다. 이들은 무조건 필요한 내용이다.
  2. 자주 사용될 내용에 인덱스를 추가하여 성능을 향상시킨다.
  3. 내용이 변화할 때마다 update 시기를 조정해야 하므로 이를 저장하는 함수를 만든다. 그리고 변화를 감지하는 트리거를 만들어 함수를 호출하도록 한다.

2편에서 계속

나머지 내용은 2편에서 계속하겠다.
일단 개요는다음과 같다.

📋 구현해야 하는 내용

🖥️ 1단계: 서버 디바이스 관리 페이지

A. 디바이스 목록 페이지

// 기능 요구사항
- 등록된 모든 디바이스 목록 표시
- 디바이스 상태 (활성/비활성/만료) 시각적 표시
- 검색/필터링 기능 (기기명, 모델, 상태별)
- 페이지네이션
- 마지막 접속일 표시

B. 디바이스 등록/편집 폼

// 필수 입력 필드
- 기기명 (1호기, 2호기 등)
- 디바이스 ID (Android Settings Secure ID)
- 시리얼 번호
- 기기 모델명
- 제조사
- 라이센스 시작일/만료일
- 활성화 여부
- 관리자 메모

C. 디바이스 상세 정보 페이지

// 표시 정보
- 기본 디바이스 정보
- 라이센스 상태 및 이력
- 해당 디바이스의 작업 데이터 통계
- 마지막 접속 로그
- 디바이스별 작업 이력

📱 2단계: 앱 라이센스 시스템

A. 라이센스 스토어 (Pinia)

// stores/license.js
export const useLicenseStore = defineStore('license', {
  state: () => ({
    isLicenseValid: false,
    licenseInfo: null,
    deviceId: null,
    isChecking: false,
    lastCheckTime: null
  }),
  
  actions: {
    async checkLicense(),
    async updateLastCheck(),
    isExpiringSoon(), // 만료 임박 알림
    getLicenseStatus()
  }
})

B. 앱 시작 시 라이센스 검증

// App.vue 또는 main.js
- 앱 로드 시 자동 라이센스 확인
- 라이센스 무효 시 제한 모드 진입
- 만료 임박 시 경고 메시지

C. MainWorkPage 접근 제어

// 핵심 기능 보호
- 작업 시작/종료 버튼 비활성화
- 데이터 저장 기능 제한
- 블루투스 연결 제한
- 라이센스 만료 시 읽기 전용 모드

D. 라이센스 상태 표시 컴포넌트

// LicenseStatusBanner.vue
- 라이센스 상태 상단바 표시
- 만료 임박 시 경고 배너
- 라이센스 갱신 안내

🛠️ 구체적인 구현 순서

1주차: 데이터베이스 및 서버 관리 페이지
✅ 스키마 수정 (serial_number 타입, 트리거 추가)
🆕 서버 디바이스 관리 페이지 개발
디바이스 목록 API
디바이스 CRUD API
웹 관리 인터페이스
2주차: 앱 라이센스 시스템 기초
🆕 라이센스 스토어 개발
🆕 디바이스 관리 페이지 개선 (현재 페이지 확장)
🆕 라이센스 확인 로직 구현
3주차: 앱 접근 제어 및 완성
🆕 MainWorkPage 라이센스 검증
🆕 라이센스 상태 UI 컴포넌트
🆕 앱 시작 시 라이센스 체크
🆕 만료/무효 라이센스 처리

0개의 댓글