Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/app.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/app.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/app.py	(revision 12089)
@@ -43,4 +43,6 @@
     _curr_doc_id = 101
 
+    _curr_app_id = 101
+
     # Setup authentication for this app. Note: this is only
     # initialized, when a new instance of this app is created.
@@ -58,7 +60,5 @@
         """A unique document id for all documents in company.
 
-        The document id returned is guaranteed to be unique. It
-        consists of some prefix (normally a single letter) followed by
-        a number with at least 7 digits.
+        The document id returned is guaranteed to be unique. 
 
         Once a document id was issued, it won't be issued again.
@@ -70,4 +70,23 @@
         new_id = u'd%s' % (self._curr_doc_id)
         self._curr_doc_id += 1
+        # self._p_changed = True
+        # commit()
+        # lock.release() # end of lock
+        return new_id
+
+    @property
+    def unique_application_id(self):
+        """A unique application id for all application objects in customers.
+
+        The application id returned is guaranteed to be unique.
+
+        Once a application id was issued, it won't be issued again.
+
+        Obtaining an application id is currently not thread-safe but can be
+        made easily by enabling commented lines.
+        """
+        # lock.acquire() # lock data
+        new_id = u'd%s' % (self._curr_app_id)
+        self._curr_app_id += 1
         # self._p_changed = True
         # commit()
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/applications.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/applications.py	(revision 12089)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/applications.py	(revision 12089)
@@ -0,0 +1,158 @@
+## $Id$
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Customer application components.
+"""
+import os
+import grok
+from zope.component import queryUtility, getUtility
+from zope.component.interfaces import IFactory
+from zope.interface import implementedBy
+from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState
+from waeup.ikoba.interfaces import MessageFactory as _
+from waeup.ikoba.interfaces import IIkobaUtils, IObjectHistory
+from waeup.ikoba.customers.interfaces import (
+    IApplicationsContainer, ICustomerNavigation,
+    IApplication, ICustomersUtils,
+    )
+from waeup.ikoba.customers.utils import generate_application_id
+from waeup.ikoba.utils.helpers import attrs_to_fields
+
+class ApplicationsContainer(grok.Container):
+    """This is a container for customer applications.
+    """
+    grok.implements(IApplicationsContainer, ICustomerNavigation)
+    grok.provides(IApplicationsContainer)
+
+    def addApplication(self, application):
+        if not IApplication.providedBy(application):
+            raise TypeError(
+                'ApplicationsContainers contain only IApplication instances')
+        self[application.application_id] = application
+        return
+
+    @property
+    def customer(self):
+        return self.__parent__
+
+    def writeLogMessage(self, view, message):
+        return self.__parent__.writeLogMessage(view, message)
+
+ApplicationsContainer = attrs_to_fields(ApplicationsContainer)
+
+class ApplicationBase(grok.Container):
+    """This is a customer application baseclass.
+    """
+    grok.implements(IApplication, ICustomerNavigation)
+    grok.provides(IApplication)
+    grok.baseclass()
+
+    def __init__(self):
+        super(ApplicationBase, self).__init__()
+        # The site doesn't exist in unit tests
+        try:
+            self.application_id = generate_application_id()
+        except AttributeError:
+            self.application_id = u'a123'
+        return
+
+    @property
+    def history(self):
+        history = IObjectHistory(self)
+        return history
+
+    @property
+    def state(self):
+        return IWorkflowState(self).getState()
+
+    @property
+    def translated_state(self):
+        try:
+            TRANSLATED_STATES = getUtility(
+                ICustomersUtils).TRANSLATED_APPLICATION_STATES
+            return TRANSLATED_STATES[self.state]
+        except KeyError:
+            return
+
+    @property
+    def class_name(self):
+        return self.__class__.__name__
+
+    @property
+    def formatted_transition_date(self):
+        try:
+            return self.last_transition_date.strftime('%Y-%m-%d %H:%M:%S')
+        except AttributeError:
+            return
+
+    @property
+    def customer(self):
+        try:
+            return self.__parent__.__parent__
+        except AttributeError:
+            return None
+
+    def writeLogMessage(self, view, message):
+        return self.__parent__.__parent__.writeLogMessage(view, message)
+
+    @property
+    def is_editable(self):
+        try:
+            # Customer must be approved
+            cond1 = self.customer.state in getUtility(
+                ICustomersUtils).APPMANAGE_CUSTOMER_STATES
+            # Application must be in state created
+            cond2 = self.state in getUtility(
+                ICustomersUtils).APPMANAGE_APPLICATION_STATES
+            if not (cond1 and cond2):
+                return False
+        except AttributeError:
+            pass
+        return True
+
+    @property
+    def translated_class_name(self):
+        try:
+            DOCTYPES_DICT = getUtility(ICustomersUtils).DOCTYPES_DICT
+            return DOCTYPES_DICT[self.class_name]
+        except KeyError:
+            return
+
+
+class SampleApplication(ApplicationBase):
+    """This is a sample application.
+    """
+
+SampleApplication = attrs_to_fields(SampleApplication)
+
+
+# Applications must be importable. So we might need a factory.
+class SampleApplicationFactory(grok.GlobalUtility):
+    """A factory for applications.
+    """
+    grok.implements(IFactory)
+    grok.name(u'waeup.SampleApplication')
+    title = u"Create a new application.",
+    description = u"This factory instantiates new sample application instances."
+
+    def __call__(self, *args, **kw):
+        return SampleApplication(*args, **kw)
+
+    def getInterfaces(self):
+        return implementedBy(SampleApplication)
+
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/batching.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/batching.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/batching.py	(revision 12089)
@@ -45,5 +45,6 @@
     ICustomerDocument)
 from waeup.ikoba.customers.workflow import  (
-    IMPORTABLE_STATES, IMPORTABLE_TRANSITIONS)
+    IMPORTABLE_REGISTRATION_STATES, IMPORTABLE_REGISTRATION_TRANSITIONS,
+    IMPORTABLE_APPLICATION_STATES, IMPORTABLE_APPLICATION_TRANSITIONS)
 from waeup.ikoba.utils.batching import BatchProcessor
 
