컴파일 시점 검증
APT가 앱 실행 전에 위반을 잡아냅니다. @QfCrypto를 빠뜨렸나요? Privilege 선언을 놓쳤나요? 빌드가 실패합니다. 경고가 아니라 에러입니다.
의도를 한 번 선언하세요. APT가 컴파일 시점에 강제하고, 런타임이 어디서든 강제합니다. 코드가 줄어드는 건 부산물입니다 — 목표는 정확성입니다.
@QfEntity
class Employee {
@QfCrypto
String salary;
@QfCrypto
String phone;
}DB: salary, phone → 자동으로 암호화 저장
API: salary, phone → 조회 시 자동 복호화
UI: salary, phone → 권한 있는 역할에만 노출
@QfCrypto가 없으면 → 컴파일 에러추가 서비스 없음. 추가 설정 없음. 어노테이션 자체가 계약입니다 — 시스템이 강제합니다.
@QfEntity(capabilityKey = "employee-management")
class Employee {
@QfCrypto
String salary;
}어노테이션이 기계가 읽을 수 있는 명세입니다. 문서가 아닙니다. 관습이 아닙니다. 계약입니다.
javac + q-apt (Annotation Processor)
→ @QfEntity, @QfCrypto, @QfCapability 등을 읽음
→ 제약 조합을 검증
→ 메타데이터 생성 (resultcodes.json, 엔티티 메타데이터)
→ 위반 발견 시 → 빌드 실패유효하지 않은 것은 실행 중인 앱에 도달하지 못합니다.
요청 → Q Runtime
→ Capability / Privilege 확인
→ 조직 범위 필터 적용
→ @QfCrypto 암호화/복호화 적용
→ 유효성 검증 규칙 강제
→ 실패 시 구조화된 QfResultCode 반환이 코드를 직접 작성하지 않습니다. 선언했습니다. Q가 실행합니다.
| 질문 | 답변 |
|---|---|
| 언제 검증되나요? | 컴파일 시점 (APT) + 런타임 (fail-fast) |
| 실패하면 어떻게 되나요? | 빌드 에러 — 또는 항상 구조화된 QfResultCode 응답 |
| 무엇이든 오버라이드 가능한가요? | 예. SPI 어댑터, @QfOn 훅, 커스텀 검증기 — 모두 순수 Java |
| 성능 오버헤드는? | 메타데이터는 컴파일 시점 생성. 리플렉션 없음. 스타트업 스캔 없음. |
| 기존 코드와 함께 사용 가능한가요? | 예. access.mode=none으로 검사 비활성화. 제약을 점진적으로 추가. |
컴파일 시점에 제약 위반 발생:
error: [Q-Framework] @QfCrypto는 같은 필드에 @QfSearch와 함께 사용할 수 없습니다.
→ Employee.salary빌드 중단. 아무것도 배포되지 않습니다.
런타임에 제약 위반 발생:
{
"code": "Q-AUTH-000001",
"cause": "Required privilege not present.",
"resolution": "Assign the required privilege to the caller's role."
}구조화됨. 일관됨. 항상.
❌ 일반 Spring — 엔티티 1개, 7개 파일, ~400줄
// UserEntity.java
@Entity @Table(name = "users")
public class UserEntity {
@Id @GeneratedValue private Long id;
@Column(nullable = false) private String name;
@Column private String email; // 암호화? 직접 구현
@Column private String orgId;
}
// UserDto.java — 필드 중복
// UserMapper.java — 보일러플레이트 매핑
// UserRepository.java — JPA 보일러플레이트
// UserService.java — 유효성, 암호화, 조직 필터
// UserController.java — REST 엔드포인트
// SecurityConfig.java — 접근 제어 규칙이 코드의 90%는 실제 비즈니스 가치가 없습니다. AI는 이것을 매번 다르게 작성합니다. 보안 검토는 여러분의 몫입니다.
✅ Q-Framework — 파일 1개. 구조상 올바릅니다.
@QfEntity(
appKey = "app",
organizationPolicy = @QfOrganizationPolicy(
enabled = true, attribute = "organizationId"),
capabilityKey = "user-management"
)
public class UserEntity {
private String organizationId;
@QfListAttribute @QfDetailAttribute
@QfCreateAttribute(requiredOn = @QfRequiredOn(always = true))
@QfDisplayLabel(text = "이름")
private String name;
@QfDetailAttribute @QfCreateAttribute
@QfCrypto
@QfControlType(QfControlType.Type.email)
@QfDisplayLabel(text = "이메일")
private String email;
}코드를 숨기는 게 아닙니다. 의미 없는 노동을 제거합니다.
가장 큰 두려움: "내가 통제할 수 없는 시스템인가?"
무엇이든 오버라이드할 수 있습니다.
// Employee의 기본 목록 쿼리를 직접 구현으로 교체
@Component
public class EmployeeSearchAdapter implements QfEntityPersistenceAdapter {
@Override
public QfEntityListResponse list(QfEntityMetadataDoc.Entity meta,
QfEntityListRequest req) {
// 여러분의 QueryDSL, 조건, 규칙.
// Q가 기본 구현 대신 이것을 호출합니다.
return queryFactory.select(...)
.where(buildComplexPredicate(req))
.fetch();
}
}| 유지되는 것 | 방법 |
|---|---|
| 쿼리 로직 | QfEntityPersistenceAdapter |
| 사전/사후 훅 | 엔티티 메서드에 @QfOn |
| 인증 프로바이더 | QfUserProvider SPI |
| 조직 계층 | QfOrganizationProvider SPI |
| 기존 스택 | Spring Boot, JPA, 사용 중인 DB — 변경 없음 |
Q가 어디서나 동일한 90%를 처리합니다.나머지 10%, 여러분의 제품을 다르게 만드는 부분은 완전히 여러분의 것입니다.
백엔드 — Spring Boot 프로젝트에 추가:
dependencies {
implementation platform('net.softminds.qframework:q-spring-boot-bom:1.0.0-SNAPSHOT')
implementation 'net.softminds.qframework:q-spring-boot-starter:1.0.0-SNAPSHOT'
implementation 'net.softminds.qframework:q-spring-boot-jpa:1.0.0-SNAPSHOT'
annotationProcessor 'net.softminds.qframework:q-apt:1.0.0-SNAPSHOT'
}<dependencyManagement>
<dependencies>
<dependency>
<groupId>net.softminds.qframework</groupId>
<artifactId>q-spring-boot-bom</artifactId>
<version>1.0.0-SNAPSHOT</version>
<type>pom</type><scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>net.softminds.qframework</groupId>
<artifactId>q-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>net.softminds.qframework</groupId>
<artifactId>q-spring-boot-jpa</artifactId>
</dependency>
</dependencies>프론트엔드 — Nuxt 3 프로젝트에 추가:
pnpm add @softminds/q-nuxtnpm install @softminds/q-nuxt// nuxt.config.ts
export default defineNuxtConfig({
extends: ['@softminds/q-nuxt'],
})엔티티에 어노테이션을 달고, 앱을 실행하세요. API와 UI가 즉시 활성화됩니다.