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
<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에 가드를 추가하여 기능의 접근 및 페이지 접근을 제한할 수 있다.
✅ 웹에는 디바이스 관리 시스템을 만든다.
-- 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로 만들어주면 가능하다.
나머지 내용은 2편에서 계속하겠다.
일단 개요는다음과 같다.
A. 디바이스 목록 페이지
// 기능 요구사항
- 등록된 모든 디바이스 목록 표시
- 디바이스 상태 (활성/비활성/만료) 시각적 표시
- 검색/필터링 기능 (기기명, 모델, 상태별)
- 페이지네이션
- 마지막 접속일 표시
B. 디바이스 등록/편집 폼
// 필수 입력 필드
- 기기명 (1호기, 2호기 등)
- 디바이스 ID (Android Settings Secure ID)
- 시리얼 번호
- 기기 모델명
- 제조사
- 라이센스 시작일/만료일
- 활성화 여부
- 관리자 메모
C. 디바이스 상세 정보 페이지
// 표시 정보
- 기본 디바이스 정보
- 라이센스 상태 및 이력
- 해당 디바이스의 작업 데이터 통계
- 마지막 접속 로그
- 디바이스별 작업 이력
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 컴포넌트
🆕 앱 시작 시 라이센스 체크
🆕 만료/무효 라이센스 처리