@@ -256,9 +257,9 @@
             row, self.factory_name, mode=mode)
         if 'transition' in row:
-            if row['transition'] not in IMPORTABLE_TRANSITIONS:
+            if row['transition'] not in IMPORTABLE_REGISTRATION_TRANSITIONS:
                 if row['transition'] not in (IGNORE_MARKER, ''):
                     errs.append(('transition', 'not allowed'))
         if 'state' in row:
-            if row['state'] not in IMPORTABLE_STATES:
+            if row['state'] not in IMPORTABLE_REGISTRATION_STATES:
                 if row['state'] not in (IGNORE_MARKER, ''):
                     errs.append(('state', 'not allowed'))
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py	(revision 12089)
@@ -35,5 +35,6 @@
 from waeup.ikoba.interfaces import (
     IContactForm, IObjectHistory, IIkobaObject, IIkobaUtils,
-    IPasswordValidator, IUserAccount)
+    IPasswordValidator, IUserAccount,
+    VERIFIED, REJECTED, EXPIRED)
 from waeup.ikoba.browser.layout import (
     IkobaPage, IkobaEditFormPage, IkobaAddFormPage, IkobaDisplayFormPage,
@@ -46,5 +47,4 @@
 from waeup.ikoba.browser.interfaces import ICaptchaManager
 from waeup.ikoba.mandates.mandate import PasswordMandate
-from waeup.ikoba.documents.workflow import VERIFIED, REJECTED, OUTDATED
 from waeup.ikoba.utils.helpers import get_current_principal, to_timezone, now
 from waeup.ikoba.customers.interfaces import (
@@ -754,5 +754,5 @@
             return True
         return (self.request.principal.user_type == 'customer' and \
-            document.state in (VERIFIED, REJECTED, OUTDATED))
+            document.state in (VERIFIED, REJECTED, EXPIRED))
 
     @property
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/interfaces.py	(revision 12089)
@@ -265,10 +265,10 @@
 
 class ICustomerDocument(IDocument):
-    """A customer document.
-
-    """
-
-    #is_editable = Attribute('Document editable by customer')
-    #translated_class_name = Attribute('Translatable class name')
+    """A customer document object.
+
+    """
+
+    is_editable = Attribute('Document editable by customer')
+    translated_class_name = Attribute('Translatable class name')
 
 
@@ -277,2 +277,37 @@
 
     """
+
+# Customer application interfaces
+
+class IApplicationsContainer(IIkobaObject):
+    """A container for customer aplication objects.
+
+    """
+
+    def addApplication(application):
+        """Add an application object.
+        """
+
+
+class IApplication(IIkobaObject):
+    """A customer application.
+
+    """
+    application_id = Attribute('Application Identifier')
+    history = Attribute('Object history, a list of messages')
+    state = Attribute('Returns the application state')
+    translated_state = Attribute(
+        'Returns a translated, more verbose appliction state')
+    class_name = Attribute('Name of the application class')
+    formatted_transition_date = Attribute('Last transition formatted date string')
+
+    title = schema.TextLine(
+        title = _(u'Application Title'),
+        required = True,
+        )
+
+    last_transition_date = schema.Datetime(
+        title = _(u'Last Transition Date'),
+        required = False,
+        readonly = False,
+        )
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_application.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_application.py	(revision 12089)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/tests/test_application.py	(revision 12089)
@@ -0,0 +1,91 @@
+## $Id$
+##
+## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+"""
+Tests for applications.
+"""
+from zope.interface.verify import verifyClass, verifyObject
+from zope.component import createObject
+from hurry.workflow.interfaces import (
+    IWorkflowInfo, IWorkflowState, InvalidTransitionError)
+from waeup.ikoba.customers.interfaces import (
+    IApplicationsContainer, IApplication)
+from waeup.ikoba.interfaces import IObjectHistory
+from waeup.ikoba.customers.applications import (
+    ApplicationsContainer, SampleApplication)
+from waeup.ikoba.testing import (FunctionalLayer, FunctionalTestCase)
+
+class ApplicationsContainerTestCase(FunctionalTestCase):
+
+    layer = FunctionalLayer
+
+    def test_interfaces(self):
+        # Make sure the correct interfaces are implemented.
+        self.assertTrue(
+            verifyClass(
+                IApplicationsContainer, ApplicationsContainer)
+            )
+        self.assertTrue(
+            verifyObject(
+                IApplicationsContainer, ApplicationsContainer())
+            )
+        self.assertTrue(
+            verifyClass(
+                IApplication, SampleApplication)
+            )
+        self.assertTrue(
+            verifyObject(
+                IApplication, SampleApplication())
+            )
+        return
+
+    def test_addApplication(self):
+        container = ApplicationsContainer()
+        application = createObject(u'waeup.SampleApplication')
+        id = application.application_id
+        container.addApplication(application)
+        self.assertEqual(container[id], application)
+        self.assertRaises(TypeError, container.addApplication, object())
+        self.assertEqual(application.class_name, 'SampleApplication')
+        self.assertEqual(id, 'a123')
+        return
+
+    def test_application_workflow(self):
+        application = createObject(u'waeup.SampleApplication')
+        IWorkflowInfo(application).fireTransition('create')
+        self.assertEqual(IWorkflowState(application).getState(), 'created')
+        IWorkflowInfo(application).fireTransition('submit')
+        self.assertEqual(IWorkflowState(application).getState(), 'submitted')
+        IWorkflowInfo(application).fireTransition('approve')
+        self.assertEqual(IWorkflowState(application).getState(), 'approved')
+        IWorkflowInfo(application).fireTransition('expire')
+        self.assertEqual(IWorkflowState(application).getState(), 'expired')
+        IWorkflowInfo(application).fireTransition('reset4')
+        self.assertEqual(IWorkflowState(application).getState(), 'created')
+        self.assertRaises(InvalidTransitionError,
+            IWorkflowInfo(application).fireTransition, 'approve')
+        IWorkflowInfo(application).fireTransition('submit')
+        IWorkflowInfo(application).fireTransition('reset3')
+        self.assertEqual(IWorkflowState(application).getState(), 'created')
+        return
+
+    def test_application_history(self):
+        doc = createObject(u'waeup.SampleApplication')
+        IWorkflowInfo(doc).fireTransition('create')
+        messages = ' '.join(doc.history.messages)
+        self.assertTrue('Application record created by system' in messages)
+        return
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/utils.py	(revision 12089)
@@ -266,4 +266,8 @@
         )
 
+def generate_application_id():
+    new_id = grok.getSite().unique_application_id
+    return new_id
+
 class CustomersUtils(grok.GlobalUtility):
     """A collection of methods subject to customization.
@@ -283,5 +287,5 @@
     APPMANAGE_CUSTOMER_STATES = DOCMANAGE_CUSTOMER_STATES
 
-    APPMANAGE_APPLICATION_STATES = (CREATED,)
+    APPMANAGE_APPLICATION_STATES = ()
 
     SKIP_UPLOAD_VIEWLETS = ()
@@ -292,4 +296,8 @@
         REQUESTED: _('requested'),
         APPROVED: _('approved'),
+        }
+
+
+    TRANSLATED_APPLICATION_STATES = {
         }
 
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/workflow.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/workflow.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/customers/workflow.py	(revision 12089)
@@ -1,3 +1,3 @@
-## $Id: batching.py 11891 2014-10-28 20:02:45Z henrik $
+## $Id$
 ##
 ## Copyright (C) 2014 Uli Fouquet & Henrik Bettermann
