Skill chuyên biệt để implement Tarot features — DivineHelper entity, Tarot Reading flow, spreads, AI interpretation, Card Content & Set Story
Skill này là domain expert cho tính năng Tarot của PixelMage. Dùng khi implement bất kỳ tính năng liên quan: CardTemplate, DivineHelper, Reading Sessions, Set Story, Collection Achievement.
project_note/TAROT_AI_SYSTEM_PROMPT.md — business logic chi tiết cho AI Readingproject_note/be_planning.md — domain model & data classificationTarotCard riêng — dùng CardTemplate + DivineHelper (1:1)Major Arcana: 22 lá (The Fool = 0 → The World = 21)
Minor Arcana: 56 lá
├── Wands (14 lá): Ace → 10 + Page, Knight, Queen, King
├── Cups (14 lá): Ace → 10 + Page, Knight, Queen, King
├── Swords (14 lá): Ace → 10 + Page, Knight, Queen, King
└── Pentacles (14 lá): Ace → 10 + Page, Knight, Queen, King
1. Single Card (1 lá) — Quick guidance
2. Three Card (3 lá) — Past / Present / Future
3. Celtic Cross (10 lá) — Deep reading (labels từng vị trí)
4. Relationship (7 lá) — Love/relationship
5. Career (5 lá) — Work/career focus
CardFramework
↓
CardTemplate (78 lá — demo: 21 lá đầu)
├── DivineHelper (1:1 — divination rules & meanings)
├── CardContent (1:N — story, lore, HD artwork, locked sau NFC)
└── SetStory (N:M — nhóm templates tạo mẫu chuyện liên hoàn)
Spread (5 loại, seed data)
↓
ReadingSession (user + spread + question + cards drawn)
↓
ReadingCard (session + cardTemplate + position + isReversed)
@Entity @Table(name = "divine_helpers")
@Data @Builder @NoArgsConstructor @AllArgsConstructor
public class DivineHelper {
@Id @GeneratedValue private UUID id;
@OneToOne @JoinColumn(name = "card_template_id", unique = true)
private CardTemplate cardTemplate;
// Core divination
private String uprightKeywords; // JSON array hoặc comma-separated
private String reversedKeywords;
@Column(columnDefinition = "NVARCHAR(MAX)")
private String uprightMeaning;
@Column(columnDefinition = "NVARCHAR(MAX)")
private String reversedMeaning;
private String archetype; // VD: "Đứa trẻ Thần Thánh"
@Column(columnDefinition = "NVARCHAR(MAX)")
private String symbolicNote; // Bắt buộc cho Death/Tower/Devil
// Elemental / Astrological
@Enumerated(EnumType.STRING)
private Element element; // AIR, WATER, FIRE, EARTH
private String zodiacSign; // cung hoàng đạo tương ứng
private String nguHanh; // KIM, MOC, THUY, HOA, THO
// Domain meanings
@Column(columnDefinition = "NVARCHAR(MAX)")
private String loveMeaning;
@Column(columnDefinition = "NVARCHAR(MAX)")
private String careerMeaning;
@Column(columnDefinition = "NVARCHAR(MAX)")
private String financeMeaning;
@Column(columnDefinition = "NVARCHAR(MAX)")
private String spiritualMeaning;
// Card interaction
private String synergyCardIds; // JSON array of template IDs
private String tensionCardIds; // JSON array of template IDs
// AI hints
@Column(columnDefinition = "NVARCHAR(MAX)")
private String framePositive; // Cách frame tích cực cho lá "khó"
private String interpretationHint; // Gợi ý cho AI
private Boolean disclaimerRequired; // true cho Death/Tower/Devil/health topics
}
@Entity @Table(name = "reading_sessions")
public class ReadingSession {
@Id @GeneratedValue private UUID id;
@ManyToOne private Account user;
@ManyToOne private Spread spread;
private String topic; // LOVE, CAREER, FINANCE, SPIRITUAL, GENERAL
@Column(columnDefinition = "NVARCHAR(MAX)")
private String question;
private String emotionalState; // CURIOUS, ANXIOUS, DECISIVE, GRIEVING
private Boolean isPublic;
private String shareToken; // UUID for public sharing
@Enumerated(EnumType.STRING)
private ReadingStatus status; // DRAFT, COMPLETED
@Column(columnDefinition = "NVARCHAR(MAX)")
private String aiInterpretation; // Kết quả AI (nullable, Phase 3)
private LocalDateTime createdAt;
}
@Entity @Table(name = "reading_cards")
public class ReadingCard {
@Id @GeneratedValue private UUID id;
@ManyToOne private ReadingSession session;
@ManyToOne private CardTemplate cardTemplate;
private Integer position; // vị trí trong spread (0-indexed)
private String positionLabel; // "Past", "Present", "Future", etc.
private Boolean isReversed;
}
POST /api/readings — Tạo reading session (chọn spread + topic)
POST /api/readings/{id}/draw — Rút bài (crypto-safe RNG, 30% reversed)
PUT /api/readings/{id}/save — Save & lock session (DRAFT → COMPLETED)
POST /api/readings/{id}/interpret — Gọi AI interpretation (Phase 3)
GET /api/readings/{id} — Chi tiết session (verify owner hoặc public)
GET /api/readings/my-history — Lịch sử reading của user
POST /api/readings/{id}/share — Toggle public + generate shareToken
GET /api/readings/public/{token} — Xem session public (no auth)
GET /api/daily-card — Rút 1 lá miễn phí mỗi ngày
GET /api/divine-helpers?templateId= — Lấy thông tin divination cho 1 template
GET /api/spreads — Danh sách spreads hệ thống
public String interpretReading(ReadingSession session, List<ReadingCard> cards) {
// 1. Build context from DivineHelper
List<DivineHelper> helpers = cards.stream()
.map(c -> divineHelperRepo.findByCardTemplate(c.getCardTemplate()))
.toList();
// 2. Build prompt (TAROT_AI_SYSTEM_PROMPT.md format)
String systemPrompt = loadSystemPrompt();
String userPrompt = buildUserPrompt(session, cards, helpers);
// 3. Call Claude API
String aiResponse = claudeApiService.complete(systemPrompt, userPrompt);
// 4. Fallback: nếu AI lỗi → trả DivineHelper meanings trực tiếp
if (aiResponse == null) {
return buildFallbackInterpretation(cards, helpers);
}
return aiResponse;
}
components/
├── TarotCardDisplay.tsx — Hiển thị 1 lá bài (front/back, animate flip)
├── CardSpread.tsx — Layout trải bài (vị trí các lá)
├── ReadingSession.tsx — Container cho cả reading flow
├── SpreadSelector.tsx — Chọn loại trải bài
├── InterpretationPanel.tsx — Hiển thị AI/DivineHelper interpretation
├── DailyCardWidget.tsx — Daily card trên home page
└── ReadingHistory.tsx — Lịch sử các lần đọc bài
react-native-reanimated + FlipInYLeft effectAnimated.sequencereact-native-haptic-feedback khi rút bàireact-native-mmkv