Loading...
Loading...
Anders & A-Cube S.r.l. / December 1, 2024 ⢠2 min read
Preservation API (Gov-It-API v2) is a production-grade digital archival service that ensures long-term preservation of electronic documents in compliance with Italian regulatory standards. Built with Symfony 6.2+ and API Platform 3, it provides secure, scalable storage with comprehensive validation and testing.
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Symfony 6.2+ Application Layer ā
ā API Platform 3 ⢠Doctrine ORM ⢠Validators ā
āāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā
āāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Business Logic Layer ā
ā Document Processing ⢠Validation ⢠Archival ā
āāāāāāāā¬āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¬āāāāāāāāāāāāā
ā ā
āāāāāāāā¼āāāāāāāāāāā āāāāāāāāāāā¼āāāāāāāāāāāāā
ā PostgreSQL ā ā AWS Services ā
ā - Documents ā ā - S3 Storage ā
ā - Metadata ā ā - Lambda Processor ā
ā - Audit Logs ā ā - CloudWatch Logs ā
āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāāāāāā
API Platform Resources:
Symfony Services:
Document Entity:
<?php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\GetCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Entity]
#[ApiResource(
operations: [
new Get(),
new GetCollection(),
new Post(security: "is_granted('ROLE_USER')")
]
)]
class Document
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Assert\NotBlank]
private string $fileName;
#[ORM\Column(length: 64)]
#[Assert\NotBlank]
private string $sha256Hash;
#[ORM\Column]
private \DateTimeImmutable $uploadedAt;
#[ORM\Column(length: 255)]
private string $s3Key;
#[ORM\Column(type: 'json')]
private array $metadata = [];
#[ORM\Column(length: 50)]
#[Assert\Choice(choices: [
'pending', 'validated', 'preserved', 'error'
])]
private string $status = 'pending';
// Getters and setters...
}Document Processor Service:
<?php
namespace App\Service;
use App\Entity\Document;
use Aws\S3\S3Client;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class DocumentProcessor
{
public function __construct(
private S3Client $s3Client,
#[Autowire('%env(AWS_S3_BUCKET)%')]
private string $bucketName,
private ValidatorService $validator
) {}
public function process(Document $document, string $fileContent): void
{
// 1. Validate document
$validationResult =
Behat Configuration (behat.yml):
default:
suites:
default:
contexts:
- App\Tests\Behat\DocumentContext
- App\Tests\Behat\ApiContext
- App\Tests\Behat\AuthenticationContext
filters:
tags: "~@wip"
extensions:
Behat\Symfony2Extension:
kernel:
bootstrap: features/bootstrap/bootstrap.php
class: App\Kernel
FriendsOfBehat\SymfonyExtension: ~Example Behat Scenario:
# features/document-preservation.feature
Feature: Document Preservation
In order to comply with regulatory requirements
As an API client
I need to be able to preserve documents securely
Background:
Given I am authenticated as "user@example.com"
@critical
Scenario: Successfully preserve a valid PDF document
Given I have a PDF document "invoice-2024.pdf"
When I send a "POST" request to "/api/documents" with:
"""
{
"fileName": "invoice-2024.pdf",
"content": "@file:invoice-2024.pdf"
}
"""
Then the response status code should be 201
And the response should be in JSON
And the JSON node "status" should be equal to "pending"
And the JSON node "fileName" should be equal to "invoice-2024.pdf"
Behat Context Implementation:
<?php
namespace App\Tests\Behat;
use Behat\Behat\Context\Context;
use Behat\Gherkin\Node\PyStringNode;
class DocumentContext implements Context
{
public function __construct(
private DocumentProcessor $processor,
private EntityManagerInterface $entityManager
) {}
/**
* @When the document is processed
*/
public function theDocumentIsProcessed(): void
{
$document = $this->entityManager
->getRepository(Document::class)
->findOneBy
PHPStan Configuration (phpstan.neon):
parameters:
level: 8
paths:
- src
- tests
excludePaths:
- tests/bootstrap.php
- var
checkMissingIterableValueType: true
checkGenericClassInNonGenericObjectType: true
reportUnmatchedIgnoredErrors: trueExample PHPStan Clean Code:
<?php
namespace App\Service;
/**
* @template T of Document
*/
class DocumentRepository
{
/**
* @param class-string<T> $className
* @return T|null
*/
public function find(string $className, int $id): ?object
{
return $this->entityManager->find($className, $id);
}
/**
* @param array<string, mixed> $criteria
S3 Client Setup:
<?php
namespace App\Service\Aws;
use Aws\S3\S3Client;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
class S3Service
{
private S3Client $client;
public function __construct(
#[Autowire('%env(AWS_REGION)%')]
private string $region,
#[Autowire('%env(AWS_S3_BUCKET)%')]
private string $bucket
) {
$this->client = new S3Client([
'region' => $this->region,
'version' => 'latest'
]);
Lambda Invocation for Document Processing:
<?php
namespace App\Service\Aws;
use Aws\Lambda\LambdaClient;
class LambdaService
{
private LambdaClient $client;
public function __construct(string $region)
{
$this->client = new LambdaClient([
'region' => $region,
'version' => 'latest'
]);
}
public function processDocument(int $documentId): void
{
$this->client->invoke([
'FunctionName'
docker-compose.yml:
version: '3.8'
services:
php:
build: docker/php
volumes:
- .:/var/www/html
environment:
APP_ENV: dev
DATABASE_URL: postgresql://preservation:secret@postgres:5432/preservation_db
AWS_S3_BUCKET: preservation-dev
depends_on:
- postgres
postgres:
image: postgres:15
environment:
POSTGRES_DB: preservation_db
POSTGRES_USER: preservation
POSTGRES_PASSWORD: secret
volumes:
- postgres-data:/var/lib/postgresql/data
nginx:
image
# Enter PHP container
docker-compose exec php bash
# Install dependencies
composer install
# Run PHPStan
composer run phpstan
# Run Behat tests
composer run behat
# Run all CI checks
composer ciDeploy Script (deploy.sh):
#!/bin/bash
set -e
# Configuration
ENV=${ENV:-dev}
AWS_PROFILE=${AWS_PROFILE:-acube-dev}
GITHUB_TOKEN=${GITHUB_TOKEN}
echo "Deploying Preservation API to ${ENV} environment"
echo "AWS Profile: ${AWS_PROFILE}"
# 1. Run tests
docker-compose exec -T php composer ci
# 2. Build production image
docker build -t preservation-api:${ENV} -f Dockerfile.prod .
# 3. Push to ECR
aws --profile=${AWS_PROFILE} ecr get-login-password --region
Preservation API demonstrates enterprise-grade backend development with exceptional code quality (PHPStan level 8) and comprehensive testing (200+ Behat scenarios), ensuring regulatory compliance and reliable long-term document archival.
License: Proprietary (A-Cube S.r.l.)