@@ -25,12 +25,17 @@
 from waeup.ikoba.interfaces import (
     IObjectHistory, IIkobaWorkflowInfo, IIkobaUtils,
-    STARTED, CREATED, REQUESTED, APPROVED)
+    STARTED, CREATED, REQUESTED, APPROVED,
+    SUBMITTED, VERIFIED, REJECTED, EXPIRED)
 from waeup.ikoba.interfaces import MessageFactory as _
 from waeup.ikoba.workflow import IkobaWorkflow, IkobaWorkflowInfo
-from waeup.ikoba.customers.interfaces import ICustomer, ICustomersUtils
+from waeup.ikoba.customers.interfaces import (
+    ICustomer, ICustomersUtils,
+    IApplication)
 from waeup.ikoba.utils.helpers import get_current_principal
-
-
-IMPORTABLE_STATES = (STARTED, REQUESTED, APPROVED)
+from waeup.ikoba.documents.workflow import VERIFICATION_TRANSITIONS
+
+# Customer workflow
+
+IMPORTABLE_REGISTRATION_STATES = (STARTED, REQUESTED, APPROVED)
 
 REGISTRATION_TRANSITIONS = (
@@ -96,5 +101,5 @@
 
 
-IMPORTABLE_TRANSITIONS = [i.transition_id for i in REGISTRATION_TRANSITIONS]
+IMPORTABLE_REGISTRATION_TRANSITIONS = [i.transition_id for i in REGISTRATION_TRANSITIONS]
 
 registration_workflow = IkobaWorkflow(REGISTRATION_TRANSITIONS)
@@ -136,2 +141,113 @@
         pass
     return
+
+# Application workflow (the same as verification workflow)
+
+IMPORTABLE_APPLICATION_STATES = (CREATED, SUBMITTED, APPROVED, REJECTED, EXPIRED)
+
+APPLICATION_TRANSITIONS = (
+    Transition(
+        transition_id = 'create',
+        title = _('Create application record'),
+        source = None,
+        condition = NullCondition,
+        msg = _('Application record created'),
+        destination = CREATED),
+
+    Transition(
+        transition_id = 'submit',
+        title = _('Submit for approval'),
+        msg = _('Submitted for approval'),
+        source = CREATED,
+        destination = SUBMITTED),
+
+    Transition(
+        transition_id = 'approve',
+        title = _('Approve'),
+        msg = _('Approved'),
+        source = SUBMITTED,
+        destination = APPROVED),
+
+    Transition(
+        transition_id = 'reject',
+        title = _('Reject'),
+        msg = _('REJECTED'),
+        source = SUBMITTED,
+        destination = REJECTED),
+
+    Transition(
+        transition_id = 'reset1',
+        title = _('Reset to initial state'),
+        msg = _('Reset to initial state'),
+        source = REJECTED,
+        destination = CREATED),
+
+    Transition(
+        transition_id = 'reset2',
+        title = _('Reset to initial state'),
+        msg = _('Reset to initial state'),
+        source = APPROVED,
+        destination = CREATED),
+
+    Transition(
+        transition_id = 'reset3',
+        title = _('Reset to initial state'),
+        msg = _('Reset to initial state'),
+        source = SUBMITTED,
+        destination = CREATED),
+
+    Transition(
+        transition_id = 'expire',
+        title = _('Set to expired'),
+        msg = _('Set to expired'),
+        source = APPROVED,
+        destination = EXPIRED),
+
+    Transition(
+        transition_id = 'reset4',
+        title = _('Reset to initial state'),
+        msg = _('Reset to initial state'),
+        source = EXPIRED,
+        destination = CREATED),
+    )
+
+
+IMPORTABLE_APPLICATION_TRANSITIONS = [
+    i.transition_id for i in REGISTRATION_TRANSITIONS]
+
+application_workflow = IkobaWorkflow(APPLICATION_TRANSITIONS)
+
+class ApplicationWorkflowState(WorkflowState, grok.Adapter):
+    """An adapter to adapt Application objects to workflow states.
+    """
+    grok.context(IApplication)
+    grok.provides(IWorkflowState)
+
+    state_key = 'wf.application.state'
+    state_id = 'wf.application.id'
+
+class ApplicationWorkflowInfo(IkobaWorkflowInfo, grok.Adapter):
+    """Adapter to adapt Application objects to workflow info objects.
+    """
+    grok.context(IApplication)
+    grok.provides(IIkobaWorkflowInfo)
+
+    def __init__(self, context):
+        self.context = context
+        self.wf = application_workflow
+
+@grok.subscribe(IApplication, IWorkflowTransitionEvent)
+def handle_document_transition_event(obj, event):
+    """Append message to application history and log file and update
+    last_transition_date when transition happened.
+    """
+    msg = event.transition.user_data['msg']
+    history = IObjectHistory(obj)
+    history.addMessage(msg)
+    obj.last_transition_date = datetime.utcnow()
+    try:
+        customers_container = grok.getSite()['customers']
+        customers_container.logger.info('%s - %s' % (obj.customer_id,msg))
+    except (TypeError, AttributeError):
+        pass
+    return
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/documents/utils.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/documents/utils.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/documents/utils.py	(revision 12089)
@@ -20,9 +20,8 @@
 import grok
 from waeup.ikoba.interfaces import MessageFactory as _
-from waeup.ikoba.documents.workflow import CREATED
+from waeup.ikoba.interfaces import (
+    CREATED, SUBMITTED,
+    VERIFIED, REJECTED, EXPIRED)
 from waeup.ikoba.documents.interfaces import IDocumentsUtils
-from waeup.ikoba.documents.workflow import (
-    CREATED, SUBMITTED,
-    VERIFIED, REJECTED, OUTDATED)
 
 
@@ -42,4 +41,4 @@
         VERIFIED: _('verified'),
         REJECTED: _('rejected'),
-        OUTDATED:_('outdated')
+        EXPIRED:_('expired')
         }
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/documents/workflow.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/documents/workflow.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/documents/workflow.py	(revision 12089)
@@ -25,5 +25,6 @@
 from waeup.ikoba.interfaces import (
     IObjectHistory, IIkobaWorkflowInfo,
-    SimpleIkobaVocabulary)
+    SimpleIkobaVocabulary,
+    CREATED, SUBMITTED, VERIFIED, REJECTED, EXPIRED)
 from waeup.ikoba.interfaces import MessageFactory as _
 from waeup.ikoba.workflow import IkobaWorkflow, IkobaWorkflowInfo
