feat: migration Ğ1v2 — Subsquid + Cesium+ g1.data.e-is.pro

Sources de données réelles Ğ1v2 (vérifiées par introspection) :
- SubsquidAdapter : https://squidv2s.syoul.fr/v1/graphql
  transfers(filter: timestamp >= since, orderBy: TIMESTAMP_DESC)
  with from.linkedIdentity.name pour jointure géo
- CesiumAdapter : https://g1.data.e-is.pro (59 841 profils)
  recherche batch par nom d'identité (title.keyword)
  g1.data.duniter.fr hors ligne depuis arrêt Ğ1v1

Schémas Zod mis à jour pour Ğ1v2 :
- G1v2KeySchema : SS58 "g1" + 47 chars = 49 chars (mesuré sur données réelles)
- SubsquidTransferSchema : id, blockNumber, timestamp ISO, amount BigInt string
- parseSubsquidAmount : BigInt string centimes → Ğ1 flottant

Activation : VITE_USE_LIVE_API=true dans .env.local
Badge "● live Ğ1v2 / ○ mock" ajouté dans l'UI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
syoul
2026-03-22 16:01:36 +01:00
parent d20d042bca
commit 2f813c5fdf
8 changed files with 392 additions and 259 deletions

View File

@@ -11,15 +11,17 @@ export default function App() {
const [transactions, setTransactions] = useState<Transaction[]>([]);
const [stats, setStats] = useState<PeriodStats | null>(null);
const [loading, setLoading] = useState(true);
const [source, setSource] = useState<'live' | 'mock'>('mock');
useEffect(() => {
let cancelled = false;
setLoading(true);
fetchData(periodDays).then(({ transactions, stats }) => {
fetchData(periodDays).then(({ transactions, stats, source }) => {
if (!cancelled) {
setTransactions(transactions);
setStats(stats);
setSource(source);
setLoading(false);
}
});
@@ -41,10 +43,19 @@ export default function App() {
<PeriodSelector value={periodDays} onChange={setPeriodDays} />
</div>
{/* Transaction count badge */}
{/* Transaction count + source badge */}
{!loading && (
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 z-[1000] bg-[#0a0b0f]/80 backdrop-blur-sm border border-[#2e2f3a] rounded-full px-4 py-1.5 text-xs text-[#6b7280]">
<span className="text-[#d4a843] font-medium">{transactions.length}</span> transactions affichées
<div className="absolute bottom-8 left-1/2 -translate-x-1/2 z-[1000] flex items-center gap-2">
<div className="bg-[#0a0b0f]/80 backdrop-blur-sm border border-[#2e2f3a] rounded-full px-4 py-1.5 text-xs text-[#6b7280]">
<span className="text-[#d4a843] font-medium">{transactions.length}</span> transactions affichées
</div>
<div className={`backdrop-blur-sm border rounded-full px-3 py-1.5 text-xs font-medium ${
source === 'live'
? 'bg-emerald-950/80 border-emerald-700 text-emerald-400'
: 'bg-[#0a0b0f]/80 border-[#2e2f3a] text-[#4b5563]'
}`}>
{source === 'live' ? '● live Ğ1v2' : '○ mock'}
</div>
</div>
)}