ワンクリックで
data-pipeline-engineering
Data pipeline design, ETL processes, Spring Integration patterns, batch processing for political data
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Data pipeline design, ETL processes, Spring Integration patterns, batch processing for political data
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Identity and access management: RBAC, least privilege, MFA, quarterly reviews per ISO 27001 A.5.15, A.8.2, A.8.3
Business continuity and disaster recovery: 30-day retention, quarterly restore tests, RTO/RPO targets per ISO 27001 A.17
Political psychology, cognitive biases, group dynamics, leadership analysis, decision-making patterns for Swedish political intelligence
Risk-based data and asset classification framework: PUBLIC, INTERNAL, CONFIDENTIAL, RESTRICTED aligned with ISO 27001 A.5.12 and CIA triad
Unified compliance verification across ISO 27001, NIST CSF, CIS Controls, NIS2, EU CRA, GDPR, SOC 2, PCI DSS, and HIPAA for cybersecurity consulting
Cryptographic controls implementation: TLS 1.3, AES-256-GCM, bcrypt, RSA-4096, key management per NIST FIPS 140-2 and ISO 27001 A.8.24
| name | data-pipeline-engineering |
| description | Data pipeline design, ETL processes, Spring Integration patterns, batch processing for political data |
| license | Apache-2.0 |
Design and implement robust data pipelines for the CIA platform that extract, transform, and load Swedish political data from multiple sources into the internal data model. Covers Spring Integration, batch processing, and monitoring patterns.
Do NOT use for:
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ Extract │───▶│ Transform │───▶│ Load │───▶│ Monitor │
│ │ │ │ │ │ │ │
│ API Fetch │ │ Validate │ │ JPA Upsert │ │ Metrics │
│ XML/JSON │ │ Map Fields │ │ Batch Save │ │ Alerts │
│ Pagination │ │ Enrich │ │ Index │ │ Dashboards │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
@Configuration
public class RiksdagPipelineConfig {
@Bean
public IntegrationFlow riksdagImportFlow() {
return IntegrationFlow
.from(pollingSource(), e -> e.poller(
Pollers.cron("0 0 2 * * *") // Daily at 2 AM
.maxMessagesPerPoll(1)
.errorHandler(pipelineErrorHandler())))
.channel("riksdagRawChannel")
.transform(xmlToJsonTransformer())
.split(personListSplitter())
.channel(c -> c.executor(taskExecutor()))
.filter(dataQualityFilter())
.transform(entityMapper())
.aggregate(batchAggregator())
.handle(jpaOutboundAdapter())
.get();
}
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(1000);
executor.setThreadNamePrefix("riksdag-pipeline-");
return executor;
}
}
@Bean
public IntegrationFlow errorFlow() {
return IntegrationFlow
.from("errorChannel")
.handle(message -> {
MessagingException exception = (MessagingException) message.getPayload();
LOG.error("Pipeline error: {}", exception.getMessage(), exception);
metricsService.incrementErrorCount("riksdag-pipeline");
// Route to dead letter queue for manual review
Message<?> failedMessage = exception.getFailedMessage();
deadLetterRepository.save(new DeadLetterEntry(
failedMessage.getPayload().toString(),
exception.getMessage(),
Instant.now()
));
})
.get();
}
@Configuration
public class VoteImportBatchConfig {
@Bean
public Job voteImportJob(JobRepository jobRepository, Step importStep) {
return new JobBuilder("voteImportJob", jobRepository)
.incrementer(new RunIdIncrementer())
.start(importStep)
.build();
}
@Bean
public Step importStep(JobRepository jobRepository,
PlatformTransactionManager txManager) {
return new StepBuilder("importVotes", jobRepository)
.<RiksdagVote, VoteData>chunk(100, txManager)
.reader(voteReader())
.processor(voteProcessor())
.writer(voteWriter())
.faultTolerant()
.retryLimit(3)
.retry(TransientDataAccessException.class)
.skipLimit(10)
.skip(DataValidationException.class)
.listener(stepListener())
.build();
}
}
| Data Type | Records/Batch | Chunk Size | Reason |
|---|---|---|---|
| Person data | ~350 | 50 | Small dataset, frequent updates |
| Vote records | ~100K/session | 500 | Large dataset, bulk insert |
| Documents | ~50K | 100 | Variable size, careful processing |
| Committee data | ~100 | 25 | Small, relational integrity |
@Component
public class RiksdagEntityMapper {
public PersonData mapPerson(RiksdagPerson source) {
PersonData target = new PersonData();
target.setId(source.getIntressentId());
target.setFirstName(sanitize(source.getFornamn()));
target.setLastName(sanitize(source.getEfternamn()));
target.setParty(normalizeParty(source.getParti()));
target.setBornYear(parseYear(source.getFoddAr()));
target.setGender(normalizeGender(source.getKon()));
target.setStatus(source.getStatus());
target.setImportTimestamp(Instant.now());
return target;
}
private String sanitize(String input) {
if (input == null) return null;
String trimmed = input.trim().replaceAll("[\\p{Cntrl}]", ""); // Remove control characters
return trimmed.substring(0, Math.min(trimmed.length(), 255));
}
private String normalizeParty(String party) {
return Optional.ofNullable(party)
.map(String::trim)
.map(String::toUpperCase)
.orElse("-");
}
}
@Component
public class PipelineScheduler {
@Scheduled(cron = "0 0 2 * * *") // Daily full refresh
public void dailyFullImport() {
LOG.info("Starting daily full import");
importService.importAll();
}
@Scheduled(cron = "0 */15 8-18 * * MON-FRI") // Every 15 min during sessions
public void incrementalVoteImport() {
if (riksdagSessionActive()) {
LOG.info("Starting incremental vote import");
importService.importRecentVotes();
}
}
}
@Component
public class PipelineMetrics {
private final MeterRegistry meterRegistry;
public void recordImport(String pipeline, int recordCount, long durationMs) {
meterRegistry.counter("pipeline.records.imported",
"pipeline", pipeline).increment(recordCount);
meterRegistry.timer("pipeline.duration",
"pipeline", pipeline).record(durationMs, TimeUnit.MILLISECONDS);
}
public void recordError(String pipeline, String errorType) {
meterRegistry.counter("pipeline.errors",
"pipeline", pipeline,
"error_type", errorType).increment();
}
}
| Control | Requirement |
|---|---|
| ISO 27001 A.8.10 | Information deletion / data retention |
| ISO 27001 A.5.33 | Protection of records |
| NIST CSF PR.DS-1 | Data-at-rest protection |
| CIS Control 3 | Data protection |