@@ -31,13 +32,7 @@
 from waeup.ikoba.documents.interfaces import IDocument
 
-CREATED = 'created'
-SUBMITTED = 'submitted'
-VERIFIED = 'verified'
-REJECTED = 'rejected'
-OUTDATED = 'outdated'
+IMPORTABLE_STATES = (CREATED, SUBMITTED, VERIFIED, REJECTED, EXPIRED)
 
-IMPORTABLE_STATES = (CREATED, SUBMITTED, VERIFIED, REJECTED)
-
-REGISTRATION_TRANSITIONS = (
+VERIFICATION_TRANSITIONS = (
     Transition(
         transition_id = 'create',
@@ -71,5 +66,5 @@
     Transition(
         transition_id = 'reset1',
-        title = _('Reset'),
+        title = _('Reset to initial state'),
         msg = _('Reset to initial state'),
         source = REJECTED,
@@ -78,5 +73,5 @@
     Transition(
         transition_id = 'reset2',
-        title = _('Reset'),
+        title = _('Reset to initial state'),
         msg = _('Reset to initial state'),
         source = VERIFIED,
@@ -85,5 +80,5 @@
     Transition(
         transition_id = 'reset3',
-        title = _('Reset'),
+        title = _('Reset to initial state'),
         msg = _('Reset to initial state'),
         source = SUBMITTED,
@@ -91,15 +86,22 @@
 
     Transition(
-        transition_id = 'outdate',
-        title = _('Set to outdated'),
-        msg = _('Set to outdated'),
+        transition_id = 'expire',
+        title = _('Set to expired'),
+        msg = _('Set to expired'),
         source = VERIFIED,
-        destination = OUTDATED),
+        destination = EXPIRED),
+
+    Transition(
+        transition_id = 'reset4',
+        title = _('Reset to initial state'),
+        msg = _('Reset to initial state'),
+        source = EXPIRED,
+        destination = CREATED),
     )
 
 
-IMPORTABLE_TRANSITIONS = [i.transition_id for i in REGISTRATION_TRANSITIONS]
+IMPORTABLE_TRANSITIONS = [i.transition_id for i in VERIFICATION_TRANSITIONS]
 
-verification_workflow = IkobaWorkflow(REGISTRATION_TRANSITIONS)
+verification_workflow = IkobaWorkflow(VERIFICATION_TRANSITIONS)
 
 class VerificationWorkflowState(WorkflowState, grok.Adapter):
Index: /main/waeup.ikoba/trunk/src/waeup/ikoba/interfaces.py
===================================================================
--- /main/waeup.ikoba/trunk/src/waeup/ikoba/interfaces.py	(revision 12088)
+++ /main/waeup.ikoba/trunk/src/waeup/ikoba/interfaces.py	(revision 12089)
@@ -45,8 +45,17 @@
 VIRT_JOBS_CONTAINER_NAME = 'jobs'
 
+# States for various workflows
+
 CREATED = 'created'
+
 STARTED = 'started'
 REQUESTED = 'requested'
 APPROVED = 'approved'
+
+SUBMITTED = 'submitted'
+VERIFIED = 'verified'
+REJECTED = 'rejected'
+EXPIRED = 'expired'
+
 
 #: A dict giving job status as tuple (<STRING>, <TRANSLATED_STRING>),
